minetest_modding_book/_de/map/storage.md
2022-11-04 18:33:30 +01:00

8.5 KiB

title layout root idx description redirect_from
Storage und Metadaten default ../.. 3.3 Mod Storage, NodeMetaRef (get_meta).
/de/chapters/node_metadata.html
/de/map/node_metadata.html

Einleitung

In diesem Kapitel erfahren Sie, wie Sie Daten speichern können.

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 Block, 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 Block-Metadaten verwendet, um den Tooltip zu speichern, der angezeigt wird, wenn man mit dem Fadenkreuz über den Block 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 Blockes oder die Anzahl eines Stapels, sind keine Metadaten.

Abrufen eines Metadatenobjekts

Wenn Sie die Position eines Blockes kennen, können Sie seine Metadaten abrufen:

local meta = minetest.get_meta({ x = 1, y = 2, z = 3 })

Spieler- und ItemStack-Metadaten werden mit get_meta() ermittelt.:

local pmeta = player:get_meta()
local imeta = stack:get_meta()

Lesen und Schreiben

In den meisten Fällen werden die Methoden get_<type>() und set_<type>() zum Lesen und zum schreiben in Metadaten verwendet . Metadaten speichern Strings, so dass die String-Methoden direkt den Wert setzen und holen.

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:

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 Block-Metadaten verwendet, um einen Tooltip anzuzeigen, wenn das Fadenkreuz über einem Block schwebt. Dies ist nützlich, um die Eigentümerschaft oder den Status eines Blockes 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 Blocks 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.

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 Block-Metadaten an den Client gesendet. Sie können Schlüssel als privat markieren, um dies zu verhindern.

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:

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.

local storage = minetest.get_mod_storage()

Sie können den Speicher nun genau wie Metadaten manipulieren:

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.

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:

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 behandelt.

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.

Block-Metadaten sind eine gute Wahl, wenn Sie blockbezogene 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 Block, der verschwindet, nachdem er fünfmal geschlagen wurde. (Verwenden Sie on_punch in der Definition des Blockes und minetest.set_node.)