--- title: Häufige Fehler layout: default root: ../.. idx: 8.1 redirect_from: /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)](#be-careful-when-storing-objectrefs-ie-players-or-entities) - [Vertrauen Sie keinen Formspec-Einsendungen](#dont-trust-formspec-submissions) - [ItemStacks nach dem Ändern einstellen](#set-itemstacks-after-changing-them) ## 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: ```lua -- 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: ```lua 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: ```lua 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: ```lua 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: ```lua 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. ```lua 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: ```lua 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.