minetest_modding_book/_de/players/formspecs.md

383 lines
15 KiB
Markdown
Raw Normal View History

2022-08-30 13:10:38 +03:00
---
title: GUIs (Formspecs)
layout: default
root: ../..
idx: 4.5
description: Lerne, wie man GUIs mit formspecs anzeigt
redirect_from: /de/chapters/formspecs.html
submit_vuln:
level: warning
title: Malicious clients can submit anything at anytime
2022-09-18 18:43:26 +03:00
message: Sie sollten niemals einer formspec-Übermittlung vertrauen. Ein böswilliger Client
kann jederzeit alles übermitteln, was er will - auch wenn Sie ihm nie die
den formspec gezeigt haben. Das bedeutet, dass Sie die Berechtigungen prüfen sollten
und sicherstellen, dass sie die Aktion durchführen dürfen.
2022-08-30 13:10:38 +03:00
---
## Einleitung <!-- omit in toc -->
<figure class="right_image">
<img src="{{ page.root }}//static/formspec_example.png" alt="Ofen-Inventar">
<figcaption>
Screenshot eines formspec für Öfen, beschriftet.
</figcaption>
</figure>
2022-11-30 20:37:49 +03:00
In diesem Kapitel werden wir lernen, wie man einen Formspec erstellt und ihn dem Benutzer anzeigt.
Ein Formspec ist der Spezifikationscode für ein Form.
2022-08-31 22:33:54 +03:00
In Minetest sind Forms Fenster wie das Spielerinventar und können eine
eine Vielzahl von Elementen wie Beschriftungen, Schaltflächen und Felder enthalten.
Beachten Sie, dass Sie, wenn Sie keine Benutzereingaben benötigen, zum Beispiel wenn Sie nur
Informationen für den Spieler bereitstellen möchten, Sie die Verwendung von
2022-11-30 20:37:49 +03:00
[Heads Up Display (HUD)](hud.html)-Elementen anstelle von Formspecs verwenden sollten, da
2022-08-31 22:33:54 +03:00
unerwartete Fenster das Spielgeschehen stören können.
- [Reale oder Legacy-Koordinaten](#reale-oder-legacy-koordinaten)
- [Anatomie eines formspecs](#anatomie-eines-a-formspecs)
- [Elemente](#elemente)
2022-08-30 13:10:38 +03:00
- [Header](#header)
2022-09-18 18:43:26 +03:00
- [Ratespiel](#ratespiel)
- [Padding und Abstände](#padding-und-abstände)
- [Empfang von Formspec-Übermittlungen](#empfang-von-formspec-übermittlungen)
2022-08-30 13:10:38 +03:00
- [Contexts](#contexts)
2022-09-18 18:43:26 +03:00
- [Formspec-Quellen](#formspec-quellen)
2022-08-30 13:10:38 +03:00
- [Node Meta Formspecs](#node-meta-formspecs)
2022-09-18 18:43:26 +03:00
- [Spieler Inventar Formspecs](#spieler-inventar-formspecs)
- [Sie sind dran](#sie-sind-dran)
2022-08-30 13:10:38 +03:00
2022-08-31 22:33:54 +03:00
## Reale oder Legacy-Koordinaten
2022-08-30 13:10:38 +03:00
2022-11-30 20:37:49 +03:00
In älteren Versionen von Minetest waren die Formspecs inkonsistent. Wegen der Art und Weise, wie verschiedene
Elemente auf unerwartete Art und Weise positioniert wurden war es schwierig, die
Platzierung der Elemente vorherzusagen und auszurichten. Minetest 5.1.0 enthält eine Funktion namens
2022-08-31 22:33:54 +03:00
Koordinaten, die dieses Problem durch die Einführung eines konsistenten
2022-11-30 20:37:49 +03:00
Koordinatensystem beheben. Die Verwendung von realen Koordinaten wird dringend empfohlen, und deshalb
2022-08-31 22:33:54 +03:00
dieses Kapitel ausschließlich diese verwenden.
2022-08-30 13:10:38 +03:00
2022-08-31 22:33:54 +03:00
Die Verwendung einer formspec_version von 2 oder höher aktiviert reale Koordinaten.
2022-08-30 13:10:38 +03:00
2022-08-31 22:33:54 +03:00
## Anatomie eines formspecs
2022-08-30 13:10:38 +03:00
2022-08-31 22:33:54 +03:00
### Elemente
2022-08-30 13:10:38 +03:00
2022-08-31 22:33:54 +03:00
Formspec ist eine domänenspezifische Sprache mit einem ungewöhnlichen Format.
Sie besteht aus einer Reihe von Elementen mit der folgenden Form:
2022-08-30 13:10:38 +03:00
type[param1;param2]
2022-08-31 22:33:54 +03:00
Der Elementtyp wird deklariert und dann werden alle Parameter
in eckigen Klammern angegeben. Mehrere Elemente können miteinander verbunden werden, oder
auf mehrere Zeilen verteilt werden, etwa so:
2022-08-30 13:10:38 +03:00
foo[param1]bar[param1]
bo[param1]
2022-11-30 20:37:49 +03:00
Elemente sind Elemente wie Textfelder oder Schaltflächen oder können Metadaten wie Größe
oder Hintergrund sein. Sie sollten nachschlagen in der
[lua_api.txt 🇬🇧](https://minetest.gitlab.io/minetest/formspec/)
2022-08-31 22:33:54 +03:00
für eine Liste aller möglichen Elemente.
2022-08-30 13:10:38 +03:00
### Header
2022-11-30 20:37:49 +03:00
Der Header eines Formspec enthält Informationen, die zuerst erscheinen müssen. Diese
umfasst die Größe des Formspec, die Position, den Anker und ob das
2022-08-31 22:33:54 +03:00
spielweite Thema angewendet werden soll.
2022-08-30 13:10:38 +03:00
2022-08-31 22:33:54 +03:00
Die Elemente im Header müssen in einer bestimmten Reihenfolge definiert werden, sonst
2022-11-30 20:37:49 +03:00
wird ein Fehler angezeigt. Diese Reihenfolge ist im obigen Absatz angegeben und - wie immer -
2022-08-31 22:33:54 +03:00
in der Lua-API-Referenz dokumentiert.
2022-08-30 13:10:38 +03:00
2022-11-30 20:37:49 +03:00
Die Größe wird in Formspec-Slots angegeben - eine Maßeinheit, die etwa
64 Pixeln entspricht, jedoch abhängig von der Bildschirmdichte und den Skalierungs
2022-08-31 22:33:54 +03:00
Einstellungen des Clients ist. Hier ist ein formspec mit der Größe "2,2":
2022-08-30 13:10:38 +03:00
formspec_version[4]
size[2,2]
2022-11-30 20:37:49 +03:00
Beachten Sie, dass wir die Formspec-Sprachversion ausdrücklich definiert haben müssen.
2022-08-31 22:33:54 +03:00
Ohne dies wird stattdessen das Altsystem verwendet - was
die Verwendung der konsistenten Elementpositionierung und anderer neuer Funktionen verhindert.
2022-08-30 13:10:38 +03:00
2022-11-30 20:37:49 +03:00
Die Elemente position und anchor werden verwendet, um das Formspec auf dem Bildschirm zu platzieren.
2022-08-31 22:33:54 +03:00
Die Position legt fest, wo auf dem Bildschirm das formspec sein wird, und ist standardmäßig auf
die Mitte (`0,5,0,5`). Der Anker legt fest, wo auf dem formspec die Position ist,
2022-11-30 20:37:49 +03:00
so dass Sie das Formspec mit dem Rand des Bildschirms ausrichten können. Das Formspec
2022-08-31 22:33:54 +03:00
kann auf diese Weise links vom Bildschirm platziert werden:
2022-08-30 13:10:38 +03:00
formspec_version[4]
size[2,2]
position[0,0.5]
anchor[0,0.5]
2022-11-30 20:37:49 +03:00
Dadurch wird der Anker an den linken mittleren Rand des Formspec-Feldes gesetzt, und die
2022-08-31 22:33:54 +03:00
Position dieses Ankers auf der linken Seite des Bildschirms.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
## Ratespiel
2022-08-30 13:10:38 +03:00
<figure class="right_image">
2022-09-18 18:43:26 +03:00
<img src="{{ page.root }}/static/formspec_guessing.png" alt="Rate-Formspec">
2022-08-30 13:10:38 +03:00
<figcaption>
2022-09-18 18:43:26 +03:00
Das Ratespiel formspec.
2022-08-30 13:10:38 +03:00
</figcaption>
</figure>
2022-09-18 18:43:26 +03:00
Der beste Weg, etwas zu lernen, ist, etwas zu machen, also lasst uns ein Ratespiel machen.
2022-11-30 20:37:49 +03:00
Das Prinzip ist einfach: Die Mod entscheidet sich für eine Zahl, und der Spieler
errät die Zahl. Die Mod sagt dann, ob die erratene Zahl höher oder niedriger ist als
2022-09-18 18:43:26 +03:00
die tatsächliche Zahl.
2022-08-30 13:10:38 +03:00
2022-11-30 20:37:49 +03:00
Zunächst erstellen wir eine Funktion, die den Formspec-Code erzeugt. Es ist gute Praxis, dies
2022-09-18 18:43:26 +03:00
zu tun, da es die Wiederverwendung an anderer Stelle erleichtert.
2022-08-30 13:10:38 +03:00
<div style="clear: both;"></div>
```lua
guessing = {}
function guessing.get_formspec(name)
2022-09-18 18:43:26 +03:00
-- TODO: Anzeige, ob die letzte Schätzung höher oder niedriger war
local text = "Ich denke an eine Zahl... Raten Sie mal!"
2022-08-30 13:10:38 +03:00
local formspec = {
"formspec_version[4]",
"size[6,3.476]",
"label[0.375,0.5;", minetest.formspec_escape(text), "]",
2022-09-18 18:43:26 +03:00
"field[0.375,1.25;5.25,0.8;nummer;Nummer;]",
"button[1.5,2.3;3,0.8;raten;Raten]"
2022-08-30 13:10:38 +03:00
}
2022-09-18 18:43:26 +03:00
-- table.concat ist schneller als String-Verkettung - `..`
2022-08-30 13:10:38 +03:00
return table.concat(formspec, "")
end
```
2022-09-18 18:43:26 +03:00
Im obigen Code platzieren wir ein Feld, eine Beschriftung und eine Schaltfläche.
2022-11-30 20:37:49 +03:00
Ein Feld erlaubt die Eingabe von Text und eine Schaltfläche dient zum
2022-09-18 18:43:26 +03:00
Absenden des Forms. Sie werden feststellen, dass die Elemente
sorgfältig positioniert sind, um Padding und Abstände hinzuzufügen, was später erklärt wird.
2022-08-30 13:10:38 +03:00
2022-11-30 20:37:49 +03:00
Als Nächstes wollen wir dem Spieler erlauben, den Formspec anzuzeigen. Der beste Weg, dies zu tun
2022-09-18 18:43:26 +03:00
ist die Verwendung von `show_formspec`:
2022-08-30 13:10:38 +03:00
```lua
function guessing.show_to(name)
minetest.show_formspec(name, "guessing:game", guessing.get_formspec(name))
end
minetest.register_chatcommand("game", {
func = function(name)
guessing.show_to(name)
end,
})
```
2022-11-30 20:37:49 +03:00
Die Funktion `show_formspec` akzeptiert einen Spielernamen, den Namen der Formspec und den
Formspec selbst. Der Formspec-Name sollte ein gültiger Itemname sein, d.h. im Format
2022-09-18 18:43:26 +03:00
`Modname:Gegenstandsname`.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
### Padding und Abstände
2022-08-30 13:10:38 +03:00
<figure class="right_image">
2022-09-18 18:43:26 +03:00
<img src="{{ page.root }}/static/formspec_padding_spacing.png" alt="Padding und Abstände">
2022-08-30 13:10:38 +03:00
<figcaption>
The guessing game formspec.
</figcaption>
</figure>
2022-11-30 20:37:49 +03:00
Padding ist der Abstand zwischen dem Rand des Formspec und seinem Inhalt oder zwischen nicht verwandten Elementen,
2022-09-18 18:43:26 +03:00
dargestellt in Rot. Abstand ist der Abstand zwischen zusammenhängenden Elementen, der blau dargestellt wird.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
Ein Padding von `0,375` und ein Abstand von `0,25` sind üblich.
2022-08-30 13:10:38 +03:00
<div style="clear: both;"></div>
2022-09-18 18:43:26 +03:00
### Empfang von Formspec-Übermittlungen
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
Wenn `show_formspec` aufgerufen wird, wird der formspec an den Client gesendet, um angezeigt zu werden.
2022-11-30 20:37:49 +03:00
Damit Formspecs nützlich sind, müssen Informationen vom Client zum Server zurückgeschickt werden.
2022-09-18 18:43:26 +03:00
Die Methode dafür heißt formspec field submission, und für `show_formspec` wird diese
Übermittlung über einen globalen Callback empfangen:
2022-08-30 13:10:38 +03:00
```lua
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "guessing:game" then
return
end
if fields.guess then
local pname = player:get_player_name()
2022-09-18 18:43:26 +03:00
minetest.chat_send_all(pname .. " riet " .. fields.number)
2022-08-30 13:10:38 +03:00
end
end)
```
2022-09-18 18:43:26 +03:00
Die in `minetest.register_on_player_receive_fields` angegebene Funktion wird
2022-11-30 20:37:49 +03:00
jedes Mal aufgerufen, wenn ein Benutzer ein Formular absendet. Die meisten Callbacks müssen den
2022-09-18 18:43:26 +03:00
an die Funktion übergebenen Formularnamen überprüfen und beenden, wenn es sich nicht um das richtige Form handelt; einige
müssen jedoch möglicherweise für mehrere Formulare oder für alle Formulare funktionieren.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
Der Parameter `fields` der Funktion ist eine Tabelle mit den vom Benutzer übermittelten Werten
Benutzer übermittelten Werte, die durch Zeichenketten indiziert sind. Benannte Elemente erscheinen in dem Feld unter ihrem eigenen
Namen, aber nur, wenn sie für das Ereignis, das die Übermittlung verursacht hat, relevant sind.
Ein Schaltflächenelement erscheint beispielsweise nur dann in Feldern, wenn die betreffende Schaltfläche
gedrückt wurde.
2022-08-30 13:10:38 +03:00
{% include notice.html notice=page.submit_vuln %}
2022-09-18 18:43:26 +03:00
Der formspec wird also an den Client gesendet, und der Client sendet Informationen zurück.
Der nächste Schritt besteht darin, den Zielwert irgendwie zu generieren und zu speichern, und die
die formspec auf der Grundlage von Schätzungen zu aktualisieren. Dies geschieht mit Hilfe eines Konzepts namens
2022-08-30 13:10:38 +03:00
"contexts".
### Contexts
2022-09-18 18:43:26 +03:00
In vielen Fällen möchten Sie, dass minetest.show_formspec Informationen
an den Callback weitergeben, die nicht an den Client gesendet werden sollen.
Dies könnte beinhalten dass ein Chat-Befehl aufgerufen wurde, oder worum es
in dem Dialog geht. In diesem Fall, der Zielwert, der gespeichert werden muss.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
Ein Context ist eine pro-Spieler-Tabelle zum Speichern von Informationen, und die Contexts für alle
Online-Spieler werden in einer dateilokalen Variablen gespeichert:
2022-08-30 13:10:38 +03:00
```lua
local _contexts = {}
local function get_context(name)
local context = _contexts[name] or {}
_contexts[name] = context
return context
end
2022-09-18 18:43:26 +03:00
minetest.register_on_leaveplayer(function(spieler)
_contexts[spieler:get_player_name()] = nil
2022-08-30 13:10:38 +03:00
end)
```
2022-09-18 18:43:26 +03:00
Als nächstes müssen wir den Show-Code ändern, um den Context zu aktualisieren
zu aktualisieren, bevor der Formspec angezeigt wird:
2022-08-30 13:10:38 +03:00
```lua
function guessing.show_to(name)
local context = get_context(name)
context.target = context.target or math.random(1, 10)
local fs = guessing.get_formspec(name, context)
minetest.show_formspec(name, "guessing:game", fs)
end
```
2022-09-18 18:43:26 +03:00
Wir müssen auch den Code für die Generierung von Formularen ändern, um den Context zu verwenden:
2022-08-30 13:10:38 +03:00
```lua
function guessing.get_formspec(name, context)
local text
if not context.guess then
text = "I'm thinking of a number... Make a guess!"
elseif context.guess == context.target then
text = "Hurray, you got it!"
elseif context.guess > context.target then
text = "Too high!"
else
text = "Too low!"
end
```
2022-11-30 20:37:49 +03:00
Beachten Sie, dass es gute Praxis ist, wenn `get_formspec` den Context nur liest und
überhaupt nicht zu aktualisiert. Dies kann die Funktion einfacher machen, und auch leichter zu testen.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
Und schließlich müssen wir den Handler aktualisieren, um den Context mit der Vermutung zu aktualisieren:
2022-08-30 13:10:38 +03:00
```lua
if fields.guess then
2022-09-18 18:43:26 +03:00
local name = spieler:get_player_name()
2022-08-30 13:10:38 +03:00
local context = get_context(name)
context.guess = tonumber(fields.number)
guessing.show_to(name)
end
```
2022-09-18 18:43:26 +03:00
## Formspec-Quellen
2022-08-30 13:10:38 +03:00
2022-11-30 20:37:49 +03:00
Es gibt drei verschiedene Möglichkeiten, wie ein Formspec an den Client übermittelt werden kann:
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
* [show_formspec](#ratespiel): Bei der oben beschriebenen Methode werden die Felder durch
`register_on_player_receive_fields` empfangen.
* [Node Meta Formspecs](#node-meta-formspecs): der Node enthält in seinen Metadaten eine Formularvorgabe,
und der Client zeigt es *sofort* an, wenn der Spieler mit der rechten Maustaste klickt. Felder werden
durch eine Methode in der Node-Definition namens `on_receive_fields` empfangen.
2022-11-30 20:37:49 +03:00
* [Player Inventory Formspecs](#spieler-inventar-formspecs): der Formspec wird irgendwann an den Client gesendet und dann
sofort angezeigt, wenn der Spieler auf "i" drückt. Felder werden durch
2022-09-18 18:43:26 +03:00
`register_on_player_receive_fields` empfangen.
2022-08-30 13:10:38 +03:00
### Node Meta Formspecs
2022-11-30 20:37:49 +03:00
`minetest.show_formspec` ist nicht die einzige Möglichkeit, einen Formspec anzuzeigen; Sie können auch
Formspecs zu den Metadaten eines [Nodes](node_metadata.html) hinzufügen. Zum Beispiel,
2022-09-18 18:43:26 +03:00
wird dieses bei Truhen verwendet, um ein schnelleres Öffnen zu ermöglichen -
2022-11-30 20:37:49 +03:00
man muss nicht darauf warten, dass der Server dem Spieler den Formspec für die Truhe schickt.
2022-08-30 13:10:38 +03:00
```lua
2022-09-18 18:43:26 +03:00
minetest.register_node("meinemod:rechtsclick", {
description = "Rechtsclicke me!",
tiles = {"mymod_rechtsclick.png"},
2022-08-30 13:10:38 +03:00
groups = {cracky = 1},
after_place_node = function(pos, placer)
2022-09-18 18:43:26 +03:00
-- Diese Funktion wird ausgeführt, wenn das Kisten-Node platziert wird.
-- Der folgende Code setzt den formspec für Kiste.
-- Meta ist eine Möglichkeit, Daten in einem Node zu speichern.
2022-08-30 13:10:38 +03:00
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
"formspec_version[4]" ..
"size[5,5]" ..
2022-09-18 18:43:26 +03:00
"label[1,1;Dies wird beim Rechtsklick angezeigt]" ..
2022-08-30 13:10:38 +03:00
"field[1,2;2,1;x;x;]")
end,
2022-09-18 18:43:26 +03:00
on_receive_fields = function(pos, formname, fields, spieler)
2022-08-30 13:10:38 +03:00
if fields.quit then
return
end
print(fields.x)
end
})
```
2022-11-30 20:37:49 +03:00
Auf diese Weise eingestellte Formspecs lösen nicht denselben Callback aus. Um
2022-09-18 18:43:26 +03:00
Formulareingaben für meta formspecs zu erhalten, müssen Sie einen
`on_receive_fields`-Eintrag bei der Registrierung des Nodes enthalten.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
Diese Art von Callback wird ausgelöst, wenn Sie die Eingabetaste
in einem Feld drücken, was mit `minetest.show_formspec` unmöglich ist;
2022-12-18 13:20:09 +03:00
diese Art von Formular kann jedoch nur durch Rechtsklick auf einen Node angezeigt werden. Sie kann nicht programmatisch ausgelöst werden.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
### Spieler Inventar Formspecs
2022-08-30 13:10:38 +03:00
2022-11-30 20:37:49 +03:00
Der Formspec für das Spielerinventar wird angezeigt, wenn der Spieler auf i drückt.
Der globale Callback wird verwendet, um Ereignisse von diesem Formspec zu empfangen, und der
2022-09-18 18:43:26 +03:00
formname ist `""`.
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
Es gibt eine Reihe von verschiedenen Mods, die es ermöglichen, das
das Spielerinventar anzupassen. Die offiziell empfohlene Mod ist
[Simple Fast Inventory (sfinv)](https://github.com/rubenwardy/sfinv/blob/master/Tutorial.md),
2022-11-30 20:37:49 +03:00
und ist in Minetest Game enthalten. Ich als Übersetzer empfehle jedoch
2022-09-18 18:43:26 +03:00
eher [i3](https://github.com/minetest-mods/i3) oder [unified inventory](https://github.com/minetest-mods/unified_inventory)
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
### Sie sind dran
2022-08-30 13:10:38 +03:00
2022-09-18 18:43:26 +03:00
* Erweitern Sie das Ratespiel, um die höchste Punktzahl jedes Spielers zu ermitteln, wobei
die höchste Punktzahl angibt, wie viele Ratschläge nötig waren.
2022-11-30 20:37:49 +03:00
* Erstellen Sie einen Node namens "Inbox", in dem Benutzer ein Formspec öffnen und Nachrichten hinterlassen können.
2022-09-18 18:43:26 +03:00
Dieser Node sollte den Namen des Placers als `owner` in der Meta speichern, und sollte
2022-11-30 20:37:49 +03:00
`show_formspec` verwenden, um verschiedene Formspecs für verschiedene Spieler anzuzeigen.