minetest_modding_book/_de/map/storage.md

248 lines
8.5 KiB
Markdown
Raw Normal View History

2022-08-20 00:51:38 +03:00
---
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)
2022-08-20 14:26:38 +03:00
- [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)
2022-08-20 00:51:38 +03:00
- [Mod Storage](#mod-storage)
2022-08-20 14:26:38 +03:00
- [Datenbanken](#datenbanken)
- [Entscheidung, was man benutzt](#entscheidung-was-man-benutzt)
2022-08-20 14:26:38 +03:00
- [Sie sind dran](#sie-sind-dran)
2022-08-20 00:51:38 +03:00
## Metadaten
2022-08-20 00:51:38 +03:00
### 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.
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 14:26:38 +03:00
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
2022-11-04 20:33:30 +03:00
`owner` abgespeichert wird.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
Metadaten sind Daten über Daten.
Die Daten selbst, wie der Typ eines Blockes oder die Anzahl eines Stapels, sind keine Metadaten.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
### Abrufen eines Metadatenobjekts
2022-08-20 00:51:38 +03:00
Wenn Sie die Position eines Blockes kennen, können Sie seine Metadaten abrufen:
2022-08-20 00:51:38 +03:00
```lua
local meta = minetest.get_meta({ x = 1, y = 2, z = 3 })
```
2022-08-20 14:26:38 +03:00
Spieler- und ItemStack-Metadaten werden mit `get_meta()` ermittelt.:
2022-08-20 00:51:38 +03:00
```lua
local pmeta = player:get_meta()
local imeta = stack:get_meta()
```
2022-08-20 14:26:38 +03:00
### Lesen und Schreiben
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
```lua
print(meta:get_string("foo")) --> ""
meta:set_string("foo", "bar")
print(meta:get_string("foo")) --> "bar"
```
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
Die nicht typisierten Getter und Setter werden in und aus Strings konvertiert:
2022-08-20 00:51:38 +03:00
```lua
print(meta:get_int("count")) --> 0
meta:set_int("count", 3)
print(meta:get_int("count")) --> 3
print(meta:get_string("count")) --> "3"
```
2022-08-20 14:26:38 +03:00
### Besondere Schlüssel
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
`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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
`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.
2022-08-20 00:51:38 +03:00
`owner` ist ein allgemeiner Schlüssel, der verwendet wird, um den Benutzernamen des Spielers zu speichern,
der Eigentümer des Elements oder Blocks ist.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
### Speichern von Tabellen
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
Tabellen müssen in Strings umgewandelt werden, bevor sie gespeichert werden können.
Minetest bietet dafür zwei Formate an: Lua und JSON.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
```lua
2022-08-20 14:26:38 +03:00
local daten = { benutzername = "spieler1", punktestand = 1234 }
meta:set_string("foo", minetest.serialize(daten))
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
daten = minetest.deserialize(minetest:get_string("foo"))
2022-08-20 00:51:38 +03:00
```
2022-08-20 14:26:38 +03:00
### Private Metadaten
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
Standardmäßig werden alle Block-Metadaten an den Client gesendet.
Sie können Schlüssel als privat markieren, um dies zu verhindern.
2022-08-20 00:51:38 +03:00
```lua
2022-08-20 14:26:38 +03:00
meta:set_string("geheim", "asd34dn")
meta:mark_as_private("geheim")
2022-08-20 00:51:38 +03:00
```
2022-08-20 14:26:38 +03:00
### Lua Tabellen
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
Sie können mit `to_table` und `from_table` in und aus Lua-Tabellen konvertieren:
2022-08-20 00:51:38 +03:00
```lua
local tmp = meta:to_table()
tmp.foo = "bar"
meta:from_table(tmp)
```
## Mod Storage
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
```lua
local storage = minetest.get_mod_storage()
```
2022-08-20 14:26:38 +03:00
Sie können den Speicher nun genau wie Metadaten manipulieren:
2022-08-20 00:51:38 +03:00
```lua
storage:set_string("foo", "bar")
```
2022-08-20 14:26:38 +03:00
## Datenbanken
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
```lua
local backend
2022-08-20 14:26:38 +03:00
if verwende_datenbank then
2022-08-20 00:51:38 +03:00
backend =
2022-08-20 14:26:38 +03:00
dofile(minetest.get_modpath("meinemod") .. "/backend_sqlite.lua")
2022-08-20 00:51:38 +03:00
else
backend =
2022-08-20 14:26:38 +03:00
dofile(minetest.get_modpath("meinemod") .. "/backend_storage.lua")
2022-08-20 00:51:38 +03:00
end
backend.get_foo("a")
backend.set_foo("a", { score = 3 })
```
2022-08-20 14:26:38 +03:00
Die Datei backend_storage.lua sollte eine Mod-Storage-Implementierung enthalten:
2022-08-20 00:51:38 +03:00
```lua
local storage = minetest.get_mod_storage()
local backend = {}
2022-08-20 14:26:38 +03:00
function backend.set_foo(schluessel, wert)
storage:set_string(schluessel, minetest.serialize(wert))
2022-08-20 00:51:38 +03:00
end
2022-08-20 14:26:38 +03:00
function backend.get_foo(schluessel)
return minetest.deserialize(storage:get_string(schluessel))
2022-08-20 00:51:38 +03:00
end
return backend
```
Backend_sqlite würde eine ähnliche Funktion erfüllen, aber Sie sollten die Lua-Bibliothek *lsqlite3* verwenden
2022-08-20 14:26:38 +03:00
anstelle des Mod-Speichers.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
```lua
2022-08-20 14:26:38 +03:00
local uu = minetest.request_insecure_environment()
assert(uu, "Bitte fügen Sie meinemod zu secure.trusted_mods in den Einstellungen hinzu")
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
local _sql = uu.require("lsqlite3")
-- Andere Mods daran hindern, die globale sqlite3-Bibliothek zu verwenden
2022-08-20 00:51:38 +03:00
if sqlite3 then
sqlite3 = nil
end
```
2022-08-20 14:26:38 +03:00
Die Vermittlung von Wissen über SQL oder die Verwendung der lsqlite3-Bibliothek ist nicht Gegenstand dieses Buches.
2022-08-20 00:51:38 +03:00
## Entscheidung, was man benutzt
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
Datenbanken kommen nur für Server in Frage, da
2022-08-20 14:26:38 +03:00
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.
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
## Sie sind dran
2022-08-20 00:51:38 +03:00
2022-08-20 14:26:38 +03:00
* 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`.)