248 lines
8.5 KiB
Markdown
248 lines
8.5 KiB
Markdown
---
|
|
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 <!-- omit in toc -->
|
|
|
|
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 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:
|
|
|
|
```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_<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.
|
|
|
|
```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 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.
|
|
|
|
```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 Block-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.
|
|
|
|
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`.)
|