2018-04-03 15:11:27 +03:00
|
|
|
---
|
|
|
|
title: Common Mistakes
|
|
|
|
layout: default
|
2018-07-15 21:36:35 +03:00
|
|
|
root: ../..
|
2019-08-14 16:45:42 +03:00
|
|
|
idx: 8.1
|
2018-07-15 21:13:16 +03:00
|
|
|
redirect_from: /en/chapters/common_mistakes.html
|
2018-04-03 15:11:27 +03:00
|
|
|
---
|
|
|
|
|
2019-05-31 20:32:40 +03:00
|
|
|
## Introduction <!-- omit in toc -->
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-10-03 20:58:35 +03:00
|
|
|
This chapter details common mistakes, and how to avoid them.
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2020-12-24 16:25:31 +03:00
|
|
|
- [Be Careful When Storing ObjectRefs (ie: players or entities)](#be-careful-when-storing-objectrefs-ie-players-or-entities)
|
2019-05-31 20:32:40 +03:00
|
|
|
- [Don't Trust Formspec Submissions](#dont-trust-formspec-submissions)
|
|
|
|
- [Set ItemStacks After Changing Them](#set-itemstacks-after-changing-them)
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2020-12-24 16:25:31 +03:00
|
|
|
## Be Careful When Storing ObjectRefs (ie: players or entities)
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2020-12-24 16:25:31 +03:00
|
|
|
An ObjectRef is invalidated when the player or entity it represents leaves
|
|
|
|
the game. This may happen when the player goes offline, or the entity is unloaded
|
|
|
|
or removed.
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2020-12-24 16:25:31 +03:00
|
|
|
The methods of ObjectRefs will always return nil when invalid, since Minetest 5.2.
|
|
|
|
Any call will essentially be ignored.
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2020-12-24 16:25:31 +03:00
|
|
|
You should avoid storing ObjectRefs where possible. If you do to store an
|
2023-04-11 20:52:09 +03:00
|
|
|
ObjectRef, you should make sure you check it before use, like so:
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-09-19 14:04:51 +03:00
|
|
|
```lua
|
2020-12-24 16:25:31 +03:00
|
|
|
-- This only works in Minetest 5.2+
|
|
|
|
if obj:get_pos() then
|
|
|
|
-- is valid!
|
|
|
|
end
|
2018-09-19 14:04:51 +03:00
|
|
|
```
|
2018-04-03 15:11:27 +03:00
|
|
|
|
|
|
|
## Don't Trust Formspec Submissions
|
|
|
|
|
2018-10-27 05:10:37 +03:00
|
|
|
Malicious clients can submit formspecs whenever they like, with
|
|
|
|
whatever content they like.
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-10-27 05:10:37 +03:00
|
|
|
For example, the following code has a vulnerability which allows players to
|
2018-10-03 20:58:35 +03:00
|
|
|
give themselves moderator privileges:
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-09-19 14:04:51 +03:00
|
|
|
```lua
|
2018-04-03 15:11:27 +03:00
|
|
|
local function show_formspec(name)
|
2024-10-23 02:39:22 +03:00
|
|
|
if not core.check_player_privs(name, { privs = true }) then
|
2018-04-03 15:11:27 +03:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2024-10-23 02:39:22 +03:00
|
|
|
core.show_formspec(name, "modman:modman", [[
|
2018-04-03 15:11:27 +03:00
|
|
|
size[3,2]
|
|
|
|
field[0,0;3,1;target;Name;]
|
|
|
|
button_exit[0,1;3,1;sub;Promote]
|
|
|
|
]])
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
2024-10-23 02:39:22 +03:00
|
|
|
core.register_on_player_receive_fields(function(player,
|
2018-09-24 19:16:00 +03:00
|
|
|
formname, fields)
|
2018-04-03 15:11:27 +03:00
|
|
|
-- BAD! Missing privilege check here!
|
|
|
|
|
2024-10-23 02:39:22 +03:00
|
|
|
local privs = core.get_player_privs(fields.target)
|
2018-04-03 15:11:27 +03:00
|
|
|
privs.kick = true
|
|
|
|
privs.ban = true
|
2024-10-23 02:39:22 +03:00
|
|
|
core.set_player_privs(fields.target, privs)
|
2018-04-03 15:11:27 +03:00
|
|
|
return true
|
|
|
|
end)
|
2018-09-19 14:04:51 +03:00
|
|
|
```
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-10-03 20:58:35 +03:00
|
|
|
Add a privilege check to solve this:
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-09-19 14:04:51 +03:00
|
|
|
```lua
|
2024-10-23 02:39:22 +03:00
|
|
|
core.register_on_player_receive_fields(function(player,
|
2018-09-24 19:16:00 +03:00
|
|
|
formname, fields)
|
2024-10-23 02:39:22 +03:00
|
|
|
if not core.check_player_privs(name, { privs = true }) then
|
2018-04-03 15:11:27 +03:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
-- code
|
|
|
|
end)
|
2018-09-19 14:04:51 +03:00
|
|
|
```
|
2018-04-03 15:11:27 +03:00
|
|
|
|
|
|
|
## Set ItemStacks After Changing Them
|
|
|
|
|
2018-10-03 20:58:35 +03:00
|
|
|
Have you noticed that it's simply called an `ItemStack` in the API, not an `ItemStackRef`,
|
|
|
|
similar to `InvRef`? This is because an `ItemStack` isn't a reference - it's a
|
2018-04-12 03:06:07 +03:00
|
|
|
copy. Stacks work on a copy of the data rather than the stack in the inventory.
|
|
|
|
This means that modifying a stack won't actually modify that stack in the inventory.
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-10-03 20:58:35 +03:00
|
|
|
For example, don't do this:
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-09-19 14:04:51 +03:00
|
|
|
```lua
|
2018-04-03 15:11:27 +03:00
|
|
|
local inv = player:get_inventory()
|
|
|
|
local stack = inv:get_stack("main", 1)
|
|
|
|
stack:get_meta():set_string("description", "Partially eaten")
|
|
|
|
-- BAD! Modification will be lost
|
2018-09-19 14:04:51 +03:00
|
|
|
```
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-10-27 05:10:37 +03:00
|
|
|
Do this instead:
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-09-19 14:04:51 +03:00
|
|
|
```lua
|
2018-04-03 15:11:27 +03:00
|
|
|
local inv = player:get_inventory()
|
|
|
|
local stack = inv:get_stack("main", 1)
|
|
|
|
stack:get_meta():set_string("description", "Partially eaten")
|
|
|
|
inv:set_stack("main", 1, stack)
|
|
|
|
-- Correct! Item stack is set
|
2018-09-19 14:04:51 +03:00
|
|
|
```
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-10-03 20:58:35 +03:00
|
|
|
The behaviour of callbacks is slightly more complicated. Modifying an `ItemStack` you
|
2018-07-16 01:04:55 +03:00
|
|
|
are given will change it for the caller too, and any subsequent callbacks. However,
|
2018-04-03 15:11:27 +03:00
|
|
|
it will only be saved in the engine if the callback caller sets it.
|
|
|
|
|
2018-09-19 14:04:51 +03:00
|
|
|
```lua
|
2024-10-23 02:39:22 +03:00
|
|
|
core.register_on_item_eat(function(hp_change, replace_with_item,
|
2018-09-24 19:16:00 +03:00
|
|
|
itemstack, user, pointed_thing)
|
2018-04-03 15:11:27 +03:00
|
|
|
itemstack:get_meta():set_string("description", "Partially eaten")
|
2018-09-24 19:16:00 +03:00
|
|
|
-- Almost correct! Data will be lost if another
|
|
|
|
-- callback cancels the behaviour
|
2018-04-03 15:11:27 +03:00
|
|
|
end)
|
2018-09-19 14:04:51 +03:00
|
|
|
```
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-10-03 20:58:35 +03:00
|
|
|
If no callbacks cancel this, the stack will be set and the description will be updated,
|
2018-10-27 05:10:37 +03:00
|
|
|
but if a callback does cancel this, then the update may be lost.
|
2018-10-03 20:58:35 +03:00
|
|
|
|
|
|
|
It's better to do this instead:
|
2018-04-03 15:11:27 +03:00
|
|
|
|
2018-09-19 14:04:51 +03:00
|
|
|
```lua
|
2024-10-23 02:39:22 +03:00
|
|
|
core.register_on_item_eat(function(hp_change, replace_with_item,
|
2018-09-24 19:16:00 +03:00
|
|
|
itemstack, user, pointed_thing)
|
2018-04-03 15:11:27 +03:00
|
|
|
itemstack:get_meta():set_string("description", "Partially eaten")
|
2018-09-24 19:16:00 +03:00
|
|
|
user:get_inventory():set_stack("main", user:get_wield_index(),
|
|
|
|
itemstack)
|
2018-04-03 15:11:27 +03:00
|
|
|
-- Correct, description will always be set!
|
|
|
|
end)
|
2018-09-19 14:04:51 +03:00
|
|
|
```
|
2018-04-03 15:11:27 +03:00
|
|
|
|
|
|
|
If the callbacks cancel or the callback runner doesn't set the stack,
|
2018-10-03 20:58:35 +03:00
|
|
|
then the update will still be set.
|
|
|
|
If the callbacks or the callback runner set the stack, then the use of
|
2018-05-01 02:00:27 +03:00
|
|
|
set_stack doesn't matter.
|