--- title: Storage und Metadaten layout: default root: ../.. idx: 3.3 description: Mod Storage, NodeMetaRef (get_meta). redirect_from: - /de/chapters/node_metadata.html - /de/map/node_metadata.html --- ## Einleitung In diesem Kapitel erfahren Sie, wie Sie Daten speichern können. - [Metadaten](#metadaten) - [Was sind Metadaten?](#was-sind-metadaten) - [Abrufen eines Metadatenobjekts](#abrufen-eines-metadatenobjekts) - [Lesen und Schreiben](#lesen-und-schreiben) - [Besondere Schlüssel](#besondere-schlüssel) - [Speichern von Tabellen](#speichern-von-tabellen) - [Private Metadaten](#private-metadaten) - [Lua Tabellen](#lua-tabellen) - [Mod Storage](#mod-storage) - [Datenbanken](#datenbanken) - [Entscheidung, was man benutzt](#entscheidung-was-man-benutzt) - [Sie sind dran](#sie-sind-dran) ## Metadaten ### Was sind Metadaten? In Minetest sind Metadaten ein Key-Value-Speicher, der verwendet wird, um benutzerdefinierte Daten an etwas anzuhängen. Sie können Metadaten verwenden, um Informationen zu einem Node, Spieler oder ItemStack zu speichern. Jede Art von Metadaten verwendet genau dieselbe API. Metadaten speichern Werte als Strings, aber es gibt eine Reihe von Methoden um andere primitive Typen zu konvertieren und zu speichern. Einige Schlüssel in Metadaten können eine besondere Bedeutung haben. Zum Beispiel wird `infotext` in den Node-Metadaten verwendet, um den Tooltip zu speichern, der angezeigt wird, wenn man mit dem Fadenkreuz über den Node fährt. Um Konflikte mit anderen Mods zu vermeiden, sollten Sie die Standard-Namensraum Konvention für Schlüssel verwenden: `Modname:Schlüsselname`. Die Ausnahme sind konventionelle Daten wie der Name des Besitzers, der als `owner` abgespeichert wird. Metadaten sind Daten über Daten. Die Daten selbst, wie der Typ eines Nodes oder die Anzahl eines Stapels, sind keine Metadaten. ### Abrufen eines Metadatenobjekts Wenn Sie die Position eines Nodes kennen, können Sie seine Metadaten abrufen: ```lua local meta = minetest.get_meta({ x = 1, y = 2, z = 3 }) ``` Spieler- und ItemStack-Metadaten werden mit `get_meta()` ermittelt.: ```lua local pmeta = player:get_meta() local imeta = stack:get_meta() ``` ### Lesen und Schreiben In den meisten Fällen werden die Methoden `get_()` und `set_()` zum Lesen und zum schreiben in Metadaten verwendet . Metadaten speichern Strings, so dass die String-Methoden direkt den Wert setzen und holen. ```lua print(meta:get_string("foo")) --> "" meta:set_string("foo", "bar") print(meta:get_string("foo")) --> "bar" ``` Alle typisierten Getter geben einen neutralen Standardwert zurück, wenn der Schlüssel nicht nicht existiert, wie zum Beispiel `""` oder `0`. Sie können `get()` verwenden, um einen String oder nil zurückzugeben. Da es sich bei Metadaten um eine Referenz handelt, werden alle Änderungen automatisch in der Quelle aktualisiert. ItemStacks sind jedoch keine Referenzen, daher müssen Sie den Itemstack im Inventar aktualisieren. Die nicht typisierten Getter und Setter werden in und aus Strings konvertiert: ```lua print(meta:get_int("count")) --> 0 meta:set_int("count", 3) print(meta:get_int("count")) --> 3 print(meta:get_string("count")) --> "3" ``` ### Besondere Schlüssel `infotext` wird in Node-Metadaten verwendet, um einen Tooltip anzuzeigen, wenn das Fadenkreuz über einem Node schwebt. Dies ist nützlich, um die Eigentümerschaft oder den Status eines Nodes anzuzeigen. `description` wird in ItemStack-Metadaten verwendet, um die Beschreibung zu überschreiben, wenn der Mauszeiger über den Stack in einem Inventar bewegt wird. Sie können Farben verwenden, indem Sie sie mit `minetest.colorize()` kodieren. `owner` ist ein allgemeiner Schlüssel, der verwendet wird, um den Benutzernamen des Spielers zu speichern, der Eigentümer des Elements oder Node ist. ### Speichern von Tabellen Tabellen müssen in Strings umgewandelt werden, bevor sie gespeichert werden können. Minetest bietet dafür zwei Formate an: Lua und JSON. Die Lua-Methode ist in der Regel viel schneller und entspricht dem Format, das Lua für Tabellen verwendet, während JSON ein standardisierteres Format ist, das besser strukturiert und sich gut für den Austausch von Informationen mit einem anderen Programm eignet. ```lua local daten = { benutzername = "spieler1", punktestand = 1234 } meta:set_string("foo", minetest.serialize(daten)) daten = minetest.deserialize(minetest:get_string("foo")) ``` ### Private Metadaten Standardmäßig werden alle Node-Metadaten an den Client gesendet. Sie können Schlüssel als privat markieren, um dies zu verhindern. ```lua meta:set_string("geheim", "asd34dn") meta:mark_as_private("geheim") ``` ### Lua Tabellen Sie können mit `to_table` und `from_table` in und aus Lua-Tabellen konvertieren: ```lua local tmp = meta:to_table() tmp.foo = "bar" meta:from_table(tmp) ``` ## Mod Storage Mod-Storage verwendet genau dieselbe API wie Metadaten, obwohl sie technisch gesehen keine Metadaten sind. Mod-Speicher ist pro Mod und kann nur während der Ladezeit abgefragt werden, um zu wissen, welche Mod sie anfordert. ```lua local storage = minetest.get_mod_storage() ``` Sie können den Speicher nun genau wie Metadaten manipulieren: ```lua storage:set_string("foo", "bar") ``` ## Datenbanken Wenn der Mod wahrscheinlich auf einem Server verwendet wird und viele Daten speichert, ist es eine gute Idee, eine Datenbank-Speichermethode anzubieten. Sie sollten dies optional machen, indem Sie trennen, wie die Daten gespeichert werden und wo sie verwendet werden. ```lua local backend if verwende_datenbank then backend = dofile(minetest.get_modpath("meinemod") .. "/backend_sqlite.lua") else backend = dofile(minetest.get_modpath("meinemod") .. "/backend_storage.lua") end backend.get_foo("a") backend.set_foo("a", { score = 3 }) ``` Die Datei backend_storage.lua sollte eine Mod-Storage-Implementierung enthalten: ```lua local storage = minetest.get_mod_storage() local backend = {} function backend.set_foo(schluessel, wert) storage:set_string(schluessel, minetest.serialize(wert)) end function backend.get_foo(schluessel) return minetest.deserialize(storage:get_string(schluessel)) end return backend ``` Backend_sqlite würde eine ähnliche Funktion erfüllen, aber Sie sollten die Lua-Bibliothek *lsqlite3* verwenden anstelle des Mod-Speichers. Die Verwendung einer Datenbank wie SQLite erfordert die Verwendung einer unsicheren Umgebung. Eine unsichere Umgebung ist eine Tabelle, die nur für Mods verfügbar ist, die vom Benutzer explizit auf eine Whitelist gesetzt wurden, und sie enthält eine weniger eingeschränkte Kopie der Lua-API, die missbraucht werden könnte, wenn sie böswilligen Mods zur Verfügung stünde. Unsichere Umgebungen werden im Detail in dem Kapitel [Sicherheit](../quality/security.html) behandelt. ```lua local uu = minetest.request_insecure_environment() assert(uu, "Bitte fügen Sie meinemod zu secure.trusted_mods in den Einstellungen hinzu") local _sql = uu.require("lsqlite3") -- Andere Mods daran hindern, die globale sqlite3-Bibliothek zu verwenden if sqlite3 then sqlite3 = nil end ``` Die Vermittlung von Wissen über SQL oder die Verwendung der lsqlite3-Bibliothek ist nicht Gegenstand dieses Buches. ## Entscheidung, was man benutzt Welche Methode Sie verwenden, hängt davon ab, worum es sich bei den Daten handelt, wie sie formatiert sind und wie groß sie sind. Als Richtlinie gilt, dass kleine Daten bis zu 10K, mittlere Daten bis zu 10MB und große Daten jede Größe darüber sind. Node-Metadaten sind eine gute Wahl, wenn Sie nodebezogene Daten speichern müssen. Die Speicherung mittlerer Daten ist recht effizient, wenn Sie sie privat machen. Item-Metadaten sollten nur zum Speichern kleiner Datenmengen verwendet werden, da es nicht möglich ist, sie an den Client zu senden. Die Daten werden auch jedes Mal kopiert, wenn der Stack verschoben oder von Lua aus aufgerufen wird. Mod-Storage ist gut für mittlere Daten, aber das Schreiben großer Daten kann ineffizient sein. Es ist besser, eine Datenbank für große Daten zu verwenden, um zu vermeiden, dass alle Daten bei jedem Speichern geschrieben werden müssen. Datenbanken kommen nur für Server in Frage, da der Mod auf eine Whitelist gesetzt werden muss, um auf eine unsichere Umgebung zugreifen zu können. Sie sind gut geeignet für große Datenmengen. ## Sie sind dran * Erstellen Sie einen Node, der verschwindet, nachdem er fünfmal geschlagen wurde. (Verwenden Sie `on_punch` in der Definition des Nodes und `minetest.set_node`.)