4.8 KiB
title | layout | root | idx | redirect_from |
---|---|---|---|---|
Häufige Fehler | default | ../.. | 8.1 | /de/chapters/common_mistakes.html |
Einleitung
In diesem Kapitel werden häufige Fehler beschrieben und es wird erklärt, wie man diese vermeiden kann.
- Vorsicht beim Speichern von ObjectRefs (z.B.: Spieler oder Entitäten)
- Vertrauen Sie keinen Formspec-Einsendungen
- ItemStacks nach dem Ändern einstellen
Vorsicht beim Speichern von ObjectRefs (z.B.: Spieler oder Entitäten)
Eine ObjectRef wird ungültig, wenn der Spieler oder die Entität, die sie repräsentiert, das das Spiel verlässt. Dies kann passieren, wenn der Spieler offline geht oder die Entität nicht mehr geladen ist oder entfernt wird.
Die Methoden von ObjectRefs geben seit Minetest 5.2 immer nil
zurück, wenn sie ungültig sind. Jeder Aufruf wird grundsätzlich ignoriert.
Sie sollten das Speichern von ObjectRefs nach Möglichkeit vermeiden. Wenn Sie dennoch eine ObjectRef speichern, sollten Sie dies vor der Verwendung überprüfen, etwa so:
-- Funktioniert nur in Minetest 5.2+
if obj:get_pos() then
-- ist gültig!
end
Vertrauen Sie keinen Formspec-Einsendungen
Hacker können Formulare übermitteln, wann immer sie wollen und mit welchem Inhalt auch immer sie wollen.
Der folgende Code weist zum Beispiel eine Schwachstelle auf, die es Spielern ermöglicht sich selbst Moderatoren-Rechte zu geben:
local function show_formspec(name)
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
minetest.show_formspec(name, "modman:modman", [[
size[3,2]
field[0,0;3,1;target;Name;]
button_exit[0,1;3,1;sub;Promote]
]])
return true
})
minetest.register_on_player_receive_fields(function(player,
formname, fields)
-- SCHLECHT! Fehlender Privilegiencheck!
local privs = minetest.get_player_privs(fields.target)
privs.kick = true
privs.ban = true
minetest.set_player_privs(fields.target, privs)
return true
end)
Fügen Sie eine Berechtigungsprüfung hinzu, um dieses Problem zu lösen:
minetest.register_on_player_receive_fields(function(player,
formname, fields)
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
-- code
end)
ItemStacks nach dem Ändern einstellen
Haben Sie bemerkt, dass es in der API einfach ItemStack
genannt wird, nicht ItemStackRef
, ähnlich wie InvRef
? Das liegt daran, dass ein ItemStack
keine Referenz ist - es ist eine Kopie. Stacks arbeiten mit einer Kopie der Daten und nicht mit dem Stapel im Inventar. Das bedeutet, dass das Ändern eines Stacks nicht wirklich den Stack im Inventar verändert.
Tun Sie zum Beispiel nicht dies:
local inv = player:get_inventory()
local stack = inv:get_stack("main", 1)
stack:get_meta():set_string("description", "Teilweise gegessen")
-- SCHLECHT! Änderung wird verloren gehen
Machen Sie stattdessen Folgendes:
local inv = player:get_inventory()
local stack = inv:get_stack("main", 1)
stack:get_meta():set_string("description", "Teilweise gegessen")
inv:set_stack("main", 1, stack)
-- Richtig! ItemStack ist eingestellt!
Das Verhalten von Callbacks ist etwas komplizierter. Das Ändern eines ItemStack
, der zurückgegeben wird, ändert diesen auch für den Aufrufer und alle nachfolgenden Aufrufe. In jedem Fall wird der ItemStack jedoch nur dann in der Engine gespeichert, wenn der Callback-Aufrufer ihn setzt.
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Teilweise gegessen")
-- Fast richtig! Die Daten gehen verloren, wenn ein anderer
-- Callback das Verhalten abbricht
end)
Wenn keine Rückrufe diesen Vorgang abbrechen, wird der Stack gesetzt und die Beschreibung aktualisiert. Wenn jedoch ein Rückruf dies abbricht, kann die Aktualisierung verloren gehen.
Es ist besser, dies stattdessen zu tun:
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Teilweise gegessen")
user:get_inventory():set_stack("main", user:get_wield_index(),
itemstack)
-- Richtig, die Beschreibung wird immer eingestellt!
end)
Wenn die Callbacks abbrechen oder der Callback-Runner den Stack nicht setzt, dann wird die Aktualisierung trotzdem durchgeführt. Wenn die Rückrufe oder der Rückruf-Läufer den Stack setzen, spielt die Verwendung von set_stack keine Rolle.