Compare commits

...

104 Commits

Author SHA1 Message Date
rubenwardy
44efd61418 Fix various issues 2024-02-06 17:08:47 +00:00
debiankaios
4d3a39f6e4 Merge branch minetest_modding_book:master into master 2024-02-02 13:41:18 +00:00
debiankaios
8bc1ea85cc Renewed by Tuxilio 2024-02-02 14:35:54 +01:00
debiankaios
15d02fb757 Add WTFPL link 2023-08-27 21:57:15 +02:00
debiankaios
6d4201300c Merge branch minetest_modding_book:master into master 2023-08-27 19:52:07 +00:00
debiankaios
f0fa254acb Merge branch minetest_modding_book:master into master 2023-06-01 17:58:42 +00:00
debiankaios
f749e15834 Merge branch minetest_modding_book:master into master 2023-05-13 08:40:09 +00:00
debiankaios
11b543c5bc Merge branch minetest_modding_book:master into master 2023-05-03 15:43:37 +00:00
debiankaios
d584267768 Merge branch 'master' of https://gitlab.com/rubenwardy/minetest_modding_book 2023-04-29 17:21:18 +02:00
debiankaios
3fb9ef51c0 Removed english part which is already translated 2023-03-04 20:30:18 +01:00
debiankaios
3c947c771e Last review by Tuxilio 2022-12-18 11:20:09 +01:00
debiankaios
13eab9451c Reviewed and corrected quality/unit_testing.md
Neu im Wörterbuch:
Mocking = Mocking
2022-12-18 10:54:46 +01:00
debiankaios
5923659439 Reviewed and corrected 2 chapters
Reviewed and corrected chapters:
- quality/security.md 
- quality/clean_arch.md
Neu im Wörterbuch:
unsandboxed environment = unsandboxed Umgebung
Bemerkungen:
Lapce(Mein Editor) ist abgestürzt als ich am Ende von clean_arch.md war.
Zum Glück waren die vorherigen Dateien abgespeichert und der Anfang von
clean_arch.md auch. Allerdings ist der Rest von clean_arch.md aufgrund des
Absturzes nicht ganz so detailiert korrigiert wie geplant.
2022-12-18 10:30:23 +01:00
debiankaios
10b29f586d Reviewed and corrected 2 chapters
Reviewed and corrected chapters:
- quality/common_mistakes.md
- quality/luacheck.md
Neu im Wörterbuch:
callback runner = Callback-Runner
2022-12-17 13:12:34 +01:00
debiankaios
7bc375a1ba Reviewed and corrected quality/translations.md
Neu im Wörterbuch:
concatenation = Konkatenation
string = Zeichenkette
textdomain = Textdomäne
2022-12-16 18:19:25 +01:00
debiankaios
3c0c956278 Reviewed and corrected basics/script.md 2022-12-16 17:33:20 +01:00
debiankaios
76fc5e98b8 Reviewd and corrected basics/getting_started.md
Neu im Wörterbuch:
hard dependency = feste Abhängigkeit
optional dependency = Optionale Abhängigkeiten
2022-12-14 20:07:12 +01:00
debiankaios
e53b0c5f57 Added debiankaios at credits for reading correct 2022-12-13 18:53:23 +01:00
debiankaios
eb3c4076e1 Corrected biomesdeco.md
Neu im Wörterbuch:
Filler node = Füllender Node
mapgen = Mapgen
noise parameters = Noise-Parameter
Schematic Decoration = schematischen Dekoration
schematic = Schematic
Top node = Oberer Node
2022-12-13 18:52:14 +01:00
debiankaios
77e881533e Tuxilio replace much changed words 2022-12-13 17:27:27 +01:00
debiankaios
4a2e607b86 lvm.md corrected by Tuxilio 2022-12-11 17:42:17 +01:00
debiankaios
fea9965901 Corrections for Chapter 26 and 27 by Tuxilio(and me a bit in Chapter 26) 2022-12-10 21:43:08 +01:00
debiankaios
65188ee7bd getting_started.md and lua.md by Tuxilio and solars 2022-12-01 20:05:38 +01:00
debiankaios
1cd8463256 Translated readmore.md 2022-12-01 13:29:36 +01:00
debiankaios
b3d2b64295 Corrected formspecs.md 2022-11-30 18:37:49 +01:00
debiankaios
178e5046ec Corrected something 2022-11-30 18:25:41 +01:00
debiankaios
109aa282c8 Added clean_arch 2022-11-30 18:24:39 +01:00
debiankaios
91567c95e6 Tuxilio corrected hud.md 2022-11-30 18:14:26 +01:00
debiankaios
7292b14a63 gamer777 renamed to Tuxilio. Added that he translated. 2022-11-29 14:47:26 +01:00
debiankaios
7ca91f3c0b Added releasing.md and change two words in wörterbuch.txt. 2022-11-27 18:00:15 +01:00
debiankaios
8fb0813f5f All by gamer777:
- Translation of unit_testing.md
- 2 Corrections by him
2022-11-27 15:34:35 +01:00
debiankaios
b66cca5574 3 new chapters by gamer777 2022-11-18 14:56:47 +01:00
debiankaios
59ca8e3e89 Corrected another thing 2022-11-16 20:02:48 +01:00
debiankaios
6760145412 Corrected something i just saw 2022-11-16 20:01:22 +01:00
debiankaios
f11bcafd86 2 new chapters translated by gamer777 2022-11-16 19:54:59 +01:00
debiankaios
c32f3d7f5d gamer777 corrected games.md 2022-11-16 19:38:09 +01:00
debiankaios
69308b5b72 Corrected Link-Error? 2022-11-11 18:17:14 +01:00
debiankaios
90123c3a92 biomesdeco translated by gamer777 2022-11-11 18:15:35 +01:00
debiankaios
d49a20fa94 Added a new keyword. 2022-11-06 20:14:38 +01:00
debiankaios
d91c3478b8 Began and finished games.md 2022-11-06 20:08:32 +01:00
debiankaios
3b7e8b2a03 Fixed wrong URL 2022-11-06 19:41:16 +01:00
debiankaios
ad543a6074 Did the changes undo. 2022-11-06 18:58:53 +01:00
debiankaios
f22ff15f91 Fixed pipeline-problems(i hope) 2022-11-06 18:50:37 +01:00
debiankaios
a21769811d Corrections for 11 by gammer777 2022-11-05 16:24:31 +01:00
debiankaios
acf02b57e3 Finished hud.md 2022-11-04 19:02:23 +01:00
debiankaios
d8e0380f4d Corrections for 10 by me 2022-11-04 18:33:30 +01:00
debiankaios
d3be4a7ca9 Corrections for 8, 10 and 14 by gamer777 2022-11-04 18:32:01 +01:00
debiankaios
6057f8b331 Corections for Chapter 9, 12 and 13(9 didn't needed a change) by gamer777 2022-11-03 19:56:52 +01:00
debiankaios
9697e56b0e Continued on hud.md 2022-10-27 11:02:49 +02:00
debiankaios
912c615016 started with _de/players/hud.md 2022-09-29 21:41:23 +02:00
debiankaios
d52ac03d5d Merge branch 'master' of gitlab.com:debiankaios/minetest_modding_book 2022-09-18 17:45:46 +02:00
debiankaios
06b5765234 Finished translating formspec.md. 2022-09-18 17:43:26 +02:00
debiankaios
6fbcef5b06 Merge branch 'master' into 'master'
Erste Korrekturen

See merge request debiankaios/minetest_modding_book!1
2022-09-01 15:53:14 +00:00
jjk1
6667fa8c89 Erste Korrekturen 2022-09-01 15:53:13 +00:00
debiankaios
498669e55a continue with formspecs.md 2022-08-31 21:33:54 +02:00
debiankaios
a994ffc078 Began translating formspecs.md 2022-08-30 12:10:38 +02:00
debiankaios
89dd970f19 Translated player_physics.md 2022-08-29 13:36:20 +02:00
debiankaios
75ddb0097f Two errors corrected 2022-08-27 23:18:30 +02:00
debiankaios
3f195de1bf Finished chat.md 2022-08-27 23:15:25 +02:00
debiankaios
c1299491f9 Begann with chat.md 2022-08-28 00:40:57 +02:00
debiankaios
e2f2c32d1c Started and finished privileges.md 2022-08-24 19:37:33 +02:00
debiankaios
a51ef8cb98 Finished objects.md 2022-08-24 11:32:15 +02:00
debiankaios
42ee2a3ad8 Continued on objects.md, switching from Block to node 2022-08-22 23:11:17 +02:00
debiankaios
b70cc8329b Continue german translation 2022-08-22 17:14:18 +02:00
debiankaios
dcdf4c3520 Finished storage.md 2022-08-20 13:26:38 +02:00
debiankaios
a3eb294b25 Added storage.md 2022-08-19 23:51:38 +02:00
debiankaios
2b949d68f7 Finished enviroment.md 2022-08-19 13:26:42 +02:00
debiankaios
80319c51e5 Begann environment.md and revised wörterbuch.txt 2022-08-18 17:58:38 +02:00
debiankaios
cb1abbb7b4 Translated timers.md 2022-08-17 22:17:41 +02:00
debiankaios
797314ac03 else if → elseif 2022-08-16 22:16:31 +02:00
debiankaios
014188e0ae Translated on index.md Minetest Modding Book 2022-08-16 14:57:04 +02:00
debiankaios
02ab233deb Finished inventories.md 2022-08-16 13:34:53 +02:00
debiankaios
670ab06a97 Began with inventories.md and added a dictionary(wörterbuch.txt) 2022-08-16 00:05:44 +02:00
debiankaios
d7b830cc8c Removed wrong written link 2022-08-15 17:31:04 +02:00
debiankaios
a77c588056 Finished node_drawtypes.md 2022-08-15 17:01:12 +02:00
debiankaios
01f51293b4 Began translating node_drawtypes.md 2022-08-15 13:55:03 +02:00
debiankaios
b03eef9975 Found anything which was wrong written 2022-08-15 11:44:21 +02:00
debiankaios
63b316e81c Finished translating callbacks.md 2022-08-15 11:34:22 +02:00
debiankaios
7016856ade Begann with callbacks.md. 2022-08-15 00:20:20 +02:00
debiankaios
6b593aba7a Instead of frontcover now Titelseite 2022-08-14 23:09:53 +02:00
debiankaios
3fceb16011 Added main-page 2022-08-14 23:08:04 +02:00
debiankaios
ed62801f72 Added creating_textures.md 2022-08-14 17:12:01 +02:00
debiankaios
98e4b086b8 Entities instead of Entitäten 2022-08-14 12:09:33 +00:00
debiankaios
2c0083caa2 Fehler korrigiert 2022-08-14 12:06:00 +00:00
debiankaios
27c25e5dae Erstes Kapitel fertig übersetzt 2022-08-14 12:04:50 +00:00
debiankaios
dced156a02 Cooking and Fuel and Groups added 2022-08-14 10:40:30 +00:00
debiankaios
db22b08d25 Crafting-types added 2022-03-01 11:05:28 +00:00
debiankaios
17299b1485 Continue Working 2021-11-07 18:07:52 +01:00
debiankaios
711a717de9 Update nodes_items_crafting.md 2021-11-07 16:50:39 +00:00
debiankaios
c5c2b37895 Update nodes_items_crafting.md 2021-11-06 21:36:23 +00:00
debiankaios
17e8d9d6d3 Update nodes_items_crafting.md 2021-06-03 17:06:01 +00:00
debiankaios
c917af7d7d Finished Itemaliase 2021-05-14 08:25:47 +00:00
debiankaios
535a6a301c Adding more to Itemaliase 2021-05-14 08:06:11 +00:00
debiankaios
e6c71abfbd Added Itemaliase(not complete) 2021-05-14 08:00:14 +00:00
debiankaios
23abf10cc9 Update nodes_items_crafting.md 2021-05-14 07:50:15 +00:00
debiankaios
709caa181a Added "Items erstellen" 2021-05-14 07:49:05 +00:00
debiankaios
154b7c9b6b Update default.html 2021-05-13 20:14:24 +00:00
debiankaios
18a16f4a14 Update _config.yml 2021-05-13 20:07:22 +00:00
debiankaios
077b25da0d Update languages.yml 2021-05-13 20:06:36 +00:00
debiankaios
73b5a7a594 Update nodes_items_crafting.md 2021-05-13 20:02:59 +00:00
debiankaios
3974e9c7f6 Adding "Was sind Blöcke und Items?" 2021-05-13 20:01:45 +00:00
debiankaios
995f048576 Add new file 2021-05-13 19:45:46 +00:00
debiankaios
7d801918fa Starting with items 2021-05-13 19:39:37 +00:00
debiankaios
a8ac722de6 German translations(tranlations by debiankaios) 2021-05-13 19:38:45 +00:00
33 changed files with 5572 additions and 0 deletions

View File

@ -10,6 +10,8 @@ plugins:
- jekyll-redirect-from
collections:
de:
output: true
en:
output: true
it:

View File

@ -4,6 +4,10 @@
name: English (UK)
cta: This book is available in English
- code: de
name: Deutsch
cta: Das Buch ist in Deutsch verfügbar
- code: it
name: Italiano
cta: Questo libro è disponibile in italiano

204
_de/advmap/biomesdeco.md Normal file
View File

@ -0,0 +1,204 @@
---
title: Biome und Dekorationen
author: Shara
layout: default
root: ../..
idx: 6.1
description: Biome und Dekorationen erstellen lernen, um die Welt anzupassen.
---
## Einleitung <!-- omit in toc -->
Die Möglichkeit, Biome und Dekorationen zu registrieren, ist von entscheidender Bedeutung, wenn es darum geht, eine
interessante und abwechslungsreiche Umgebung im Spiel zu schaffen. In diesem Kapitel lernen Sie, Biome zu registrieren, die Verteilung der Biome zu steuern und Dekorationen in Biomen zu platzieren.
- [Was sind Biome?](#was-sind-biome)
- [Biom-Platzierung](#biom-platzierung)
- [Hitze und Feuchtigkeit](#hitze-und-feuchtigkeit)
- [Visualisierung von Grenzen mithilfe von Voronoi-Diagrammen](#visualisierung-von-grenzen-mithilfe-von-voronoi-diagrammen)
- [Erstellen eines Voronoi-Diagramms mithilfe von Geogebra](#erstellen-eines-voronoi-diagramms-mithilfe-von-geogebra)
- [Ein Biom registrieren](#ein-biom-registrieren)
- [Was sind Dekorationen?](#was-sind-dekorationen)
- [Registrierung einer einfachen Dekoration](#registrierung-einer-einfachen-dekoration)
- [Registrierung einer Schematischen Dekoration](#registrierung-einer-schematischen-dekoration)
- [Kartenerstellungs-Aliase (Mapgen Aliases)](#kartenerstellungs-aliase-mapgen-aliases)
## Was sind Biome?
Ein Minetest-Biom ist eine bestimmte Umgebung im Spiel. Wenn Sie Biome registrieren, können Sie können Sie die Arten von Nodes bestimmen, die während der Kartenerstellung darin erscheinen. Einige der gebräuchlichsten Nodetypen, die von Biom zu Biom variieren können, sind:
* Oberer Node: Dies ist der Node, der am häufigsten auf der Oberfläche zu finden ist. Ein bekanntes Beispiel wäre "Dirt with Grass", also "Erde mit Gras" aus dem Minetest-Grundspiel (Minetest Game).
* Füllender Node: Dies ist die Schicht unmittelbar unter dem obersten Node. In Biomen mit Gras ist dies oft Erde.
* Steinnode: Dies ist der Node, den man am häufigsten unter der Erde sieht.
* Wassernode: Dies ist normalerweise eine Flüssigkeit. Der Node erscheint dort,
wo man Wasserflächen erwarten würde.
Andere Arten von Nodes können auch zwischen den Biomen variieren und bieten die Möglichkeit, innerhalb desselben Spiels sehr unterschiedliche Umgebungen zu schaffen.
## Biom-Platzierung
### Hitze und Feuchtigkeit
Es reicht nicht aus, ein Biom zu registrieren; Sie müssen auch entscheiden, wo es im Spiel vorkommen kann. Dies geschieht, indem Sie jedem Biom einen Wärme- und einen Feuchtigkeitswert zuweisen.
Sie sollten sich diese Werte gut überlegen, denn diese Werte bestimmen, welche Biome nebeneinander liegen können. Schlechte Entscheidungen könnten dazu führen, dass zum Beispiel eine heiße Wüste an einen Gletscher grenzt, und andere unwahrscheinliche
Kombinationen, die Sie vielleicht lieber vermeiden möchten.
Im Spiel liegen die Wärme- und Feuchtigkeitswerte an jedem Punkt der Karte normalerweise zwischen 0 und 100. Die Werte ändern sich allmählich und steigen oder sinken, wenn Sie sich auf der Karte bewegen. Das Biom an einem bestimmten Punkt wird dadurch bestimmt, welches der registrierten Biome die Wärme- und Luftfeuchtigkeitswerte aufweisen, die den Werten an dieser Stelle der Karte am nächsten kommen.
Da sich die Wärme- und Luftfeuchtigkeitswerte allmählich ändern, ist es ratsam, den Biomen Wärme- und Luftfeuchtigkeitswerte auf der Grundlage vernünftiger Erwartungen über die Umgebung des Bioms zuzuordnen. Zum Beispiel:
* Eine Wüste könnte eine hohe Hitze und eine niedrige Luftfeuchtigkeit aufweisen.
* Ein verschneiter Wald könnte eine geringe Wärme und eine mittlere Luftfeuchtigkeit aufweisen.
* Ein Sumpfbiom würde im Allgemeinen eine hohe Luftfeuchtigkeit aufweisen.
In der Praxis bedeutet dies, dass die aneinander angrenzenden Biome eine logische Abfolge bilden, solange Sie eine Vielzahl von Biomen haben.
### Visualisierung von Grenzen mithilfe von Voronoi-Diagrammen
<figure class="right_image">
<img src="{{ page.root }}/static/biomes_voronoi.png" alt="Voronoi-Diagramm">
<figcaption>
Voronoi-Diagramm, das den nächstgelegenen Punkt zeigt.
<span class="credit">Von <a href="https://en.wikipedia.org/wiki/Voronoi_diagram#/media/File:Euclidean_Voronoi_diagram.svg">Balu Ertl</a>, CC BY-SA 4.0.</span>
</figcaption>
</figure>
Die Feinabstimmung von Wärme- und Feuchtigkeitswerten für Biome
ist einfacher, wenn Sie sich die Beziehung zwischen den von Ihnen verwendeten Biomen gut vorstellen können.
Dies ist besonders wichtig, wenn Sie einen vollständigen Satz Ihrer eigenen Biome erstellen, aber
kann auch hilfreich sein, wenn Sie ein Biom zu einem bestehenden Satz hinzufügen.
Am einfachsten lässt sich veranschaulichen, welche Biome möglicherweise gemeinsame Grenzen haben, indem Sie ein
Voronoi-Diagramm erstellen, das zeigt, welchem Punkt in einem 2-dimensionalen
Diagramm einer bestimmte Position am nächsten liegt.
Ein Voronoi-Diagramm kann aufzeigen, wo Biome, die aneinander grenzen sollten, dies nicht tun,
und wo Biome, die nicht aneinander grenzen sollten, dies tun. Es kann auch einen Einblick in die Häufigkeit der Biome im Spiel geben, wobei größere und zentralere Biome häufiger vorkommen als kleinere Biome oder Biome, die
am äußeren Rand des Diagramms liegen.
Dazu wird für jedes Biom ein Punkt auf der Grundlage von Wärme- und Feuchtigkeitswerten markiert,
wobei die x-Achse für die Wärme und die y-Achse für die Feuchtigkeit steht. Das Diagramm wird dann
in Bereiche unterteilt, so dass jede Position in einem bestimmten Bereich näher an dem
Punkt innerhalb dieses Bereichs näher ist als zu jedem anderen Punkt des Diagramms.
Jedes Gebiet stellt ein Biom dar. Wenn zwei Bereiche eine gemeinsame Grenze haben, können die Biome im Spiel nebeneinander liegen. Die Länge der Grenze zwischen zwei Gebieten im Vergleich zu der Länge, die sie mit anderen Gebieten teilen, zeigt an, wie häufig zwei Biome nebeneinander zu finden sein werden.
### Erstellen eines Voronoi-Diagramms mithilfe von Geogebra
Sie können Voronoi-Diagramme nicht nur von Hand zeichnen, sondern auch mit
Programmen wie [Geogebra](https://www.geogebra.org) erstellen.
1. Erstellen Sie Punkte, indem Sie das Punktwerkzeug in der Symbolleiste auswählen (Symbol ist ein Punkt mit 'A'),
und dann auf das Diagramm klicken. Sie können Punkte verschieben oder ihre Position explizit in der linken Seitenleiste festlegen. Zur besseren Übersichtlichkeit sollten Sie außerdem jedem Punkt eine Bezeichnung geben.
2. Erstellen Sie nun das Voronoi-Diagramm, indem Sie die folgende Funktion in das
Eingabefeld in der linken Seitenleiste eingeben:
```cpp
Voronoi({ A, B, C, D, E })
```
3. Fertig! Sie sollten nun ein Voronoi-Diagramm mit allen verschiebbaren Punkten haben.
## Ein Biom registrieren
Mit dem folgenden Code wird ein einfaches Biom mit dem Namen "grasslands" (Grasland-Biom) registriert:
```lua
minetest.register_biome({
name = "grasslands",
node_top = "default:dirt_with_grass",
depth_top = 1,
node_filler = "default:dirt",
depth_filler = 3,
y_max = 1000,
y_min = -3,
heat_point = 50,
humidity_point = 50,
})
```
Dieses Biom hat eine Schicht aus Erde mit GrasNode an der Oberfläche und drei Schichten von Erde-Node darunter. Es wird kein SteinNode angegeben, so dass der Node, der in der Kartenerstellung-Alias-Registrierung (mapgen alias registration) für "mapgen_stone" definiert ist, unter der Erde vorhanden sein wird.
Es gibt viele Optionen bei der Registrierung eines Bioms. Diese sind dokumentiert in der [Minetest Lua API Referenz 🇬🇧](https://minetest.gitlab.io/minetest/definition-tables/#biome-definition).
Sie müssen nicht jede Option für jedes Biom, das Sie erstellen, definieren, aber in einigen Fällen kann das Auslassen einer bestimmte Option oder einem geeigneten Kartenerstellungs-Alias (mapgen alias) zu Fehlern bei der Kartenerstellung führen.
## Was sind Dekorationen?
Dekorationen sind entweder Nodes oder Schematics, die bei der Kartenerstellung (mapgen) auf der Karte platziert werden können.
Einige gängige Beispiele sind Blumen, Sträucher und Bäume. Andere, kreativere Verwendungen sind z. B. hängende Eiszapfen oder Stalagmiten in Höhlen, unterirdische Kristallgebilde oder sogar die Platzierung von kleinen Gebäuden.
Dekorationen können auf bestimmte Biome, auf die Höhe oder auf die Nodepunkte beschränkt werden. Sie werden oft verwendet, um die Umgebung eines Bioms zu entwickeln,indem sie dafür sorgen, dass es bestimmte Pflanzen, Bäume oder andere Merkmale hat.
## Registrierung einer einfachen Dekoration
Einfache Dekorationen werden verwendet, um während der Kartenerstellung einzelne Nodedekorationen auf der Karte zu platzieren.
Sie müssen den Node angeben, der als Dekoration platziert werden soll, Angaben dazu, wo er platziert werden kann und wie häufig er vorkommt.
Zum Beispiel:
```lua
minetest.register_decoration({
deco_type = "simple",
place_on = {"base:dirt_with_grass"},
sidelen = 16,
fill_ratio = 0.1,
biomes = {"grassy_plains"},
y_max = 200,
y_min = 1,
decoration = "plants:grass",
})
```
In diesem Beispiel wird der Node mit dem Namen `plants:grass` im Biom mit dem Namen grassy_plains auf den Node `base:dirt_with_grass` platziert, zwischen den Höhen `y = 1` und `y = 200`.
Der Wert fill_ratio bestimmt, wie häufig die Dekoration erscheint, wobei höhere Werte bis 1 führen dazu, dass eine große Anzahl von Dekorationen platziert wird. Es ist möglich, stattdessen Noise-Parameter zu verwenden, um die Platzierung zu bestimmen.
## Registrierung einer Schematischen Dekoration
Schematic Dekorationen sind der einfachen Dekoration sehr ähnlich, beinhalten aber die Platzierung eines Schematics statt der Platzierung eines einzelnen Nodes, zum Beispiel:
```lua
minetest.register_decoration({
deco_type = "schematic",
place_on = {"base:desert_sand"},
sidelen = 16,
fill_ratio = 0.0001,
biomes = {"desert"},
y_max = 200,
y_min = 1,
schematic = minetest.get_modpath("plants") .. "/schematics/cactus.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
```
In diesem Beispiel wird das Schematic cactus.mts in Wüstenbiomen platziert. Sie müssen einen Pfad zu einem Schematic angeben, das in diesem Fall in einem speziellen Schematic-Verzeichnis innerhalb des Mods gespeichert ist.
In diesem Beispiel werden auch flags gesetzt, um die Platzierung des Schematics zu zentrieren, und die Rotation
ist auf zufällig gesetzt. Die zufällige Drehung von Schemen, wenn sie als Dekoration platziert werden
sorgt für mehr Abwechslung, wenn asymmetrische Schemen verwendet werden.
## Kartenerstellungs-Aliase (Mapgen Aliases)
Vorhandene Spiele sollten bereits geeignete Kartenerstellungs-Aliase enthalten, so dass Sie nur die Registrierung eigener Kartenerstellungs-Aliase in Betracht ziehen, wenn Sie Ihr eigenes Spiel entwickeln.
Mapgen-Aliase liefern Informationen für das Kern-Mapgen und können so registriert werden:
```lua
minetest.register_alias("mapgen_stone", "base:smoke_stone")
```
Zumindest sollten Sie registrieren:
* mapgen_stone
* mapgen_water_source
* mapgen_river_water_source
Wenn Sie nicht für alle Biome HöhlenflüssigkeitsNode definieren, sollten Sie diese trotzdem ebenfalls registrieren:
* mapgen_lava_source

174
_de/advmap/lvm.md Normal file
View File

@ -0,0 +1,174 @@
---
title: Lua Voxel Manipulator
layout: default
root: ../..
idx: 6.2
description: Erfahren Sie, wie Sie LVMs nutzen können, um Map-Operationen zu beschleunigen.
redirect_from:
- /de/chapters/lvm.html
- /de/map/lvm.html
mapgen_object:
level: warning
title: LVMs und Mapgen
message: Verwenden Sie nicht `minetest.get_voxel_manip()` mit mapgen, da dies zu Störungen führen kann.
Verwenden Sie stattdessen `minetest.get_mapgen_object("voxelmanip")`.
---
## Einleitung <!-- omit in toc -->
Die im Kapitel [Grundlegende Kartenoperationen](environment.html) beschriebenen Funktionen sind bequem und einfach zu benutzen, aber für große Gebiete sind sie ineffizient. Jedes Mal, wenn Sie `set_node` oder `get_node` aufrufen, muss Ihr Mod mit der Engine kommunizieren. Dies führt zu ständigen einzelnen Kopiervorgängen zwischen der
Engine und Ihrem Mod, was langsam ist und die Leistung des Spiels schnell verringert. Die Verwendung eines Lua Voxel Manipulators (LVM) kann eine gute Alternative sein.
- [Konzepte](#konzepte)
- [Einlesen in den LVM](#einlesen-in-den-lvm)
- [Nodes lesen](#nodes-lesen)
- [Nodes schreiben](#nodes-schreiben)
- [Beispiel](#beispiel)
- [Sie sind dran](#sie-sind-dran)
## Konzepte
Ein LVM ermöglicht es Ihnen, große Bereiche der Karte in den Speicher Ihres Mods zu laden. Sie können diese Daten dann ohne weitere Interaktion mit der Engine und ohne die Ausführung von Callbacks lesen und schreiben, was bedeutet, dass diese Operationen sehr schnell sind. Anschließend können Sie den Bereich wieder in die Engine zurückschreiben und Beleuchtungsberechnungen durchführen.
## Einlesen in den LVM
Sie können nur einen kubischen Bereich in einen LVM laden, also müssen Sie die minimalen und maximalen Positionen ausarbeiten, die Sie ändern möchten. Dann können Sie einen LVM erstellen und einlesen LVM einlesen. Zum Beispiel:
```lua
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos1, pos2)
```
Aus Leistungsgründen wird ein LVM fast nie genau den Bereich lesen, den Sie ihm vorgeben. Stattdessen wird er wahrscheinlich einen größeren Bereich lesen. Der größere Bereich wird durch `emin` und `emax` angegeben, die für *emerged min pos* und *emerged max pos* stehen, auf Deutch: *Ermittelte Minimum-Position* bzw. *Ermittelte Maximum-Position*. Ein LVM lädt den Bereich, den er enthält, für Sie - sei es durch Laden aus dem Speicher, von der Festplatte oder Aufruf des Map-Generators.
{% include notice.html notice=page.mapgen_object %}
## Nodes lesen
Um die Typen von Node an bestimmten Positionen zu lesen, müssen Sie `get_data()` verwenden. Dies gibt ein flaches Array zurück, in dem jeder Eintrag den Typ eines bestimmten Nodes darstellt.
```lua
local data = vm:get_data()
```
Sie können param2 und Beleuchtungsdaten mit den Methoden `get_param2_data()` und `get_light_data()` erhalten.
Sie müssen `emin` und `emax` verwenden, um herauszufinden, wo ein Node in den flachen Arrays ist, die durch die oben genannten Methoden gegeben sind. Es gibt eine Hilfsklasse namens `VoxelArea`, die die die die Berechnung für Sie übernimmt.
```lua
local a = VoxelArea:new{
MinEdge = emin,
MaxEdge = emax
}
-- Index des Nodees abrufen
local idx = a:index(x, y, z)
-- Node lesen
print(data[idx])
```
Wenn Sie den obigen Code ausführen, werden Sie feststellen, dass `data[vi]` eine Ganzzahl ist. Das ist so, weil die Engine aus Leistungsgründen keine Nodes in Form von Zeichenketten speichert. Stattdessen verwendet die Engine eine ganze Zahl, die sogenannte Inhalts-ID. Sie können die Inhalts-ID für einen bestimmten Nodetyp herausfinden mit `get_content_id()` herausfinden. Zum Beispiel:
```lua
local c_stone = minetest.get_content_id("default:stone")
```
Sie können dann überprüfen, ob der Node zum Beispiel Stein ist:
```lua
local idx = a:index(x, y, z)
if data[idx] == c_stone then
print("ist Stein!")
end
```
Die Inhalts-IDs eines Nodetyps können sich während der Ladezeit ändern, daher wird es nicht empfohlen, diese während dieser Zeit abzurufen.
Node in einem LVM-Datenarray werden in umgekehrter Koordinatenreihenfolge gespeichert. Deshalb sollten Sie immer in der Reihenfolge `z, y, x` *iterieren* (umdrehen). Zum Beispiel:
```lua
for z = min.z, max.z do
for y = min.y, max.y do
for x = min.x, max.x do
-- vi, Voxel-Index, ist hier ein gängiger Variablenname
local vi = a:index(x, y, z)
if data[vi] == c_stone then
print("ist Stein!")
end
end
end
end
```
Der Grund dafür liegt im Bereich der Computerarchitektur. Das Lesen aus dem RAM ist ziemlich kostspielig, daher verfügen CPUs über mehrere Caching-Ebenen. Wenn die Daten, die ein Prozess anfordert,
im Cache sind, kann er sie sehr schnell abrufen. Wenn sich die Daten nicht im Cache befinden, kommt es zu einem Cache-Miss und der Prozess holt sich die benötigten Daten aus dem RAM. Alles,
was die angeforderten Daten umgibt, wird ebenfalls geholt und ersetzt dann die Daten im Cache. Dies geschieht, weil es sehr wahrscheinlich ist, dass der Prozess erneut Daten in der Nähe dieser Stelle anfordert. Das bedeutet, dass es eine gute Optimierungsregel ist, so zu iterieren, dass die Daten nacheinander gelesen werden und *Chache Trashing* zu vermeiden.
## Nodes schreiben
Zunächst müssen Sie eine neue Inhalts-ID im Datenfeld festlegen:
```lua
for z = min.z, max.z do
for y = min.y, max.y do
for x = min.x, max.x do
local vi = a:index(x, y, z)
if data[vi] == c_stone then
data[vi] = c_air
end
end
end
end
```
Wenn Sie die Einstellung der Node im LVM abgeschlossen haben, müssen Sie das Daten Array in die Engine hochladen:
```lua
vm:set_data(data)
vm:write_to_map(true)
```
Zum Setzen von Beleuchtungs- und Param2-Daten verwenden Sie, wie schon erwähnt, die entsprechend benannten Methoden `set_light_data()` und `set_param2_data()`.
Die Methode `write_to_map()` nimmt einen booleschen Wert an, der `true` ist, wenn die Beleuchtung berechnet werden soll. Wenn Sie `false` übergeben, müssen Sie die Beleuchtung zu einem späteren Zeitpunkt mit `minetest.fix_light` neu berechnen lassen.
## Beispiel
```lua
local function grass_to_dirt(pos1, pos2)
local c_dirt = minetest.get_content_id("default:dirt")
local c_grass = minetest.get_content_id("default:dirt_with_grass")
-- Daten in LVM einlesen
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos1, pos2)
local a = VoxelArea:new{
MinEdge = emin,
MaxEdge = emax
}
local data = vm:get_data()
-- Daten ändern
for z = pos1.z, pos2.z do
for y = pos1.y, pos2.y do
for x = pos1.x, pos2.x do
local vi = a:index(x, y, z)
if data[vi] == c_grass then
data[vi] = c_dirt
end
end
end
end
-- Daten schreiben
vm:set_data(data)
vm:write_to_map(true)
end
```
## Sie sind dran
* Erstellen Sie `replace_in_area(from, to, pos1, pos2)`, das alle Instanzen von `von` durch `bis` in dem angegebenen Bereich ersetzt, wobei `von` und `bis` Nodenamen sind.
* Programmieren Sie eine Funktion, die alle BrustNode um 90&deg; dreht.
* Erstellen Sie eine Funktion, die einen LVM benutzt, um zu bewirken, dass sich moosiges Kopfsteinpflaster auf nahegelegene Stein- und PflastersteinNode ausbreitet. Verursacht Ihre Implementierung, dass sich das Moospflaster auf mehr als einen Node ausbreitet? Wenn ja, wie können Sie dies verhindern?

View File

@ -0,0 +1,148 @@
---
title: Erste Schritte
layout: default
root: ../..
idx: 1.1
description: Lerne wie man einen Mod-Ordner mit init.lua, mod.conf und mehr anlegt.
redirect_from:
- /de/chapters/folders.html
- /de/basics/folders.html
---
## Einführung <!-- omit in toc -->
Es ist wesentlich, den Aufbau der grundlegenden Strukturen des Mod-Verzeichnisses zu verstehen, wenn man Mods erstellt.
- [Was sind Spiele und Mods?](#was-sind-spiele-und-mods)
- [Wo werden die Mods gespeichert?](#wo-werden-die-mods-gespeichert)
- [Ihren ersten Mod erstellen](#ihren-ersten-mod-erstellen)
- [Mod-Verzeichnis](#mod-verzeichnis)
- [mod.conf](#modconf)
- [init.lua](#initlua)
- [Zusammenfassung](#zusammenfassung)
- [Abhängigkeiten](#abhängigkeiten)
- [Mod-Pakete (Modpacks)](#mod-pakete-modpacks)
## Was sind Spiele und Mods?
Die Stärke von Minetest ist die Fähigkeit, Spiele zu erstellen, ohne eigene Voxel-Grafik, Voxel Algorithmen und raffinierten Netzwerk-Code erstellen zu müssen.
In Minetest ist ein Spiel eine Sammlung von Modulen, welche miteinander arbeiten, um den Inhalt und das Verhalten des Spiels zur Verfügung zu stellen.
Ein Modul, allgemein als Mod bezeichnet, ist eine Sammlung von Skripten und Ressourcen.
Es ist möglich, ein Spiel mit nur einem Mod zu erstellen, aber das wird nur selten gemacht, weil es sonst nicht mehr so einfach ist, Teile des Spieles unabhängig von den Anderen anzupassen oder zu ersetzen.
Ebenfalls ist es möglich, Mods außerhalb eines Spieles zu verbreiten. In diesem Fall sind sie ebenfalls *Mods*, aber in einem traditionellerem Sinn: *Modifikationen*. Diese Mods verändern oder erweitern die Eigenschaften eines Spiels.
Sowohl die Mods die im Spiel enthalten sind, als auch die Mods von Dritten nutzen die selbe API (Programmierschnittstelle).
## Wo werden die Mods gespeichert?
<a name="mod-locations"></a>
Jede Mod hat ihr eigenes Verzeichnis, wo sich ihre Lua-Quelltexte, Texturen, Modelle und Tondateien befinden. Minetest überprüft verschiedene Orte auf Mods. Diese Orte werden allgemein *Mod-Lade-Verzeichnisse* genannt.
Für eine bestimmte Welt/ein bestimmtes Spiel werden drei Mod-Speicherorte überprüft. Diese sind, in dieser Reihenfolge:
1. Spiel-Mods. Dies sind die Mods, die das Spiel (die Welt) bilden.
z.B.: `minetest/games/minetest_game/mods/`, `/usr/share/minetest/games/minetest/`
2. Globale Mods. Der Ort, an dem Mods fast immer installiert werden.
Im Zweifelsfall legen Sie Mods hier ab.
z.B.: `minetest/mods/`
3. Welt-Mods. Der Ort, an dem Mods gespeichert werden, die für eine bestimmte bestimmte Welt sind.
z.B.: `minetest/worlds/world/worldmods/`
`minetest` ist das Verzeichnis für die Benutzerdaten. Sie können den Ort des Benutzerdaten-Verzeichnis finden, indem Sie Minetest öffnen und auf "Benutzerdatenverzeichnis öffnen" in der Registerkarte "Über" klicken.
Falls Minetest mithilfe von Flathub installiert wurde, kann es sein, dass bei einem Klick nichts passiert. Normalerweise ist das `minetest`-Verzeichnis dann in `/home/USER/.var/app/net.minetest.Minetest/.minetest/`
Beim Laden von Mods prüft Minetest alle oben genannten Verzeichnisse der Reihe nach. Wenn es auf einen Mod stößt, der denselben Namen trägt wie ein zuvor gefundener, wird der spätere Mod anstelle des früheren Mods geladen. Das bedeutet, dass Sie die Spielmods überschreiben, indem Sie einen Mod mit demselben Namen in den globalen Mod-Speicherort einfügen.
## Ihren ersten Mod erstellen
### Mod-Verzeichnis
Gehen Sie in das globale Mods-Verzeichnis (Über > Benutzerdatenverzeichnis öffnen > mods) und
erstellen Sie einen neuen Ordner namens `mymod`. mymod ist der Name des Mods.
Jeder Mod sollte einen eindeutigen *Mod-Namen* haben, eine technische Kennung (id), die auf den Mod verweist. Mod-Namen können Buchstaben, Zahlen und Unterstriche enthalten. Ein guter Name sollte beschreiben, was die Mod tut. Das Verzeichnis, das die Komponenten einer Mod enthält, muss denselben Namen wie den Mod-Namen haben. Um herauszufinden, ob ein Mod-Name verfügbar ist, suchen Sie ihn auf
[content.minetest.net](https://content.minetest.net).
mymod
├── textures
│   └── mymod_node.png Dateien
├── init.lua
└── mod.conf
Mods benötigen nur eine init.lua-Datei. Es wird jedoch empfohlen, die Datei mod.conf zu verwenden und je nach Funktionsumfang können weitere Komponenten erforderlich sein, abhängig von der Funktionalität der Mod.
### mod.conf
Erstellen Sie eine `mod.conf`-Datei mit folgendem Inhalt:
```
name = mymod
description = Fügt foo, bar und bo hinzu.
depends = default
```
Diese Datei wird für Mod-Metadaten verwendet, darunter der Name der Mod, die Beschreibung und andere
Informationen.
### init.lua
Erstellen Sie eine `init.lua`-Datei mit folgendem Inhalt:
```lua
print("Diese Datei wird zum Zeitpunkt des Ladens ausgeführt!")
minetest.register_node("mymod:node", {
description = "Das ist ein Node",
tiles = {"mymod_node.png"},
groups = {cracky = 1}
})
minetest.register_craft({
type = "shapeless",
output = "mymod:node 3",
recipe = { "default:dirt", "default:stone" },
})
```
Die Datei init.lua ist der Einstiegspunkt für einen Mod und wird ausgeführt, wenn der Mod geladen wird.
### Zusammenfassung
Diese Mod hat den Namen "mymod". Er hat zwei Textdateien: init.lua und mod.conf. Das Skript gibt eine Nachricht aus und registriert dann einen Node und ein Handwerksrezept - diese
werden später erklärt. Es gibt eine einzige Abhängigkeit, die
[default mod](https://content.minetest.net/metapackages/default/), die
normalerweise im Minetest-Grundspiel (Minetest Game) zu finden ist. Außerdem gibt es eine Textur in textures/ für den Node.
## Abhängigkeiten
Eine Abhängigkeit entsteht, wenn eine Mod eine andere Mod benötigt, der vor ihr geladen werden muss. Ein Mod kann verlangen, dass der Code, die Gegenstände oder andere Ressourcen einer anderen Mod verfügbar sein müssen, damit sie verwendet werden können.
Es gibt zwei Arten von Abhängigkeiten: feste und optionale Abhängigkeiten. Beide erfordern, dass die Mod zuerst geladen wird. Wenn die Mod, von die die Abhängigkeit besteht, nicht verfügbar ist, führt eine feste Abhängigkeit dazu, dass die Mod nicht geladen wird, während eine optionale Abhängigkeit dazu führen kann, dass weniger Funktionen aktiviert werden.
Eine optionale Abhängigkeit ist nützlich, wenn Sie optional eine andere Mod unterstützen wollen; diese kann zusätzliche Inhalte aktivieren, wenn der Benutzer beide Mods gleichzeitig nutzen möchte.
Abhängigkeiten werden in einer kommagetrennten Liste in mod.conf angegeben.
depends = modeins, modzwei
optional_depends = moddrei
## Mod-Pakete (Modpacks)
Mods können in Mod-Pakete gruppiert werden, die es ermöglichen, mehrere Mods zu verpacken und zusammen zu verschieben. Sie sind nützlich, wenn Sie einem Spieler mehrere Mods zur Verfügung stellen wollen, aber nicht wollen, dass er sie einzeln herunterladen muss.
modpack1
├── modpack.conf (required) - signalisiert, dass es sich um ein Mod-Paket handelt
├── mod1
│   └── ... Mod-Dateien
└── mymod (optional)
   └── ... Mod-Dateien
Bitte beachten Sie, dass ein Modpack kein *Spiel* ist.
Spiele haben ihre eigene Organisationsstruktur, die im Kapitel “Spiele” erklärt wird.

283
_de/basics/lua.md Normal file
View File

@ -0,0 +1,283 @@
---
title: Lua-Skripting
layout: default
root: ../..
idx: 1.2
description: Eine grundlegende Einführung in Lua, einschließlich eines Leitfadens zum globalen/lokalen Geltungsbereich.
redirect_from: /de/chapters/lua.html
---
## Einleitung <!-- omit in toc -->
In diesem Kapitel geht es um die Skripterstellung in Lua, die dazu benötigten Werkzeuge und einige Techniken, die Sie vielleicht nützlich finden.
- [Code-Editoren](#code-editoren)
- [Programmieren in Lua](#programmieren-in-lua)
- [Programmablauf](#programmablauf)
- [Typen von Variablen](#typen-von-variablen)
- [Arithmetische, also Mathematische, Operatoren](#arithmetische-also-mathematische-operatoren)
- [Auswahl](#auswahl)
- [Logische Operatoren](#logische-operatoren)
- [Programmierung](#programmierung)
- [Lokale und globale Reichweite](#lokale-und-globale-reichweite)
- [Es sollte so viel wie möglich auf lokale Variablen zurückgegriffen werden.](#es-sollte-so-viel-wie-möglich-auf-lokale-variablen-zurückgegriffen-werden)
- [Einbindung anderer Lua-Skripte](#einbindung-anderer-lua-skripte)
## Code-Editoren
Für das Schreiben von Skripten in Lua reicht ein Code-Editor mit Code-Hervorhebung aus.
Die Codehervorhebung verwendet unterschiedliche Farben für Wörter und Zeichen je nachdem, wofür sie stehen. Auf diese Weise können Sie leicht Fehler und Ungereimtheiten erkennen.
Zum Beispiel:
```lua
function ctf.post(team,msg)
if not ctf.team(team) then
return false
end
if not ctf.team(team).log then
ctf.team(team).log = {}
end
table.insert(ctf.team(team).log,1,msg)
ctf.save()
return true
end
```
Die Schlüsselwörter in diesem Beispiel sind hervorgehoben, einschließlich `if`, `then`, `end` und `return`. Funktionen, die standardmäßig mit Lua ausgeliefert werden, wie z.B. `table.insert`, sind ebenfalls hervorgehoben.
Zu den häufig verwendeten Editoren, die sich gut für Lua eignen, gehören:
* [VSCode 🇬🇧](https://code.visualstudio.com/) - quelloffen (als Code-OSS oder VSCodium), populär, und hat [Plugins für Minetest Modding 🇬🇧](https://marketplace.visualstudio.com/items?itemName=GreenXenith.minetest-tools).
* [Notepad++ 🇬🇧](http://notepad-plus-plus.org/) - nur für Windows
Andere geeignete Editoren sind ebenfalls verfügbar.
## Programmieren in Lua
### Programmablauf
Programme sind eine Reihe von Befehlen, die nacheinander ausgeführt werden. Wir nennen diese Befehle "Anweisungen". Der Programmablauf gibt an, wie diese Anweisungen ausgeführt werden. Verschiedene Arten des Ablaufs ermöglichen es Ihnen, Befehlsreihen zu überspringen.
Es gibt drei Haupttypen von Abläufen:
* Sequenz: führt eine Anweisung nach der anderen aus, ohne zu überspringen.
* Auswahl: Überspringt Sequenzen in Abhängigkeit von Bedingungen.
* Iteration: Wiederholung der gleichen Anweisungen, bis eine Bedingung erfüllt ist.
Wie sehen also die Anweisungen in Lua aus?
```lua
local a = 2 -- Setzt 'a' auf 2
local b = 2 -- Setzt 'b' auf 2
local result = a + b -- Setzt 'result' (Deutsch: Ergebnis) auf a + b, was 4 ergibt
a = a + 10
print("Die Summe aus a und b ist "..result)
```
In diesem Beispiel sind `a`, `b` und `result` *Variablen*. Lokale Variablen werden
mit dem Schlüsselwort `local` deklariert und erhalten dann einen Anfangswert. `local`
wird später besprochen, denn es ist Teil eines sehr wichtigen Konzepts namens
*scope* (Deutsch: Geltungsbereich).
Das `=`-Zeichen bedeutet *assignment* (Deutsch: Zuweisung), also bedeutet `result = a + b`, dass der Wert von `result` auf den Wert von `a + b` gesetzt wird. Variablennamen können länger als ein Zeichen lang sein, wie bei der Variable `result` zu sehen ist. Es ist auch erwähnenswert, dass, wie wie die meisten Sprachen die Groß- und Kleinschreibung beachtet wird; `A` ist eine andere Variable als `a`.
### Typen von Variablen
Eine Variable hat nur einen der folgenden Typen und kann nach einer Zuweisung den Typ wechseln. Es ist gute Praxis, sicherzustellen, dass eine Variable immer nur nil oder einen einzigen Nicht-Nil-Typ hat.
| Typ | Beschreibung | Beispiel |
|----------|-----------------------------------------------------------------|----------------|
| Nil | Nicht initialisiert. Die Variable ist leer, sie hat keinen Wert | `local A`, `D = nil` |
| Number | Eine ganze oder dezimale Zahl. | `local A = 4` |
| String | Ein Stück Text. | `local D = "one two three"` |
| Boolean | True oder False. (Wahr oder Falsch) | `local is_true = false`, `local E = (1 == 1)` |
| Table | Listen. | Unten erklärt. |
| Function | Kann ausgeführt werden. Kann Eingaben erfordern und einen Wert zurückgeben. | `local result = func(1, 2, 3)` |
### Arithmetische, also Mathematische, Operatoren
Zu den Operatoren in Lua gehören:
| Symbol | Zweck | Beispiel |
|--------|-------------------------------------------|---------------------------|
| A + B | Addition | 2 + 2 = 4 |
| A - B | Subtraktion | 2 - 10 = -8 |
| A * B | Multiplikation | 2 * 2 = 4 |
| A / B | Division | 100 / 50 = 2 |
| A ^ B | Potenzieren | 2 ^ 2 = 2<sup>2</sup> = 4 |
| A .. B | Konkatenation (Zeichenketten verbinden) | "foo" .. "bar" = "foobar" |
Bitte beachten Sie, dass diese Liste nicht vollständig ist; sie enthält nicht alle möglichen Operatoren.
### Auswahl
Die einfachste Methode der Auswahl ist die if-Anweisung. Zum Beispiel:
```lua
local random_number = math.random(1, 100) -- Zwischen 1 und 100.
if random_number > 50 then
print("Woohoo!")
else
print("Oh nein!")
end
```
Dies erzeugt eine Zufallszahl zwischen 1 und 100. Es gibt dann "Woohoo!" aus, wenn diese Zahl größer als 50 ist, andernfalls wird "Oh nein!" ausgegeben.
### Logische Operatoren
Zu den logischen Operatoren in Lua gehören:
| Symbol | Zweck | Beispiel |
|---------|-----------------------------------------------------|-------------------------------------------------------------|
| A == B | Gleich | 1 == 1 (true), 1 == 2 (false) |
| A ~= B | nicht gleich | 1 ~= 1 (false), 1 ~= 2 (true) |
| A > B | Größer als | 5 > 2 (true), 1 > 2 (false), 1 > 1 (false) |
| A < B | Kleiner als | 1 < 3 (true), 3 < 1 (false), 1 < 1 (false) |
| A >= B | Größer als oder gleich | 5 >= 5 (true), 5 >= 3 (true), 5 >= 6 (false) |
| A <= B | Kleiner als oder gleich | 3 <= 6 (true), 3 <= 3 (true) |
| A and B | Und (beides muss `true`, also wahr sein) | (2 > 1) and (1 == 1) (true), (2 > 3) and (1 == 1) (false) |
| A or B | Entweder oder. Eines oder mehrere müssen wahr sein. | (2 > 1) or (1 == 2) (true), (2 > 4) or (1 == 3) (false) |
| not A | Nicht `true`, also nicht wahr | not (1 == 2) (true), not (1 == 1) (false) |
Bitte beachten Sie, dass dies nicht alle möglichen Operatoren enthält.
Es ist auch möglich, Operatoren zu kombinieren. Zum Beispiel:
```lua
if not A and B then
print("Juhu!")
end
```
Dies gibt "Juhu!" aus, wenn A `False`, also falsch, und B `True`, also wahr, ist.
Logische und arithmetische Operatoren funktionieren auf die gleiche Weise; beide akzeptieren Eingaben und geben einen Wert zurück, der gespeichert werden kann. Zum Beispiel:
```lua
local A = 5
local ist_gleich = (A == 5)
if ist_gleich then
print("Ist gleich!")
end
```
## Programmierung
Beim Programmieren geht es darum, ein Problem, z. B. das Sortieren einer Liste
und in Schritte umzuwandeln, die ein Computer verstehen kann.
Ihnen den logischen Prozess des Programmierens beizubringen, würde den Rahmen dieses Buches sprengen. Die folgenden Websites sind jedoch sehr nützlich, um dies zu entwickeln:
* [Codecademy 🇬🇧](http://www.codecademy.com/) ist eines der besten Quellen, um zu
Lernen, wie man Code schreibt. Sie bietet ein interaktives Lernprogramm an.
* [Scratch](https://scratch.mit.edu) ist eine gute Quelle, um mit den
absoluten Grundlagen zu beginnen und die zum Programmieren erforderlichen Problemlösungstechniken zu erlernen.\\
Scratch *wurde konzipiert, um Kindern das Programmieren beizubringen* und ist keine ernsthafte, sondern eine Block basierte Programmiersprache.
## Lokale und globale Reichweite
Ob eine Variable lokal oder global ist, bestimmt, wohin sie geschrieben oder gelesen werden kann. Auf eine lokale Variable kann nur von dort aus zugegriffen werden, wo sie definiert ist. Hier sind einige Beispiele:
```lua
-- Von dieser Skriptdatei aus zugänglich
local one = 1
function myfunc()
-- Von dieser Funktion aus zugänglich
local two = one + one
if two == one then
-- Zugänglich aus dieser if-Anweisung
local three = one + two
end
end
```
Im Gegensatz dazu, kann auf globale Variablen von jeder Stelle in der Skriptdatei aus zugegriffen werden und von jeder anderen Mod aus.
```lua
function one()
foo = "bar"
end
function two()
print(dump(foo)) -- Gibt "bar" aus
end
one()
two()
```
### Es sollte so viel wie möglich auf lokale Variablen zurückgegriffen werden.
Wann immer möglich, sollten lokale Variablen verwendet werden. Mods sollten nur eine globale variable mit dem gleichen Namen wie die Mod haben. Das Erstellen weiterer globaler Variablen ist unsaubere
Kodierung, und Minetest wird davor warnen:
Assignment to undeclared global 'foo' inside function at init.lua:2
Auf Deutsch: Zuweisung an eine nicht deklarierte globale Variable 'foo' innerhalb der Funktion in init.lua:2
Um dies zu korrigieren, verwenden Sie "local":
```lua
function one()
local foo = "bar"
end
function two()
print(dump(foo)) -- Gibt "nil" aus
end
one()
two()
```
Denken Sie daran, dass nil **nicht initialisiert** bedeutet. Die Variable wurde noch nicht mit einem Wert zugewiesen, existiert nicht oder wurde nicht initialisiert (d.h. auf null gesetzt).
Funktionen sind Variablen eines besonderen Typs sollten aber auch lokal gemacht werden, weil andere Mods Funktionen mit demselben Namen haben könnten.
```lua
local function foo(bar)
return bar * 2
end
```
Damit Mods Ihre Funktionen aufrufen können, sollten Sie eine Tabelle mit dem gleichen Namen wie die Mod erstellen und darin ihre Funktion einfügen. Diese Tabelle wird oft als "API table" (Deutsch: API-Tabelle) oder Namespace bezeichnet.
```lua
mymod = {}
function mymod.foo(bar)
return "foo" .. bar
end
-- In einer anderen Mod oder einem anderen Skript:
mymod.foo("foobar")
```
## Einbindung anderer Lua-Skripte
Der empfohlene Weg, um andere Lua-Skripte in eine Mod einzubinden, ist die Verwendung von *dofile*.
```lua
dofile(minetest.get_modpath("modname") .. "/script.lua")
```
Ein Skript kann einen Wert zurückgeben, der für die gemeinsame Nutzung privater locals nützlich ist:
```lua
-- script.lua
return "Hallo Welt!"
-- init.lua
local ret = dofile(minetest.get_modpath("modname") .. "/script.lua")
print(ret) -- Hallo Welt!
```
[In späteren Kapiteln](../quality/clean_arch.html) wird erklärt, wie man den Code einer Mod am besten aufteilt.

81
_de/games/games.md Normal file
View File

@ -0,0 +1,81 @@
---
title: Spiele kreieren
layout: default
root: ../..
idx: 7.1
---
## Einleitung <!-- omit in toc -->
Die Stärke von Minetest ist die Möglichkeit, Spiele einfach zu entwickeln, ohne
dass man eigene Voxel-Grafiken, Voxel-Algorithmen oder ausgefallenen
Netzwerkcode erstellen muss.
- [Was ist ein Spiel?](#was-ist-ein-spiel)
- [Spiel-Verzeichnis](#spiel-verzeichnis)
- [Spielübergreifende Kompatibilität](#spielübergreifende-kompatibilität)
- [API-Kompatibilität](#api-kompatibilität)
- [Gruppen und Aliase](#gruppen-und-aliase)
- [Sie sind dran](#sie-sind-dran)
## Was ist ein Spiel?
Spiele sind eine Sammlung von Mods, die zusammen ein zusammenhängendes Spiel ergeben.
Ein gutes Spiel hat zum Beispiel ein einheitliches Grundthema und eine Richtung,
es könnte ein klassischer Craft-Miner mit harten Survival-Elementen sein oder
ein Weltraum-Simulationsspiel mit einer Steampunk-Ästhetik.
Spieldesign ist ein komplexes Thema und eigentlich ein ganzes Fachgebiet.
Es würde den Rahmen des Buches sprengen, es auch nur kurz zu besprechen.
## Spiel-Verzeichnis
Die Struktur und der Ort eines Spiels werden nach der Arbeit mit Mods ziemlich
vertraut erscheinen.
Spiele befinden sich in einem Spielverzeichnis, z. B. `minetest/games/foo_game`.
foo_game
├── game.conf
├── menu
│   ├── header.png
│   ├── background.png
│   └── icon.png
├── minetest.conf
├── mods
│   └── ... mods
├── README.txt
└── settingtypes.txt
Das einzige, was erforderlich ist, ist ein Mod-Ordner, aber `game.conf` und `menu/icon.png`
werden empfohlen.
## Spielübergreifende Kompatibilität
### API-Kompatibilität
Es ist eine gute Idee, zu versuchen, so viel API-Kompatibilität mit dem Minetest-Grundspiel (Minetest Game) zu erhalten wie geeignet, da dies die Portierung von Mods in ein anderes Spiel
sehr viel einfacher macht.
Der beste Weg, um die Kompatibilität mit einem anderen Spiel zu erhalten, ist die
API-Kompatibilität mit allen Mods, die denselben Namen tragen. Das heißt, wenn ein Mod den gleichen Namen wie ein anderer Mod verwendet, auch wenn sie von einem Drittanbieter stammt, sollte sie eine kompatible API haben. Wenn ein Spiel zum Beispiel einen Mod mit dem Namen `doors` enthält, dann sollte dieser die gleiche API haben wie `doors` in Minetest Game.
Die API-Kompatibilität eines Mods ist die Summe der folgenden Punkte:
* Lua-API-Tabelle - Alle dokumentierten/angekündigten Funktionen in der globalen Tabelle, die den gleichen Namen haben. Zum Beispiel: `mobs.register_mob`.
* Registrierte Nodes/Items - Das Vorhandensein von Items.
Kleine Fehler sind nicht so schlimm, wie z.B. das Fehlen eines zufälligen Nutzens
Funktion zu haben, die eigentlich nur intern verwendet wurde, aber größere Brüche
in Bezug auf Kernfunktionen sind sehr schlecht.
Es ist schwierig, die API-Kompatibilität mit einem Mega-God-Mod wie *default* in Minetest Game aufrechtzuerhalten. In diesem Fall sollte das Spiel keinen Mod namens default enthalten.
Die API-Kompatibilität gilt auch für andere Mods und Spiele von Drittanbietern, Stellen Sie also sicher, dass alle neuen Mods einen eindeutigen Mod-Namen haben. Um zu überprüfen, ob ein Mod-Name bereits vergeben ist, suchen Sie ihn z.B. auf [content.minetest.net](https://content.minetest.net/).
### Gruppen und Aliase
Gruppen und Aliase sind beides nützliche Werkzeuge, um die Kompatibilität zwischen Spielen zu gewährleisten, da sie es ermöglichen, dass die Namen von Gegenständen in verschiedenen Spielen unterschiedlich sein können. Gemeinsame Nodes wie Stein und Holz sollten Gruppen haben, um das Material zu kennzeichnen Es ist auch eine gute Idee, Aliasnamen von Standardnodes zu direkten Ersetzungen zu erstellen.
## Sie sind dran
* Erstellen Sie ein einfaches Spiel, bei dem der Spieler durch das Abbauen spezieller Nodes Punkte erhält.

37
_de/index.md Normal file
View File

@ -0,0 +1,37 @@
---
title: Titelseite
layout: default
homepage: true
no_header: true
root: ..
idx: 0.1
---
<header>
<h1>Minetest Modding-Buch</h1>
<span>von <a href="https://rubenwardy.com" rel="author">rubenwardy</a></span>
<span>Editiert von <a href="http://rc.minetest.tv/">Shara</a></span>
<span>Übersetzt von von <a href="https://www.solars.de/">solars</a>, <a href="http://debiankaios.de/">debiankaios</a> und <a href="https://forum.minetest.net/memberlist.php?mode=viewprofile&u=41923">Tuxilio</a></span>
<span>Korrekturgelessen von <a href="https://jojokorpi.ddns.net/">jjk1</a>, <a href="https://forum.minetest.net/memberlist.php?mode=viewprofile&u=41923">Tuxilio</a> und <a href="http://debiankaios.de/">debiankaios</a></span>
</header>
## Einleitung
Minetest verwendet Lua-Skripte, um Modding-Unterstützung zu bieten.
Dieses Buch soll Ihnen beibringen, wie Sie Ihre eigenen Mods erstellen können, beginnend mit den Grundlagen.
Jedes Kapitel konzentriert sich auf einen bestimmten Teil der API und wird Sie bald dazu bringen
eigene Mods zu erstellen.
Sowohl als [online lesbares Buch](https://rubenwardy.com/minetest_modding_book),
oder [in HTML form downloadbar](https://gitlab.com/rubenwardy/minetest_modding_book/-/releases).
### Feedback und Beiträge
Haben Sie einen Fehler bemerkt oder möchten Sie ein Feedback geben? Teilen Sie mir das bitte mit.
* Erstelle eine [GitLab Issue](https://gitlab.com/rubenwardy/minetest_modding_book/-/issues).
* Poste es im [Forum Topic](https://forum.minetest.net/viewtopic.php?f=14&t=10729).
* [Kontaktiere mich](https://rubenwardy.com/contact/).
* Lust Mitzumachen?
[Read the README](https://gitlab.com/rubenwardy/minetest_modding_book/-/blob/master/README.md).

203
_de/items/callbacks.md Normal file
View File

@ -0,0 +1,203 @@
---
title: Node und Item Callbacks
layout: default
root: ../..
idx: 2.15
description: Erfahren sie über callbacks, Aktionen, und Ereignissen, einschließlich on_use, on_punch, on_place, on_rightclick
---
## Einleitung <!-- omit in toc -->
Minetest verwendet hauptsächlich ein Callback-basiertes Modding-Design. Ein Callback ist eine Funktion,
die Sie an eine API übergeben und die aufgerufen wird, wenn ein Ereignis eintritt. Zum Beispiel können Sie
eine Funktion `on_punch` in einer Node-Definition angeben, die aufgerufen wird, wenn ein Spieler
einen Node anstößt. Es gibt auch globale Callbacks wie
`minetest.register_on_punchnode`, um Ereignisse für alle Nodes zu empfangen.
- [Item Callbacks](#item-callbacks)
- [on\_use](#on_use)
- [on\_place und on\_secondary\_use](#on_place-und-on_secondary_use)
- [on\_drop](#on_drop)
- [after\_use](#after_use)
- [item\_place vs place\_item](#item_place-vs-place_item)
- [Node Callbacks](#node-callbacks)
- [Rechtsklick und Platzieren eines Nodes](#rechtsklick-und-platzieren-eines-nodes)
- [Schlagen und abbauen](#schlagen-und-abbauen)
- [...und mehr!](#und-mehr)
## Item Callbacks
Wenn ein Spieler einen Node, einen Handwerksgegenstand oder ein Werkzeug in seinem Inventar hat, kann er folgende Ereignisse auslösen
bestimmte Ereignisse:
| Callback | Standard-Bindung | Standard Wert |
|------------------|-------------------------------|----------------------------------------------|
| on_use | links-click | nil |
| on_place | rechts-click auf einen Node | `minetest.item_place` |
| on_secondary_use | rechts-click auf keinen Node | `minetest.item_secondary_use` (does nothing) |
| on_drop | Q | `minetest.item_drop` |
| after_use | Abbauen eines Nodes | nil |
### on_use
Mit einem on_use Callback wird verhindert, dass das Item zum abbauen von Blöcken verwendet wird. Eine häufige
Verwendung des on_use Callback ist für Lebensmittel:
```lua
minetest.register_craftitem("meinemod:matschekuchen", {
description = "Alien Matschekuchen",
inventory_image = "meinessen_matschekuchen.png",
on_use = minetest.item_eat(20),
})
```
Die Zahl, die an die Funktion minetest.item_eat übergeben wird, ist die Anzahl der Hitpoints,
Punkte, die durch den Verzehr dieser Nahrung geheilt werden. Jedes Herzsymbol, das der Spieler hat, ist
zwei Hitpoints wert. Ein Spieler kann in der Regel bis zu 10 Herzen haben, was gleichbedeutend ist mit
20 Hitpoints.
minetest.item_eat() ist eine Funktion, die eine Funktion zurückgibt und diese als on_use Callback. Das bedeutet, dass der obige Code dem hier entspricht:
```lua
minetest.register_craftitem("meinemod:matschekuchen", {
description = "Alien Matschekuchen",
inventory_image = "meinessen_matschekuchen.png",
on_use = function(...)
return minetest.do_item_eat(20, nil, ...)
end,
})
```
Wenn man versteht, wie item_eat funktioniert, indem es einfach eine Funktion zurückgibt, ist es möglich, die Funktion so zu ändern, dass sie ein komplexeres Verhalten wie das Abspielen eines benutzerdefinierten Sounds ermöglicht.
### on_place und on_secondary_use
Der Unterschied zwischen `on_place` und `on_secondary_use` ist, dass `on_place` aufgerufen wird,
wenn der Spieler auf einen Node zeigt und `on_secondary_use`, wenn der
Spieler dies nicht tut.
Beide Callbacks werden für alle Arten von Items aufgerufen. `on_place` ist standardmäßig auf die
Funktion `minetest.item_place`, die den Aufruf des `on_rightclick`
Callback des angezeigten Nodes aufruft oder das gehaltene Item platziert, wenn es ein Node ist.
### on_drop
on_drop wird aufgerufen, wenn der Spieler einen Gegenstand fallen lassen will, zum Beispiel mit
der Abwurftaste (Q) oder durch herausziehen aus dem Inventar. Es wird standardmäßig die Funktion
`minetest.item_drop` verwendet, die das Fallenlassen des Gegenstandes übernimmt.
### after_use
`after_use` wird beim abbauen eines Nodes aufgerufen und ermöglicht es Ihnen, dass die Art der Abnutzung
auf ein Werkzeug angewendet wird. Wenn after_use nicht existiert, dann ist es das gleiche wie:
```lua
after_use = function(itemstack, user, node, digparams)
itemstack:add_wear(digparams.wear)
return itemstack
end
```
## item_place vs place_item
Die API von Minetest enthält viele verschiedene integrierte Callback-Implementierungen, die Sie verwenden können. Diese Callbacks werden mit dem Elementtyp zuerst benannt, zum Beispiel,
`minetest.item_place` und `minetest.node_dig`. Einige Callback-Implementierungen werden
direkt verwendet, während einige Funktionen sind, die den Rückruf zurückgeben:
```lua
minetest.register_item("meinemod:beispiel", {
on_place = minetest.item_place,
on_use = minetest.item_eat(10),
})
```
Die API von Minetest enthält auch eingebaute Funktionen, die etwas _tun_. Diese sind
oft verwirrend ähnlich benannt wie die eingebauten Callback-Implementierungen
haben aber das Verb vorangestellt. Beispiele sind `minetest.place_item` und
`minetest.dig_node` - diese Funktionen ermöglichen das abbauen und Platzieren von Blöcken mit einem
ähnlichen Effekt wie Spieler.
## Node Callbacks
Wenn sich ein Node in einem Inventar befindet, verwendet er, wie oben beschrieben, Item Callback. Wenn
ein Node in der Welt platziert ist, verwendet er Node Callbacks. Es gibt eine ganze Menge von
Node Callbacks, zu viele, um sie in diesem Buch zu behandeln. Allerdings werden einige von ihnen
später in diesem Buch behandelt.
Einige der Callbacks beziehen sich auf Nodeoperationen wie das Platzieren und
Entfernen aus der Welt. Es ist wichtig zu beachten, dass Nodeoperationen-Callbacks
wie diese aus Leistungsgründen nicht von bulk changes - also solchen, die eine große Anzahl von
Blöcken auf einmal setzen - aufgerufen werden. Daher kann man sich nicht darauf verlassen, dass diese
Callbacks immer aufgerufen werden.
### Rechtsklick und Platzieren eines Nodes
Wenn der Benutzer mit der rechten Maustaste auf ein Item klickt, während er auf einen Node zeigt, wird der Callback
`on_place` des Items aufgerufen. Standardmäßig ist dieser auf `minetest.item_place` gesetzt.
Wenn der gezeigte Node einen `on_rightclick` Callback hat und sneak (shift) gehalten wird,
dann wird der `on_rightclick` Callback aufgerufen. Andernfalls wird `minetest.item_place`
den Node platzieren.
Das Platzieren eines Nodes ruft sowohl `on_construct` als auch `after_place_node` auf.
`on_construct` wird von jedem Node-Platzier-Ereignis aufgerufen, das nicht in Bulk war und es wird nur
die Position und den Wert des Nodes gegeben. `after_place_node` wird nur von node
place aufgerufen und hat daher mehr Informationen - wie den Placer und den Itemstack.
Es ist wichtig zu wissen, dass Spieler nicht die einzigen Objekte sind, die
Blöcke platzieren können; es ist üblich, dass auch Mobs und Mods Blöcke platzieren können. `Placer` kann ein Spieler, eine Entity oder nil sein.
```lua
minetest.register_node("mymod:mynode", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if clicker:is_player() then
minetest.chat_send_player(clicker:get_player_name(), "Hallo Welt!")
end
end,
on_construct = function(pos, node)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Mein Node!")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
-- Überprüfen des Platzierers
if placer and placer:is_player() then
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
end
end,
})
```
### Schlagen und abbauen
Schlagen bedeutet, dass der Spieler kurz mit der linken Maustaste klickt. Wenn der benutze Gegenstand
einen `on_use` Callback hat, wird dieser aufgerufen. Andernfalls wird der `on_punch`
Callback auf dem angezeigten Node aufgerufen.
Wenn der Spieler versucht, einen Node abzubauen, wird der `on_dig` Callback auf dem Node aufgerufen.
Dieser ist standardmäßig auf `minetest.node_dig` eingestellt, der den Gebietsschutz prüft, das
das Werkzeug verschleißt, den Node entfernt und den `after_dig_node` Callback ausführt.
```lua
minetest.register_node("meinemod:meinnode", {
on_punch = function(pos, node, puncher, pointed_thing)
if puncher:is_player() then
minetest.chat_send_player(puncher:get_player_name(), "Au!")
end
end,
})
```
### ...und mehr!
In der Lua-API-Referenz von Minetest finden Sie eine Liste aller Node-Callbacks und
weitere Informationen zu den oben genannten Rückrufen.

View File

@ -0,0 +1,96 @@
---
title: Texturen erstellen
layout: default
root: ../..
idx: 2.2
description: Eine Einführung in die Erstellung von Texturen mit dem Editor Ihrer Wahl und eine Anleitung zu GIMP.
redirect_from: /de/chapters/creating_textures.html
---
## Einleitung <!-- omit in toc -->
Bei der Entwicklung für Minetest ist es sehr nützlich, Texturen zu erstellen und optimieren zu können.
Es gibt viele Techniken, die für die Arbeit an Pixel-Art-Texturen relevant sind
und das Verständnis dieser Techniken wird
die Qualität der von Ihnen erstellten Texturen erheblich verbessern.
Detaillierte Ansätze zur Erstellung guter Pixel-Art liegen außerhalb des Rahmens
dieses Buches, stattdessen werden nur die wichtigsten Grundtechniken
behandelt werden.
Es sind viele [gute Online-Tutorials](http://www.photonstorm.com/art/tutorials-art/16x16-pixel-art-tutorial)
zur Verfügung, die die Pixel-Art viel detaillierter behandeln.
- [Techniken](#techniken)
- [Nutzung des Stiftes](#nutzung-des-stiftes)
- [Kacheln](#kacheln)
- [Transparenz](#transparenz)
- [Farbpaletten](#farbpaletten)
- [Editore](#editore)
- [MS Paint](#ms-paint)
- [Aseprite / LibreSprite](#aseprite--libresprite)
- [GIMP](#gimp)
## Techniken
### Nutzung des Stiftes
Das Stiftwerkzeug ist in den meisten Editoren verfügbar. Wenn es auf die kleinste Größe eingestellt ist,
können Sie damit einen Pixel nach dem anderen bearbeiten, ohne andere Teile des Bildes zu
ändern. Indem Sie die Pixel einzeln bearbeiten, schaffen Sie klare
und scharfe Texturen ohne ungewollte Unschärfen. Außerdem bietet es Ihnen ein hohes
Maß an Präzision und Kontrolle.
### Kacheln
Texturen, die für Nodes verwendet werden, sollten in der Regel kachelfähig sein. Das bedeutet
wenn Sie mehrere Nodes mit der gleichen Textur zusammen platzieren, sehen die Kanten
korrekt aus.
<!-- IMAGE NEEDED - cobblestone that tiles correctly -->
Wenn Sie die Kanten nicht richtig anpassen, ist das Ergebnis weit weniger ansprechend.
<!-- IMAGE NEEDED - node that doesn't tile correctly -->
### Transparenz
Transparenz ist wichtig bei der Erstellung von Texturen für fast alle Craftitems
und einige Nodes, wie z. B. Glas.
Nicht alle Editoren unterstützen Transparenz, also stellen Sie sicher, dass Sie einen
Editor, der für die Texturen, die Sie erstellen möchten, geeignet ist.
### Farbpaletten
Die Verwendung einer einheitlichen Farbpalette ist ein einfacher Weg, um Ihre Texturen viel besser aussehen zu lassen.
Es ist eine gute Idee, eine Palette mit einer begrenzten Anzahl von Farben zu verwenden, vielleicht höchstens 32.
Vorgefertigte Paletten finden Sie unter
[lospec.com](https://lospec.com/palette-list).
## Editore
### MS Paint
MS Paint ist ein einfacher Editor, der für einfaches Texturendesign nützlich sein kann;
allerdings unterstützt er keine Transparenz.
Dies spielt normalerweise keine Rolle, wenn Sie Texturen für die Seiten von Nodes erstellen,
aber wenn Sie Transparenz in Ihren Texturen benötigen, sollten Sie einen
anderen Editor wählen.
### Aseprite / LibreSprite
[Aseprite](https://www.aseprite.org/) ist ein proprietärer Pixel-Art-Editor.
Er enthält standardmäßig eine Menge nützlicher Funktionen wie Farbpaletten und
Animationswerkzeuge.
[LibreSprite](https://libresprite.github.io/) ist ein Open-Source-Fork von Aseprite
bevor es proprietär wurde.
### GIMP
GIMP wird in der Minetest-Community häufig verwendet. Es hat eine ziemlich hohe
Lernkurve, da viele seiner Funktionen nicht sofort
offensichtlich sind.
Bei der Verwendung von GIMP kann das Bleistift-Werkzeug aus der Toolbox
ausgewählt werden.s Es ist außerdem ratsam, das Kontrollkästchen "Harte Kanten"
für das Radiergummi-Werkzeug zu aktivieren.

343
_de/items/inventories.md Normal file
View File

@ -0,0 +1,343 @@
---
title: ItemStacks und Inventare
layout: default
root: ../..
idx: 2.4
description: Manipulieren von InvRefs und ItemStacks
redirect_from:
- /de/chapters/inventories.html
- /de/chapters/itemstacks.html
- /de/inventories/inventories.html
- /de/inventories/itemstacks.html
---
## Einleitung <!-- omit in toc -->
In diesem Kapitel werden Sie lernen, wie man Inventare verwendet und manipuliert, egal
ob es sich um ein Spielerinventar, ein Nodeinventar oder ein freistehendes Inventar handelt.
- [Was sind ItemStacks und Inventare?](#was-sind-itemstacks-und-inventare)
- [ItemStacks](#itemstacks)
- [Inventarstandorte](#inventarstandorte)
- [Listen](#listen)
- [Größe und Breite](#größe-und-breite)
- [Inhalt überprüfen](#inhalt-überprüfen)
- [Ändern von Inventaren und ItemStacks](#ändern-von-inventaren-und-itemstacks)
- [Zu einer Liste hinzufügen](#zu-einer-liste-hinzufügen)
- [Items nehmen](#items-nehmen)
- [Stacks manipulieren](#stacks-manipulieren)
- [Abnutzung](#abnutzung)
- [Lua Tabellen](#lua-tabellen)
## Was sind ItemStacks und Inventare?
Ein ItemStack sind die Daten hinter einer einzelnen Zelle in einem Inventar.
Ein *Inventar* ist eine Sammlung von *Inventarlisten*, von denen jede
ein 2D-Gitter aus ItemStacks ist.
Inventarlisten werden im Kontext von Inventaren einfach *Listen* genannt.
Der Sinn eines Inventars ist es, mehrere Raster zu ermöglichen, wenn Spieler
und Nodes nur maximal ein Inventar haben.
## ItemStacks
ItemStacks haben vier Komponenten: name, count, wear und metadata.
Der Itemname kann der Itemname eines registrierten Items, ein Alias oder ein
unbekannter Itemname sein.
Unbekannte Items treten häufig auf, wenn Benutzer Mods deinstallieren oder wenn Mods
Items ohne Vorsichtsmaßnahmen, z. B. durch die Registrierung von Aliasen, entfernen.
```lua
print(stack:get_name())
stack:set_name("default:dirt")
if not stack:is_known() then
print("Ist ein unbekanntes Item!")
end
```
Die Anzahl wird immer 0 oder größer sein.
Bei normalem Spielverlauf sollte die Anzahl nicht größer sein als die maximale
Stackgröße des Gegenstands - `stack_max`.
Allerdings können Admin-Befehle und fehlerhafte Mods dazu führen, dass Stacks die maximale Größe überschreiten.
```lua
print(stack:get_stack_max())
```
Ein ItemStack kann leer sein, in diesem Fall ist die Anzahl 0.
```lua
print(stack:get_count())
stack:set_count(10)
```
ItemStacks können auf verschiedene Weise mit der Funktion ItemStack konstruiert werden.
```lua
ItemStack() -- name="", count=0
ItemStack("default:pick_stone") -- count=1
ItemStack("default:stone 30")
ItemStack({ name = "default:wood", count = 10 })
```
Item-Metadaten sind ein unbegrenzter Schlüssel-Wert-Speicher für Daten über das Item.
Schlüssel-Wert bedeutet, dass Sie einen Namen (den sogenannten key) verwenden, um auf die Daten (den sogenannten value) zuzugreifen.
Einige Keys haben eine besondere Bedeutung, wie z. B. `description`, welches für eine per-Item-Beschreibung verwendet wird.
Dies wird im Kapitel über Metadaten und Speicherung ausführlicher behandelt.
## Inventarstandorte
Ein Inventarstandort ist der Ort und die Art und Weise, wie das Inventar gespeichert wird.
Es gibt drei Arten von Inventarstandorten: Spieler, Nodes und freistehend.
Ein Inventar ist direkt an einen und nur einen Ort gebunden - eine Aktualisierung des
Inventars wird es sofort aktualisieren.
Nodeinventare beziehen sich auf die Position eines bestimmten Nodes, z. B. einer Truhe.
Der Node muss geladen werden, da er in den [Node-Metadaten](../map/storage.html#metadata) gespeichert ist.
```lua
local inv = minetest.get_inventory({ type="node", pos={x=1, y=2, z=3} })
```
Auf diese Weise erhält man eine *Inventar-Referenz*, auch als *InvRef* bekannt.
Inventar-Referenzen werden verwendet, um ein Inventar zu manipulieren.
*Referenz* bedeutet, dass die Daten nicht tatsächlich in diesem Objekt gespeichert sind,
sondern das Objekt aktualisiert die Daten direkt an Ort und Stelle.
Der Standort eines Inventar-Referenz kann wie folgt ermittelt werden:
```lua
local location = inv:get_location()
```
Spielerinventare können auf ähnliche Weise oder über eine Spielerreferenz abgerufen werden.
Der Spieler muss online sein, um auf sein Inventar zugreifen zu können.
```lua
local inv = minetest.get_inventory({ type="player", name="spieler1" })
-- oder
local inv = player:get_inventory()
```
Ein freistehendes Inventar ist ein Inventar, das unabhängig von Spielern oder Nodes ist.
Freistehende Inventare werden auch nicht bei einem Neustart gespeichert.
```lua
local inv = minetest.get_inventory({
type="detached", name="inventar_name" })
```
Im Gegensatz zu den anderen Inventararten müssen Sie zunächst ein freistehendes Inventar erstellen
erstellen, bevor Sie darauf zugreifen:
```lua
minetest.create_detached_inventory("inventar_name")
```
Die Funktion create_detached_inventory akzeptiert 3 Argumente, wobei nur das erste -
der Inventarname - erforderlich ist.
Das zweite Argument nimmt eine Tabelle von Callbacks entgegen, die verwendet werden können,
um zu steuern, wie Spieler mit dem Inventar interagieren:
```lua
-- Nur-Eingabefähiges freistehendes Inventar
minetest.create_detached_inventory("inventory_name", {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
return count -- erlaubt bewegen
end,
allow_put = function(inv, listname, index, stack, player)
return stack:get_count() -- erlaubt ablegen
end,
allow_take = function(inv, listname, index, stack, player)
return 0 -- erlaubt Nehmen nicht
end,
on_put = function(inv, listname, index, stack, player)
minetest.chat_send_all(player:get_player_name() ..
" gab " .. stack:to_string() ..
" In die Spendenkiste von " .. minetest.pos_to_string(player:get_pos()))
end,
})
```
Berechtigungsaufrufe - d.h. diejenigen, die mit `allow_` beginnen - geben die Anzahl
der zu übertragenden Items zurück, wobei 0 verwendet wird, um die Übertragung vollständig zu verhindern.
Im Gegensatz dazu haben Aktionsrückrufe - beginnend mit `on_` - keinen Rückgabewert.
## Listen
Inventarlisten sind ein Konzept, das es ermöglicht, mehrere Raster an einem einzigen Ort zu speichern.
Dies ist besonders nützlich für den Spieler, da es eine Reihe von allgemeinen Listen
gibt, die alle Spiele haben, wie das *Hauptinventar* und die *Craftingplätze*.
### Größe und Breite
Listen haben eine Größe, die die Gesamtzahl der Zellen im Raster angibt, und eine
Breite, die nur innerhalb der Engine verwendet wird.
Die Breite der Liste wird beim Zeichnen des Inventars in einem Fenster nicht verwendet, denn der Code hinter dem Fenster bestimmt die zu verwendende Breite.
```lua
if inv:set_size("main", 32) then
inv:set_width("main", 8)
print("Größe: " .. inv:get_size("main"))
print("Breite: " .. inv:get_width("main"))
else
print("Fehler! Ungültiger itemname oder ungültige Größe für set_size()")
end
```
`set_size` wird fehlschlagen und false zurückgeben, wenn der Listenname oder die Größe ungültig ist.
Zum Beispiel kann die neue Größe zu klein sein, damit alle aktuellen Gegenstände
im Inventar zu passen.
### Inhalt überprüfen
`is_empty` kann benutzt werden, um zu sehen, ob eine Liste Items enthält:
```lua
if inv:is_empty("main") then
print("Die Liste ist leer!")
end
```
`contains_item` kann verwendet werden, um festzustellen, ob eine Liste ein bestimmtes Item enthält:
```lua
if inv:contains_item("main", "default:stone") then
print("Ich habe ein paar Steine gefunden!")
end
```
## Ändern von Inventaren und ItemStacks
### Zu einer Liste hinzufügen
`add_item` fügt Items zu einer Liste hinzu (in diesem Fall `"main"`). Im folgenden
Beispiel wird auch die maximale Stackgröße beachtet:
```lua
local stack = ItemStack("default:stone 99")
local reste = inv:add_item("main", stack)
if reste:get_count() > 0 then
print("Inventar ist voll! " ..
reste:get_count() .. " Items wurden nicht hinzugefügt")
end
```
### Items nehmen
Um Items von einer Liste zu löschen:
```lua
local genommen = inv:remove_item("main", stack)
print("Nahm " .. genommen:get_count())
```
### Stacks manipulieren
Sie können einzelne Stacks ändern, indem Sie sie zuerst auswählen:
```lua
local stack = inv:get_stack(listenname, 0)
```
Dann ändern Sie sie durch das Setzen von Eigenschaften oder durch die Verwendung von
Methoden, welche die `stack_size` respektieren:
```lua
local stack = ItemStack("default:stone 50")
local zum_hinzufuegen = ItemStack("default:stone 100")
local reste = stack:add_item(to_add)
local genommen = stack:take_item(19)
print("Konnte nicht" .. reste:get_count() .. " der items hinzufügen.")
-- ^ wird 51 seind
print("Habe " .. stack:get_count() .. " items")
-- ^ wird 80 sein
-- min(50+100, stack_max) - 19 = 80
-- wobei stack_max = 99
```
`add_item` fügt Items zu einem ItemStack hinzu und gibt alle zurück, die nicht hinzugefügt werden konnten.
`take_item` nimmt bis zu der Anzahl der Items, kann aber auch weniger nehmen, und gibt den genommenen Stack zurück.
Legen Sie schließlich den ItemStack fest:
```lua
inv:set_stack(listenname, 0, stack)
```
## Abnutzung
Werkzeuge können abgenutzt sein; die Abnutzung wird in einem Fortschrittsbalken angezeigt und führt zum Abbruch des Werkzeugs, wenn es vollständig abgenutzt ist.
Die Abnutzung ist eine Zahl bis 65535; je höher sie ist, desto mehr ist das Werkzeug abgenutzt.
Die Abnutzung kann mit `add_wear()`, `get_wear()` und `set_wear(wear)` beeinflusst werden.
```lua
local stack = ItemStack("default:pick_mese")
local max_nutzungen = 10
-- Dies geschieht automatisch, wenn Sie ein Werkzeug verwenden, das Dinge abbaut
-- Sie erhöht die Abnutzung eines Gegenstandes um einen Einsatz.
stack:add_wear(65535 / (max_nutzungen - 1))
```
Beim abbauen eines Nodes kann die Abnutzung des Werkzeugs von dem Node abhängen,
der abgebaut wird. Daher variiert max_nutzungen je nachdem, was abgebaut wird.
## Lua Tabellen
ItemStacks und Inventare können in und aus Tabellen konvertiert werden.
Dies ist nützlich für Kopier- und Bulk-Operationen.
```lua
-- Gesamtes Inventar
local daten = inv1:get_lists()
inv2:set_lists(daten)
-- Eine Liste
local listendaten = inv1:get_list("main")
inv2:set_list("main", listendaten)
```
Die Tabelle der Listen, die von `get_lists()` zurückgegeben wird, wird in dieser Form vorliegen:
```lua
{
liste_eins = {
ItemStack,
ItemStack,
ItemStack,
ItemStack,
-- inv:get_size("liste_eins") Elemente
},
liste_zwei = {
ItemStack,
ItemStack,
ItemStack,
ItemStack,
-- inv:get_size("liste_zwei") Elemente
}
}
```
`get_list()` gibt eine einzelne Liste zurück, die lediglich eine Liste von ItemStacks ist.
Ein wichtiger Punkt ist, dass die obigen Set-Methoden die Größe der Listen nicht verändern.
Das bedeutet, dass Sie eine Liste löschen können, indem Sie sie auf eine leere Tabelle setzen, ohne dass sie verkleinert wird:
```lua
inv:set_list("main", {})
```

442
_de/items/node_drawtypes.md Normal file
View File

@ -0,0 +1,442 @@
---
title: Node Zeichnungstypen
layout: default
root: ../..
idx: 2.3
description: Ratgeber für alle Zeichnungstypen, einschließlich node boxen/Nodeboxen und mesh nodes.
redirect_from: /de/chapters/node_drawtypes.html
---
## Einleitung <!-- omit in toc -->
Die Methode, mit der ein Node gezeichnet wird, wird als *Zeichnungstyp* bezeichnet. Es gibt viele
verfügbare Zeichnungstypen. Das Verhalten eines Zeichnungstyps kann
durch Angabe von Eigenschaften in der Nodetypdefinition gesteuert werden. Diese Eigenschaften
sind für alle Instanzen dieses Nodes festgelegt. Es ist möglich, einige Eigenschaften
pro Node zu steuern, indem man `param2` verwendet.
Im vorigen Kapitel wurde das Konzept der Nodes und Items eingeführt, aber eine
vollständige Definition eines Nodes wurde nicht gegeben. Die Minetest-Welt ist ein 3D-Gitter aus
Positionen. Jede Position wird als Node bezeichnet und besteht aus dem Nodetyp
(Name) und zwei Parametern (param1 und param2). Die Funktion
`minetest.register_node` (übersetzt `minetest.registriere_node`)ist ein wenig irreführend, da sie nicht wirklich
einen Node registriert - sie registriert einen neuen *Typ* von Node.
Die Nodeparameter werden zum steuern, wie ein Nde individuell gerendert wird, verwendet.
`param1` wird verwendet, um die Beleuchtung eines Nodes zu speichern, und die Bedeutung von
`param2` hängt von der Eigenschaft `paramtype2` der Nodetypdefinition ab.
- [Würfelförmiger Node: Normale und allfaces](#würfelförmiger-node-normale-und-allfaces)
- [Glasartige Nodes](#glasartige-nodes)
- [Glasartig gerahmt](#glasartig-gerahmt)
- [Luftartige Nodes](#luftartige-nodes)
- [Beleuchtung und Sonnenlichtausbreitung](#beleuchtung-und-sonnenlichtausbreitung)
- [Flüssige Nodes](#flüssige-nodes)
- [Nodeboxen](#nodeboxen)
- [Wandgehaltene Nodeboxen](#wandgehaltene-nodeboxen)
- [Mesh Nodes](#mesh-nodes)
- [Signlike Nodes](#signlike-nodes)
- [Plantlike Nodes](#plantlike-nodes)
- [Firelike Nodes](#firelike-nodes)
- [Mehr Zeichnungstypen](#mehr-zeichnungstypen)
## Würfelförmiger Node: Normale und allfaces
<figure class="right_image">
<img src="{{ page.root }}//static/drawtype_normal.png" alt="Normaler Zeichnungstyp">
<figcaption>
Normaler Zeichnungstyp
</figcaption>
</figure>
Der Zeichnungstyp normal wird typischerweise zum Rendern eines Würfelförmigen Nodes verwendet.
Wenn die Seite eines normalen Nodes an einer festen Seite anliegt, wird diese Seite nicht gerendert,
was zu einem großen Leistungsgewinn führt.
Im Gegensatz dazu wird der Zeichnungstyp allfaces immer noch die Innenseite darstellen, wenn er auf einen
soliden Node ist. Dies ist gut für Nodes mit teilweise transparenten Seiten, wie z.B. den
Blatt-Node. Sie können den allfaces_optional drawtype verwenden, um den Benutzern die Möglichkeit zu geben, die
langsamere Zeichnen auszuschalten, in diesem Fall verhält er sich wie ein normaler Node.
```lua
minetest.register_node("meinemod:diamant", {
description = "Alien Diamant",
tiles = {"meinemod_diamant.png"},
groups = {cracky = 3},
})
minetest.register_node("default:leaves", {
description = "Blätter",
drawtype = "allfaces_optional",
tiles = {"default_leaves.png"}
})
```
Hinweis: Der normale Zeichentyp ist der Standard-Zeichentyp, Sie müssen ihn also nicht explizit
angeben.
## Glasartige Nodes
Der Unterschied zwischen glasartigen(glasslike) und normalen Nodes besteht darin, dass die Platzierung eines glasartigen Nodes
neben einem normalen Node, nicht dazu führt, dass die Seite des normalen Nodes ausgeblendet wird.
Dies ist nützlich, weil glasartige Nodes in der Regel transparent sind und daher die Verwendung eines normalen
Drawtype dazu führen würde, dass man durch die Welt hindurchsehen kann.
<figure>
<img src="{{ page.root }}//static/drawtype_glasslike_edges.png" alt="Glasartige Ränder">
<figcaption>
Glasartige Ränder
</figcaption>
</figure>
```lua
minetest.register_node("default:obsidian_glass", {
description = "Obsidian Glas",
drawtype = "glasslike",
tiles = {"default_obsidian_glass.png"},
paramtype = "light",
is_ground_content = false,
sunlight_propagates = true,
sounds = default.node_sound_glass_defaults(),
groups = {cracky=3,oddly_breakable_by_hand=3},
})
```
### Glasartig gerahmt
Dies führt dazu, dass die Kante des Nodes mit einem 3D-Effekt um das ganze Ding herumgeht und nicht
um einen einzelnen Node, wie im Folgenden dargestellt:
<figure>
<img src="{{ page.root }}//static/drawtype_glasslike_framed.png" alt="Glasartig gerahmt Ränder">
<figcaption>
Glasartig gerahmt Ränder
</figcaption>
</figure>
Sie können den Zeichnungstyp `glasslike_framed_optional` verwenden, um dem Benutzer die Möglichkeit zu geben,
das gerahmte Erscheinungsbild manuell zu aktivieren.
```lua
minetest.register_node("default:glass", {
description = "Glas",
drawtype = "glasslike_framed",
tiles = {"default_glass.png", "default_glass_detail.png"},
inventory_image = minetest.inventorycube("default_glass.png"),
paramtype = "light",
sunlight_propagates = true, -- Sonnenlicht kann durch den Node scheinen
groups = {cracky = 3, oddly_breakable_by_hand = 3},
sounds = default.node_sound_glass_defaults()
})
```
## Luftartige Nodes
Diese Nodes werden nicht gerendert und haben daher keine Texturen.
```lua
minetest.register_node("meineluft:luft", {
description = "MeineLuft (Du hacker du!)",
drawtype = "airlike",
paramtype = "light",
sunlight_propagates = true,
walkable = false, -- Würde den Spieler mit dem Luftnode kollidieren lassen
pointable = false, -- Sie können den Node nicht auswählen
diggable = false, -- Sie können den Node nicht abbauen
buildable_to = true, -- Nodes können diesen Node ersetzen
-- (Sie können einen Node platzieren und den Luftnode
-- entfernen die früher einmal da waren)
air_equivalent = true,
drop = "",
groups = {not_in_creative_inventory=1}
})
```
## Beleuchtung und Sonnenlichtausbreitung
Die Beleuchtung eines Nodes wird in param1 gespeichert. Um herauszufinden, wie man die
Seite eines Nodes zu schattieren hat, wird der Lichtwert des benachbarten Nodes verwendet.
Aus diesem Grund haben solide Nodes keine Lichtwerte, da sie das Licht blockieren.
Standardmäßig lässt ein Nodetyp nicht zu, dass Licht in Nodeinstanzen gespeichert wird.
Es ist normalerweise wünschenswert, dass einige Nodes wie Glas und Luft in der Lage sind,
Licht durchzulassen. Zu diesem Zweck müssen zwei Eigenschaften definiert werden:
```lua
paramtype = "light",
sunlight_propagates = true,
```
Die erste Zeile bedeutet, dass param1 in der Tat den Lichtwert speichert.
Die zweite Zeile bedeutet, dass das Sonnenlicht diesen Node durchlaufen sollte, ohne an Wert zu verlieren.
## Flüssige Nodes
<figure class="right_image">
<img src="{{ page.root }}//static/drawtype_liquid.png" alt="Flüssigkeiten Zeichnungstyp">
<figcaption>
Flüssigkeiten Zeichnungstyp
</figcaption>
</figure>
Jede Art von Flüssigkeit erfordert zwei Nodedefinitionen - eine für die Flüssigkeitsquelle und
eine weitere für die fließende Flüssigkeit.
```lua
-- Einige Eigenschaften wurden entfernt, da sie nicht mehr
-- den Anwendungsbereich dieses Kapitels entsprechen.
minetest.register_node("default:water_source", {
drawtype = "liquid",
paramtype = "light",
inventory_image = minetest.inventorycube("default_water.png"),
-- ^ dies ist erforderlich, damit das Inventarbild nicht auch animiert wird
tiles = {
{
name = "default_water_source_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 2.0
}
}
},
special_tiles = {
-- Wasserquellenmaterial neuen Typs (größtenteils unbenutzt)
{
name = "default_water_source_animated.png",
animation = {type = "vertical_frames", aspect_w = 16,
aspect_h = 16, length = 2.0},
backface_culling = false,
}
},
--
-- Verhalten
--
walkable = false, -- Der Spieler fällt durch
pointable = false, -- Der Spieler kann es nicht auswählen
diggable = false, -- Der Spieler kann es nicht abbauen
buildable_to = true, -- Nodes können diesen Node ersetzen
alpha = 160,
--
-- Flüssigkeits Eigenschaften
--
drowning = 1,
liquidtype = "source",
liquid_alternative_flowing = "default:water_flowing",
-- ^ wenn die Flüssigkeit fließt
liquid_alternative_source = "default:water_source",
-- ^ wenn die Flüssigkeit eine Quelle ist
liquid_viscosity = WATER_VISC,
-- ^ wie schnell
liquid_range = 8,
-- ^ wie weit
post_effect_color = {a=64, r=100, g=100, b=200},
-- ^ Farbe des Bildschirms, wenn der Spieler untergetaucht ist
})
```
Fließende Nodes haben eine ähnliche Definition, allerdings mit einem anderen Namen und einer anderen Animation.
Siehe `default:water_flowing` in der Standard-Mod in `minetest_game` für ein vollständiges Beispiel.
## Nodeboxen
<figure class="right_image">
<img src="{{ page.root }}//static/drawtype_nodebox.gif" alt="Nodebox Zeichnungstyp">
<figcaption>
Nodebox Zeichnungstyp
</figcaption>
</figure>
Mit Nodeboxen können Sie einen Node erstellen, der nicht würfelförmig ist, sondern
aus beliebig vielen Quadern besteht.
```lua
minetest.register_node("stairs:stair_stone", {
drawtype = "nodebox",
paramtype = "light",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, 0, 0.5, 0.5, 0.5},
},
}
})
```
Der wichtigste Teil ist die Nodebox-Tabelle:
```lua
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, 0, 0.5, 0.5, 0.5}
```
Jede Zeile ist ein Quader, der zu einem einzigen Nodepunkt verbunden ist.
Die ersten drei Zahlen sind die Koordinaten (von -0,5 bis einschließlich 0,5) der
der unteren, vorderen, linken Ecke, die letzten drei Zahlen sind die gegenüberliegende Ecke.
Sie haben die Form X, Y, Z, wobei Y für oben steht.
Sie können den [NodeBoxEditor](https://forum.minetest.net/viewtopic.php?f=14&t=2840) benutzen um
Nodeboxen durch Ziehen der Kanten zu erstellen. Das ist anschaulicher als die Arbeit von Hand.
### Wandgehaltene Nodeboxen
Manchmal möchte man verschiedene Nodeboxen für die Platzierung auf dem Boden, an der Wand oder an der Decke wie bei Fackeln.
```lua
minetest.register_node("default:sign_wall", {
drawtype = "nodebox",
node_box = {
type = "wallmounted",
-- Decke
wall_top = {
{-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125}
},
-- Boden
wall_bottom = {
{-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125}
},
-- Wand
wall_side = {
{-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375}
}
},
})
```
## Mesh Nodes
Nodeboxen sind zwar im Allgemeinen einfacher zu erstellen, doch sind sie insofern eingeschränkt, als dass
sie nur aus Quadern bestehen können. Nodeboxen sind außerdem nicht optimiert;
Innenflächen werden auch dann noch gerendert, wenn sie vollständig ausgeblendet sind.
Eine Fläche ist eine ebene Oberfläche in einem Mesh(Netz). Eine innere Fläche entsteht, wenn sich die Flächen von zwei
verschiedenen Nodeboxen überlappen, wodurch Teile des Nodebox-Modells
unsichtbar sind, aber dennoch gerendert werden.
So können Sie ein Mesh Node registrieren:
```lua
minetest.register_node("mymod:meshy", {
drawtype = "mesh",
-- Enthält die Textur für jedes "material"
tiles = {
"mymod_meshy.png"
},
-- Verzeichnis zum Mesh
mesh = "mymod_meshy.b3d",
})
```
Vergewissern Sie sich, dass das Mesh in einem `models`-Verzeichnis verfügbar ist.
Meistens sollte sich das Mesh im eigenen Mod-Ordner befinden, aber es ist auch in Ordnung, wenn
ein Mesh zu verwenden, das von einer anderen Mod bereitgestellt wird, von dem sie abhängig ist. Zum Beispiel kann eine Mod, die
weitere Möbeltypen hinzufügt, das Modell einer grundlegenden
Möbel-Mod sein.
## Signlike Nodes
Signlike Nodes sind flache Nodes, die an den Seiten anderer Nodes angebracht werden können.
Trotz des Namens dieses Zeichentyps verwenden Schilder in der Regel nicht signlike,
sondern verwenden stattdessen den Zeichnungstyp `Nodebox`, um einen 3D-Effekt zu erzielen. Der Zeichentyp `signlike`
wird jedoch häufig von Leitern verwendet.
```lua
minetest.register_node("default:ladder_wood", {
drawtype = "signlike",
tiles = {"default_ladder_wood.png"},
-- Erforderlich: Speichern der Drehung in param2
paramtype2 = "wallmounted",
selection_box = {
type = "wallmounted",
},
})
```
## Plantlike Nodes
<figure class="right_image">
<img src="{{ page.root }}//static/drawtype_plantlike.png" alt="Plantlike Zeichnungstyp">
<figcaption>
Plantlike Zeichnungstyp
</figcaption>
</figure>
Plantlike Nodes zeichnen ihre Kacheln in einem X-ähnlichen Muster.
```lua
minetest.register_node("default:papyrus", {
drawtype = "plantlike",
-- Nur eine Textur in Verwendung
tiles = {"default_papyrus.png"},
selection_box = {
type = "fixed",
fixed = {-6 / 16, -0.5, -6 / 16, 6 / 16, 0.5, 6 / 16},
},
})
```
## Firelike Nodes
Firelike ist ähnlich zu plantlike, mit der Ausnahme, dass es so konmzipiert ist, dass es auch an Wänden und Decken haften kann.
<figure>
<img src="{{ page.root }}//static/drawtype_firelike.png" alt="Firelike nodes">
<figcaption>
Firelike nodes
</figcaption>
</figure>
```lua
minetest.register_node("meinemod:klinger", {
drawtype = "firelike",
-- Nur eine Textur in Verwendung
tiles = { "mymod:klinger" },
})
```
## Mehr Zeichnungstypen
Dies ist keine vollständige Liste, es gibt noch weitere Arten:
* Fencelike
* Plantlike rooted - für Unterwasser-Pflanzen
* Raillike - für Schienen
* Torchlike - für 2D Wand/Boden/Decken-Nodes.
Die Fackeln in Minetest Game verwenden zwei verschiedene Node-Definitionen von
mesh nodes (default:torch und default:torch_wall).
Und lese immer [Lua API dokumentation](https://minetest.gitlab.io/minetest/nodes/#node-drawtypes)
für eine komplette Liste.

View File

@ -0,0 +1,309 @@
---
title: Nodes, Items und Craften
layout: default
root: ../..
idx: 2.1
description: Benutze register_node, register_item und register_craft um zu lernen, wie man Nodes, Items und Rezepte erstellt.
redirect_from: /de/chapters/nodes_items_crafting.html
---
## Einführung <!-- omit in toc -->
Neue Nodes, Craftitems und Rezepte zu erstellen
sind Grundlagen von vielen Mods
- [Was sind Nodes und Craftitems?](#was-sind-nodes-und-craftitems)
- [Items erstellen](#items-erstellen)
- [Itemnamen](#itemnamen)
- [Itemaliase](#itemaliase)
- [Texturen](#texturen)
- [Erstellen von Basis-Nodes](#erstellen-von-basis-nodes)
- [Crafting](#crafting)
- [Shaped](#shaped)
- [Shapeless](#shapeless)
- [Cooking und Fuel](#cooking-und-fuel)
- [Gruppen](#gruppen)
- [Werkzeuge, Fähigkeiten und Grabungstypen](#werkzeuge-fähigkeiten-und-grabungstypen)
## Was sind Nodes und Craftitems?
Nodes, Craftitems und Tools sind alles Items. Ein Item ist etwas, das im Inventar gefunden werden kann - sogar wenn es im normalen Gameplay nicht möglich ist.
Ein Node ist ein Item, das platziert oder in der Welt gefunden werden kann. Jede Position muss belegt werden mit einem und nur einem Node - scheinbar leere Position sind normalerweise Luftnodes.
Ein Craftitem kann nicht platziert werden. Man kann es nur im Inventar finden oder als gedropptes Item in der Welt.
Ein Werkzeug ist wie ein Item, hat aber die Fähigkeit zu verschleißen. Wenn das Werkzeug benutzt wird, geht der Abnutzungsbalken nach unten, bis das Werkzeug zerbricht. Werkzeuge können auch nicht gestapelt werden. In Zukunft werden Craftitems und Werkzeuge wahrscheinlich verschmelzen, weil die Unterscheidung zwischen ihnen eher ausgedacht ist.
## Items erstellen
Itemdefinitionen bestehen aus einen *Itemnamen* und einer *Definitionstabelle*. Die Definitionstabellen beinhalten Attribute, welche das Verhalten eines Items beeinflussen.
```lua
minetest.register_craftitem("modname:itemname", {
description = "Mein spezielles Item",
inventory_image = "modname_itemname.png"
})
```
### Itemnamen
jedes Item hat einen Itemnamen, welches auf sich verweist. Er sollte folgendes Format haben:
modname:itemname
### Itemaliase
Items können auch *Aliase* haben, die auf ihren Namen zeigen. Ein *Alias* ist ein nachgemachter Itemname, der dazu führt, dass die Engine alle Aliase so behandelt als wären es Itemnamen. Es gibt hierfür zwei verbreitete Anwendungsmöglichkeiten:
* Umbenennen von entfernten Items. Es kann unbekannte Items in der Welt oder im Inventar geben, wenn ein Gegenstand ohne Korrektur aus einen Mod entfernt wird.
* Hinzufügen von Abkürzungen. `/giveme dirt` ist einfacher als `/giveme default:dirt`.
Ein Itemalias zu erstellen ist richtig einfach. Ein guter Weg um sich die Reinfolge von der Argumenten zu merken ist `von → zu` wo *von* der alias ist und *zu* das Orginal.
```lua
minetest.register_alias("dirt", "default:dirt")
```
Mods müssen sicher gehen, dass Alias aufgelöst werden, bevor sie sich direkt mit Itemnamen befassen, da die Engine dies nicht tut. Das ist allerdings ziemlich einfach:
```lua
itemname = minetest.registered_aliases[itemname] or itemname
```
### Texturen
Texturen solten in den textures/ Pfad mit Namen im Format
`modname_itemname.png`.\\
platziert werden. JPEG Texturen werden unterstüzt, aber sie unterstützen keine Transparenz und haben generell
schlechte Qualität und eine niedrige Auflösung.
Es ist oft besser das PNG Format zu benutzen.
Texturen in Minetest sind in der Regel 16 mal 16 Pixel.
Sie können in jeder Auflösung sein, es wird jedoch empfohlen, dass sie in der Größenordnung von 2 liegen, beispielsweise 16, 32, 64 oder 128.
Das liegt daran, dass andere Auflösungen auf älteren Geräten möglicherweise nicht korrekt unterstützt werden, was zu einer geringeren Leistung führt.
## Erstellen von Basis-Nodes
```lua
minetest.register_node("meinemod:diamant", {
description = "Alien Diamanten",
tiles = {"meinemod_diamant.png"},
is_ground_content = true,
groups = {cracky=3, stone=1}
})
```
Die Eigenschaft `tiles` ist eine Tabelle mit Texturnamen, die der Node verwenden wird.
Wenn es nur eine Textur gibt, wird diese Textur auf jeder Seite verwendet.
Um eine andere Textur pro Seite zu erhalten, geben Sie die Namen von 6 Texturen in dieser Reihenfolge an:
oben (+Y), unten (-Y), rechts (+X), links (-X), hinten (+Z), vorne (-Z).
(+Y, -Y, +X, -X, +Z, -Z)
Denken Sie daran, dass +Y in Minetest nach oben zeigt, wie es in den meisten 3D-Computerspielen der Fall ist.
```lua
minetest.register_node("meinemod:diamant", {
description = "Alien Diamanten",
tiles = {
"meinemod_diamant_oben.png", -- y+
"meinemod_diamant_unten.png", -- y-
"meinemod_diamant_rechts.png", -- x+
"meinemod_diamant_links.png", -- x-
"meinemod_diamant_hinten.png", -- z+
"meinemod_diamant_vorne.png", -- z-
},
is_ground_content = true,
groups = {cracky = 3},
drop = "meinemod:diamant_fragment"
-- ^ Anstatt diamanten dropen zu lassen, lassen Sie meinemod:diamant_fragment dropen
})
```
Mit dem Attribut `is_ground_content` können Höhlen über dem Stein erzeugt werden. Dies ist wichtig für jeden Node, der während der Kartenerstellung unterirdisch platziert werden kann. Höhlen werden aus der Welt herausgeschnitten, nachdem alle anderen Nodes in einem Gebiet generiert wurden.
## Crafting
Es gibt verschiedene Arten von Craftingrezepten, die durch die Eigenschaft `type` angezeigt werden.
* shaped - Die Zutaten müssen sich an der richtigen Stelle befinden.
* shapeless - Es spielt keine Rolle, wo sich die Zutaten befinden,
es muss nur die richtige Menge vorhanden sein.
* cooking - Rezepte, die der Ofen verwenden soll.
* fuel - Definiert Gegenstände, die in Öfen verbrannt werden können.
* tool_repair - Definiert Gegenstände, die mit Werkzeugen repariert werden können.
Craftingrezepte sind keine Gegenstände, daher verwenden sie keine eindeutigen Itemnamen um sie zu identifizieren.
### Shaped
Shaped Rezepte sind Rezepte, bei denen die Zutaten die richtige Form oder das richtige
Muster haben müssen, um zu funktionieren. In dem folgenden Beispiel müssen die Fragmente in einem
stuhlähnlichen Muster liegen, damit das Crafting funktioniert.
```lua
minetest.register_craft({
type = "shaped",
output = "meinemod:diamant_stuhl 99",
recipe = {
{"meinemod:diamant_fragment", "", ""},
{"meinemod:diamant_fragment", "meinemod:diamant_fragment", ""},
{"meinemod:diamant_fragment", "meinemod:diamant_fragment", ""}
}
})
```
Zu beachten ist auch die leere Spalte auf der rechten Seite.
Das bedeutet, dass rechts von der Form eine leere Spalte vorhanden sein *muss*, sonst
wird dies nicht funktionieren.
Wenn diese leere Spalte nicht erforderlich sein sollte, können die leeren Strings
folgendermaßen weggelassen werden:
```lua
minetest.register_craft({
type = "shaped",
output = "meinemod:diamant_stuhl 99",
recipe = {
{"meinemod:diamant_fragment", "" },
{"meinemod:diamant_fragment", "meinemod:diamant_fragment"},
{"meinemod:diamant_fragment", "meinemod:diamant_fragment"}
}
})
```
Das Feld "type" wird für Shaped Rezepte nicht benötigt, da "shaped" der
Standard-Craftingtyp ist.
### Shapeless
Shapeless Rezepte sind eine Art von Rezepten, bei denen es nicht darauf ankommt
wo die Zutaten platziert werden, sondern nur, dass sie da sind.
```lua
minetest.register_craft({
type = "shapeless",
output = "meinemod:diamant 3",
recipe = {
"meinemod:diamant_fragment",
"meinemod:diamant_fragment",
"meinemod:diamant_fragment",
},
})
```
### Cooking und Fuel
Rezepte des Typs "cooking" werden nicht im crafting grid hergestellt,
sondern im Ofen oder anderen Kochwerkzeugen, welche womöglich in Mods gefunden werden können, gekocht
```lua
minetest.register_craft({
type = "cooking",
output = "meinemod:diamant_fragment",
recipe = "default:coalblock",
cooktime = 10,
})
```
Der einzige wirklich Unterschied im Code ist, dass das Rezept nur ein Item
im Vergleich zu einer Tabelle (zwischen geschweiften Klammern) beinhaltet.
Sie haben optional auch einen "cooktime" Parameter, welcher
definiert wie lange die Items zu kochen brauchen.
Wenn dies nicht gesetzt ist, ist der Standard 3.
Das Rezept oben funktioniert, wenn der Kohlenode im Input-Slot ist,
mit irgendeiner Form von Brennstoff darunter.
Es stellt nach 10 Sekunden ein Diamant-Fragment her!
Dieser Typ ist eine Ergänzung zum Kochtyp, da er definiert,
was in Öfen und anderen Kochgeräten aus Mods verbrannt werden kann.
```lua
minetest.register_craft({
type = "fuel",
recipe = "meinemod:diamant",
burntime = 300,
})
```
Sie haben keinen Ausgabe wie andere Rezepte, aber sie haben eine Brenndauer
die angibt, wie lange sie in Sekunden als Brennstoff reichen.
Der Diamant ist also 300 Sekunden lang als Brennstoff verwendbar!
## Gruppen
Items können Mitglieder von vielen Gruppen sein und Gruppen können viele Mitglieder haben.
Gruppen werden durch die Verwendung der `groups`-Eigenschaft in der Definitions-Tabelle definiert
und haben einen dazugehörigen Wert.
```lua
groups = {cracky = 3, wood = 1}
```
Es gibt mehrere Gründe für die Verwendung von Gruppen.
Erstens werden Gruppen verwendet, um Eigenschaften wie Abbautyp und Entflammbarkeit zu beschreiben.
Zweitens können Gruppen in einem Handwerksrezept anstelle eines Itemnamens verwendet werden, damit
ein beliebiges Item aus der Gruppe verwendet werden kann.
```lua
minetest.register_craft({
type = "shapeless",
output = "meinemod:diamant_ding 3",
recipe = {"group:holz", "mymod:diamant"}
})
```
## Werkzeuge, Fähigkeiten und Grabungstypen
Grabungstypen sind Gruppen, die dazu benutzt werden, um zu definieren wie stark ein Node ist, wenn er
von verschiedenen Werkzeugen abgebaut wird.
Eine Grabtypgruppe mit einem höheren Wert bedeutet, dass der Node leichter
und schneller abzubauen ist.
Es ist möglich, mehrere Grabtypen zu kombinieren, um eine effizientere Nutzung
von mehreren Werkzeugtypen zu erzielen.
Ein Node ohne Grabtypen kann mit keinem Werkzeug abgebaut werden.
| Gruppe | Bestes Werkzeug | Beschreibung |
|---------|-----------------|-------------|
| crumbly | Schaufel | Erde, Sand |
| cracky | Spitzhacke | Zähes (aber brüchiges) Material wie Stein |
| snappy | *irgendeins* | Kann mit feinen Werkzeugen geschnitten werden;<br>z.B. Blätter, kleine Pflanzen, Draht, Metallbleche |
| choppy | Axt | Kann mit scharfer Gewalt geschnitten werden, z. B. Bäume, Holzbretter |
| fleshy | Schwert | Lebende Dinge wie Tiere und der Spieler <br>Das könnte einige Bluteffekte beim Schlagen mit sich bringen. |
| explody | ? | Besonders anfällig für Explosionen |
| oddly_breakable_by_hand | *irgendeins* | Fackeln und dergleichen - sehr schnell zu graben |
Jedes Werkzeug hat eine Werkzeugfähigkeit.
Eine Fähigkeit umfasst eine Liste der unterstützten Grabtypen und die zugehörigen Eigenschaften
für jeden Typ, wie z. B. die Grabungszeiten und der Grad der Abnutzung.
Werkzeuge können auch eine maximal unterstützte Härte für jeden Typ haben, was es ermöglicht
schwächere Werkzeuge daran zu hindern, härtere Nodes zu graben.
Es ist sehr üblich, dass Werkzeuge alle Grabtypen in ihren Fähigkeiten enthalten.
Die weniger geeigneten haben dabei sehr ineffiziente Eigenschaften.
Wenn der Gegenstand, den ein Spieler gerade trägt, keine explizite Werkzeugfähigkeit
hat, dann wird stattdessen die Fähigkeit der aktuellen Hand verwendet.
```lua
minetest.register_tool("meinemod:werkzeug", {
description = "Mein Werkzeug",
inventory_image = "meinemod_werkzeug.png",
tool_capabilities = {
full_punch_interval = 1.5,
max_drop_level = 1,
groupcaps = {
crumbly = {
maxlevel = 2,
uses = 20,
times = { [1]=1.60, [2]=1.20, [3]=0.80 }
},
},
damage_groups = {fleshy=2},
},
})
```
Groupcaps ist die Liste der unterstützten Grabungstypen für Grabungsnodes.
Schadensgruppen (Damage Groups) dienen zur Steuerung der Art und Weise, wie Werkzeuge Objekte beschädigen; dies wird
später im Kapitel Objekte, Spieler und Entities behandelt werden.

232
_de/map/environment.md Normal file
View File

@ -0,0 +1,232 @@
---
title: Grundlegende Kartenoperationen
layout: default
root: ../..
idx: 3.1
description: Grundlegende Operationen wie set_node und get_node
redirect_from: /de/chapters/environment.html
---
## Einleitung <!-- omit in toc -->
In diesem Kapitel erfahren Sie, wie Sie grundlegende Aktionen auf der Karte durchführen können.
- [Karten-Struktur](#karten-struktur)
- [Lesen](#lesen)
- [Nodes lesen](#nodes-lesen)
- [Nodes finden](#nodes-finden)
- [Schreiben](#schreiben)
- [Nodes schreiben](#nodes-schreiben)
- [Nodes löschen](#nodes-löschen)
- [Mapblöcke laden](#mapblöcke-laden)
- [Nodes löschen](#nodes-löschen-1)
## Karten-Struktur
Die Minetest-Karte ist in Map-Blöcke(nicht zu verwechseln mit Nodes im Deutschen) aufgeteilt, wobei jeder Map-Block ein Würfel der
Kantenlänge 16 ist. Während die Spieler auf der Karte unterwegs sind, werden Map-Blöcke erstellt, geladen,
aktiv und entladen. Bereiche der Karte, die noch nicht geladen sind, sind voll von
*ignore*-Nodes, einem unpassierbaren, nicht auswählbaren Platzhalternode. Leerer Raum ist
voll von *Luft*-Blöcken, einem unsichtbaren Node, durch den man hindurchgehen kann.
Ein aktiver Map-Block ist ein Node, der geladen ist und für den Aktualisierungen durchgeführt werden.
Geladene Map-Blöcke werden oft als *aktive Nodes* bezeichnet. Aktive Nodes können
von Mods oder Spielern gelesen oder beschrieben werden und haben aktive Entities. Die Engine
führt auch Operationen auf der Karte durch, wie z. B. die Ausführung der Flüssigkeitsphysik.
Map-Blöcke können entweder aus der Weltdatenbank geladen oder generiert werden. Map-Blöcke
werden bis zum Limit der Kartengenerierung (`mapgen_limit`) generiert, das
standardmäßig auf den Maximalwert von 31000 gesetzt ist. Vorhandene Map-Blöcke können jedoch
außerhalb des Generierungslimits aus der Weltdatenbank geladen werden.
## Lesen
### Nodes lesen
Sobald Sie eine Position haben, können Sie diese auf der Karte ablesen:
```lua
local node = minetest.get_node({ x = 1, y = 3, z = 4 }) --Warnung: Im Englischen ist mit Node der Map-Block gemeint. Daher emphielt sich für die Variabelnamen node(Node) zu verwenden
print(dump(node)) --> { name=.., param1=.., param2=.. }
```
Handelt es sich bei der Position um eine Dezimalzahl, so wird sie auf den enthaltenen Node gerundet.
Die Funktion gibt immer eine Tabelle mit den Nodeinformationen zurück:
* `name` - Der Nodename, der beim Entladen des Bereichs *ignoriert* wird.
* `param1` - Siehe Node-Definition. Dieser ist in der Regel light.
* `param2` - Siehe Node-Definition.
Es ist erwähnenswert, dass die Funktion den enthaltenen Node nicht lädt, wenn der Node
inaktiv ist, sondern stattdessen eine Tabelle zurückgibt, in der `name` `ignore` ist.
Sie können stattdessen `minetest.get_node_or_nil` verwenden, was `nil` zurückgibt
und nicht eine Tabelle mit dem Namen `ignore`. Allerdings wird der Node dann immer noch nicht geladen.
Dies kann immer noch `ignore` zurückgeben, wenn ein Node tatsächlich ignore enthält.
Dies wird in der Nähe des Randes der Karte passieren, wie es durch die Kartengenerierung definiert ist
Grenze (`mapgen_limit`) definiert ist.
### Nodes finden
Minetest bietet eine Reihe von Hilfsfunktionen, um gängige Map-Aktionen zu beschleunigen.
Die am häufigsten verwendeten Funktionen dienen dem Auffinden von Nodesn.
Angenommen, wir wollen eine bestimmte Pflanzenart herstellen, die besser in der Nähe von Mese wächst;
müssten Sie nach allen Mese-Blöcke in der Nähe suchen,
und die Wachstumsrate entsprechend anpassen.
`minetest.find_node_near` liefert den ersten gefundenen Node in einem bestimmten Radius
der mit den angegebenen Nodenamen oder Gruppen übereinstimmt. Im folgenden Beispiel,
suchen wir nach einem Mese-Node innerhalb von 5 Node von der Position:
```lua
local wachstums_geschwindigkeit = 1
local node_pos = minetest.find_node_near(pos, 5, { "default:mese" })
if node_pos then
minetest.chat_send_all("Bei " .. dump(node_pos) .. " Node gefunden")
wachstums_geschwindigkeit = 2
end
```
Nehmen wir zum Beispiel an, dass die Wachstumsrate steigt, je mehr Mese in der Nähe ist.
Dann sollten Sie eine Funktion verwenden, die mehrere Nodes in dem Gebiet finden kann:
```lua
local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
local pos2 = vector.add(pos, { x = 5, y = 5, z = 5 })
local pos_list =
minetest.find_nodes_in_area(pos1, pos2, { "default:mese" })
local wachstums_geschwindigkeit = 1 + #pos_list
```
Der obige Code ermittelt die Anzahl der Node in einem *kubischen Volumen*. Dies ist anders
zu `find_node_near`, das den Abstand zur Position (d.h. einer *Kugel*) verwendet.
Um dies zu beheben, müssen wir den Bereich manuell selbst überprüfen:
```lua
local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
local pos2 = vector.add(pos, { x = 5, y = 5, z = 5 })
local pos_list =
minetest.find_nodes_in_area(pos1, pos2, { "default:mese" })
local grow_speed = 1
for i=1, #pos_list do
local delta = vector.subtract(pos_list[i], pos)
if delta.x*delta.x + delta.y*delta.y + delta.z*delta.z <= 5*5 then
wachstums_geschwindigkeit = wachstums_geschwindigkeit + 1
end
end
```
Jetzt erhöht der Code korrekt die `wachstums_geschwindigkeit` basierend auf der Anzahl der Node in Reichweite.
Beachten Sie, dass wir den quadrierten Abstand von der Position verglichen haben, anstatt
ihn zu quadrierenum die tatsächliche Entfernung zu erhalten. Dies liegt daran, dass Quadratwurzeln
für den Computer sehr rechenintensiv sind und daher möglichst vermieden werden sollten.
Es gibt weitere Variationen der beiden oben genannten Funktionen, wie z.B.
`find_nodes_with_meta` und `find_nodes_in_area_under_air`, die ähnlich funktionieren
und unter anderen Umständen nützlich sind.
## Schreiben
### Nodes schreiben
Sie können `set_node` verwenden, um in die Karte zu schreiben. Jeder Aufruf von set_node wird dazu führen, dass
die Beleuchtung neu berechnet und Node-Callbacks ausgeführt werden, was bedeutet, dass set_node
bei einer großen Anzahl von Nodesn ziemlich langsam ist.
```lua
minetest.set_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
local node = minetest.get_node({ x = 1, y = 3, z = 4 })
print(node.name) --> default:mese
```
set_node entfernt alle zugehörigen Metadaten oder Bestände von dieser Position.
Dies ist nicht unter allen Umständen wünschenswert, insbesondere wenn Sie mehrere
Node-Definitionen verwenden, um einen konzeptionellen Nodes zu repräsentieren. Ein Beispiel hierfür ist der
Ofennode - während man ihn konzeptionell als einen Node betrachtet, sind es eigentlich
zwei.
Sie können einen Node setzen, ohne die Metadaten oder das Inventar zu löschen, wie folgt:
```lua
minetest.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
```
### Nodes löschen
Ein Node muss immer vorhanden sein. Um einen Node zu entfernen, setzen Sie die Position auf "Luft".
Die folgenden beiden Zeilen entfernen beide einen Node und sind identisch:
```lua
minetest.remove_node(pos)
minetest.set_node(pos, { name = "air" })
```
Tatsächlich ist remove_node nur eine Hilfsfunktion, die set_node mit `"air"` aufruft.
## Mapblöcke laden
Sie können `minetest.emerge_area` verwenden, um Map-Blöcke zu laden. Emerge area ist asynchron,
das heißt, die Mapblöcke werden nicht sofort geladen. Stattdessen werden sie
in der Zukunft geladen und der Callback wird jedes Mal aufgerufen.
```lua
-- Lädt einen 20x20x20-Bereich
local halbegroesse = { x = 10, y = 10, z = 10 } --ss = ß
local pos1 = vector.subtract(pos, halbegroesse)
local pos2 = vector.add (pos, halbegroesse)
local kontext = {} -- Daten zwischen Callback-Aufrufen aufrechterhalten
minetest.emerge_area(pos1, pos2, emerge_callback, kontext)
```
Minetest ruft `emerge_callback` immer dann auf, wenn er einen Map-Block, mit einigen
Fortschrittsinformationen, lädt.
```lua
local function emerge_callback(pos, aktion,
verbleibende_calls, kontext)
-- Beim ersten Aufruf, Anzahl der Mapblöcke erfassen
if not kontext.bloecke_insgesamt then
kontext.bloecke_insgesamt = verbleibende_calls + 1
kontext.geladene_bloecke = 0
end
-- Erhöhung der Anzahl der geladenen Nodes
kontext.bloecke_insgesamt = kontext.geladene_bloecke + 1
-- Fortschrittsmeldung senden
if kontext.bloecke_insgesamt == kontext.geladene_bloecke then
minetest.chat_send_all("Blöcke laden abgeschlossen!")
end
local perc = 100 * kontext.geladene_bloecke / kontext.bloecke_insgesamt
local msg = string.format("Geladene Nodes %d/%d (%.2f%%)",
kontext.geladene_bloecke, kontext.bloecke_insgesamt, perc)
minetest.chat_send_all(msg)
end
end
```
Dies ist nicht die einzige Möglichkeit, Mapblöcke zu laden; die Verwendung eines
[Lua Voxel Manipulator (LVM)](../advmap/lvm.html) bewirkt ebenfalls, dass die
umschlossenen Mapblöcke synchron geladen werden.
## Nodes löschen
Sie können delete_blocks verwenden, um einen Bereich von Map-Blöcken zu löschen:
```lua
-- Löscht einen 20x20x20-Bereich
local halbegroesse = { x = 10, y = 10, z = 10 }
local pos1 = vector.subtract(pos, halbegroesse)
local pos2 = vector.add (pos, halbegroesse)
minetest.delete_area(pos1, pos2)
```
Dadurch werden alle Map-Blöcke in diesem Bereich *inklusive* gelöscht. Das bedeutet, dass einige
Blöcke außerhalb des Bereichs gelöscht werden, da sie sich auf einem Map-Block befinden, der sich mit den
die Bereichsgrenzen überlappen.

363
_de/map/objects.md Normal file
View File

@ -0,0 +1,363 @@
---
title: Objekte, Spieler und Entities
layout: default
root: ../..
idx: 3.4
description: Nutzung eines ObjectRef
degrad:
level: warning
title: Grad and Radiant
message: >-
Die Drehung von Anbauteilen wird in Grad angegeben, während die Drehung
von Objekten in Radiant angegeben wird. Stellen Sie sicher, dass Sie das
richtige Winkelmaß verwenden.
---
## Einleitung <!-- omit in toc -->
In diesem Kapitel lernen Sie, wie man Objekte manipuliert und eigene Objekte
definiert.
- [Was sind Objekte, Spieler, und Entities?](#was-sind-objekte-spieler-und-entities)
- [Position und Geschwindigkeit](#position-und-geschwindigkeit)
- [Objekt-Eigenschaften](#objekt-eigenschaften)
- [Entities](#entities)
- [Leben und Schaden](#leben-und-schaden)
- [Lebenspunkte (HP)](#lebenspunkte-hp)
- [Schlagen, Damage Groups, und Armor Groups](#schlagen-damage-groups-und-armor-groups)
- [Beispiel für die Schadensberechnung](#beispiel-für-die-schadensberechnung)
- [Anhänge](#anhänge)
- [Sie sind dran](#sie-sind-dran)
## Was sind Objekte, Spieler, und Entities?
Spieler und Entities sind beide Arten von Objekten. Ein Objekt ist etwas, das sich unabhängig
vom Node-Raster bewegen kann und Eigenschaften wie Geschwindigkeit und Skalierung besitzt.
Objekte sind keine Gegenstände, und sie haben ihr eigenes Registrierungssystem.
Es gibt ein paar Unterschiede zwischen Spielern und Entities.
Der größte ist, dass Spieler von Spielern gesteuert werden, während Entities von Mods gesteuert werden.
Das bedeutet, dass die Geschwindigkeit eines Spielers nicht von Mods eingestellt werden kann -
Spieler sind client-seitig, und Entities sind serverseitig.
Ein weiterer Unterschied ist, dass Spieler das Laden von Kartenblöcken verursachen, während Entities
nur gespeichert werden und inaktiv werden.
Diese Unterscheidung wird durch die Tatsache erschwert, dass Entities über eine Tabelle
gesteuert werden, die als Lua entity bezeichnet wird, wie später erläutert wird.
## Position und Geschwindigkeit
`get_pos` und `set_pos` existieren, um die Position eines Entitys zu ermitteln und zu setzen.
```lua
local objekt = minetest.get_player_by_name("bob")
local pos = objekt:get_pos()
objekt:set_pos({ x = pos.x, y = pos.y + 1, z = pos.z })
```
`set_pos` setzt die Position sofort und ohne Animation. Wenn Sie ein Objekt
sanft an die neue Position animieren möchten, sollte man `move_to` verwenden.
Dies funktioniert leider nur für Entities.
```lua
objekt:move_to({ x = pos.x, y = pos.y + 1, z = pos.z })
```
Ein wichtiger Punkt beim Umgang mit Entities ist die Latenzzeit im Netz.
In einer idealen Welt würden Nachrichten über Entitybewegungen sofort ankommen,
in der richtigen Reihenfolge und in einem ähnlichen Intervall ankommen, wie Sie sie gesendet haben.
Solange man sich jedoch nicht im Einzelspielermodus befindet, ist dies keine ideale Welt.
Nachrichten brauchen eine Weile, bis sie ankommen. Positionsnachrichten können in der falschen Reihenfolge ankommen,
was dazu führt, dass einige `set_pos`-Aufrufe übersprungen werden, da es keinen Sinn macht, zu einer
Position zu gehen, die älter ist als die aktuell bekannte Position.
Bewegungen können nicht in ähnlichen Abständen erfolgen, was es schwierig macht, sie für Animationen zu verwenden.
All dies führt dazu, dass der Client andere Dinge sieht als der Server, und das ist etwas,
das Sie beachten müssen.
## Objekt-Eigenschaften
Objekt-Eigenschaften werden verwendet, um dem Client mitzuteilen, wie ein Objekt zu rendern und zu behandeln ist.
Es ist nicht möglich, benutzerdefinierte Eigenschaften zu definieren, denn die Eigenschaften sind
per Definition von der Engine zu verwenden.
Im Gegensatz zu Blöcken haben Objekte ein dynamisches und kein festes Aussehen.
Sie können unter anderem das Aussehen eines Objekts jederzeit ändern, indem Sie
seine Eigenschaften ändern.
```lua
object:set_properties({
visual = "mesh",
mesh = "character.b3d",
textures = {"character_texture.png"},
visual_size = {x=1, y=1},
})
```
Die aktualisierten Eigenschaften werden an alle Spieler in Reichweite gesendet.
Dies ist sehr nützlich, um eine große Menge an Vielfalt sehr einfach zu bekommen, wie zum Beispiel
verschiedene Skins pro Spieler.
Wie im nächsten Abschnitt gezeigt wird, können Entities Erst-Eigenschaften haben,
die in ihrer Definition angegeben werden.
Die Standardeigenschaften des Spielers sind jedoch in der Engine definiert, so dass man
`on_joinplayer` die Funktion `set_properties()` verwenden kann, um die Eigenschaften für neue
Spieler zu setzen.
## Entities
Ein Entity hat eine Definitionstabelle, die einer Objektdefinitionstabelle ähnelt.
Diese Tabelle kann Callback-Methoden, anfängliche Objekteigenschaften und benutzerdefinierte
Mitglieder enthalten.
```lua
local MeinEntity = {
initial_properties = {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
visual = "wielditem",
visual_size = {x = 0.4, y = 0.4},
textures = {""},
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
},
message = "Default message",
}
function MeinEntity:set_message(msg)
self.message = msg
end
```
Entity-Definitionen unterscheiden sich in einem sehr wichtigen Punkt von Item-Definitionen.
Wenn ein Entity auftaucht (d.h.: geladen oder erstellt wird), wird eine neue Tabelle für
dieses Entity erstellt, die es von der Definitionstabelle *erbt*.
<!--
Diese Vererbung wird mit Hilfe von Metatabellen durchgeführt.
Metatabellen sind eine wichtige Lua-Funktion, die Sie kennen müssen, da sie
ist ein wesentlicher Bestandteil der Lua-Sprache. Laienhaft ausgedrückt, erlaubt eine Metatabelle
zu steuern, wie sich die Tabelle bei der Verwendung bestimmter Lua-Syntaxen verhält. Die häufigste
Verwendung von Metatabellen ist die Möglichkeit, eine andere Tabelle als Prototyp zu verwenden,
Eigenschaften und Methoden der anderen Tabelle zu verwenden,
wenn sie in der aktuellen Tabelle nicht vorhanden sind.
Angenommen, Sie wollen auf `a.x` zugreifen. Wenn die Tabelle `a` dieses Element hat, dann wird es
normal zurückgegeben. Wenn die Tabelle jedoch nicht über dieses Element verfügt und die
metatable eine Tabelle `b` als Prototyp aufführt, wird die Tabelle `b` daraufhin überprüft
um zu sehen, ob sie dieses Mitglied hat.
-->
Sowohl ein ObjectRef als auch eine Entity-Tabelle bieten Möglichkeiten, das Gegenstück zu erhalten:
```lua
local entity = object:get_luaentity()
local objekt = entity.objekt
print("Entity ist bei " .. minetest.pos_to_string(objekt:get_pos()))
```
Es gibt eine Reihe von Callbacks für die Verwendung mit Entities.
Eine vollständige Liste findet sich in [lua_api.txt 🇬🇧](https://minetest.gitlab.io/minetest/minetest-namespace-reference/#registered-definition-tables).
```lua
function MeinEntity:on_step(dtime)
local pos = self.object:get_pos()
local pos_drunter = vector.subtract(pos, vector.new(0, 1, 0))
local delta
if minetest.get_node(pos_drunter).name == "air" then
delta = vector.new(0, -1, 0)
elseif minetest.get_node(pos).name == "air" then
delta = vector.new(0, 0, 1)
else
delta = vector.new(0, 1, 0)
end
delta = vector.multiply(delta, dtime)
self.object:move_to(vector.add(pos, delta))
end
function MeinEntity:on_punch(hitter)
minetest.chat_send_player(hitter:get_player_name(), self.message)
end
```
Wenn Sie nun diese Entity spawnen und verwenden würden, würden Sie feststellen, dass die Nachricht
vergessen wird, wenn die Entity inaktiv und dann wieder aktiv wird.
Das liegt daran, dass die Nachricht nicht gespeichert wird.
Anstatt alles in der Entity-Tabelle zu speichern, gibt Minetest Ihnen die Kontrolle darüber
wie die Dinge gespeichert werden sollen.
Staticdata ist ein String, der alle benutzerdefinierten Informationen enthält, die
gespeichert werden müssen.
```lua
function MeinEntity:get_staticdata()
return minetest.write_json({
message = self.message,
})
end
function MeinEntity:on_activate(staticdata, dtime_s)
if staticdata ~= "" and staticdata ~= nil then
local data = minetest.parse_json(staticdata) or {}
self:set_message(data.message)
end
end
```
Minetest kann `get_staticdata()` so oft wie gewünscht und zu jeder Zeit aufrufen.
Der Grund dafür ist, dass Minetest nicht darauf wartet, dass ein Map-Block inaktiv wird,
um ihn zu speichern, da dies zu Datenverlusten führen würde. Map-Blöcke werden ungefähr alle 18
Sekunden gespeichert, also sollten Sie ein ähnliches Intervall für den Aufruf von `get_staticdata()` feststellen.
`on_activate()` wird dagegen nur aufgerufen, wenn eine Entity
aktiv wird, entweder wenn der Map-Block aktiv wird oder wenn die Entity spawnen wird.
Dies bedeutet, dass staticdata leer sein könnte.
Schließlich müssen Sie die Typentabelle mit der treffenden Bezeichnung `register_entity` registrieren.
```lua
minetest.register_entity("meinemod:entity", MeinEntity)
```
Die Entity kann von einem Mod wie folgt erzeugt werden:
```lua
local pos = { x = 1, y = 2, z = 3 }
local obj = minetest.add_entity(pos, "meinemod:entity", nil)
```
Der dritte Parameter sind die anfänglichen statischen Daten.
Um die Nachricht einzustellen, können Sie die Methode der Entity-Tabelle verwenden:
```lua
obj:get_luaentity():set_message("hello!")
```
Spieler mit dem *give* [Privileg](../players/privileges.html) können
einen [Chat command](../players/chat.html) zum spawnen von entities benutzen:
/spawnentity mymod:entity
## Leben und Schaden
### Lebenspunkte (HP)
Jedes Objekt hat eine Anzahl von Lebenspunkten (HP), die die aktuelle Gesundheit darstellt.
Spieler haben eine maximale Lebenspunktzahl, die mit der Objekteigenschaft `hp_max` festgelegt wird.
Ein Objekt stirbt, wenn seine HP 0 erreichen.
```lua
local hp = object:get_hp()
object:set_hp(hp + 3)
```
### Schlagen, Damage Groups, und Armor Groups
Schaden ist die Verringerung der HP eines Objekts. Ein Objekt kann ein anderes Objekt *schlagen*, um
Schaden zuzufügen. Ein Schlag muss nicht unbedingt ein echter Schlag sein - es kann auch eine
Explosion, ein Schwerthieb oder etwas anderes sein.
Der Gesamtschaden wird durch Multiplikation der Schadensgruppen des Schlags mit den
Verwundbarkeiten des Ziels berechnet. Dies wird dann begrenzt, je nachdem, wie lange der letzte
Schlag her war. Wir werden gleich ein Beispiel für diese Berechnung erläutern.
Genau wie [Node Grabungsgruppen](../items/nodes_items_crafting.html#tools-capabilities-and-dig-types),
können diese Gruppen jeden Namen annehmen und müssen nicht registriert werden. Es ist jedoch
üblich, dieselben Gruppennamen wie bei Node digging zu verwenden.
Wie anfällig ein Objekt für bestimmte Arten von Schaden ist, hängt von seiner
`armor_groups` [Objekteigenschaft](#objekt-eigenschaften) ab. Trotz seines irreführenden
Namen gibt `armor_groups` den prozentualen Schaden von bestimmten
Schadensgruppen an und nicht den Widerstand. Wenn eine Schadensgruppe nicht in den Armor Groups eines Objekts aufgeführt ist,
ist das Objekt völlig unverwundbar.
```lua
target:set_armor_groups({
fleshy = 90,
crumbly = 50,
})
```
Im obigen Beispiel erleidet das Objekt 90 % `fleshy` Schadens und 50 % des
`crumbly`-Schaden.
Wenn ein Spieler ein Objekt schlägt, stammen die Schadensgruppen von dem Gegenstand, das er
gerade trägt. In anderen Fällen entscheiden die Mods, welche Schadensgruppen verwendet werden.
### Beispiel für die Schadensberechnung
Schlagen wir das Objekt `target`:
```lua
local werkzeug_faehigkeiten = {
full_punch_interval = 0.8,
damage_groups = { fleshy = 5, choppy = 10 },
-- Dies wird nur für das abbauen von Nodes verwendet, ist aber dennoch erforderlich
max_drop_level=1,
groupcaps={
fleshy={times={[1]=2.5, [2]=1.20, [3]=0.35}, uses=30, maxlevel=2},
},
}
local zeit_seit_letzten_schlag = werkzeug_faehigkeiten.full_punch_interval
target:punch(object, zeit_seit_letzten_schlag, werkzeug_faehigkeiten)
```
Berechnen wir nun, wie hoch der Schaden sein wird. Die Schadensgruppen des Schlags sind
`fleshy=5` und `choppy=10`, und die Zielperson erleidet 90% Schaden durch fleshy und 0%
von choppy.
Zuerst multiplizieren wir die Schadensgruppen mit der Verwundbarkeit und addieren das Ergebnis.
Dann multiplizieren wir mit einer Zahl zwischen 0 oder 1, abhängig von der `zeit_seit_letzten_schlag`.
```lua
= (5*90/100 + 10*0/100) * limit(zeit_seit_letzten_schlag / full_punch_interval, 0, 1)
= (5*90/100 + 10*0/100) * 1
= 4.5
```
Da die HP eine ganze Zahl sind, wird der Schaden auf 5 Lebenspunkte gerundet.
## Anhänge
Angehängte Objekte bewegen sich, wenn das übergeordnete Objekt - also das Objekt, an das sie angehängt sind -
bewegt wird. Ein angefügtes Objekt ist ein Kind des übergeordneten Objekts.
Ein Objekt kann eine unbegrenzte Anzahl von Kindern haben, aber höchstens ein Elternteil.
```lua
child:set_attach(parrent, knochen, position, drehung)
```
Die Funktion `get_pos()` eines Objekts gibt immer die globale Position des Objekts zurück,
unabhängig davon, ob es angehängt ist oder nicht.
`set_attach` nimmt eine relative Position, aber nicht so, wie man es erwarten würde.
Die Anhängeposition ist relativ zum Ursprung des Elternobjekts und wird um das 10-fache vergrößert.
Also wäre "0,5,0" ein halber Node über dem Ursprung des Elternobjekts.
{% include notice.html notice=page.degrad %}
Bei 3D-Modellen mit Animationen wird das Argument knochen verwendet, um das Entity
an einen Knochen zu binden.
3D-Animationen basieren auf Skeletten - einem Netzwerk von Knochen im Modell, bei dem
jedem Knochen eine Position und Drehung zugewiesen werden kann, um das Modell zu verändern, z. B,
um den Arm zu bewegen.
Das Anhängen an einen Knochen ist nützlich, wenn Sie eine Figur etwas halten lassen wollen:
```lua
obj:set_attach(spieler,
"Arm_Right", -- normaler Knochen
{x=0.2, y=6.5, z=3}, -- normale Position
{x=-100, y=225, z=90}) -- normale Drehung
```
## Sie sind dran
* Erstelle eine Windmühle, indem du Nodes und eine Entity kombinierst.
* Erstelle einen Mob deiner Wahl (nur mit der Entity-API und ohne andere Mods zu verwenden).

247
_de/map/storage.md Normal file
View File

@ -0,0 +1,247 @@
---
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 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_<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 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`.)

109
_de/map/timers.md Normal file
View File

@ -0,0 +1,109 @@
---
title: Node Timer und ABMs
layout: default
root: ../..
idx: 3.2
description: Lernen Sie, wie man ABMs zum Ändern von Mapblöcken erstellt.
redirect_from:
- /de/chapters/abms.html
- /de/map/abms.html
---
## Einleitung <!-- omit in toc -->
Die periodische Ausführung einer Funktion auf bestimmten Node ist eine häufige Aufgabe.
Minetest bietet dafür zwei Methoden: Aktive Map-Block Modifikatoren (ABMs) und Node-Timer(node timers).
ABMs scannen alle geladenen Map-Blöcke auf der Suche nach Blöcken, die einem Kriterium entsprechen.
Sie eignen sich am besten für Blöcken, die in der Welt häufig vorkommen,
wie zum Beispiel Gras.
Sie haben einen hohen CPU-Overhead, aber einen geringen Speicher- und Storage-Overhead.
Für Blöcke, die ungewöhnlich sind oder bereits Metadaten verwenden, wie Öfen
und Maschinen, sollten stattdessen Nodetimer verwendet werden.
Nodetimer funktionieren, indem sie die ausstehenden Timer in jedem Map-Block verfolgen und dann ausführen
wenn sie ablaufen.
Dies bedeutet, dass die Zeitgeber nicht alle geladenen Blöcke durchsuchen müssen, um Übereinstimmungen zu finden,
sondern stattdessen etwas mehr Speicherplatz für die Verfolgung
der ausstehenden Timer benötigen.
- [Nodetimer](#nodetimer)
- [Aktive Mapblock Modifikatoren](#aktive-mapblock-modifikatoren)
- [Sie sind dran](#sie-sind-dran)
## Nodetimer
Nodetimer sind direkt an einen einzelnen Node gebunden.
Sie können Nodetimer verwalten, indem Sie ein NodeTimerRef-Objekt erhalten.
```lua
local timer = minetest.get_node_timer(pos)
timer:start(10.5) -- in Sekunden
```
Wenn der Zeitgeber eines Nodes abgelaufen ist, wird die Methode `on_timer` in der Definitionstabelle des Nodes
aufgerufen. Die Methode benötigt nur einen einzigen Parameter, die Position des Nodes:
```lua
minetest.register_node("autotuer:offene_tuer", {
on_timer = function(pos)
minetest.set_node(pos, { name = "autotuer:offene_tuer" })
return false
end
})
```
Die Rückgabe von true in `on_timer` bewirkt, dass der Timer wieder für das gleiche Intervall läuft.
Es ist auch möglich, `get_node_timer(pos)` innerhalb von `on_timer` zu verwenden, stellen Sie nur sicher
dass Sie false zurückgeben, um Konflikte zu vermeiden.
Sie haben vielleicht eine Einschränkung bei den Zeitgebern bemerkt: Aus Optimierungsgründen ist
nur eine Art von Timern pro Nodetyp und nur ein Timer pro Node möglich.
## Aktive Mapblock Modifikatoren
Für die Zwecke dieses Kapitels ist Aliengras eine Grasart, die
in der Nähe von Wasser vorkommen kann.
```lua
minetest.register_node("aliens:gras", {
description = "Aliengras",
light_source = 3, -- Der Node strahlt Licht aus. Min 0, max 14
tiles = {"aliens_grass.png"},
groups = {choppy=1},
on_use = minetest.item_eat(20)
})
minetest.register_abm({
nodenames = {"default:dirt_with_grass"},
neighbors = {"default:water_source", "default:water_flowing"},
interval = 10.0, -- Wird alle 10 Sekunden ausgeführt
chance = 50, -- Jeder Node hat eine Chance von 1 zu 50 ausgewählt zu werden
action = function(pos, node, active_object_count,
active_object_count_wider)
local pos = {x = pos.x, y = pos.y + 1, z = pos.z}
minetest.set_node(pos, {name = "aliens:gras"})
end
})
```
Dieser ABM läuft alle zehn Sekunden, und für jeden passenden Node besteht eine
Chance von 1 zu 50, dass es ausgeführt wird.
Wenn die ABM auf einem Node ausgeführt wird, wird ein fremder Grasnode über ihm platziert.
Bitte seien Sie gewarnt, dies löscht alle Blöcke, die sich zuvor an dieser Position befanden.
Um dies zu verhindern, sollten Sie eine Überprüfung mit minetest.get_node einbauen, um sicherzustellen, dass Platz für das Gras vorhanden ist.
Die Angabe eines Nachbarn(neighbor) ist optional.
Wenn Sie mehrere Nachbarn angeben, muss nur einer von ihnen vorhanden sein
vorhanden sein, um die Anforderungen zu erfüllen.
Die Angabe der Chance ist ebenfalls optional.
Wenn Sie die Chance nicht angeben, wird der ABM immer ausgeführt, wenn die anderen Bedingungen erfüllt sind.
## Sie sind dran
* Midas Berührung: Verwandelt Wasser alle 5 Sekunden mit einer Wahrscheinlichkeit von 1 zu 100 in Goldblöcke.
* Fäulnis: Verwandelt Holz in Dreck um, wenn Wasser der Nachbar ist.
* Brennen: Bringt jeden LuftNode in Brand. (Tipp: "air" und "fire:basic_flame").
Warnung: Rechnen Sie damit, dass das Spiel abstürzt.

166
_de/players/chat.md Normal file
View File

@ -0,0 +1,166 @@
---
title: Chat und Befehle
layout: default
root: ../..
idx: 4.2
description: Registrierung eines Chatbefehls und Behandlung von Chatnachrichten mit register_on_chat_message
redirect_from: /de/chapters/chat.html
cmd_online:
level: warning
title: Offline-Spieler können Befehle ausführen
message: <p>Ein Spielername wird anstelle eines Spielerobjekts übergeben, da Mods
Befehle im Namen von Offline-Spielern ausführen können. Zum Beispiel erlaubt die IRC-
Brücke den Spielern, Befehle auszuführen, ohne dem Spiel beizutreten.</p>
<p>Stellen Sie also sicher, dass Sie nicht davon ausgehen, dass der Spieler online ist.
Sie können überprüfen, ob <pre>minetest.get_player_by_name</pre> einen Spieler liefert.</p>
cb_cmdsprivs:
level: warning
title: Privilegien und Chat-Befehle
message: Das "Shout"-Privileg ist für einen Spieler nicht erforderlich, um diesen Callback auszulösen.
Das liegt daran, dass Chat-Befehle in Lua implementiert sind, und nur
Chat-Nachrichten sind, die mit einem / beginnen.
---
## Einleitung <!-- omit in toc -->
Mods können mit dem Spielerchat interagieren, einschließlich
Senden von Nachrichten, Abfangen von Nachrichten und Registrieren von Chat-Befehlen.
- [Senden von Nachrichten an alle Spieler](#senden-von-nachrichten-an-alle-spieler)
- [Nachrichten an bestimmte Spieler senden](#nachrichten-an-bestimmte-spieler-senden)
- [Chat-Befehle](#chat-befehle)
- [Komplexe Unterbefehle](#komplexe-unterbefehle)
- [Abfangen von Nachrichten](#abfangen-von-nachrichten)
## Senden von Nachrichten an alle Spieler
Um eine Nachricht an alle Spieler im Spiel zu senden, rufen Sie die Funktion chat_send_all auf.
```lua
minetest.chat_send_all("Dies ist eine Chat-Nachricht an alle Spieler")
```
Hier ist ein Beispiel dafür, wie dies im Spiel aussieht:
<player1> Sehen Sie sich diesen Eingang an
Dies ist eine Chat-Nachricht an alle Spieler
<player2> Was ist damit?
Die Nachricht erscheint in einer separaten Zeile, um sie vom Spieler-Chat im Spiel zu unterscheiden.
## Nachrichten an bestimmte Spieler senden
Um eine Nachricht an einen bestimmten Spieler zu senden, rufen Sie die Funktion chat_send_player auf:
```lua
minetest.chat_send_player("Spieler1", "Dies ist eine Chat-Nachricht für Spieler1")
```
Diese Nachricht wird auf dieselbe Weise angezeigt wie die Nachrichten an alle Spieler, ist aber
nur für den benannten Spieler sichtbar, in diesem Fall für Spieler1.
## Chat-Befehle
Um einen Chat-Befehl zu registrieren, zum Beispiel `/foo`, verwenden Sie `register_chatcommand`:
```lua
minetest.register_chatcommand("foo", {
privs = {
interact = true,
},
func = function(name, param)
return true, "Sie sagten " .. param .. "!"
end,
})
```
Im obigen Ausschnitt ist "interact" als erforderliches
[Privileg](privileges.html) aufgeführt, was bedeutet, dass nur Spieler mit dem Privileg "interact" den Befehl ausführen können.
Chat-Befehle können bis zu zwei Werte zurückgeben,
Der erste ist ein boolescher Wert, der den Erfolg anzeigt, und der zweite ist eine
Nachricht, die an den Benutzer gesendet wird.
{% include notice.html notice=page.cmd_online %}
## Komplexe Unterbefehle
Es wird oft benötigt, komplexe Chat-Befehle zu bereitzustellen, wie z.B.:
* `/msg <zu> <Nachricht>`
* `/team join <Teamname>`
* `/team leave <Teamname>`
* `/team list`
Dies geschieht normalerweise mit [Lua-Mustern] (https://www.lua.org/pil/20.2.html).
Patterns sind eine Methode, um anhand von Regeln Dinge aus Text zu extrahieren.
```lua
local to, msg = param:match("^([%a%d_-]+) (.+)$")
```
Der obige Code implementiert `/msg <zu> <Nachricht>`. Lassen Sie uns von links nach rechts vorgehen:
* `^` bedeutet, dass der Anfang der Zeichenkette übereinstimmt.
* `()` ist eine übereinstimmende Gruppe - alles, was hier drin steht, wird
von string.match zurückgegeben.
* `[]` bedeutet, dass die Zeichen in dieser Liste akzeptiert werden.
* `%a` bedeutet, jeden Buchstaben zu akzeptieren und `%d` bedeutet, eine beliebige Ziffer zu akzeptieren.
* `[%a%d_-]` bedeutet, einen beliebigen Buchstaben, eine beliebige Ziffer, `_` oder `-` zu akzeptieren.
* `+` bedeutet, dass die Sache ein oder mehrere Male übereinstimmt.
* `.` bedeutet, dass ein beliebiges Zeichen in diesem Zusammenhang übereinstimmt.
* `$` bedeutet, das Ende der Zeichenkette zu finden.
Einfach ausgedrückt: Das Muster entspricht dem Namen (ein Wort mit nur Buchstaben/Zahlen/-/_),
dann ein Leerzeichen, dann die Nachricht (ein oder mehrere beliebige Zeichen). Der Name und die
werden zurückgegeben, da sie von Klammern umgeben sind.
Das ist die Art und Weise, wie die meisten Mods komplexe Chat-Befehle implementieren. Eine bessere Anleitung für Lua
Patterns wäre wahrscheinlich das
[lua-users.org tutorial](http://lua-users.org/wiki/PatternsTutorial)
oder die [PIL-Dokumentation](https://www.lua.org/pil/20.2.html).
<p class="book_hide">
Es gibt auch eine vom Autor dieses Buches geschriebene Bibliothek, die man dazu benutzen
kann um komplexe Chat-Befehle ohne Muster zu erstellen, den
<a href="https://gitlab.com/rubenwardy/ChatCmdBuilder">Chat Command Builder</a>.
</p>
## Abfangen von Nachrichten
Um eine Nachricht abzufangen, verwenden Sie register_on_chat_message:
```lua
minetest.register_on_chat_message(function(name, message)
print(name .. " sagte " .. message)
return false
end)
```
Wenn Sie false zurückgeben, erlauben Sie, dass die Chat-Nachricht vom Standard
Handler gesendet wird. Sie können die Zeile `return false` sogar entfernen und es würde immer noch
funktionieren, da `nil` implizit zurückgegeben wird und wie false behandelt wird.
{% include notice.html notice=page.cb_cmdsprivs %}
Sie sollten berücksichtigen, dass es sich um einen Chat-Befehl handeln könnte,
oder der Benutzer vielleicht kein `shout` hat.
```lua
minetest.register_on_chat_message(function(name, message)
if message:sub(1, 1) == "/" then
print(name .. " hat einen Chat-Befehl ausgeführt")
elseif minetest.check_player_privs(name, { shout = true }) then
print(name .. " sagte " .. message)
else
print(name .. " versucht zu sagen " .. message ..
" hat aber kein shout")
end
return false
end)
```

382
_de/players/formspecs.md Normal file
View File

@ -0,0 +1,382 @@
---
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
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.
---
## 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>
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.
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
[Heads Up Display (HUD)](hud.html)-Elementen anstelle von Formspecs verwenden sollten, da
unerwartete Fenster das Spielgeschehen stören können.
- [Reale oder Legacy-Koordinaten](#reale-oder-legacy-koordinaten)
- [Anatomie eines formspecs](#anatomie-eines-formspecs)
- [Elemente](#elemente)
- [Header](#header)
- [Ratespiel](#ratespiel)
- [Padding und Abstände](#padding-und-abstände)
- [Empfang von Formspec-Übermittlungen](#empfang-von-formspec-übermittlungen)
- [Contexts](#contexts)
- [Formspec-Quellen](#formspec-quellen)
- [Node Meta Formspecs](#node-meta-formspecs)
- [Spieler Inventar Formspecs](#spieler-inventar-formspecs)
- [Sie sind dran](#sie-sind-dran)
## Reale oder Legacy-Koordinaten
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
Koordinaten, die dieses Problem durch die Einführung eines konsistenten
Koordinatensystem beheben. Die Verwendung von realen Koordinaten wird dringend empfohlen, und deshalb
dieses Kapitel ausschließlich diese verwenden.
Die Verwendung einer formspec_version von 2 oder höher aktiviert reale Koordinaten.
## Anatomie eines formspecs
### Elemente
Formspec ist eine domänenspezifische Sprache mit einem ungewöhnlichen Format.
Sie besteht aus einer Reihe von Elementen mit der folgenden Form:
type[param1;param2]
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:
foo[param1]bar[param1]
bo[param1]
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/)
für eine Liste aller möglichen Elemente.
### Header
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
spielweite Thema angewendet werden soll.
Die Elemente im Header müssen in einer bestimmten Reihenfolge definiert werden, sonst
wird ein Fehler angezeigt. Diese Reihenfolge ist im obigen Absatz angegeben und - wie immer -
in der Lua-API-Referenz dokumentiert.
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
Einstellungen des Clients ist. Hier ist ein formspec mit der Größe "2,2":
formspec_version[4]
size[2,2]
Beachten Sie, dass wir die Formspec-Sprachversion ausdrücklich definiert haben müssen.
Ohne dies wird stattdessen das Altsystem verwendet - was
die Verwendung der konsistenten Elementpositionierung und anderer neuer Funktionen verhindert.
Die Elemente position und anchor werden verwendet, um das Formspec auf dem Bildschirm zu platzieren.
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,
so dass Sie das Formspec mit dem Rand des Bildschirms ausrichten können. Das Formspec
kann auf diese Weise links vom Bildschirm platziert werden:
formspec_version[4]
size[2,2]
position[0,0.5]
anchor[0,0.5]
Dadurch wird der Anker an den linken mittleren Rand des Formspec-Feldes gesetzt, und die
Position dieses Ankers auf der linken Seite des Bildschirms.
## Ratespiel
<figure class="right_image">
<img src="{{ page.root }}/static/formspec_guessing.png" alt="Rate-Formspec">
<figcaption>
Das Ratespiel formspec.
</figcaption>
</figure>
Der beste Weg, etwas zu lernen, ist, etwas zu machen, also lasst uns ein Ratespiel machen.
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
die tatsächliche Zahl.
Zunächst erstellen wir eine Funktion, die den Formspec-Code erzeugt. Es ist gute Praxis, dies
zu tun, da es die Wiederverwendung an anderer Stelle erleichtert.
<div style="clear: both;"></div>
```lua
guessing = {}
function guessing.get_formspec(name)
-- TODO: Anzeige, ob die letzte Schätzung höher oder niedriger war
local text = "Ich denke an eine Zahl... Raten Sie mal!"
local formspec = {
"formspec_version[4]",
"size[6,3.476]",
"label[0.375,0.5;", minetest.formspec_escape(text), "]",
"field[0.375,1.25;5.25,0.8;nummer;Nummer;]",
"button[1.5,2.3;3,0.8;raten;Raten]"
}
-- table.concat ist schneller als String-Verkettung - `..`
return table.concat(formspec, "")
end
```
Im obigen Code platzieren wir ein Feld, eine Beschriftung und eine Schaltfläche.
Ein Feld erlaubt die Eingabe von Text und eine Schaltfläche dient zum
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.
Als Nächstes wollen wir dem Spieler erlauben, den Formspec anzuzeigen. Der beste Weg, dies zu tun
ist die Verwendung von `show_formspec`:
```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,
})
```
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
`Modname:Gegenstandsname`.
### Padding und Abstände
<figure class="right_image">
<img src="{{ page.root }}/static/formspec_padding_spacing.png" alt="Padding und Abstände">
<figcaption>
The guessing game formspec.
</figcaption>
</figure>
Padding ist der Abstand zwischen dem Rand des Formspec und seinem Inhalt oder zwischen nicht verwandten Elementen,
dargestellt in Rot. Abstand ist der Abstand zwischen zusammenhängenden Elementen, der blau dargestellt wird.
Ein Padding von `0,375` und ein Abstand von `0,25` sind üblich.
<div style="clear: both;"></div>
### Empfang von Formspec-Übermittlungen
Wenn `show_formspec` aufgerufen wird, wird der formspec an den Client gesendet, um angezeigt zu werden.
Damit Formspecs nützlich sind, müssen Informationen vom Client zum Server zurückgeschickt werden.
Die Methode dafür heißt formspec field submission, und für `show_formspec` wird diese
Übermittlung über einen globalen Callback empfangen:
```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()
minetest.chat_send_all(pname .. " riet " .. fields.number)
end
end)
```
Die in `minetest.register_on_player_receive_fields` angegebene Funktion wird
jedes Mal aufgerufen, wenn ein Benutzer ein Formular absendet. Die meisten Callbacks müssen den
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.
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.
{% include notice.html notice=page.submit_vuln %}
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
"contexts".
### Contexts
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.
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:
```lua
local _contexts = {}
local function get_context(name)
local context = _contexts[name] or {}
_contexts[name] = context
return context
end
minetest.register_on_leaveplayer(function(spieler)
_contexts[spieler:get_player_name()] = nil
end)
```
Als nächstes müssen wir den Show-Code ändern, um den Context zu aktualisieren
zu aktualisieren, bevor der Formspec angezeigt wird:
```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
```
Wir müssen auch den Code für die Generierung von Formularen ändern, um den Context zu verwenden:
```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
```
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.
Und schließlich müssen wir den Handler aktualisieren, um den Context mit der Vermutung zu aktualisieren:
```lua
if fields.guess then
local name = spieler:get_player_name()
local context = get_context(name)
context.guess = tonumber(fields.number)
guessing.show_to(name)
end
```
## Formspec-Quellen
Es gibt drei verschiedene Möglichkeiten, wie ein Formspec an den Client übermittelt werden kann:
* [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.
* [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
`register_on_player_receive_fields` empfangen.
### Node Meta Formspecs
`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,
wird dieses bei Truhen verwendet, um ein schnelleres Öffnen zu ermöglichen -
man muss nicht darauf warten, dass der Server dem Spieler den Formspec für die Truhe schickt.
```lua
minetest.register_node("meinemod:rechtsclick", {
description = "Rechtsclicke me!",
tiles = {"mymod_rechtsclick.png"},
groups = {cracky = 1},
after_place_node = function(pos, placer)
-- 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.
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
"formspec_version[4]" ..
"size[5,5]" ..
"label[1,1;Dies wird beim Rechtsklick angezeigt]" ..
"field[1,2;2,1;x;x;]")
end,
on_receive_fields = function(pos, formname, fields, spieler)
if fields.quit then
return
end
print(fields.x)
end
})
```
Auf diese Weise eingestellte Formspecs lösen nicht denselben Callback aus. Um
Formulareingaben für meta formspecs zu erhalten, müssen Sie einen
`on_receive_fields`-Eintrag bei der Registrierung des Nodes enthalten.
Diese Art von Callback wird ausgelöst, wenn Sie die Eingabetaste
in einem Feld drücken, was mit `minetest.show_formspec` unmöglich ist;
diese Art von Formular kann jedoch nur durch Rechtsklick auf einen Node angezeigt werden. Sie kann nicht programmatisch ausgelöst werden.
### Spieler Inventar Formspecs
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
formname ist `""`.
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),
und ist in Minetest Game enthalten. Ich als Übersetzer empfehle jedoch
eher [i3](https://github.com/minetest-mods/i3) oder [unified inventory](https://github.com/minetest-mods/unified_inventory)
### Sie sind dran
* 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.
* Erstellen Sie einen Node namens "Inbox", in dem Benutzer ein Formspec öffnen und Nachrichten hinterlassen können.
Dieser Node sollte den Namen des Placers als `owner` in der Meta speichern, und sollte
`show_formspec` verwenden, um verschiedene Formspecs für verschiedene Spieler anzuzeigen.

293
_de/players/hud.md Normal file
View File

@ -0,0 +1,293 @@
---
title: HUD
layout: default
root: ../..
idx: 4.6
description: Lernen Sie, wie man HUD-Elemente anzeigt
redirect_from: /de/chapters/hud.html
---
## Einleitung <!-- omit in toc -->
Heads Up Display (HUD) Elemente ermöglichen es Ihnen, Texte, Bilder und andere grafische Elemente anzuzeigen.
Das HUD akzeptiert keine Benutzereingaben; dafür sollten Sie eine [formspec](formspecs.html) verwenden.
- [Positionierung](#positionierung)
- [Position und Versatz](#position-und-versatz)
- [Ausrichtung](#ausrichtung)
- [Anzeigetafel](#anzeigetafel)
- [Textelemente](#textelemente)
- [Parameter](#parameter)
- [Unser Beispiel](#unser-beispiel)
- [Bild-Elemente](#bild-elemente)
- [Parameter](#parameter-1)
- [Scale](#scale)
- [Ein Element verändern](#ein-element-verändern)
- [IDs speichern](#ids-speichern)
- [Andere Elemente](#andere-elemente)
## Positionierung
### Position und Versatz
<figure class="right_image">
<img
width="300"
src="{{ page.root }}//static/hud_diagram_center.svg"
alt="Diagramm mit einem zentrierten Textelement">
</figure>
Bildschirme gibt es in verschiedenen Größen und Auflösungen. Ein HUD muss auf allen
Bildschirmtypen gut funktionieren.
Die Lösung von Minetest besteht darin, die Position eines Elements sowohl durch
einer prozentualen Position und einem Versatz festzulegen.
Die prozentuale Position bezieht sich auf die Bildschirmgröße, d. h. um ein Element
in der Mitte des Bildschirms zu platzieren, müssen Sie eine prozentuale Position von der Hälfte
des Bildschirms, z. B. (50%, 50%), und einen Versatz von (0, 0) angeben.
Der Versatz wird dann verwendet, um ein Element relativ zur Prozentposition zu verschieben.
<div style="clear:both;"></div>
### Ausrichtung
Die Ausrichtung gibt an, wo das Ergebnis von Position und Versatz auf dem Element liegt -
zum Beispiel `{x = -1.0, y = 0.0}` lässt das Ergebnis von Position und Versatz
auf die linke Seite der Elementbegrenzung liegen. Dies ist besonders nützlich, wenn Sie
ein Textelement links-, mittel- oder rechtsbündig ausrichten wollen.
<figure>
<img
width="500"
src="{{ page.root }}//static/hud_diagram_alignment.svg"
alt="Diagramm zur Ausrichtung">
</figure>
Das obige Diagramm zeigt 3 Fenster (blau), jedes mit einem einzelnen HUD-Element (gelb)
und jeweils einer anderen Ausrichtung. Der Pfeil ist das Ergebnis der Berechnung von Position
und Versatzberechnung.
### Anzeigetafel
In diesem Kapitel werden Sie lernen, wie Sie eine Anzeigetafel
positionieren und aktualisieren können:
<figure>
<img
src="{{ page.root }}//static/hud_final.png"
alt="Screenshot vom uns angestrebten HUD">
</figure>
Im obigen Screenshot haben alle Elemente die gleiche prozentuale Position
(100%, 50%) - aber unterschiedliche Versätze. Dadurch wird das Ganze am rechten Rand des Fensters verankert, kann aber in der Größe verändert werden, ohne einen Bruch zu benutzen.
## Textelemente
Sie können ein HUD-Element erstellen, sobald Sie eine Kopie des Spieler-Objekts haben:
```lua
local player = minetest.get_player_by_name("benutzername")
local idx = player:hud_add({
hud_elem_type = "text",
position = {x = 0.5, y = 0.5},
offset = {x = 0, y = 0},
text = "Hallo Welt!",
alignment = {x = 0, y = 0}, -- mittig Ausrichtung
scale = {x = 100, y = 100}, -- Später behandelt
})
```
Die Funktion `hud_add` gibt eine Element-ID zurück - diese kann später verwendet werden, um ein
HUD-Element zu modifizieren oder zu entfernen.
### Parameter
Der Typ des Elements wird mit der Eigenschaft `hud_elem_type` in der Definitionstabelle angegeben
Tabelle angegeben. Die Bedeutung der anderen Eigenschaften hängt von diesem Typ ab.
`scale` ist die maximale Begrenzung des Textes; Text außerhalb dieser Begrenzung wird abgeschnitten, z. B.: `{x=100, y=100}`.
`number` ist die Farbe des Textes in [hexadezimaler Form] (http://www.colorpicker.com/), z. B.: `0xFF0000`.
### Unser Beispiel
Lassen Sie uns fortfahren und den gesamten Text in unserer Punkte-Tafel platzieren:
```lua
-- Holt sich die Anzahl der Abbauungen und Platzierungen aus dem Speicher, oder setzt den Wert auf standardmäßig 0
local meta = player:get_meta()
local abbau_text = "Abgebaut: " .. meta:get_int("score:digs")
local platzier_text = "Platziert: " .. meta:get_int("score:places")
player:hud_add({
hud_elem_type = "text",
position = {x = 1, y = 0.5},
offset = {x = -120, y = -25},
text = "Statistiken",
alignment = 0,
scale = { x = 100, y = 30},
number = 0xFFFFFF,
})
player:hud_add({
hud_elem_type = "text",
position = {x = 1, y = 0.5},
offset = {x = -180, y = 0},
text = abbau_text,
alignment = -1,
scale = { x = 50, y = 10},
number = 0xFFFFFF,
})
player:hud_add({
hud_elem_type = "text",
position = {x = 1, y = 0.5},
offset = {x = -70, y = 0},
text = platzier_text,
alignment = -1,
scale = { x = 50, y = 10},
number = 0xFFFFFF,
})
```
Daraus ergibt sich das Folgende:
<figure>
<img
src="{{ page.root }}//static/hud_text.png"
alt="Screenshot des HUD, den wir anstreben">
</figure>
## Bild-Elemente
Bild-Elemente werden auf sehr ähnliche Weise wie Text-Elemente erstellt:
```lua
player:hud_add({
hud_elem_type = "image",
position = {x = 1, y = 0.5},
offset = {x = -220, y = 0},
text = "punkte_hintergrund.png",
scale = { x = 1, y = 1},
alignment = { x = 1, y = 0 },
})
```
Sie werden jetzt dies haben:
<figure>
<img
src="{{ page.root }}//static/hud_background_img.png"
alt="Screenshot des bisherigen HUDs">
</figure>
### Parameter
Das Feld `text` wird für die Angabe des Bildnamens verwendet.
Wenn eine Koordinate positiv ist, handelt es sich um einen Skalierungsfaktor, wobei 1
die ursprüngliche Bildgröße, 2 die doppelte Größe usw. ist.
Ist eine Koordinate jedoch negativ, handelt es sich um einen Prozentsatz der Bildschirmgröße.
Zum Beispiel ist `x=-100` 100% der Breite.
### Scale
Lassen Sie uns den Fortschrittsbalken für unser Score-Panel als Beispiel für die Skala erstellen:
```lua
local percent = tonumber(meta:get("score:score") or 0.2)
player:hud_add({
hud_elem_type = "image",
position = {x = 1, y = 0.5},
offset = {x = -215, y = 23},
text = "punkte_balken_leer.png",
scale = { x = 1, y = 1},
alignment = { x = 1, y = 0 },
})
player:hud_add({
hud_elem_type = "image",
position = {x = 1, y = 0.5},
offset = {x = -215, y = 23},
text = "punkte_balken_voll.png",
scale = { x = percent, y = 1},
alignment = { x = 1, y = 0 },
})
```
Wir haben jetzt ein HUD, der wie der im ersten Abschnitt aussieht!
Es gibt jedoch ein Problem: Es wird nicht aktualisiert, wenn sich die Statistiken ändern.
## Ein Element verändern
Sie können die von der Methode `hud_add` zurückgegebene ID verwenden, um es später zu aktualisieren oder zu entfernen.
```lua
local idx = player:hud_add({
hud_elem_type = "text",
text = "Hallo Welt!",
-- Parameter der Kürze halber entfernt
})
player:hud_change(idx, "text", "Neuer Text")
player:hud_remove(idx)
```
Die Methode `hud_change` nimmt die Element-ID, die zu ändernde Eigenschaft und den
neuen Wert. Der obige Aufruf ändert die Eigenschaft `text` von "Hallo Welt!" in "Neuer Text".
Das bedeutet, dass die Ausführung von `hud_change` unmittelbar nach `hud_add` funktionell
äquivalent zu folgendem ist, und zwar auf eine ziemlich ineffiziente Weise:
```lua
local idx = player:hud_add({
hud_elem_type = "text",
text = "Neuer Text",
})
```
## IDs speichern
```lua
punkte = {}
local gespeicherte_huds = {}
function punkte.update_hud(player)
local player_name = player:get_player_name()
-- Holt die Anzahl der Abbauungen und Orte aus dem Speicher, oder setzt ihn auf standardmäßig 0
local meta = player:get_meta()
local abbau_text = "Abbauungen: " .. meta:get_int("score:digs")
local platier_text = "Platzierungen: " .. meta:get_int("score:places")
local prozent = tonumber(meta:get("score:score") or 0.2)
local ids = gespeicherte_huds[player_name]
if ids then
player:hud_change(ids["platzierungen"], "text", places_text)
player:hud_change(ids["abbauungen"], "text", digs_text)
player:hud_change(ids["balken_vordergrund"],
"scale", { x = prozent, y = 1 })
else
ids = {}
gespeicherte_huds[player_name] = ids
-- Erstellt HUD-Elemente und setzt die IDs in `ids`
end
end
minetest.register_on_joinplayer(punkte.update_hud)
minetest.register_on_leaveplayer(function(player)
gespeicherte_huds[player:get_player_name()] = nil
end)
```
## Andere Elemente
Lesen Sie [lua_api.txt 🇬🇧](https://minetest.gitlab.io/minetest/hud/) für eine vollständige Liste der HUD-Elemente.

View File

@ -0,0 +1,77 @@
---
title: Spielerphysiken
layout: default
root: ../..
idx: 4.4
description: Erfahren Sie, wie Sie einen Spieler schneller laufen, höher springen oder einfach schweben lassen können.
redirect_from: /de/chapters/player_physics.html
---
## Einleitung <!-- omit in toc -->
Die Spielerphysik kann mit Hilfe von Physik-Overrides verändert werden.
Physik-Overrides können die Gehgeschwindigkeit, die Sprunggeschwindigkeit
und Schwerkraftkonstanten einstellen.
Physiküberschreibungen werden für jeden Spieler einzeln festgelegt
und sind Multiplikatoren.
Ein Wert von 2 für die Schwerkraft würde zum Beispiel die Schwerkraft doppelt so stark machen.
- [Grundlegendes Beispiel](#grundlegendes-beispiel)
- [Verfügbare Overrides](#verfügbare-overrides)
- [Altes Bewegungsverhalten](#altes-bewegungsverhalten)
- [Mod-Inkompatibilität](#mod-inkompatibilität)
- [Sie sind dran](#sie-sind-dran)
## Grundlegendes Beispiel
Hier ist ein Beispiel für das Hinzufügen eines Antigravitationsbefehls, der
den Aufrufer in eine niedrige Schwerkraft versetzt:
```lua
minetest.register_chatcommand("antigravity", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
player:set_physics_override({
gravity = 0.1, -- setzt die Schwerkraft auf 10% des ursprünglichen Wertes
-- (0.1 * 9.81)
})
end,
})
```
## Verfügbare Overrides
`player:set_physics_override()` wird eine Tabelle mit Overrides übergeben.\\
Laut [lua_api.txt](https://minetest.gitlab.io/minetest/class-reference/#player-only-no-op-for-other-objects),
können diese sein:
* speed: Multiplikator zum Standardwert für die Gehgeschwindigkeit (Standard: 1)
* jump: Multiplikator auf Standard-Sprungwert (Standard: 1)
* gravity: Multiplikator zum Standardwert für die Schwerkraft (Standard: 1)
* sneak: ob der Spieler schleichen kann (Standard: true)
### Altes Bewegungsverhalten
Die Spielerbewegung vor der Version 0.4.16 beinhaltete den sneak glitch, der
verschiedene Bewegungs-Glitches erlaubt, darunter die Fähigkeit
einen 'Aufzug' zu erklimmen, der aus einer bestimmten Anordnung von Nodes besteht, indem man sich anschleicht
(Umschalttaste drücken) und die Leertaste drücken, um aufzusteigen.
Obwohl dieses Verhalten nicht beabsichtigt war, wurde es in den Überschreibungen beibehalten, da es auf vielen Servern verwendet wird.
Um das alte Bewegungsverhalten vollständig wiederherzustellen, sind zwei Überschreibungen erforderlich:
* new_move: ob der Spieler neue Bewegungen verwendet (Standard: true)
* sneak_glitch: ob der Spieler 'Schleichfahrstühle' benutzen kann (Standard: false)
## Mod-Inkompatibilität
Bitte beachten Sie, dass Mods, die denselben Physikwert eines Spielers überschreiben,
inkompatibel zueinander sind. Wenn ein Override gesetzt wird, überschreibt er
Überschreibungen, die zuvor gesetzt wurden. Das bedeutet, dass wenn mehrere Überschreibungen
die Geschwindigkeit eines Spielers festlegen, ist nur die zuletzt ausgeführte wirksam.
## Sie sind dran
* **Sonic**: Setzen Sie den Geschwindigkeitsmultiplikator auf einen hohen Wert (mindestens 6), wenn ein Spieler dem Spiel beitritt.
* **Super bounce**: Erhöhe den Sprungwert, so dass der Spieler 20 Meter weit springen kann (1 Meter ist 1 Node).
* **Space**: Die Schwerkraft sollte abnehmen, wenn der Spieler höher steigt.

138
_de/players/privileges.md Normal file
View File

@ -0,0 +1,138 @@
---
title: Privilegien
layout: default
root: ../..
idx: 4.1
description: Privs registrieren.
redirect_from: /de/chapters/privileges.html
---
## Einleitung <!-- omit in toc -->
Privilegien, oft privs abgekürzt, geben Spielern die Möglichkeit,
bestimmte Aktionen durchzuführen. Serverbesitzer können Privilegien vergeben und entziehen, um zu kontrollieren
welche Fähigkeiten jeder Spieler hat.
- [Wann sollten Sie Privilegien nutzen?](#wann-sollten-sie-privilegien-nutzen)
- [Erklärung von Privilegien](#erklärung-von-privilegien)
- [Überprüfung der Privilegien](#überprüfung-der-privilegien)
- [Abrufen und Festlegen von Privilegien](#abrufen-und-festlegen-von-privilegien)
- [Privilegien zu basic\_privs hinzufügen](#privilegien-zu-basic_privs-hinzufügen)
## Wann sollten Sie Privilegien nutzen?
Ein Privileg sollte einem Spieler die Möglichkeit geben, etwas zu tun(siehe Gute Privilegien).
Privilegien sind **nicht** dazu da, Klassen- oder Statusangaben zu machen(siehe Schlechte Privilegien).
**Gute Privilegien:**
* interact
* shout
* noclip
* fly
* kick
* ban
* vote
* worldedit
* area_admin - Adminfunktionen eines Mods sind in Ordnung
**Schlechte Privilegien:**
* moderator
* admin
* elf
* dwarf
## Erklärung von Privilegien
Verwenden Sie `register_privilege`, um ein neues Privileg zu deklarieren:
```lua
minetest.register_privilege("vote", {
description = "Kann über Themen abstimmen",
give_to_singleplayer = true
})
```
`give_to_singleplayer` steht standardmäßig auf true, wenn es nicht angegeben wird, so dass es
in der obigen Definition nicht wirklich benötigt wird.
## Überprüfung der Privilegien
Um schnell zu überprüfen, ob ein Spieler alle erforderlichen Rechte besitzt:
```lua
local has, missing = minetest.check_player_privs(player_or_name, {
interact = true,
vote = true })
```
In diesem Beispiel ist `has` wahr, wenn der Spieler alle benötigten Privilegien hat.
Wenn `has` falsch ist, dann enthält `missing` eine Schlüssel-Wert-Tabelle
mit den fehlenden Privilegien.
```lua
local has, missing = minetest.check_player_privs(name, {
interact = true,
vote = true })
if has then
print("Spieler hat alle Privilegien!")
else
print("Dem Spieler fehlen folgende Privilegien:" .. dump(missing))
end
```
Wenn Sie die fehlenden Privilegien nicht überprüfen müssen, können Sie
check_player_privs" direkt in die if-Anweisung einfügen.
```lua
if not minetest.check_player_privs(name, { interact=true }) then
return false, "Hierfür brauchen Sie Interaktion!"
end
```
## Abrufen und Festlegen von Privilegien
Auf die Spielerprivilegien kann unabhängig, ob der Spieler
online ist, zugegriffen werden.
```lua
local privs = minetest.get_player_privs(name)
print(dump(privs))
privs.vote = true
minetest.set_player_privs(name, privs)
```
Privilegien werden immer als Schlüssel-Wert-Tabelle angegeben, wobei der Schlüssel der
Name der Berechtigung und der Wert ein Boolescher Wert ist.
```lua
{
fly = true,
interact = true,
shout = true
}
```
## Privilegien zu basic_privs hinzufügen
Spieler mit dem Privileg `basic_privs` können eine begrenzte Anzahl von Privilegien gewähren und entziehen.
Es ist üblich, dieses Privileg an Moderatoren zu vergeben, so dass
sie `interact` und `shout` gewähren und entziehen können, aber nicht sich selbst oder anderen
Spieler Privilegien mit größerem Missbrauchspotential wie `give` und `server` gewähren können.
Um ein Privileg zu `basic_privs` hinzuzufügen, und um einzustellen, welche Privilegien Ihre Moderatoren
anderen Spielern gewähren und entziehen können, müssen Sie die Einstellung `basic_privs` ändern.
Standardmäßig hat `basic_privs` den folgenden Wert:
basic_privs = interact, shout
Um `vote` hinzuzufügen, aktualisieren Sie dies zu:
basic_privs = interact, shout, vote
Dies wird es Spielern mit `basic_privs` erlauben, das `vote` Privileg zu gewähren und zu entziehen.

221
_de/quality/clean_arch.md Normal file
View File

@ -0,0 +1,221 @@
---
title: Einführung in saubere Architekturen
layout: default
root: ../..
idx: 8.4
---
## Einleitung <!-- omit in toc -->
Sobald Ihre Mod eine beachtliche Größe erreicht hat, wird es immer schwieriger, den Code
sauber und frei von Fehlern zu halten. Dies ist ein besonders großes Problem bei der
Verwendung von einer dynamisch typisierte Sprache wie Lua, da der Compiler Ihnen sehr
wenig Hilfe und Möglichkeiten zur Compilerzeit gibt, wenn es darum geht, sicherzustellen,
dass Typen ordnungsgemäß verwendet werden.
Dieses Kapitel behandelt wichtige Konzepte, um Ihren Code sauber zu halten und gängige
Entwurfsmuster, um dies zu erreichen. Bitte beachten Sie, dass dieses Kapitel nicht als
Vorschrift gedacht ist, sondern Ihnen eine Vorstellung von den Möglichkeiten geben soll.
Es gibt nicht nur einen guten Weg, eine Mod zu entwerfen und gutes Mod-Design ist sehr
subjektiv.
- [Kohäsion, Kopplung und Trennung der Programmbereiche](#kohäsion-kopplung-und-trennung-der-programmbereiche)
- [Observer](#observer)
- [Modell-View-Controller](#modell-view-controller)
- [API-View](#api-view)
- [Zusammenfassung](#zusammenfassung)
## Kohäsion, Kopplung und Trennung der Programmbereiche
Ohne jegliche Planung neigt ein Programmierprojekt dazu, allmählich in
Spaghetti-Code zu verfallen. Spaghetti-Code zeichnet sich durch einen Mangel an Struktur
aus - der gesamte Code wird ohne klare Grenzen zusammengewürfelt. Das macht ein Projekt
völlig unwartbar und endet damit, dass es aufgegeben wird.
Das Gegenteil davon ist, dass ein Projekt als eine Sammlung interagierender kleinerer
Programme oder Code-Bereiche zu entwickeln. <!-- Weird wording? -->
> Inside every large program, there is a small program trying to get out.
>
> --C.A.R. Hoare
Die deutsche Übersetzung davon: <!-- Weird wording? -->
> In jedem großen Programm gibt es ein kleines Programm, das versucht, herauszukommen.
Dies sollte so geschehen, dass Sie eine Trennung der Programmteile erreichen - jeder
Bereich sollte klar abgegrenzt sein und einem separaten Bedürfnis oder einer Aufgabe
entsprechen.
Diese Programme/Bereiche sollten die folgenden zwei Eigenschaften haben:
* **Hohe Kohäsion** - die Bereiche sollten eng miteinander verbunden sein.
* **Niedrige Kopplung** - die Abhängigkeiten zwischen den Bereichen sollten so gering
wie möglich sein und es sollte vermieden werden, sich auf interne Implementierungen zu
verlassen. Es ist eine sehr gute Idee, sicherzustellen, dass Sie eine geringe Kopplung
gewährleisten, da dies bedeutet, dass eine Änderung der APIs bestimmter Bereiche
leichter durchführbar sein wird.
Beachten Sie, dass dies sowohl für die Beziehung zwischen Mods gilt,
als auch für die Beziehung zwischen Bereichen innerhalb eines Mods.
## Observer
Eine einfache Möglichkeit, verschiedene Bereiche des Codes zu trennen, ist die Verwendung des Observer-Musters.
Nehmen wir als Beispiel der Freischaltung einer Leistung, wenn ein Spieler zum ersten Mal ein seltenes Tier tötet. Der naive Ansatz wäre, den Code für die Errungenschaft in der mobkill-Funktion den Mob-Namen überprüfen zu lassen und die Auszeichnung freizuschalten, wenn er übereinstimmt.
Dies ist jedoch eine schlechte Idee, da es den Mobs-Mod an die Errungenschaften gekoppelt macht. Wenn man so weitermacht - zum Beispiel, indem man XP zum Mob-Todescode hinzufügt - könnte man eine Menge chaotischer Abhängigkeiten haben.
Hier kommt das Observer-Muster ins Spiel. Anstatt dass sich die mymobs-Mod um Auszeichnungen kümmert,
erhält die mymobs-Mod eine Möglichkeit für andere Bereiche des Codes, ihr Interesse an an einem Ereignis zu registrieren und Daten über das Ereignis zu erhalten.
```lua
mymobs.registered_on_death = {}
function mymobs.register_on_death(func)
table.insert(mymobs.registered_on_death, func)
end
-- im Mob-Death-Code
for i=1, #mymobs.registered_on_death do
mymobs.registered_on_death[i](entity, reason)
end
```
Dann meldet der andere Code sein Interesse an:
```lua
mymobs.register_on_death(function(mob, reason)
if reason.type == "punch" and reason.object and
reason.object:is_player() then
awards.notify_mob_kill(reason.object, mob.name)
end
end)
```
Vielleicht denken Sie jetzt: Moment mal, das kommt mir doch irgendwie bekannt vor. Und Sie haben Recht!
Die Minetest-API ist stark Observer-basiert, damit sich die Engine nicht darum kümmern muss, was auf wen hört.
## Modell-View-Controller
Im nächsten Kapitel werden wir besprechen, wie Sie Ihren Code automatisch testen können. Eines der Probleme wird sein, wie man die Logik(Berechnungen, was getan werden sollte) von API-Aufrufen (`minetest.*`, andere Mods) so weit wie möglich zu trennen.
Eine Möglichkeit, dies zu tun, ist, darüber nachzudenken:
* Welche **Daten** Sie haben.
* Welche **Aktionen** man mit diesen Daten durchführen kann.
* Wie **Ereignisse** (z.B. Formspecs, Schläge, etc.) diese Aktionen auslösen und wie
diese Aktionen in der Engine etwas bewirken.
Nehmen wir ein Beispiel für einen Landschutz-Mod. Die Daten, die Sie haben, sind die Gebiete und alle zugehörigen Metadaten. Mögliche Aktionen sind `Erzeugen`, `Bearbeiten` oder `löschen`. Die Ereignisse, die diese Aktionen auslösen, sind Chat-Befehle und Formspec-Empfangsfelder. Dies sind 3 Bereiche, die sich in der Regel gut voneinander trennen lassen.
In Ihren Tests können Sie sicherstellen, dass eine Aktion, wenn sie ausgelöst wird,
das Richtige mit den Daten macht. Sie brauchen nicht zu testen, dass ein Ereignis eine
Aktion aufruft (dazu müsste die Minetest-API verwendet werden, und dieser Bereich des Codes sollte ohnehin so klein wie möglich gehalten werden).
Sie sollten Ihre Datendarstellung in reinem Lua schreiben. "Sauber" bedeutet in diesem Zusammenhang, dass die Funktionen außerhalb von Minetest ausgeführt werden können - keiner der Funktionen der Engine aufgerufen werden müssen.
```lua
-- Daten
function land.create(name, area_name)
land.lands[area_name] = {
name = area_name,
owner = name,
-- mehr Dinge
}
end
function land.get_by_name(area_name)
return land.lands[area_name]
end
```
Ihre Aktionen sollten auch sauber sein, aber der Aufruf anderer Funktionen ist akzeptabler als im obigen Beispiel.
```lua
-- Controller
function land.handle_create_submit(name, area_name)
-- Prozessmaterial
-- (d.h.: auf Überschneidungen prüfen, Quoten prüfen, erechtigungen prüfen)
land.create(name, area_name)
end
function land.handle_creation_request(name)
-- Dies ist ein schlechtes Beispiel, wie später erklärt wird
land.show_create_formspec(name)
end
```
Ihre Event-Handler müssen mit der Minetest-API interagieren. Sie sollten die die Anzahl der Berechnungen auf ein Minimum beschränken, da Sie diesen Bereich nicht sehr gut testen können.
```lua
-- View
function land.show_create_formspec(name)
-- Beachten Sie, dass es hier keine komplexen Berechnungen gibt!
return [[
size[4,3]
label[1,0;This is an example]
field[0,1;3,1;area_name;]
button_exit[0,2;1,1;exit;Exit]
]]
end
minetest.register_chatcommand("/land", {
privs = { land = true },
func = function(name)
land.handle_creation_request(name)
end,
})
minetest.register_on_player_receive_fields(function(player,
formname, fields)
land.handle_create_submit(player:get_player_name(),
fields.area_name)
end)
```
Das obige Muster ist das Model-View-Controller-Muster. Das Modell ist eine Sammlung von Daten mit minimalen Funktionen. Der View ist eine Sammlung von Funktionen, die auf
Ereignisse abhören und an den Controller weiterleiten und auch Aufrufe vom Controller erhalten, um etwas mit der Minetest-API zu tun. Der Controller ist der Ort, an dem die Entscheidungen und die meisten Berechnungen getroffen werden.
Der Controller sollte keine Kenntnisse über die Minetest-API haben - beachten Sie, dass
es keine Minetest-Aufrufe oder View-Funktionen, die ihnen ähneln, gibt. Sie sollten *NICHT* eine Funktion wie `view.hud_add(player, def)` haben. Stattdessen definiert der View einige Aktionen, die der Controller dem View mitteilen kann, wie z. B. `view.add_hud(info)`, wobei info ein Wert oder eine Tabelle ist, die in keiner Weise mit der Minetest-API etwas zu tun hat.
<figure class="right_image">
<img
width="100%"
src="{{ page.root }}/static/mvc_diagram.svg"
alt="Diagramm mit einem zentrierten Textelement">
</figure>
Es ist wichtig, dass jeder Bereich nur mit seinen direkten Nachbarn kommuniziert,
wie oben gezeigt, um die Anzahl der Änderungen zu reduzieren, die Sie vornehmen müssen, wenn Sie die Interna oder Externa eines Bereichs ändern. Um beispielsweise die Formularvorgabe zu ändern, müssen Sie nur die Ansicht bearbeiten. Um die View-API zu ändern, müssten Sie nur nur den View und den Controller ändern, nicht aber das Modell.
In der Praxis wird dieses Design nur selten verwendet, da es die Komplexität erhöht
und weil es für die meisten Arten von Mods nicht viele Vorteile bietet. Stattdessen,
wird man häufig eine weniger formale und strenge Art von Design sehen -
Varianten der API-Ansicht.
### API-View
In einer idealen Welt würden Sie die oben genannten 3 Bereiche perfekt getrennt haben, wobei alle Ereignisse in den Controller gehen, bevor sie in die normale Ansicht zurückkehren. Aber das ist nicht die reale Welt. Ein guter Kompromiss ist die Reduzierung der Mod in zwei
Teile:
**API** - Dies war das Modell und der Controller oben. Es sollte keine Verwendung von
`minetest.` geben.
* **View** - Dies war auch die obige Ansicht. Es ist eine gute Idee, dies in separate Dateien für jede Art von Ereignis zu strukturieren.
rubenwardy's [crafting mod](https://github.com/rubenwardy/crafting 🇬🇧) folgt ungefähr diesem Design. Die Datei `api.lua` besteht fast ausschließlich aus reinen Lua-Funktionen, die die Daten Speicherung und Controller-ähnliche Berechnungen handhaben. `gui.lua` ist die Ansicht für Formspecs und Formspec-Übermittlung, und `async_crafter.lua` ist der View und Controller für einen Node formspec und Nodezeitgeber.
Wenn man die Mods auf diese Weise trennt, kann man den API-Teil sehr einfach testen,
da sie keine Minetest-APIs verwendet - wie im [nächstes Kapitel](unit_testing.html) und in der Crafting-Mod zu sehen.
## Zusammenfassung
Gutes Code-Design ist subjektiv und hängt stark von dem Projekt ab, an dem Sie arbeiten. Generell sollte man versuchen, die Kohäsion hoch und die Kopplung niedrig zu halten. Anders formuliert, Halten Sie verwandten Code zusammen und nicht verwandten Code auseinander und halten Sie Abhängigkeiten einfach.
rubenwardy empfehlt dringend die Lektüre des [Game Programming Patterns 🇬🇧](http://gameprogrammingpatterns.com/) Buch. Es ist frei verfügbar, [online (auf Englisch) lesbar](http://gameprogrammingpatterns.com/contents.html)
und geht viel detaillierter als in diesem Buch auf allgemeine Programmiermuster ein, die für Spiele relevant sind.

View File

@ -0,0 +1,126 @@
---
title: Häufige Fehler
layout: default
root: ../..
idx: 8.1
redirect_from: /de/chapters/common_mistakes.html
---
## Einleitung <!-- omit in toc -->
In diesem Kapitel werden häufige Fehler beschrieben und es wird erklärt, wie man diese vermeiden kann.
- [Vorsicht beim Speichern von ObjectRefs (z.B.: Spieler oder Entitäten) ](#vorsicht-beim-speichern-von-objectrefs-zb-spieler-oder-entitäten-)
- [Vertrauen Sie keinen Formspec-Einsendungen ](#vertrauen-sie-keinen-formspec-einsendungen-)
- [ItemStacks nach dem Ändern einstellen ](#itemstacks-nach-dem-ändern-einstellen-)
## Vorsicht beim Speichern von ObjectRefs (z.B.: Spieler oder Entitäten) <a name="be-careful-when-storing-objectrefs-ie-players-or-entities"></a>
Eine ObjectRef wird ungültig, wenn der Spieler oder die Entität, die sie repräsentiert, das Spiel verlässt. Dies kann passieren, wenn der Spieler offline geht oder die Entität nicht mehr geladen ist oder entfernt wird.
Die Methoden von ObjectRefs geben seit Minetest 5.2 immer `nil` zurück, wenn sie ungültig sind. Jeder Aufruf wird grundsätzlich ignoriert.
Sie sollten das Speichern von ObjectRefs nach Möglichkeit vermeiden. Wenn Sie dennoch eine ObjectRef speichern, sollten Sie dies vor der Verwendung überprüfen, etwa so:
```lua
-- Funktioniert nur in Minetest 5.2+
if obj:get_pos() then
-- ist gültig!
end
```
## Vertrauen Sie keinen Formspec-Einsendungen <a name="dont-trust-formspec-submissions"></a>
Hacker können Formulare übermitteln, wann immer sie wollen und mit welchem Inhalt auch immer sie wollen.
Der folgende Code weist zum Beispiel eine Schwachstelle auf, die es Spielern ermöglicht sich selbst Moderatoren-Rechte zu geben:
```lua
local function show_formspec(name)
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
minetest.show_formspec(name, "modman:modman", [[
size[3,2]
field[0,0;3,1;target;Name;]
button_exit[0,1;3,1;sub;Promote]
]])
return true
})
minetest.register_on_player_receive_fields(function(player,
formname, fields)
-- SCHLECHT! Fehlender Privilegiencheck!
local privs = minetest.get_player_privs(fields.target)
privs.kick = true
privs.ban = true
minetest.set_player_privs(fields.target, privs)
return true
end)
```
Fügen Sie eine Berechtigungsprüfung hinzu, um dieses Problem zu lösen:
```lua
minetest.register_on_player_receive_fields(function(player,
formname, fields)
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
-- code
end)
```
## ItemStacks nach dem Ändern einstellen <a name="set-itemstacks-after-changing-them"></a>
Haben Sie bemerkt, dass es in der API einfach `ItemStack` genannt wird, nicht `ItemStackRef`, ähnlich wie `InvRef`? Das liegt daran, dass ein `ItemStack` keine Referenz ist - es ist eine Kopie. Stacks arbeiten mit einer Kopie der Daten und nicht mit dem Stapel im Inventar. Das bedeutet, dass das Ändern eines Stacks nicht wirklich den Stack im Inventar verändert.
Tun Sie zum Beispiel nicht dies:
```lua
local inv = player:get_inventory()
local stack = inv:get_stack("main", 1)
stack:get_meta():set_string("description", "Teilweise gegessen")
-- SCHLECHT! Änderung wird verloren gehen
```
Machen Sie stattdessen Folgendes:
```lua
local inv = player:get_inventory()
local stack = inv:get_stack("main", 1)
stack:get_meta():set_string("description", "Teilweise gegessen")
inv:set_stack("main", 1, stack)
-- Richtig! ItemStack ist eingestellt!
```
Das Verhalten von Callbacks ist etwas komplizierter. Das Ändern eines `ItemStack`, der zurückgegeben wird, ändert diesen auch für den Aufrufer und alle nachfolgenden Aufrufe. In jedem Fall wird der ItemStack jedoch nur dann in der Engine gespeichert, wenn der Callback-Aufrufer ihn setzt.
```lua
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Teilweise gegessen")
-- Fast richtig! Die Daten gehen verloren, wenn ein anderer
-- Callback das Verhalten abbricht
end)
```
Wenn keine Callbacks diesen Vorgang abbrechen, wird der Stack gesetzt und die Beschreibung aktualisiert. Wenn jedoch ein Callback dies abbricht, kann die Aktualisierung verloren gehen.
Es ist besser, dies stattdessen zu tun:
```lua
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Teilweise gegessen")
user:get_inventory():set_stack("main", user:get_wield_index(),
itemstack)
-- Richtig, die Beschreibung wird immer eingestellt!
end)
```
Wenn die Callbacks abbrechen oder der Callback-Runner den Stack nicht setzt, dann wird die Aktualisierung trotzdem durchgeführt.
Wenn die Callbacks oder der Callback-Runner den Stack setzen, spielt die Verwendung von set_stack keine Rolle.

93
_de/quality/luacheck.md Normal file
View File

@ -0,0 +1,93 @@
---
title: Automatische Fehlerüberprüfung
layout: default
root: ../..
idx: 8.2
description: Verwenden Sie LuaCheck, um Fehler zu finden
redirect_from: /de/chapters/luacheck.html
---
## Einleitung <!-- omit in toc -->
In diesem Kapitel werden Sie lernen, wie Sie das Werkzeug LuaCheck benutzen, um Ihre Mod auf Fehler zu überprüfen. Dieses Werkzeug kann in Kombination mit deinem Editor verwendet werden, um auf Fehler aufmerksam zu machen.
- [Installation von LuaCheck](#installation-von-luacheck)
- [Windows](#windows)
- [Linux](#linux)
- [LuaCheck ausführen ](#luacheck-ausführen-)
- [LuaCheck konfigurieren](#luacheck-konfigurieren)
- [Fehlerbehebung](#fehlerbehebung)
- [Verwendung mit einem Editor](#verwendung-mit-einem-editor)
## Installation von LuaCheck
### Windows
Laden Sie einfach luacheck.exe von [der Github-Releaseseite 🇬🇧](https://github.com/mpeterv/luacheck/releases) herunter.
### Linux
Zuerst müssen Sie LuaRocks installieren:
sudo apt install luarocks
Sie können LuaCheck dann global (also für alle Benutzer) installieren:
sudo luarocks install luacheck
Prüfen Sie mit dem folgenden Befehl, ob es installiert ist:
luacheck -v
## LuaCheck ausführen <a name="run"></a>
Wenn Sie LuaCheck zum ersten Mal ausführen, wird es wahrscheinlich eine Menge falscher Fehler erkennen. Das liegt daran, dass es noch konfiguriert werden muss.
Unter Windows öffnen Sie die Powershell oder Bash im Stammverzeichnis Ihres Projekts und führen Sie `path\to\luacheck.exe .` aus.
Unter Linux führen Sie `luacheck .` aus, während Sie sich im Stammordner Ihres Projekts befinden.
## LuaCheck konfigurieren
Erstellen Sie eine Datei namens `.luacheckrc` im Stammverzeichnis Ihres Projekts. Dies kann das Stammverzeichnis Ihres Spiels, Modpacks oder Mods sein.
Fügen Sie den folgenden Inhalt in diese Datei ein:
```lua
unused_args = false
allow_defined_top = true
globals = {
"minetest",
}
read_globals = {
string = {fields = {"split"}},
table = {fields = {"copy", "getn"}},
-- Eingebaut
"vector", "ItemStack",
"dump", "DIR_DELIM", "VoxelArea", "Settings",
-- MTG
"default", "sfinv", "creative",
}
```
Als nächstes müssen Sie testen, ob es funktioniert, indem Sie LuaCheck ausführen. Diesmal sollten Sie viel weniger Fehler erhalten. Ändern Sie ab dem ersten Fehler, den Sie erhalten, den Code, um um das Problem zu beseitigen oder ändern Sie die Konfiguration, wenn der Code korrekt ist. Siehe die Liste unten.
### Fehlerbehebung
* **accessing undefined variable foobar** - Wenn `foobar` eine globale Variable sein soll, fügen Sie diese zu `read_globals` hinzu. Andernfalls fügen Sie alle fehlenden `local` zum Mod hinzu.
* **setting non-standard global variable foobar** - Wenn `foobar` eine globale Variable sein soll, fügen Sie diese zu `globals` hinzu. Entfernen Sie diese aus `read_globals`, falls vorhanden.
Andernfalls fügen Sie alle fehlenden `local` zum Mod hinzu.
* **mutating read-only global variable 'foobar'** - Verschieben Sie `foobar` von `read_globals` nach `globals` oder hören Sie auf, in foobar zu schreiben.
## Verwendung mit einem Editor
Es wird dringend empfohlen, dass Sie ein Plugin für den Editor Ihrer Wahl finden und installieren, das Ihnen Fehler anzeigt, ohne dass Sie einen Befehl ausführen müssen. Für die meisten Editoren ist wahrscheinlich ein Plugin verfügbar.
* **VSCode** - Ctrl+P, dann einfügen: `ext install dwenegar.vscode-luacheck`
* **Sublime** - Installieren Sie mit Hilfe von package-control:
[SublimeLinter 🇬🇧](https://github.com/SublimeLinter/SublimeLinter),
[SublimeLinter-luacheck 🇬🇧](https://github.com/SublimeLinter/SublimeLinter-luacheck).

28
_de/quality/readmore.md Normal file
View File

@ -0,0 +1,28 @@
---
title: Mehr lesen
layout: default
root: ../..
idx: 8.7
redirect_from: /de/chapters/readmore.html
---
## Liste der Ressourcen
Nachdem Sie dieses Buch gelesen haben, sollten Sie sich Folgendes ansehen.
### Minetest Modding
* Minetests Lua API Referenz - [HTML version 🇬🇧](https://minetest.gitlab.io/minetest/class-reference/#player-only-no-op-for-other-objects) |
[Text version 🇬🇧](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt).
* Erforschen Sie das [Developer Wiki](https://dev.minetest.net/Main_Page/de).
* Schauen Sie sich [existierende Mods 🇬🇧](https://forum.minetest.net/viewforum.php?f=11) an.
### Lua-Programmierung
* [Programming in Lua (PIL) 🇬🇧](http://www.lua.org/pil/).
* [Lua Crash Course 🇬🇧](http://luatut.com/crash_course.html).
### 3D Modelling
* [Blender Dokumentation](https://de.wikibooks.org/wiki/Blender_Dokumentation).
* [Using Blender with Minetest 🇬🇧](http://wiki.minetest.net/Using_Blender).

161
_de/quality/releasing.md Normal file
View File

@ -0,0 +1,161 @@
---
title: Eine Mod veröffentlichen
layout: default
root: ../..
idx: 8.6
redirect_from: /de/chapters/releasing.html
---
## Einleitung <!-- omit in toc -->
Das Veröffentlichen einer Mod erlaubt es anderen Leuten, sie zu nutzen. Sobald eine Mod
veröffentlicht ist, kann sie in Einzelspieler-Spielen oder auf Servern, einschließlich öffentlichen Servern, verwendet werden.
- [Eine Lizenz auswählen](#eine-lizenz-auswählen)
- [LGPL und CC-BY-SA](#lgpl-und-cc-by-sa)
- [CC0](#cc0)
- [MIT](#mit)
- [Verpacken](#verpacken)
- [README.txt](#readmetxt)
- [mod.conf / game.conf](#modconf--gameconf)
- [screenshot.png](#screenshotpng)
- [Hochladen](#hochladen)
- [Version Control Systeme](#version-control-systeme)
- [Veröffentlichen auf ContentDB](#veröffentlichen-auf-contentdb)
- [Forum Thema](#forum-thema)
## Eine Lizenz auswählen
Sie müssen eine Lizenz für Ihren Mod angeben. Das ist wichtig, weil sie anderen Leuten
mitteilt, auf welche Weise sie Ihre Arbeit verwenden dürfen. Wenn Ihre Mod keine Lizenz hat
hat, wissen andere nicht, ob sie Ihre Mod auf einem öffentlichen Server verändern,
verbreiten oder verwenden dürfen.
Ihr Code und Ihre Kunst brauchen unterschiedliche Lizenzen, die sie verwenden. Zum Beispiel sollten Creative-Commons-Lizenzen nicht für Quellcode verwendet werden,
können aber für künstlerische Werke wie Bilder, Texte und Meshes eine gute Wahl sein.
Sie dürfen jede Lizenz verwenden; Mods, die Derivate nicht zulassen, werden jedoch aus dem
offiziellen Minetest-Forum verboten. (Damit eine Mod im Forum zugelassen wird, müssen andere Entwickler
in der Lage sein, sie zu modifizieren und die modifizierte Version zu veröffentlichen.)
Bitte beachten Sie, dass **public domain** keine gültige Lizenz ist, da die Definition in verschiedenen
Ländern variiert.
Es ist wichtig zu beachten, dass WTFPL
[dringend abgeraten wird 🇬🇧](https://content.minetest.net/help/wtfpl/) und Leute möglicherweise
Ihre Mod nicht verwenden, wenn sie diese Lizenz hat.
### LGPL und CC-BY-SA
Dies ist eine gängige Lizenzkombination in der Minetest-Gemeinschaft und wird von
Minetest und Minetest Game verwendet.
Sie lizenzieren Ihren Code unter LGPL 2.1 und Ihre Kunst unter CC-BY-SA.
Dies bedeutet, dass:
* Jeder kann veränderte oder unveränderte Versionen verändern, weitergeben und verkaufen.
* Wenn jemand Ihre Modifikation verändert, muss er seiner Version die gleiche Lizenz geben.
* Ihr Urheberrechtsvermerk muss beibehalten werden.
### CC0
Diese Lizenz kann sowohl für Code als auch für Kunst verwendet werden und erlaubt es jedem, das
mit Ihrem Werk zu machen, was er will. Das heißt, er kann es verändern, weitergeben, verkaufen oder
die Namensnennung weglassen.
### MIT
Dies ist eine gängige Lizenz für Code. Die einzige Einschränkung, die die Nutzer
Ihres Codes haben, dass sie denselben Copyright-Vermerk und dieselbe Lizenz
in alle Kopien des Codes oder wesentlicher Teile des Codes aufnehmen müssen.
## Verpacken
Es gibt einige Dateien, die Sie in Ihre Mod oder Ihr Spiel aufnehmen sollten
bevor Sie es veröffentlichen.
### README.txt
In der README-Datei sollte stehen:
* Was der Mod/das Spiel macht und wie man es benutzt.
* Was die Lizenz ist
* Optional:
* Wo man Probleme melden oder Hilfe bekommen kann.
* Namensnennungen
### mod.conf / game.conf
Vergewissern Sie sich, dass Sie einen Beschreibungsschlüssel hinzufügen, um zu erklären,
was Ihr Mod oder Spiel tut. Seien Sie prägnant, ohne vage zu sein. Sie sollte kurz sein,
denn sie wird im Content-Installer angezeigt, der nur begrenzten Platz hat.
Gutes Beispiel:
description = Fügt Suppe, Kuchen, Gebäck und Säfte hinzu.
Vermeiden Sie dies:
description = Die Lebensmittel-Mod für Minetest. (<-- SCHLECHT! Es ist vage)
### screenshot.png
Screenshots sollten im Verhältnis 3:2 (3 Pixel Breite für 2 Pixel Höhe)
und eine Mindestgröße von 300 x 200 Pixel haben.
Der Screenshot wird innerhalb von Minetest als Vorschaubild für den Inhalt angezeigt.
## Hochladen
Damit ein potenzieller Benutzer Ihre Mod herunterladen kann, müssen Sie sie irgendwo hochladen und
öffentlich zugänglich machen. Es gibt mehrere Möglichkeiten, dies zu tun, aber Sie sollten die Möglichkeit wählen, die für Sie am besten geeignet ist, solange diese die folgenden Anforderungen erfüllt und auch alle anderen, die von den Moderatoren des Forums hinzugefügt werden können:
* **Stabil** - Es sollte unwahrscheinlich sein, dass die Hosting-Webseite ohne Vorwarnung abgeschaltet wird.
* **Direkter Link** - Sie sollten in der Lage sein, auf einen Link zu klicken und die Datei herunterzuladen, ohne eine andere Seite aufrufen zu müssen.
* **Virenfrei** - Betrügerische Upload-Hosts können unsichere Werbung enthalten.
ContentDB ermöglicht das Hochladen von Zip-Dateien und erfüllt diese Kriterien.
### Version Control Systeme
Ein Versionskontrollsystem (VCS) ist eine Software, die Änderungen an Software verwaltet,
Dadurch wird es oft einfacher, Änderungen zu verteilen und zu erhalten.
Die meisten Minetest-Modder verwenden Git und eine Webseite wie [Mesehub 🇬🇧](https://git.minetest.land/),
um ihren Code zu veröffentlichen.
Die Verwendung von git kann anfangs schwierig sein. Wenn Sie dabei Hilfe benötigen, lesen Sie bitte:
* [Pro Git Buch](https://git-scm.com/book/de/v2/Erste-Schritte-Was-ist-Versionsverwaltung%3F) - Kostenlos online lesbar.
## Veröffentlichen auf ContentDB
ContentDB ist der offizielle Ort, um Inhalte wie Mods, Spiele und Texturpakete zu finden und zu verbreiten.
Benutzer können Inhalte über die Webseite finden oder über die Integration in das Minetest-Hauptmenü
herunterladen und installieren, indem sie die Integration des Hauptmenü von Minetest nutzen.
Melden Sie sich bei [ContentDB](https://content.minetest.net) an und fügen Sie Ihre Inhalte hinzu.
Lesen Sie unbedingt die Hinweise im Abschnitt "Hilfe".
## Forum Thema
Sie können auch ein Forumthema erstellen, damit die Benutzer über Ihre Kreation diskutieren können.
Mod-Themen sollten im ["WIP Mods" 🇬🇧](https://forum.minetest.net/viewforum.php?f=9) (Work In Progress(deutsch: In Arbeit))
Forum erstellt werden, und Spiele-Themen im ["WIP Games"🇬🇧](https://forum.minetest.net/viewforum.php?f=50) Forum.
Wenn Sie Ihren Mod nicht mehr als "Work In Progress" betrachten, können Sie
[beantragen, dass sie in "Mod-Veröffentlichungen" verschoben wird 🇬🇧](https://forum.minetest.net/viewtopic.php?f=11&t=10418).
Das Forumsthema sollte einen ähnlichen Inhalt wie das README haben, aber
mehr Werbung machen und auch einen Link zum Download der Mod enthalten.
Es ist eine gute Idee, wenn möglich, Screenshots von Ihrer Mod in Aktion zu zeigen.
Das Thema muss in einem dieser Formate angegeben werden:
* [Mod] Mod Titel [Modname]
* [Mod] Mod Titel [Versionsnummer] [Modname]
Zum Beispiel:
* [Mod] More Blox [0.1] [moreblox]

107
_de/quality/security.md Normal file
View File

@ -0,0 +1,107 @@
---
title: Sicherheit
layout: default
root: ../..
idx: 8.3
---
## Einleitung <!-- omit in toc -->
Sicherheit ist sehr wichtig, um sicherzustellen, dass Serverbesitzer durch die Mod keine Daten oder die Kontrolle verlieren.
- [Zentrale Konzepte](#zentrale-konzepte)
- [Formspecs](#formspecs)
- [Trauen Sie niemals Einsendungen](#trauen-sie-niemals-einsendungen)
- [Der Zeitpunkt der Prüfung ist nicht der Zeitpunkt der Nutzung ](#der-zeitpunkt-der-prüfung-ist-nicht-der-zeitpunkt-der-nutzung-)
- [(Unsichere) Umgebungen ](#unsichere-umgebungen-)
## Zentrale Konzepte
Das wichtigste Sicherheitskonzept lautet: **Niemals dem Benutzer vertrauen**.
Alles, was der Benutzer eingibt, sollte als bösartig betrachtet werden. Das
bedeutet, dass Sie immer prüfen sollten, ob die eingegebenen Informationen
gültig sind, dass der Benutzer über die richtigen Berechtigungen verfügt und
dass er ansonsten berechtigt ist, diese Aktion durchzuführen
(d.h. im Bereich oder als Eigentümer).
Eine böswillige Aktion ist nicht unbedingt die Änderung oder Zerstörung von Daten,
sondern kann der Zugriff auf sensible Daten sein, z. B. Passwort-Hashes oder
private Nachrichten. Dies ist besonders schlimm, wenn der Server Informationen
wie E-Mails oder das Alter speichert, was manche zu Überprüfungszwecken tun.
## Formspecs
### Trauen Sie niemals Einsendungen
Jeder Benutzer kann jederzeit fast jeden Formspec mit beliebigen Werten eingeben.
Hier ist ein echter Code, der in einer Mod gefunden wurde:
```lua
minetest.register_on_player_receive_fields(function(player,
formname, fields)
for key, field in pairs(fields) do
local x,y,z = string.match(key,
"goto_([%d-]+)_([%d-]+)_([%d-]+)")
if x and y and z then
player:set_pos({ x=tonumber(x), y=tonumber(y),
z=tonumber(z) })
return true
end
end
end
```
Können Sie das Problem erkennen? Ein böswilliger Benutzer könnte eine Formularvorgabe
mit selbst bestimmten Positionswerten übermitteln, die es ihm ermöglichen, sich an
jeden beliebigen Ort zu teleportieren. Dies könnte sogar automatisiert werden, indem
man Änderungen am Client vornimmt, um im Wesentlichen den Befehl den Befehl `/teleport`
zu replizieren, ohne dass ein Privileg erforderlich ist.
Die Lösung für diese Art von Problem ist die Verwendung eines
[Contexts](../players/formspecs.html#contexts), wie zuvor im Kapitel Formspecs gezeigt.
### Der Zeitpunkt der Prüfung ist nicht der Zeitpunkt der Nutzung <a name="check-use"></a>
Jeder Benutzer kann jederzeit einen beliebigen Formspec mit beliebigen Werten übermitteln,
außer wenn die Engine dies verbietet:
* Die Eingabe einer `Node Meta Formspec-Einsendungen` wird blockiert, wenn der Benutzer zu weit entfernt ist.
* Ab 5.0 werden benannte formspecs blockiert, wenn sie noch nicht angezeigt wurden.
Das bedeutet, dass Sie im Handler prüfen sollten, ob der Benutzer die Bedingungen erfüllt,
um die Formspec überhaupt anzuzeigen, sowie alle entsprechenden Aktionen.
Die Schwachstelle, die dadurch entsteht, dass die Berechtigungen in der show formspec geprüft werden,
aber nicht in der handle formspec verursacht wird, wird Time Of Check is not Time Of Use (TOCTOU) genannt.
## (Unsichere) Umgebungen <a name="umgebungen"></a>
Minetest erlaubt es Mods, eine unsandboxed Umgebung anzufordern, die ihnen Zugang auf die gesamte Lua-API gibt.
Können Sie die Schwachstelle im Folgenden erkennen?
```lua
local ie = minetest.request_insecure_environment()
ie.os.execute(("path/to/prog %d"):format(3))
```
`string.format` ist eine Funktion in der globalen gemeinsamen Tabelle `string`. Eine
bösartige Mod könnte diese Funktion überschreiben und Material an os.execute übergeben:
```lua
string.format = function()
return "xdg-open 'http://example.com'"
end
```
Die Mod könnte etwas viel Bösartigeres als das Öffnen einer Website weitergeben, wie z. B.
einem entfernten Benutzer die Kontrolle über den Rechner zu geben.
Einige Regeln für die Verwendung einer unsicheren Umgebung:
* Speichern Sie sie immer in einem lokalen Verzeichnis und geben Sie sie nie in eine Funktion ein.
* Stellen Sie sicher, dass Sie jeder Eingabe in eine unsichere Funktion vertrauen können, um das
oben genannte Problem zu vermeiden. Dies bedeutet, dass global umdefinierbare Funktionen vermieden
werden sollten.

159
_de/quality/translations.md Normal file
View File

@ -0,0 +1,159 @@
---
title: Übersetzung (i18n / l10n)
layout: default
root: ../..
idx: 8.05
marked_text_encoding:
level: info
title: Markierter-Text-Kodierung
message: |
Sie müssen das genaue Format des markierten Textes nicht kennen, aber es könnte Ihnen helfen Sie zu verstehen.
```
"\27(T@mymod)Hello everyone!\27E"
```
* `\27` ist das Escape-Zeichen - es wird verwendet, um Minetest mitzuteilen, dass er aufpassen soll, da
etwas Besonderes bevorsteht. Es wird sowohl für Übersetzungen als auch für Text
Einfärbung benutzt.
* `(T@mymod)` besagt, dass der folgende Text mit Hilfe der `mymod` Textdomäne
übersetzbar wird.
* `Hello everyone!` ist der übersetzbare Text in Englisch, wie er an die
Übersetzer-Funktion übergeben wird.
* `\27E` ist das Escape-Zeichen mit `E`, um zu signalisieren, dass das Ende
erreicht wurde.
---
## Einleitung <!-- omit in toc -->
Wenn Sie ihre Mods und Spiele mit Übersetzungsunterstützung versehen, können mehr Menschen sie genießen. Laut Google Play haben 64 % der Minetest-Android-Nutzer Englisch nicht als ihre Hauptsprache. Minetest verfolgt keine Statistiken für Benutzer
über alle Plattformen hinweg, aber es ist wahrscheinlich, dass es einen hohen Anteil an
nicht-englischsprachiger Benutzer gibt.
Minetest ermöglicht es Ihnen, ihre Mods und Spiele in verschiedene Sprachen zu übersetzen, indem Sie Texte auf Englisch verfassen und mit Hilfe von Übersetzungsdateien die Texte in unterschiedliche Sprachen zu übersetzen. Die Übersetzung wird auf dem Client jedes Spielers durchgeführt, so dass jeder Spieler eine andere Sprache sieht.
- [Wie funktioniert die clientseitige Übersetzung?](#wie-funktioniert-die-clientseitige-übersetzung)
- [Markierter Text](#markierter-text)
- [Übersetzungsdateien](#übersetzungsdateien)
- [Formatierte Zeichenketten](#formatierte-zeichenketten)
- [Beste Verfahren und verbreitete Unwahrheiten über die Übersetzung ](#beste-verfahren-und-verbreitete-unwahrheiten-über-die-übersetzung-)
- [Server-seitige Übersetzungen ](#server-seitige-übersetzungen-)
- [Zusammenfassung](#zusammenfassung)
## Wie funktioniert die clientseitige Übersetzung?
### Markierter Text
Der Server muss den Clients mitteilen, wie der Text zu übersetzen ist. Dies geschieht durch die Platzierung von Kontrollzeichen im Text, die Minetest mitteilen, wo und wie der Text zu übersetzen ist. Dies wird als *markierter Text* bezeichnet und wird später näher erläutert.
Um Text als übersetzbar zu markieren, verwenden Sie eine Übersetzungsfunktion (`S()`), die Sie mit `minetest.get_translator(textdomain)` nutzen können`:
```lua
local S = minetest.get_translator("mymod")
minetest.register_craftitem("mymod:item", {
description = S("My Item"),
})
```
Das erste Argument von `get_translator` ist `textdomain`, die als Namensraum dient. Anstatt alle Übersetzungen für eine Sprache in einer einzigen Datei zu speichern, werden die Übersetzungen in Textdomänen aufgeteilt (eine Datei pro Textdomäne
pro Sprache). Die Textdomäne sollte mit dem Namen des Mods übereinstimmen, da dies hilft, Mod-Konflikte zu vermeiden.
Markierter Text kann an den meisten Stellen verwendet werden, wo menschenlesbarer Text akzeptiert wird, einschließlich *formspecs*, *item def*-Felder, Infotext und mehr. Wenn Sie markierten Text in Formspecs einfügen, müssen Sie den Text mit `minetest.formspec_escape` entschlüsseln.
Wenn der Client auf übersetzbaren Text stößt, wie den, der an `description` übergeben wird, schaut er in der Übersetzungsdatei der Sprache des Spielers nach. Wenn eine Übersetzung nicht gefunden wird, greift er auf die englische Übersetzung zurück.
Der übersetzbare markierte Text enthält den englischen Ausgangstext, die Textdomäne,
und alle zusätzlichen Argumente, die an `S()` übergeben werden. Es ist im wesentlichen eine Textkodierung des `S`-Aufrufs, die alle erforderlichen Informationen enthält.
Eine andere Art von markiertem Text ist der, der von `minetest.colorize` zurückgegeben wird.
{% include notice.html notice=page.marked_text_encoding %}
### Übersetzungsdateien
Übersetzungsdateien sind Mediendateien, die sich im Ordner `locale` von jeder Mod befinden. Zurzeit wird nur das Format `.tr` unterstützt, aber die Unterstützung für weitere gängige Formate wird wahrscheinlich in der Zukunft hinzugefügt. Übersetzungsdateien müssen folgendermaßen benannt werden: `[Textdomäne].[Sprache].tr`.
Dateien im `.tr` beginnen mit einem Kommentar, der die Textdomäne angibt, und dann weiteren Zeilen, die den englischen Ausgangstext in die Übersetzung übertragen.
Zum Beispiel: `mymod.de.tr`:
```
# textdomain: mymod
Hello everyone!=Hallo zusammen!
I like grapefruit=Ich mag Traubenfrüchte
```
Sie sollten Übersetzungsdateien auf der Grundlage des Quellcodes Ihres Mods/Spiels erstellen, unter Verwendung eines Tools wie [update_translations 🇬🇧](https://github.com/minetest-tools/update_translations). Dieses Tool sucht nach `S(` in Ihrem Lua-Code und erstellt automatisch eine Vorlage, die Übersetzer für die Übersetzung in ihre Sprache verwenden können. Es kümmert sich auch darum, die Übersetzungsdateien zu aktualisieren, wenn sich Ihr Quelltext ändert.
Sie sollten immer wörtlichen Text (`"`) in S einfügen, anstatt eine Variable zu verwenden,
da dies den Werkzeugen hilft, Übersetzungen zu finden.
## Formatierte Zeichenketten
Es ist üblich, variable Informationen in einen Übersetzungsstring aufzunehmen. Dabei ist es ist wichtig, dass der Text nicht einfach aneinandergereiht wird, da das Übersetzer daran hindert, die Reihenfolge der Variablen innerhalb eines Satzes zu ändern. Stattdessen, sollten Sie das Format/Argumente-System des Übersetzungssystems verwenden:
```lua
minetest.register_on_joinplayer(function(player)
minetest.chat_send_all(S("Everyone, say hi to @1!", player:get_player_name()))
end)
```
Wenn Sie ein wörtliches `@` in Ihre Übersetzung einfügen wollen, müssen Sie die Escape-Schreibweise verwenden, indem Sie `@@` schreiben.
Sie sollten die Konkatenation *innerhalb* eines Satzes vermeiden, aber es wird empfohlen, mehrere Sätze durch Konkatenation zu verbinden. Dies hilft den Übersetzern, weil Zeichenketten kleiner gehalten sind.
```lua
S("Hello @1!", player_name) .. " " .. S("You have @1 new messages.", #msgs)
```
## Beste Verfahren und verbreitete Unwahrheiten über die Übersetzung <a name="verfahren"></a>
* Vermeiden Sie die Konkatenation von Text und verwenden Sie stattdessen Formatierungsargumente.
Dies gibt den Übersetzern die volle Kontrolle über die Änderung der Reihenfolge.
* Erstellen Sie Übersetzungsdateien automatisch, indem Sie
[update_translations 🇬🇧](https://github.com/minetest-tools/update_translations) verwenden.
* Es ist üblich, dass Variablen den umgebenden Text verändern, zum Beispiel durch
Geschlecht und Pluralisierung. Dies ist oft schwer zu behandeln, daher wird
häufig mit geschlechtsneutralen Formulierungen umgangen.
* Übersetzungen können viel länger oder viel kleiner als der englische Text sein. Stellen Sie
sicher, dass Sie viel Platz lassen.
* In anderen Sprachen werden Zahlen möglicherweise anders geschrieben, zum Beispiel
mit Kommas als Dezimalkomma(also wie im Deutschen). `1.000,23`, `1'000'000,32`
* Gehen Sie nicht davon aus, dass andere Sprachen die Großschreibung auf die gleiche Weise verwenden.
## Server-seitige Übersetzungen <a name="server"></a>
Manchmal muss man z. B. die Übersetzung eines Textes auf dem Server kennen, um Text zu sortieren oder zu suchen. Sie können `get_player_information` benutzen, um die Sprache des Spielers zu erhalten und `get_translated_string`, um markierten Text zu übersetzen.
```lua
local list = {
S("Hello world!"),
S("Potato")
}
minetest.register_chatcommand("find", {
func = function(name, param)
local info = minetest.get_player_information(name)
local language = info and info.language or "en"
for _, line in ipairs(list) do
local trans = minetest.get_translated_string(language, line)
if trans:contains(query) then
return line
end
end
end,
})
```
## Zusammenfassung
Die Übersetzungs-API ermöglicht es, Mods und Spiele besser zugänglich zu machen, aber es ist Vorsicht geboten, um sie richtig zu nutzen.
Minetest wird ständig verbessert und die Übersetzungs-API wird wahrscheinlich in Zukunft erweitert werden. Zum Beispiel wird die Unterstützung für gettext-Übersetzungsdateien die Verwendung gängiger Übersetzungswerkzeuge und -plattformen (wie weblate) ermöglichen und es wird wahrscheinlich eine Unterstützung für Pluralisierung und Geschlecht hinzugefügt werden.

184
_de/quality/unit_testing.md Normal file
View File

@ -0,0 +1,184 @@
---
title: Automatische Unit-Tests
layout: default
root: ../..
idx: 8.5
---
## Einleitung <!-- omit in toc -->
Unit-Tests sind ein wichtiges Instrument, um zu beweisen und sich zu vergewissern,
dass der Code korrekt ist. Dieses Kapitel zeigt Ihnen, wie Sie Tests für
Minetest-Mods und Spiele mit Busted schreiben. Das Schreiben von Unit-Tests für
Funktionen, die Minetest Funktionen aufruft, ist ziemlich schwierig, aber zum Glück
haben wir [im vorherigen Kapitel](clean_arch.html), besprochen, wie man seinen Code
strukturiert, um dies zu vermeiden.
- [Busted installieren](#busted-installieren)
- [Ihr erster Test](#ihr-erster-test)
- [init.lua](#initlua)
- [api.lua](#apilua)
- [tests/api\_spec.lua](#testsapi_speclua)
- [Mocking: Externe Funktionen verwenden](#mocking-externe-funktionen-verwenden)
- [Überprüfen von Commits mit Travis](#überprüfen-von-commits-mit-travis)
- [Zusammenfassung](#zusammenfassung)
## Busted installieren
Zuerst müssen Sie LuaRocks installieren.
* Windows: Folgen Sie den [Installationsanweisungen im LuaRocks-Wiki 🇬🇧](https://github.com/luarocks/luarocks/wiki/Installation-instructions-for-Windows).
* Debian/Ubuntu Linux: `sudo apt install luarocks`
Als nächstes sollten Sie Busted global, also für alle Benutzer, installieren:
sudo luarocks install busted
Prüfen Sie schließlich, ob es installiert ist:
busted --version
## Ihr erster Test
Busted ist das führende Unit-Test-Framework für Lua. Busted sucht nach Lua-Dateien mit Namen, die auf `_spec` enden und führt sie dann in einer eigenständigen Lua-Umgebung aus.
mymod/
├── init.lua
├── api.lua
└── tests
└── api_spec.lua
### init.lua
```lua
mymod = {}
dofile(minetest.get_modpath("mymod") .. "/api.lua")
```
### api.lua
```lua
function mymod.add(x, y)
return x + y
end
```
### tests/api_spec.lua<a name="testsapispeclua"></a>
```lua
-- Sucht nach erforderlichen Dingen in
package.path = "../?.lua;" .. package.path
-- Setzt mymod global für API zum Schreiben in
_G.mymod = {} --_
-- Ausführen von der api.lua-Datei
require("api")
-- Testen
describe("add", function()
it("adds", function()
assert.equals(2, mymod.add(1, 1))
end)
it("supports negatives", function()--in Deutschen ist "supports negatives" "unterstützt Negative (Zahlen)"
assert.equals(0, mymod.add(-1, 1))
assert.equals(-2, mymod.add(-1, -1))
end)
end)
```
Sie können die Tests nun ausführen, indem Sie ein Terminal im Verzeichnis der Mods öffnen und `busted` ausführen.
Es ist wichtig, dass die API-Datei die Tabelle nicht selbst erstellt, da Globals in Busted anders funktionieren. Jede Variable, die in Minetest global wäre, ist stattdessen
eine lokale Datei in Busted. Dies wäre ein besserer Weg für Minetest gewesen, die Dinge zu erledigen, aber dafür ist es jetzt zu spät.
Eine weitere Sache, die man beachten sollte, ist, dass alle Dateien, die man testet, keine Aufrufe an irgendwelche Funktionen vermeiden, die nicht darin enthalten sind. In der Regel schreibt man nur Tests für eine einzige Datei auf einmal.
## Mocking: Externe Funktionen verwenden
Beim Mocking werden die Funktionen ersetzt, von denen das zu testende Objekt abhängt. Dies kann zwei Zwecke haben: Erstens ist die Funktion in der Testumgebung möglicherweise nicht verfügbar Testumgebung nicht zur Verfügung und zweitens möchten Sie vielleicht die Aufrufe der Funktion und alle übergebenen Argumente.
Wenn Sie die Ratschläge im Kapitel [Saubere Architekturen](clean_arch.html) befolgen,
haben Sie bereits eine ziemlich saubere Datei zum Testen. Sie müssen jedoch noch
Dinge, die nicht in Ihrem Bereich liegen, mocken - zum Beispiel müssen Sie den View mocken, wenn Sie Controller/API testen. Wenn Sie die Ratschläge nicht befolgt haben, ist es etwas etwas schwieriger, da Sie möglicherweise die Minetest-API nachbilden müssen.
```lua
-- Wie oben eine Tabelle erstellen
_G.minetest = {}
-- Definieren Sie die Mock-Funktion
local chat_send_all_calls = {}
function minetest.chat_send_all(name, message)
table.insert(chat_send_all_calls, { name = name, message = message })
end
-- Tests
describe("list_areas", function()
it("returns a line for each area", function()
chat_send_all_calls = {} -- reset table
mymod.list_areas_to_chat("singleplayer", "singleplayer")
assert.equals(2, #chat_send_all_calls)
end)
it("sends to right player", function()
chat_send_all_calls = {} -- reset table
mymod.list_areas_to_chat("singleplayer", "singleplayer")
for _, call in pairs(chat_send_all_calls) do --_
assert.equals("singleplayer", call.name)
end
end)
-- Die beiden oben genannten Tests sind eigentlich sinnlos,
-- denn dieser testet beide Dinge
it("returns correct thing", function()
chat_send_all_calls = {} -- reset table
mymod.list_areas_to_chat("singleplayer", "singleplayer")
local expected = {
{ name = "singleplayer", message = "Town Hall (2,43,63)" },
{ name = "singleplayer", message = "Airport (43,45,63)" },
}
assert.same(expected, chat_send_all_calls)
end)
end)
```
## Überprüfen von Commits mit Travis
Das Travis-Skript aus dem Kapitel [Automatische Fehlerüberprüfung](luacheck.html) kann so modifiziert werden, dass es auch Busted ausführt.
```yml
language: generic
sudo: false
addons:
apt:
packages:
- luarocks
before_install:
- luarocks install --local luacheck && luarocks install --local busted
script:
- $HOME/.luarocks/bin/luacheck .
- $HOME/.luarocks/bin/busted .
notifications:
email: false
```
## Zusammenfassung
Unit-Tests können die Qualität und Zuverlässigkeit Ihres Projekts erheblich steigern. Diese erfordern jedoch, dass Sie Ihren Code anders strukturieren als üblich.
Ein Beispiel für einen Mod mit vielen Unit-Tests finden Sie unter
[crafting von rubenwardy 🇬🇧](https://github.com/rubenwardy/crafting).

143
_de/wörterbuch.txt Normal file
View File

@ -0,0 +1,143 @@
Active Block Modifiers = Aktive Mapblock Modifikatoren
Admin = Admin
Administrator = Administrator
Alignment = Ausrichtung
anchor = Anker
Armor Groups = Armor Groups
Attachment = Anhang
block = Mapblock
bulk = bulk
callback = Callback
callback runner = Callback-Runner
Chapter = Kapitel
chat message = Chat-Nachricht
child = Kind
client = Client
Cohesion = Kohäsion
Command = Befehl
concatenation = Konkatenation
Context = Context
Cubic Nodes = Würfelförmiger Block
craft slots = Handwerksplätze
Credits = Namensnennungen
Damage = Schaden
Damage Groups = Damage Groups
database = Datenbank
Degrees = Grad
detached inventory = freistehendes Inventar
dig = abbauen
Dig Types = Grabungstypen
drawtype = Zeichnungstyp
element = Element
Entities = Entitäten
Entity = Entität
false = falsch
Filler node = Füllender Node
Folder = Verzeichnis
form = Form
forms = Forms
formspec = formspec
formspec language version = formspec-Sprachversion
formspec slot = formspec-Slot
formspec submission = formspec-Einsendung
games = Spiele
getter = Getter
glasslike = Glasartig
glitch = Störung
grid = Raster
hard dependency = feste Abhängigkeit
Header = Header
Heads Up Display = Heads Up Display
Health = Leben
Health Points = Lebenspunkte
HP = HP
hud = hud
HUD = HUD
initial properties = Erst-Eigenschaften
insecure environment = unsichere Umgebung
Introduction = Einleitung
Inventory = Inventar
Inventory List = Inventarliste
Inventory Location = Inventarstandort
Inventory reference = Inventar-Referenz
Item metadata = Item-Metadaten
ItemStack = ItemStack
key = Schlüssel
key-value table = Schlüssel-Wert-Tabelle
large data = große Daten
Legacy Coordinates = Legacy-Koordinaten
Lua entity = Lua entity
Lua Voxel Manipulator
main inventory = Hauptinventar
map = Karte
MapBlock = Map-Block
mapgen = Mapgen
medium data = mittlere Daten
Mesh = Mesh
Mesh Nodes = Mesh Nodes
Metadata Object = Metadatenobjekt
Mocking = Mocking
mod load paths = Mod-Lade-Verzeichnisse
mod's folder = Mod-Verzeichnis
mods = Mods
Mod storage = Mod-Storage
Mod Packs = Mod-Pakete
module = Modul
mymod = mymod
network latency = Latenzzeit im Netz
node = Node
Node metadata = Node-Metadaten
nodes = Blöcke
nodebox = Nodebox
nodeboxes = Nodeboxen
Node inventory = Blockinventar
node timer = Blocktimer
noise parameters = Noise-Parameter
Object properties = Objekt-Eigenschaften
offset = Versatz
optional dependency = Optionale Abhängigkeiten
Overrides = Overrides
path = Verzeichnis
parent = Elternteil
per-player = pro-Spieler
pixel art = Pixel-Art
physics overrides = Physik-Overrides
placer = plazierer
player = Spieler
player inventory = Spielerinventar
player reference = Spielerreferenz
Player Physic = Spielerphysik
pointed_thing = angeschautes_ding
priv = priv
privilege = Privileg
punch = schlagen
put = ablegen
Radians = Radiant
Real Coordinates = Reale Koordinaten
releasing=veröffentlichen
scale = scale
schematic = Schematic
Schematic Decoration = schematischen Dekoration
Scoreboard = Anzeigetafel
score panel = Anzeigetafel
shout = shout
small data = kleine Daten
sneak elevators = Schleichfahrstühle
sneak glitch = sneak glitch
Stack = Stack
string = Zeichenkette
storage = Storage
Subcommand = Unterbefehl
table = Tabelle
textdomain = Textdomäne
tile = Kachel
tiles = Kacheln
timer = timer
Top node = Oberer Node
true = wahr
Unit Testing = Unit-Tests
unsandboxed = unsandboxed
unsandboxed environment = unsandboxed Umgebung
Version Control System = Version Control System
wear = Abnutzung
Your turn = Sie sind dran

View File

@ -9,6 +9,9 @@ layout: base
{% if language == "_it" %}
{% assign language = "it" %}
{% assign links = site.it %}
{% elsif language == "_de" %}
{% assign language = "de" %}
{% assign links = site.de %}
{% else %}
{% assign language = "en" %}
{% assign links = site.en %}

14
cat.html Normal file
View File

@ -0,0 +1,14 @@
---
layout: none
---
{% if site.calc_word_count %}
{% assign chapters = site.en | sort: "idx" %}
{% for chapter in chapters %}
{% unless chapter.homepage %}
{{ chapter.content }}
{% endunless %}
{% endfor %}
{% else %}
Cat disabled.
{% endif %}