minetest_modding_book/_de/quality/common_mistakes.md

127 lines
4.8 KiB
Markdown
Raw Normal View History

2022-11-18 16:56:47 +03:00
---
title: Häufige Fehler
layout: default
root: ../..
idx: 8.1
redirect_from: /de/chapters/common_mistakes.html
---
## Einleitung <!-- omit in toc -->
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) <a name="be-careful-when-storing-objectrefs-ie-players-or-entities"></a>
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 <a name="dont-trust-formspec-submissions"></a>
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 <a name="set-itemstacks-after-changing-them"></a>
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.