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
85 changed files with 5958 additions and 384 deletions

View File

@ -1,4 +1,4 @@
# Luanti Modding Book
# Minetest Modding Book
[![Build status](https://gitlab.com/rubenwardy/minetest_modding_book/badges/master/pipeline.svg)](https://gitlab.com/rubenwardy/minetest_modding_book/pipelines)<br>
[Read Online](https://rubenwardy.com/minetest_modding_book/)

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

@ -130,7 +130,7 @@ programs such as [Geogebra](https://www.geogebra.org).
The following code registers a simple biome named grasslands biome:
```lua
core.register_biome({
minetest.register_biome({
name = "grasslands",
node_top = "default:dirt_with_grass",
depth_top = 1,
@ -174,7 +174,7 @@ details for where it can be placed, and how frequently it occurs.
For example:
```lua
core.register_decoration({
minetest.register_decoration({
deco_type = "simple",
place_on = {"base:dirt_with_grass"},
sidelen = 16,
@ -199,7 +199,7 @@ Schematic decorations are very similar to simple decoration, but involve the pla
of a schematic instead of the placement of a single node. For example:
```lua
core.register_decoration({
minetest.register_decoration({
deco_type = "schematic",
place_on = {"base:desert_sand"},
sidelen = 16,
@ -207,7 +207,7 @@ core.register_decoration({
biomes = {"desert"},
y_max = 200,
y_min = 1,
schematic = core.get_modpath("plants") .. "/schematics/cactus.mts",
schematic = minetest.get_modpath("plants") .. "/schematics/cactus.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
@ -229,7 +229,7 @@ to consider registering mapgen aliases of your own if you are making your own ga
Mapgen aliases provide information to the core mapgen, and can be registered in the form:
```lua
core.register_alias("mapgen_stone", "base:smoke_stone")
minetest.register_alias("mapgen_stone", "base:smoke_stone")
```
At a minimum you should register:

View File

@ -10,8 +10,8 @@ redirect_from:
mapgen_object:
level: warning
title: LVMs and Mapgen
message: Don't use `core.get_voxel_manip()` with mapgen, as it can cause glitches.
Use `core.get_mapgen_object("voxelmanip")` instead.
message: Don't use `minetest.get_voxel_manip()` with mapgen, as it can cause glitches.
Use `minetest.get_mapgen_object("voxelmanip")` instead.
---
## Introduction <!-- omit in toc -->
@ -45,7 +45,7 @@ and maximum positions that you need to modify. Then you can create and read into
an LVM. For example:
```lua
local vm = core.get_voxel_manip()
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos1, pos2)
```
@ -93,7 +93,7 @@ You can find out the content ID for a particular type of node with
`get_content_id()`. For example:
```lua
local c_stone = core.get_content_id("default:stone")
local c_stone = minetest.get_content_id("default:stone")
```
You can then check whether the node is stone:
@ -164,17 +164,17 @@ For setting lighting and param2 data, use the appropriately named
`write_to_map()` takes a Boolean which is true if you want lighting to be
calculated. If you pass false, you need to recalculate lighting at a future
time using `core.fix_light`.
time using `minetest.fix_light`.
## Example
```lua
local function grass_to_dirt(pos1, pos2)
local c_dirt = core.get_content_id("default:dirt")
local c_grass = core.get_content_id("default:dirt_with_grass")
local c_dirt = minetest.get_content_id("default:dirt")
local c_grass = minetest.get_content_id("default:dirt_with_grass")
-- Read data into LVM
local vm = core.get_voxel_manip()
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos1, pos2)
local a = VoxelArea:new{
MinEdge = emin,

View File

@ -122,13 +122,13 @@ Create an init.lua file with the following content:
```lua
print("This file will be run at load time!")
core.register_node("mymod:node", {
minetest.register_node("mymod:node", {
description = "This is a node",
tiles = {"mymod_node.png"},
groups = {cracky = 1}
})
core.register_craft({
minetest.register_craft({
type = "shapeless",
output = "mymod:node 3",
recipe = { "default:dirt", "default:stone" },

View File

@ -177,7 +177,7 @@ nicer way to write it.
The recommended way to include other Lua scripts in a mod is to use *dofile*.
```lua
dofile(core.get_modpath("modname") .. "/script.lua")
dofile(minetest.get_modpath("modname") .. "/script.lua")
```
A script can return a value, which is useful for sharing private locals:
@ -189,7 +189,7 @@ module.message = "Hello World!"
return module
-- init.lua
local ret = dofile(core.get_modpath("modname") .. "/script.lua")
local ret = dofile(minetest.get_modpath("modname") .. "/script.lua")
print(ret.message) -- Hello world!
```

View File

@ -9,7 +9,7 @@ idx: 0.1
---
<header>
<h1>Luanti Modding Book (formerly Minetest)</h1>
<h1>Minetest Modding Book</h1>
<span>by <a href="https://rubenwardy.com" rel="author">rubenwardy</a></span>
<span>with editing by <a href="http://rc.minetest.tv/">Shara</a></span>

View File

@ -12,7 +12,7 @@ Minetest heavily uses a callback-based modding design. A callback is a function
that you give to an API and is called when an event happens. For example, you
can provide an `on_punch` function in a node definition to be called when a player
punches a node. There are also global callbacks like
`core.register_on_punchnode` to receive events for all nodes.
`minetest.register_on_punchnode` to receive events for all nodes.
- [Item Callbacks](#item-callbacks)
- [on_use](#on_use)
@ -34,9 +34,9 @@ certain events:
| Callback | Default binding | Default value |
|------------------|---------------------------|----------------------------------------------|
| on_use | left-click | nil |
| on_place | right-click on a node | `core.item_place` |
| on_secondary_use | right-click not on a node | `core.item_secondary_use` (does nothing) |
| on_drop | Q | `core.item_drop` |
| on_place | right-click on a node | `minetest.item_place` |
| on_secondary_use | right-click not on a node | `minetest.item_secondary_use` (does nothing) |
| on_drop | Q | `minetest.item_drop` |
| after_use | digging a node | nil |
@ -46,27 +46,27 @@ Having a use callback prevents the item from being used to dig nodes. One common
use of the use callback is for food:
```lua
core.register_craftitem("mymod:mudpie", {
minetest.register_craftitem("mymod:mudpie", {
description = "Alien Mud Pie",
inventory_image = "myfood_mudpie.png",
on_use = core.item_eat(20),
on_use = minetest.item_eat(20),
})
```
The number supplied to the core.item_eat function is the number of hit
The number supplied to the minetest.item_eat function is the number of hit
points healed when this food is consumed. Each heart icon the player has is
worth two hitpoints. A player can usually have up to 10 hearts, which is equal
to 20 hitpoints.
core.item_eat() is a function that returns a function, setting it as the
minetest.item_eat() is a function that returns a function, setting it as the
on_use callback. This means the code above is equivalent to this:
```lua
core.register_craftitem("mymod:mudpie", {
minetest.register_craftitem("mymod:mudpie", {
description = "Alien Mud Pie",
inventory_image = "myfood_mudpie.png",
on_use = function(...)
return core.do_item_eat(20, nil, ...)
return minetest.do_item_eat(20, nil, ...)
end,
})
```
@ -82,7 +82,7 @@ called when the player is pointing at a node and `on_secondary_use` when the
player isn't.
Both callbacks are called for all types of items. `on_place` defaults to the
`core.item_place` function, which handles calling the `on_rightclick`
`minetest.item_place` function, which handles calling the `on_rightclick`
callback of the pointed node or placing the wielded item if it is a node.
@ -90,7 +90,7 @@ callback of the pointed node or placing the wielded item if it is a node.
on_drop is called when the player requests to drop an item, for example using
the drop key (Q) or dragging it outside of the inventory. It defaults to the
`core.item_drop` function, which will handle dropping the item.
`minetest.item_drop` function, which will handle dropping the item.
### after_use
@ -110,20 +110,20 @@ end
Minetest's API includes many different built-in callback implementations for you
to use. These callbacks are named with the item type first, for example,
`core.item_place` and `core.node_dig`. Some callback implementations are
`minetest.item_place` and `minetest.node_dig`. Some callback implementations are
used directly whereas some are functions that return the callback:
```lua
core.register_item("mymod:example", {
on_place = core.item_place,
on_use = core.item_eat(10),
minetest.register_item("mymod:example", {
on_place = minetest.item_place,
on_use = minetest.item_eat(10),
})
```
Minetest's API also includes built-in functions that _do_ something. These are
often named in a confusingly similar way to built-in callback implementations
but have the verb first. Examples include `core.place_item` and
`core.dig_node` - these functions allow you to dig and place nodes with a
but have the verb first. Examples include `minetest.place_item` and
`minetest.dig_node` - these functions allow you to dig and place nodes with a
similar effect to players.
@ -144,9 +144,9 @@ callbacks to always be called.
### Right-clicking and placing a node
When the user right-clicks with an item whilst pointing at a node, the item's
`on_place` callback is called. By default, this is set to `core.item_place`.
`on_place` callback is called. By default, this is set to `minetest.item_place`.
If the pointed node has an `on_rightclick` callback and sneak (shift) is held,
then the `on_rightclick` callback is called. Otherwise, `core.item_place`
then the `on_rightclick` callback is called. Otherwise, `minetest.item_place`
will place the node.
Placing a node will call both `on_construct` and `after_place_node`.
@ -159,20 +159,20 @@ nodes; it's common for mobs and mods to place nodes. To account for this,
`placer` could be a player, entity, or nil.
```lua
core.register_node("mymod:mynode", {
minetest.register_node("mymod:mynode", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if clicker:is_player() then
core.chat_send_player(clicker:get_player_name(), "Hello world!")
minetest.chat_send_player(clicker:get_player_name(), "Hello world!")
end
end,
on_construct = function(pos, node)
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "My node!")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
-- Make sure to check placer
if placer and placer:is_player() then
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
end
end,
@ -186,15 +186,15 @@ has an `on_use` callback, this will be called. Otherwise, the `on_punch`
callback on the pointed node will be called.
When the player attempts to dig a node, the `on_dig` callback on the node will be called.
This defaults to `core.node_dig`, which will check for area protection, wear
This defaults to `minetest.node_dig`, which will check for area protection, wear
out the tool, remove the node, and run the `after_dig_node` callback.
```lua
core.register_node("mymod:mynode", {
minetest.register_node("mymod:mynode", {
on_punch = function(pos, node, puncher, pointed_thing)
if puncher:is_player() then
core.chat_send_player(puncher:get_player_name(), "Ow!")
minetest.chat_send_player(puncher:get_player_name(), "Ow!")
end
end,
})

View File

@ -106,7 +106,7 @@ chest. The node must be loaded because it is stored in
```lua
on_punch = function(pos, node)
local inv = core.get_inventory({ type="node", pos=pos })
local inv = minetest.get_inventory({ type="node", pos=pos })
-- now use the inventory
end,
```
@ -128,7 +128,7 @@ Player inventories can be obtained similarly or using a player reference.
The player must be online to access their inventory.
```lua
local inv = core.get_inventory({ type="player", name="player1" })
local inv = minetest.get_inventory({ type="player", name="player1" })
-- or
local inv = player:get_inventory()
```
@ -139,7 +139,7 @@ A detached inventory is one that is independent of players or nodes. Detached
inventories also don't save over a restart.
```lua
local inv = core.get_inventory({
local inv = minetest.get_inventory({
type="detached", name="inventory_name" })
```
@ -147,7 +147,7 @@ Unlike the other types of inventory, you must first create a detached inventory
before accessing it:
```lua
core.create_detached_inventory("inventory_name")
minetest.create_detached_inventory("inventory_name")
```
The `create_detached_inventory` function accepts 3 arguments, where only the
@ -156,7 +156,7 @@ callbacks, which can be used to control how players interact with the inventory:
```lua
-- Input only detached inventory
core.create_detached_inventory("inventory_name", {
minetest.create_detached_inventory("inventory_name", {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
return count -- allow moving
end,
@ -170,9 +170,9 @@ core.create_detached_inventory("inventory_name", {
end,
on_put = function(inv, listname, index, stack, player)
core.chat_send_all(player:get_player_name() ..
minetest.chat_send_all(player:get_player_name() ..
" gave " .. stack:to_string() ..
" to the donation chest from " .. core.pos_to_string(player:get_pos()))
" to the donation chest from " .. minetest.pos_to_string(player:get_pos()))
end,
})
```

View File

@ -19,7 +19,7 @@ In the previous chapter, the concept of nodes and items was introduced, but a
full definition of a node wasn't given. The Minetest world is a 3D grid of
positions. Each position is called a node, and consists of the node type
(name) and two parameters (param1 and param2). The function
`core.register_node` is a bit misleading in that it doesn't actually
`minetest.register_node` is a bit misleading in that it doesn't actually
register a node - it registers a new *type* of node.
The node params are used to control how a node is individually rendered.
@ -60,13 +60,13 @@ leaf nodes. You can use the allfaces_optional drawtype to allow users to opt-out
of the slower drawing, in which case it'll act like a normal node.
```lua
core.register_node("mymod:diamond", {
minetest.register_node("mymod:diamond", {
description = "Alien Diamond",
tiles = {"mymod_diamond.png"},
groups = {cracky = 3},
})
core.register_node("default:leaves", {
minetest.register_node("default:leaves", {
description = "Leaves",
drawtype = "allfaces_optional",
tiles = {"default_leaves.png"}
@ -92,7 +92,7 @@ drawtype would result in the ability to see through the world.
</figure>
```lua
core.register_node("default:obsidian_glass", {
minetest.register_node("default:obsidian_glass", {
description = "Obsidian Glass",
drawtype = "glasslike",
tiles = {"default_obsidian_glass.png"},
@ -120,11 +120,11 @@ You can use the glasslike_framed_optional drawtype to allow the user to *opt-in*
to the framed appearance.
```lua
core.register_node("default:glass", {
minetest.register_node("default:glass", {
description = "Glass",
drawtype = "glasslike_framed",
tiles = {"default_glass.png", "default_glass_detail.png"},
inventory_image = core.inventorycube("default_glass.png"),
inventory_image = minetest.inventorycube("default_glass.png"),
paramtype = "light",
sunlight_propagates = true, -- Sunlight can shine through block
groups = {cracky = 3, oddly_breakable_by_hand = 3},
@ -138,7 +138,7 @@ core.register_node("default:glass", {
These nodes are not rendered and thus have no textures.
```lua
core.register_node("myair:air", {
minetest.register_node("myair:air", {
description = "MyAir (you hacker you!)",
drawtype = "airlike",
paramtype = "light",
@ -192,11 +192,11 @@ another for flowing liquid.
```lua
-- Some properties have been removed as they are beyond
-- the scope of this chapter.
core.register_node("default:water_source", {
minetest.register_node("default:water_source", {
drawtype = "liquid",
paramtype = "light",
inventory_image = core.inventorycube("default_water.png"),
inventory_image = minetest.inventorycube("default_water.png"),
-- ^ this is required to stop the inventory image from being animated
tiles = {
@ -271,7 +271,7 @@ Node boxes allow you to create a node which is not cubic, but is instead made ou
of as many cuboids as you like.
```lua
core.register_node("stairs:stair_stone", {
minetest.register_node("stairs:stair_stone", {
drawtype = "nodebox",
paramtype = "light",
node_box = {
@ -305,7 +305,7 @@ create node boxes by dragging the edges, it is more visual than doing it by hand
Sometimes you want different nodeboxes for when it is placed on the floor, wall, or ceiling like with torches.
```lua
core.register_node("default:sign_wall", {
minetest.register_node("default:sign_wall", {
drawtype = "nodebox",
node_box = {
type = "wallmounted",
@ -341,7 +341,7 @@ invisible but still rendered.
You can register a mesh node as so:
```lua
core.register_node("mymod:meshy", {
minetest.register_node("mymod:meshy", {
drawtype = "mesh",
-- Holds the texture for each "material"
@ -370,7 +370,7 @@ instead use the `nodebox` drawtype to provide a 3D effect. The `signlike` drawty
is, however, commonly used by ladders.
```lua
core.register_node("default:ladder_wood", {
minetest.register_node("default:ladder_wood", {
drawtype = "signlike",
tiles = {"default_ladder_wood.png"},
@ -397,7 +397,7 @@ core.register_node("default:ladder_wood", {
Plantlike nodes draw their tiles in an X like pattern.
```lua
core.register_node("default:papyrus", {
minetest.register_node("default:papyrus", {
drawtype = "plantlike",
-- Only one texture used
@ -423,7 +423,7 @@ and ceilings.
</figure>
```lua
core.register_node("mymod:clingere", {
minetest.register_node("mymod:clingere", {
drawtype = "firelike",
-- Only one texture used

View File

@ -48,7 +48,7 @@ Item definitions consist of an *item name* and a *definition table*.
The definition table contains attributes that affect the behaviour of the item.
```lua
core.register_craftitem("modname:itemname", {
minetest.register_craftitem("modname:itemname", {
description = "My Special Item",
inventory_image = "modname_itemname.png"
})
@ -83,7 +83,7 @@ Registering an alias is pretty simple. A good way to remember the order of the
arguments is `from → to` where *from* is the alias and *to* is the target.
```lua
core.register_alias("dirt", "default:dirt")
minetest.register_alias("dirt", "default:dirt")
```
Mods need to make sure to resolve aliases before dealing directly with item names,
@ -91,7 +91,7 @@ as the engine won't do this.
This is pretty simple though:
```lua
itemname = core.registered_aliases[itemname] or itemname
itemname = minetest.registered_aliases[itemname] or itemname
```
### Textures
@ -113,7 +113,7 @@ Registering nodes is similar to registering items, just with a different
function:
```lua
core.register_node("mymod:diamond", {
minetest.register_node("mymod:diamond", {
description = "Alien Diamond",
tiles = {"mymod_diamond.png"},
is_ground_content = true,
@ -135,7 +135,7 @@ Remember that +Y is upwards in Minetest, as is the convention with
most 3D computer games.
```lua
core.register_node("mymod:diamond", {
minetest.register_node("mymod:diamond", {
description = "Alien Diamond",
tiles = {
"mymod_diamond_up.png", -- y+
@ -178,7 +178,7 @@ pattern to work. In the example below, the fragments need to be in a
chair-like pattern for the craft to work.
```lua
core.register_craft({
minetest.register_craft({
type = "shaped",
output = "mymod:diamond_chair 99",
recipe = {
@ -196,7 +196,7 @@ If this empty column shouldn't be required, then the empty strings can be left
out like so:
```lua
core.register_craft({
minetest.register_craft({
output = "mymod:diamond_chair 99",
recipe = {
{"mymod:diamond_fragments", "" },
@ -215,7 +215,7 @@ Shapeless recipes are a type of recipe which is used when it doesn't matter
where the ingredients are placed, just that they're there.
```lua
core.register_craft({
minetest.register_craft({
type = "shapeless",
output = "mymod:diamond 3",
recipe = {
@ -232,7 +232,7 @@ Recipes with the type "cooking" are not made in the crafting grid,
but are cooked in furnaces, or other cooking tools that might be found in mods.
```lua
core.register_craft({
minetest.register_craft({
type = "cooking",
output = "mymod:diamond_fragments",
recipe = "default:coalblock",
@ -254,7 +254,7 @@ This type is an accompaniment to the cooking type, as it defines
what can be burned in furnaces and other cooking tools from mods.
```lua
core.register_craft({
minetest.register_craft({
type = "fuel",
recipe = "mymod:diamond",
burntime = 300,
@ -281,7 +281,7 @@ Secondly, groups can be used in a craft recipe instead of an item name to allow
any item in the group to be used.
```lua
core.register_craft({
minetest.register_craft({
type = "shapeless",
output = "mymod:diamond_thing 3",
recipe = {"group:wood", "mymod:diamond"}
@ -322,7 +322,7 @@ If the item a player is currently wielding doesn't have an explicit tool
capability, then the capability of the current hand is used instead.
```lua
core.register_tool("mymod:tool", {
minetest.register_tool("mymod:tool", {
description = "My Tool",
inventory_image = "mymod_tool.png",
tool_capabilities = {

View File

@ -48,7 +48,7 @@ loaded from the world database outside of the generation limit.
You can read from the map once you have a position:
```lua
local node = core.get_node({ x = 1, y = 3, z = 4 })
local node = minetest.get_node({ x = 1, y = 3, z = 4 })
print(dump(node)) --> { name=.., param1=.., param2=.. }
```
@ -62,7 +62,7 @@ The function will always return a table containing the node information:
It's worth noting that the function won't load the containing block if the block
is inactive, but will instead return a table with `name` being `ignore`.
You can use `core.get_node_or_nil` instead, which will return `nil` rather
You can use `minetest.get_node_or_nil` instead, which will return `nil` rather
than a table with a name of `ignore`. It still won't load the block, however.
This may still return `ignore` if a block actually contains ignore.
This will happen near the edge of the map as defined by the map generation
@ -77,15 +77,15 @@ For example, say we wanted to make a certain type of plant that grows
better near mese; you would need to search for any nearby mese nodes,
and adapt the growth rate accordingly.
`core.find_node_near` will return the first found node in a certain radius
`minetest.find_node_near` will return the first found node in a certain radius
which matches the node names or groups given. In the following example,
we look for a mese node within 5 nodes of the position:
```lua
local grow_speed = 1
local node_pos = core.find_node_near(pos, 5, { "default:mese" })
local node_pos = minetest.find_node_near(pos, 5, { "default:mese" })
if node_pos then
core.chat_send_all("Node found at: " .. dump(node_pos))
minetest.chat_send_all("Node found at: " .. dump(node_pos))
grow_speed = 2
end
```
@ -97,7 +97,7 @@ nearby. You should then use a function that can find multiple nodes in the area:
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 =
core.find_nodes_in_area(pos1, pos2, { "default:mese" })
minetest.find_nodes_in_area(pos1, pos2, { "default:mese" })
local grow_speed = 1 + #pos_list
```
@ -109,7 +109,7 @@ order to fix this, we will need to manually check the range ourselves:
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 =
core.find_nodes_in_area(pos1, pos2, { "default:mese" })
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)
@ -138,9 +138,9 @@ lighting to be recalculated and node callbacks to run, which means that set_node
is fairly slow for large numbers of nodes.
```lua
core.set_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
minetest.set_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
local node = core.get_node({ x = 1, y = 3, z = 4 })
local node = minetest.get_node({ x = 1, y = 3, z = 4 })
print(node.name) --> default:mese
```
@ -153,7 +153,7 @@ two.
You can set a node without deleting metadata or the inventory like so:
```lua
core.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
minetest.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
```
### Removing Nodes
@ -163,15 +163,15 @@ A node must always be present. To remove a node, you set the position to `air`.
The following two lines will both remove a node, and are both identical:
```lua
core.remove_node(pos)
core.set_node(pos, { name = "air" })
minetest.remove_node(pos)
minetest.set_node(pos, { name = "air" })
```
In fact, remove_node is just a helper function that calls set_node with `"air"`.
## Loading Blocks
You can use `core.emerge_area` to load map blocks. Emerge area is asynchronous,
You can use `minetest.emerge_area` to load map blocks. Emerge area is asynchronous,
meaning the blocks won't be loaded instantly. Instead, they will be loaded
soon in the future, and the callback will be called each time.
@ -182,7 +182,7 @@ local pos1 = vector.subtract(pos, halfsize)
local pos2 = vector.add (pos, halfsize)
local context = {} -- persist data between callback calls
core.emerge_area(pos1, pos2, emerge_callback, context)
minetest.emerge_area(pos1, pos2, emerge_callback, context)
```
Minetest will call `emerge_callback` whenever it loads a block, with some
@ -202,12 +202,12 @@ local function emerge_callback(pos, action,
-- Send progress message
if context.total_blocks == context.loaded_blocks then
core.chat_send_all("Finished loading blocks!")
minetest.chat_send_all("Finished loading blocks!")
else
local perc = 100 * context.loaded_blocks / context.total_blocks
local msg = string.format("Loading blocks %d/%d (%.2f%%)",
context.loaded_blocks, context.total_blocks, perc)
core.chat_send_all(msg)
minetest.chat_send_all(msg)
end
end
```
@ -226,7 +226,7 @@ local halfsize = { x = 10, y = 10, z = 10 }
local pos1 = vector.subtract(pos, halfsize)
local pos2 = vector.add (pos, halfsize)
core.delete_area(pos1, pos2)
minetest.delete_area(pos1, pos2)
```
This will delete all map blocks in that area, *inclusive*. This means that some

View File

@ -48,7 +48,7 @@ which is referred to as a Lua entity, as discussed later.
`get_pos` and `set_pos` exist to allow you to get and set an entity's position.
```lua
local object = core.get_player_by_name("bob")
local object = minetest.get_player_by_name("bob")
local pos = object:get_pos()
object:set_pos({ x = pos.x, y = pos.y + 1, z = pos.z })
```
@ -152,7 +152,7 @@ Both an ObjectRef and an entity table provide ways to get the counterpart:
```lua
local entity = object:get_luaentity()
local object = entity.object
print("entity is at " .. core.pos_to_string(object:get_pos()))
print("entity is at " .. minetest.pos_to_string(object:get_pos()))
```
There are a number of available callbacks for use with entities.
@ -164,9 +164,9 @@ function MyEntity:on_step(dtime)
local pos_down = vector.subtract(pos, vector.new(0, 1, 0))
local delta
if core.get_node(pos_down).name == "air" then
if minetest.get_node(pos_down).name == "air" then
delta = vector.new(0, -1, 0)
elseif core.get_node(pos).name == "air" then
elseif minetest.get_node(pos).name == "air" then
delta = vector.new(0, 0, 1)
else
delta = vector.new(0, 1, 0)
@ -178,7 +178,7 @@ function MyEntity:on_step(dtime)
end
function MyEntity:on_punch(hitter)
core.chat_send_player(hitter:get_player_name(), self.message)
minetest.chat_send_player(hitter:get_player_name(), self.message)
end
```
@ -192,14 +192,14 @@ needs to stored.
```lua
function MyEntity:get_staticdata()
return core.write_json({
return minetest.write_json({
message = self.message,
})
end
function MyEntity:on_activate(staticdata, dtime_s)
if staticdata ~= "" and staticdata ~= nil then
local data = core.parse_json(staticdata) or {}
local data = minetest.parse_json(staticdata) or {}
self:set_message(data.message)
end
end
@ -217,14 +217,14 @@ This means that staticdata could be empty.
Finally, you need to register the type table using the aptly named `register_entity`.
```lua
core.register_entity("mymod:entity", MyEntity)
minetest.register_entity("mymod:entity", MyEntity)
```
The entity can be spawned by a mod like so:
```lua
local pos = { x = 1, y = 2, z = 3 }
local obj = core.add_entity(pos, "mymod:entity", nil)
local obj = minetest.add_entity(pos, "mymod:entity", nil)
```
The third parameter is the initial staticdata.

View File

@ -14,13 +14,13 @@ redirect_from:
In this chapter, you will learn how you can store data.
- [Metadata](#metadata)
- [What is Metadata?](#what-is-metadata)
- [Obtaining a Metadata Object](#obtaining-a-metadata-object)
- [Reading and Writing](#reading-and-writing)
- [Special Keys](#special-keys)
- [Storing Tables](#storing-tables)
- [Private Metadata](#private-metadata)
- [Lua Tables](#lua-tables)
- [What is Metadata?](#what-is-metadata)
- [Obtaining a Metadata Object](#obtaining-a-metadata-object)
- [Reading and Writing](#reading-and-writing)
- [Special Keys](#special-keys)
- [Storing Tables](#storing-tables)
- [Private Metadata](#private-metadata)
- [Lua Tables](#lua-tables)
- [Mod Storage](#mod-storage)
- [Databases](#databases)
- [Deciding Which to Use](#deciding-which-to-use)
@ -53,7 +53,7 @@ The data itself, such as a node's type or an stack's count, is not metadata.
If you know the position of a node, you can retrieve its metadata:
```lua
local meta = core.get_meta({ x = 1, y = 2, z = 3 })
local meta = minetest.get_meta({ x = 1, y = 2, z = 3 })
```
Player and ItemStack metadata are obtained using `get_meta()`:
@ -99,7 +99,7 @@ This is useful when showing the ownership or status of a node.
`description` is used in ItemStack Metadata to override the description when
hovering over the stack in an inventory.
You can use colours by encoding them with `core.colorize()`.
You can use colours by encoding them with `minetest.colorize()`.
`owner` is a common key used to store the username of the player that owns the
item or node.
@ -116,9 +116,9 @@ with another program.
```lua
local data = { username = "player1", score = 1234 }
meta:set_string("foo", core.serialize(data))
meta:set_string("foo", minetest.serialize(data))
data = core.deserialize(meta:get_string("foo"))
data = minetest.deserialize(minetest:get_string("foo"))
```
### Private Metadata
@ -149,7 +149,7 @@ Mod storage is per-mod, and can only be obtained during load time in order to
know which mod is requesting it.
```lua
local storage = core.get_mod_storage()
local storage = minetest.get_mod_storage()
```
You can now manipulate the storage just like metadata:
@ -169,10 +169,10 @@ it is used.
local backend
if use_database then
backend =
dofile(core.get_modpath("mymod") .. "/backend_sqlite.lua")
dofile(minetest.get_modpath("mymod") .. "/backend_sqlite.lua")
else
backend =
dofile(core.get_modpath("mymod") .. "/backend_storage.lua")
dofile(minetest.get_modpath("mymod") .. "/backend_storage.lua")
end
backend.get_foo("a")
@ -182,15 +182,15 @@ backend.set_foo("a", { score = 3 })
The backend_storage.lua file should include a mod storage implementation:
```lua
local storage = core.get_mod_storage()
local storage = minetest.get_mod_storage()
local backend = {}
function backend.set_foo(key, value)
storage:set_string(key, core.serialize(value))
storage:set_string(key, minetest.serialize(value))
end
function backend.get_foo(key)
return core.deserialize(storage:get_string(key))
return minetest.deserialize(storage:get_string(key))
end
return backend
@ -207,7 +207,7 @@ Insecure environments will be covered in more detail in the
[Security](../quality/security.html) chapter.
```lua
local ie = core.request_insecure_environment()
local ie = minetest.request_insecure_environment()
assert(ie, "Please add mymod to secure.trusted_mods in the settings")
local _sql = ie.require("lsqlite3")
@ -244,4 +244,4 @@ They're well suited for large data sets.
## Your Turn
* Make a node which disappears after it has been punched five times.
(Use `on_punch` in the node definition and `core.set_node`.)
(Use `on_punch` in the node definition and `minetest.set_node`.)

View File

@ -37,7 +37,7 @@ Node timers are directly tied to a single node.
You can manage node timers by obtaining a NodeTimerRef object.
```lua
local timer = core.get_node_timer(pos)
local timer = minetest.get_node_timer(pos)
timer:start(10.5) -- in seconds
```
@ -45,9 +45,9 @@ When a node timer is up, the `on_timer` method in the node's definition table wi
be called. The method only takes a single parameter, the position of the node:
```lua
core.register_node("autodoors:door_open", {
minetest.register_node("autodoors:door_open", {
on_timer = function(pos)
core.set_node(pos, { name = "autodoors:door" })
minetest.set_node(pos, { name = "autodoors:door" })
return false
end
})
@ -68,15 +68,15 @@ has a chance to appear near water.
```lua
core.register_node("aliens:grass", {
minetest.register_node("aliens:grass", {
description = "Alien Grass",
light_source = 3, -- The node radiates light. Min 0, max 14
tiles = {"aliens_grass.png"},
groups = {choppy=1},
on_use = core.item_eat(20)
on_use = minetest.item_eat(20)
})
core.register_abm({
minetest.register_abm({
nodenames = {"default:dirt_with_grass"},
neighbors = {"default:water_source", "default:water_flowing"},
interval = 10.0, -- Run every 10 seconds
@ -84,7 +84,7 @@ core.register_abm({
action = function(pos, node, active_object_count,
active_object_count_wider)
local pos = {x = pos.x, y = pos.y + 1, z = pos.z}
core.set_node(pos, {name = "aliens:grass"})
minetest.set_node(pos, {name = "aliens:grass"})
end
})
```
@ -93,7 +93,7 @@ This ABM runs every ten seconds, and for each matching node, there is
a 1 in 50 chance of it running.
If the ABM runs on a node, an alien grass node is placed above it.
Please be warned, this will delete any node previously located in that position.
To prevent this you should include a check using core.get_node to make sure there is space for the grass.
To prevent this you should include a check using minetest.get_node to make sure there is space for the grass.
Specifying a neighbour is optional.
If you specify multiple neighbours, only one of them needs to be

View File

@ -14,7 +14,7 @@ cmd_online:
bridge allows players to run commands without joining the game.
So make sure that you don't assume that the player is online.
You can check by seeing if `core.get_player_by_name` returns a player.
You can check by seeing if `minetest.get_player_by_name` returns a player.
cb_cmdsprivs:
level: warning
@ -47,7 +47,7 @@ sending messages, intercepting messages, and registering chat commands.
To send a message to every player in the game, call the `chat_send_all` function.
```lua
core.chat_send_all("This is a chat message to all players")
minetest.chat_send_all("This is a chat message to all players")
```
Here is an example of how this appears in-game:
@ -63,7 +63,7 @@ The message appears on a separate line to distinguish it from in-game player cha
To send a message to a specific player, call the `chat_send_player` function:
```lua
core.chat_send_player("player1", "This is a chat message for player1")
minetest.chat_send_player("player1", "This is a chat message for player1")
```
This message displays in the same manner as messages to all players, but is
@ -74,7 +74,7 @@ only visible to the named player, in this case, player1.
To register a chat command, for example `/foo`, use `register_chatcommand`:
```lua
core.register_chatcommand("foo", {
minetest.register_chatcommand("foo", {
privs = {
interact = true,
},
@ -166,7 +166,7 @@ or the [PIL documentation](https://www.lua.org/pil/20.2.html).
To intercept a message, use register_on_chat_message:
```lua
core.register_on_chat_message(function(name, message)
minetest.register_on_chat_message(function(name, message)
print(name .. " said " .. message)
return false
end)
@ -182,10 +182,10 @@ You should make sure you take into account that it may be a chat command,
or the user may not have `shout`.
```lua
core.register_on_chat_message(function(name, message)
minetest.register_on_chat_message(function(name, message)
if message:sub(1, 1) == "/" then
print(name .. " ran chat command")
elseif core.check_player_privs(name, { shout = true }) then
elseif minetest.check_player_privs(name, { shout = true }) then
print(name .. " said " .. message)
else
print(name .. " tried to say " .. message ..

View File

@ -146,7 +146,7 @@ function guessing.get_formspec(name)
local formspec = {
"formspec_version[4]",
"size[6,3.476]",
"label[0.375,0.5;", core.formspec_escape(text), "]",
"label[0.375,0.5;", minetest.formspec_escape(text), "]",
"field[0.375,1.25;5.25,0.8;number;Number;]",
"button[1.5,2.3;3,0.8;guess;Guess]"
}
@ -166,10 +166,10 @@ is using `show_formspec`:
```lua
function guessing.show_to(name)
core.show_formspec(name, "guessing:game", guessing.get_formspec(name))
minetest.show_formspec(name, "guessing:game", guessing.get_formspec(name))
end
core.register_chatcommand("game", {
minetest.register_chatcommand("game", {
func = function(name)
guessing.show_to(name)
end,
@ -206,19 +206,19 @@ The method for this is called formspec field submission, and for `show_formspec`
submission is received using a global callback:
```lua
core.register_on_player_receive_fields(function(player, formname, fields)
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()
core.chat_send_all(pname .. " guessed " .. fields.number)
minetest.chat_send_all(pname .. " guessed " .. fields.number)
end
end)
```
The function given in `core.register_on_player_receive_fields` is called
The function given in `minetest.register_on_player_receive_fields` is called
every time a user submits a form. Most callbacks will need to check the formname given
to the function, and exit if it is not the right form; however, some callbacks
may need to work on multiple forms, or on all forms.
@ -239,7 +239,7 @@ the formspec based on guesses. The way to do this is using a concept called
### Contexts
In many cases you want core.show_formspec to give information
In many cases you want minetest.show_formspec to give information
to the callback which you don't want to send to the client. This might include
what a chat command was called with, or what the dialog is about. In this case,
the target value that needs to be remembered.
@ -255,7 +255,7 @@ local function get_context(name)
return context
end
core.register_on_leaveplayer(function(player)
minetest.register_on_leaveplayer(function(player)
_contexts[player:get_player_name()] = nil
end)
```
@ -269,7 +269,7 @@ function guessing.show_to(name)
context.target = context.target or math.random(1, 10)
local fs = guessing.get_formspec(name, context)
core.show_formspec(name, "guessing:game", fs)
minetest.show_formspec(name, "guessing:game", fs)
end
```
@ -318,13 +318,13 @@ There are three different ways that a formspec can be delivered to the client:
### Node Meta Formspecs
`core.show_formspec` is not the only way to show a formspec; you can also
`minetest.show_formspec` is not the only way to show a formspec; you can also
add formspecs to a [node's metadata](../map/storage.html). For example,
this is used with chests to allow for faster opening times -
you don't need to wait for the server to send the player the chest formspec.
```lua
core.register_node("mymod:rightclick", {
minetest.register_node("mymod:rightclick", {
description = "Rightclick me!",
tiles = {"mymod_rightclick.png"},
groups = {cracky = 1},
@ -333,7 +333,7 @@ core.register_node("mymod:rightclick", {
-- The following code sets the formspec for chest.
-- Meta is a way of storing data onto a node.
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
"formspec_version[4]" ..
"size[5,5]" ..
@ -355,7 +355,7 @@ receive form input for meta formspecs, you must include an
`on_receive_fields` entry when registering the node.
This style of callback triggers when you press enter
in a field, which is impossible with `core.show_formspec`;
in a field, which is impossible with `minetest.show_formspec`;
however, this kind of form can only be shown by right-clicking on a
node. It cannot be triggered programmatically.

View File

@ -89,7 +89,7 @@ to the right of the window, but to resize without breaking.
You can create a HUD element once you have a copy of the player object:
```lua
local player = core.get_player_by_name("username")
local player = minetest.get_player_by_name("username")
local idx = player:hud_add({
hud_elem_type = "text",
position = {x = 0.5, y = 0.5},
@ -281,9 +281,9 @@ function score.update_hud(player)
end
end
core.register_on_joinplayer(score.update_hud)
minetest.register_on_joinplayer(score.update_hud)
core.register_on_leaveplayer(function(player)
minetest.register_on_leaveplayer(function(player)
saved_huds[player:get_player_name()] = nil
end)
```

View File

@ -28,9 +28,9 @@ Here is an example of how to add an antigravity command, which
puts the caller in low G:
```lua
core.register_chatcommand("antigravity", {
minetest.register_chatcommand("antigravity", {
func = function(name, param)
local player = core.get_player_by_name(name)
local player = minetest.get_player_by_name(name)
player:set_physics_override({
gravity = 0.1, -- set gravity to 10% of its original value
-- (0.1 * 9.81)

View File

@ -48,7 +48,7 @@ Privileges are **not** for indicating class or status.
Use `register_privilege` to declare a new privilege:
```lua
core.register_privilege("vote", {
minetest.register_privilege("vote", {
description = "Can vote on issues",
give_to_singleplayer = true
})
@ -62,7 +62,7 @@ actually needed in the above definition.
To quickly check whether a player has all the required privileges:
```lua
local has, missing = core.check_player_privs(player_or_name, {
local has, missing = minetest.check_player_privs(player_or_name, {
interact = true,
vote = true })
```
@ -72,7 +72,7 @@ If `has` is false, then `missing` will contain a key-value table
of the missing privileges.
```lua
local has, missing = core.check_player_privs(name, {
local has, missing = minetest.check_player_privs(name, {
interact = true,
vote = true })
@ -87,7 +87,7 @@ If you don't need to check the missing privileges, you can put
`check_player_privs` directly into the if statement.
```lua
if not core.check_player_privs(name, { interact=true }) then
if not minetest.check_player_privs(name, { interact=true }) then
return false, "You need interact for this!"
end
```
@ -99,11 +99,11 @@ being online.
```lua
local privs = core.get_player_privs(name)
local privs = minetest.get_player_privs(name)
print(dump(privs))
privs.vote = true
core.set_player_privs(name, privs)
minetest.set_player_privs(name, privs)
```
Privileges are always specified as a key-value table with the key being

View File

@ -100,7 +100,7 @@ what is listening to something.
In the next chapter, we will discuss how to automatically test your
code and one of the problems we will have is how to separate your logic
(calculations, what should be done) from API calls (`core.*`, other mods)
(calculations, what should be done) from API calls (`minetest.*`, other mods)
as much as possible.
One way to do this is to think about:
@ -173,14 +173,14 @@ function land.show_create_formspec(name)
]]
end
core.register_chatcommand("/land", {
minetest.register_chatcommand("/land", {
privs = { land = true },
func = function(name)
land.handle_creation_request(name)
end,
})
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
land.handle_create_submit(player:get_player_name(),
fields.area_name)
@ -227,7 +227,7 @@ this isn't the real world. A good compromise is to reduce the mod into two
parts:
* **API** - This was the model and controller above. There should be no uses of
`core.` here.
`minetest.` here.
* **View** - This was also the view above. It's a good idea to structure this into separate
files for each type of event.

View File

@ -43,11 +43,11 @@ give themselves moderator privileges:
```lua
local function show_formspec(name)
if not core.check_player_privs(name, { privs = true }) then
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
core.show_formspec(name, "modman:modman", [[
minetest.show_formspec(name, "modman:modman", [[
size[3,2]
field[0,0;3,1;target;Name;]
button_exit[0,1;3,1;sub;Promote]
@ -55,14 +55,14 @@ local function show_formspec(name)
return true
})
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
-- BAD! Missing privilege check here!
local privs = core.get_player_privs(fields.target)
local privs = minetest.get_player_privs(fields.target)
privs.kick = true
privs.ban = true
core.set_player_privs(fields.target, privs)
minetest.set_player_privs(fields.target, privs)
return true
end)
```
@ -70,9 +70,9 @@ end)
Add a privilege check to solve this:
```lua
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
if not core.check_player_privs(name, { privs = true }) then
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
@ -111,7 +111,7 @@ are given will change it for the caller too, and any subsequent callbacks. Howev
it will only be saved in the engine if the callback caller sets it.
```lua
core.register_on_item_eat(function(hp_change, replace_with_item,
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Partially eaten")
-- Almost correct! Data will be lost if another
@ -125,7 +125,7 @@ but if a callback does cancel this, then the update may be lost.
It's better to do this instead:
```lua
core.register_on_item_eat(function(hp_change, replace_with_item,
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Partially eaten")
user:get_inventory():set_stack("main", user:get_wield_index(),

View File

@ -19,6 +19,7 @@ After you've read this book, take a look at the following.
### Lua Programming
* [Programming in Lua (PIL)](http://www.lua.org/pil/).
* [Lua Crash Course](http://luatut.com/crash_course.html).
### 3D Modelling

View File

@ -40,7 +40,7 @@ Any users can submit almost any formspec with any values at any time.
Here's some real code found in a mod:
```lua
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
for key, field in pairs(fields) do
local x,y,z = string.match(key,
@ -87,7 +87,7 @@ to the full Lua API.
Can you spot the vulnerability in the following?
```lua
local ie = core.request_insecure_environment()
local ie = minetest.request_insecure_environment()
ie.os.execute(("path/to/prog %d"):format(3))
```

View File

@ -57,12 +57,12 @@ control characters in text, telling Minetest where and how to translate
text. This is referred to as marked up text, and will be discussed more later.
To mark text as translatable, use a translator function (`S()`), obtained using
`core.get_translator(textdomain)`:
`minetest.get_translator(textdomain)`:
```lua
local S = core.get_translator("mymod")
local S = minetest.get_translator("mymod")
core.register_craftitem("mymod:item", {
minetest.register_craftitem("mymod:item", {
description = S("My Item"),
})
```
@ -75,7 +75,7 @@ avoid mod conflicts.
Marked up text can be used in most places where human-readable text is accepted,
including formspecs, item def fields, infotext, and more. When including marked
text in formspecs, you need to escape the text using `core.formspec_escape`.
text in formspecs, you need to escape the text using `minetest.formspec_escape`.
When the client encounters translatable text, such as that passed to
`description`, it looks it up in the player's language's translation file. If a
@ -85,7 +85,7 @@ Translatable marked up text contains the English source text, the textdomain,
and any additional arguments passed to `S()`. It's essentially a text encoding
of the `S` call, containing all the required information.
Another type of marked up text is that returned by `core.colorize`.
Another type of marked up text is that returned by `minetest.colorize`.
{% include notice.html notice=page.marked_text_encoding %}
@ -127,8 +127,8 @@ translators from changing the order of variables within a sentence. Instead,
you should use the translation system's format/arguments system:
```lua
core.register_on_joinplayer(function(player)
core.chat_send_all(S("Everyone, say hi to @1!", player:get_player_name()))
minetest.register_on_joinplayer(function(player)
minetest.chat_send_all(S("Everyone, say hi to @1!", player:get_player_name()))
end)
```
@ -172,13 +172,13 @@ local list = {
S("Potato")
}
core.register_chatcommand("find", {
minetest.register_chatcommand("find", {
func = function(name, param)
local info = core.get_player_information(name)
local info = minetest.get_player_information(name)
local language = info and info.language or "en"
for _, line in ipairs(list) do
local trans = core.get_translated_string(language, line)
local trans = minetest.get_translated_string(language, line)
if trans:contains(query) then
return line
end

View File

@ -54,7 +54,7 @@ names ending in `_spec`, and then executes them in a standalone Lua environment.
```lua
mymod = {}
dofile(core.get_modpath("mymod") .. "/api.lua")
dofile(minetest.get_modpath("mymod") .. "/api.lua")
```
@ -122,7 +122,7 @@ _G.minetest = {}
-- Define the mock function
local chat_send_all_calls = {}
function core.chat_send_all(name, message)
function minetest.chat_send_all(name, message)
table.insert(chat_send_all_calls, { name = name, message = message })
end

View File

@ -107,7 +107,7 @@ Oltre che farli a mano, per creare dei diagrammi di Voronoi si possono usare pro
Il seguente codice registra un semplice bioma chiamato "distesa_erbosa":
```lua
core.register_biome({
minetest.register_biome({
name = "distesa_erbosa",
node_top = "default:dirt_with_grass",
depth_top = 1,
@ -144,7 +144,7 @@ Ricordati che devi specificare il nodo che vuoi usare in quanto decorazione, i d
Per esempio:
```lua
core.register_decoration({
minetest.register_decoration({
deco_type = "simple",
place_on = {"base:dirt_with_grass"},
sidelen = 16,
@ -167,7 +167,7 @@ Le schematic sono molto simili alle decorazioni semplici, solo che piazzano più
Per esempio:
```lua
core.register_decoration({
minetest.register_decoration({
deco_type = "schematic",
place_on = {"base:desert_sand"},
sidelen = 16,
@ -175,7 +175,7 @@ core.register_decoration({
biomes = {"desert"},
y_max = 200,
y_min = 1,
schematic = core.get_modpath("plants") .. "/schematics/cactus.mts",
schematic = minetest.get_modpath("plants") .. "/schematics/cactus.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
@ -195,7 +195,7 @@ I giochi disponibili dovrebbero già includere un alias del generatore mappa (*m
Gli alias del generatore mappa forniscono informazioni al generatore principale, e possono essere registrati secondo lo schema:
```lua
core.register_alias("mapgen_stone", "base:smoke_stone")
minetest.register_alias("mapgen_stone", "base:smoke_stone")
```
Almeno almeno dovresti registrare:

View File

@ -10,8 +10,8 @@ redirect_from:
mapgen_object:
level: warning
title: LVM e generatore mappa
message: Non usare `core.get_voxel_manip()` con il generatore mappa, in quanto può causare glitch.
Usa invece `core.get_mapgen_object("voxelmanip")`.
message: Non usare `minetest.get_voxel_manip()` con il generatore mappa, in quanto può causare glitch.
Usa invece `minetest.get_mapgen_object("voxelmanip")`.
---
## Introduzione <!-- omit in toc -->
@ -39,7 +39,7 @@ Si possono caricare solamente aree cubiche negli LVM, quindi devi capire da te q
Fatto ciò, puoi creare l'LVM:
```lua
local vm = core.get_voxel_manip()
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos1, pos2)
```
@ -82,7 +82,7 @@ Per scoprire qual è l'ID assegnato a un tipo di nodo, si usa `get_content_id()`
Per esempio:
```lua
local c_pietra = core.get_content_id("default:stone")
local c_pietra = minetest.get_content_id("default:stone")
```
Si può ora controllare se un nodo è effettivamente di pietra:
@ -143,16 +143,16 @@ vm:write_to_map(true)
Per la luce e param2, invece si usano `set_light_data()` e `set_param2_data()`.
`write_to_map()` richiede un booleano che è `true` se si vuole che venga calcolata anche la luce.
Se si passa `false` invece, ci sarà bisogno di ricalcolarla in un secondo tempo usando `core.fix_light`.
Se si passa `false` invece, ci sarà bisogno di ricalcolarla in un secondo tempo usando `minetest.fix_light`.
## Esempio
```lua
local function da_erba_a_terra(pos1, pos2)
local c_terra = core.get_content_id("default:dirt")
local c_erba = core.get_content_id("default:dirt_with_grass")
local c_terra = minetest.get_content_id("default:dirt")
local c_erba = minetest.get_content_id("default:dirt_with_grass")
-- legge i dati nella LVM
local vm = core.get_voxel_manip()
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos1, pos2)
local a = VoxelArea:new{
MinEdge = emin,

View File

@ -81,7 +81,7 @@ La posizione di ogni percorso dipende da quale sistema operativo si sta usando,
Il *nome mod* è usato per riferirsi a una mod e ognuna di esse dovrebbe averne uno unico.
Questi possono includere lettere, numeri e trattini bassi, e un buon nome dovrebbe descrivere brevemente cosa fa la mod (è anche consigliato rinominare la cartella della mod con il nome di quest'ultima).
Per scoprire se un nome è disponibile, prova a cercarlo su
Per scoprire se un nome è disponibile, prova a cercarlo su
[content.minetest.net](https://content.minetest.net).
@ -150,7 +150,7 @@ Segue un esempio che mette insieme tutto ciò discusso finora:
```lua
print("Questo file parte all'avvio!")
core.register_node("lamiamod:nodo", {
minetest.register_node("lamiamod:nodo", {
description = "Questo è un nodo",
tiles = {"lamiamod_nodo.png"},
groups = {cracky = 1}

View File

@ -159,7 +159,7 @@ mymod.foo("foobar")
Il metodo consigliato per includere in una mod altri script Lua è usare *dofile*.
```lua
dofile(core.get_modpath("modname") .. "/script.lua")
dofile(minetest.get_modpath("modname") .. "/script.lua")
```
Uno script può ritornare un valore, che è utile per condividere variabili locali private:
@ -169,7 +169,7 @@ Uno script può ritornare un valore, che è utile per condividere variabili loca
return "Hello world!"
-- init.lua
local ret = dofile(core.get_modpath("modname") .. "/script.lua")
local ret = dofile(minetest.get_modpath("modname") .. "/script.lua")
print(ret) -- Hello world!
```

View File

@ -10,7 +10,7 @@ description: Scopri i richiami, le azioni e gli eventi, come on_use, on_punch, o
Minetest usa una struttura di moddaggio estensivamente incentrata sui richiami. Un richiamo è una funzione che si dà a un'API e che viene chiamata quando l'evento registrato si verifica.
Per esempio, puoi aggiungere una funzione `on_punch` nella definizione di un nodo, che verrà chiamata quando questo viene colpito.
Ci sono poi anche dei richiami globali, come `core.register_on_punchnode`, che in questo caso verrà invocato al colpire qualsiasi nodo.
Ci sono poi anche dei richiami globali, come `minetest.register_on_punchnode`, che in questo caso verrà invocato al colpire qualsiasi nodo.
- [Richiami degli oggetti](#richiami-degli-oggetti)
- [on_use](#on_use)
@ -31,9 +31,9 @@ Quando un giocatore ha un nodo, un oggetto fabbricabile o uno strumento nel prop
| Richiamo | Assegnazione base | Valore base |
|------------------|---------------------------|----------------------------------------------|
| on_use | clic sinistro | nil |
| on_place | clic destro su un nodo | `core.item_place` |
| on_secondary_use | clic destro a vuoto | `core.item_secondary_use` (non fa nulla) |
| on_drop | Q | `core.item_drop` |
| on_place | clic destro su un nodo | `minetest.item_place` |
| on_secondary_use | clic destro a vuoto | `minetest.item_secondary_use` (non fa nulla) |
| on_drop | Q | `minetest.item_drop` |
| after_use | allo scavare un nodo | nil |
@ -43,26 +43,26 @@ Sovrascrivere l'uso dell'oggetto impedisce che quest'ultimo possa essere usato p
Un impiego comune di questo richiamo lo si trova nel cibo:
```lua
core.register_craftitem("miamod:fangotorta", {
minetest.register_craftitem("miamod:fangotorta", {
description = "Torta aliena di fango",
inventory_image = "miamod_fangotorta.png",
on_use = core.item_eat(20),
on_use = minetest.item_eat(20),
})
```
Il numero fornito alla funzione core.item_eat è il numero di punti salute ripristinati al consumare il cibo.
Il numero fornito alla funzione minetest.item_eat è il numero di punti salute ripristinati al consumare il cibo.
In gioco ogni cuore equivale a due punti.
Un giocatore ha solitamente un massimo di 10 cuori, ovvero 20 punti salute, e quest'ultimi non devono per forza essere interi - bensì anche decimali.
`core.item_eat()` è una funzione che ritorna un'altra funzione, in questo caso quindi impostandola come richiamo di on_use.
`minetest.item_eat()` è una funzione che ritorna un'altra funzione, in questo caso quindi impostandola come richiamo di on_use.
Ciò significa che il codice in alto è alquanto simile al seguente:
```lua
core.register_craftitem("miamod:fangotorta", {
minetest.register_craftitem("miamod:fangotorta", {
description = "Torta aliena di fango",
inventory_image = "miamod_fangotorta.png",
on_use = function(...)
return core.do_item_eat(20, nil, ...)
return minetest.do_item_eat(20, nil, ...)
end,
})
```
@ -76,13 +76,13 @@ come per esempio riprodurre un suono personalizzato.
La differenza tra `on_place` e `on_secondary_use` consiste nel fatto che `on_place` viene chiamato quando il giocatore sta puntando un nodo, mentre `on_secondary_use` quando non ne punta uno.
Entrambi i richiami sono invocati per tutti i tipi di oggetti.
`on_place` risponde alla funzione `core.item_place`, la quale o gestisce la chiamata a `on_rightclick` del nodo puntato, o piazza l'oggetto in mano se questo è un nodo.
`on_place` risponde alla funzione `minetest.item_place`, la quale o gestisce la chiamata a `on_rightclick` del nodo puntato, o piazza l'oggetto in mano se questo è un nodo.
### on_drop
`on_drop` viene chiamato quando il giocatore fa richiesta per buttare un oggetto, per esempio usando il tasto apposito (Q) o trascinando l'oggetto fuori dall'inventario.
Risponde alla funzione `core.item_drop`, la quale gestisce il buttare l'oggetto.
Risponde alla funzione `minetest.item_drop`, la quale gestisce il buttare l'oggetto.
### after_use
@ -100,18 +100,18 @@ end
## item_place contro place_item
L'API di Minetest include varie implementazioni già pronte di richiami.
Queste seguono la nomenclatura "tipodioggetto_azione", per esempio `core.item_place` e `core.node_dig`.
Queste seguono la nomenclatura "tipodioggetto_azione", per esempio `minetest.item_place` e `minetest.node_dig`.
Alcune sono usate direttamente, mentre altre sono funzioni che ritornano il richiamo vero e proprio:
```lua
core.register_item("miamod:esempio", {
on_place = core.item_place,
on_use = core.item_eat(10),
minetest.register_item("miamod:esempio", {
on_place = minetest.item_place,
on_use = minetest.item_eat(10),
})
```
Inoltre, l'API di Minetest include funzioni già pronte che _fanno_ qualcosa.
Queste sono spesso chiamate con nomi che rischiano di farle confondere con le implementazioni dei richiami, tuttavia hanno un verbo all'inizio (per esempio `core.place_item` e `core.dig_node`, che permettono rispettivamente di scavare e piazzare nodi come se lo stesse facendo un giocatore).
Queste sono spesso chiamate con nomi che rischiano di farle confondere con le implementazioni dei richiami, tuttavia hanno un verbo all'inizio (per esempio `minetest.place_item` e `minetest.dig_node`, che permettono rispettivamente di scavare e piazzare nodi come se lo stesse facendo un giocatore).
## Richiami dei nodi
@ -128,9 +128,9 @@ Molti richiami dei nodi sono collegati alle operazioni effettuate - appunto - su
### Tasto destro e nodi piazzati
Quando un utente preme col tasto destro un nodo mentre ha un oggetto in mano, viene invocato il richiamo `on_place` dell'oggetto.
Di base, questo è impostato a `core.item_place`.
Di base, questo è impostato a `minetest.item_place`.
Se il nodo puntato ha un richiamo `on_rightclick` e il tasto accovacciati (shift) è tenuto premuto, allora verrà chiamato `on_rightclick`.
Diversamente, `core.item_place` piazzerà il nodo.
Diversamente, `minetest.item_place` piazzerà il nodo.
Piazzare un nodo invocherà simultaneamente `on_construct` e `after_place_node`: il primo è chiamato da ogni evento che cambia i singoli nodi (quindi non in blocco) e ritorna la posizione e il valore del nodo.
`after_place_node` viene invece chiamato solamente al piazzare un nodo, contenendo di conseguenza più informazioni - come chi l'ha piazzato e l'ItemStack.
@ -139,20 +139,20 @@ Piazzare un nodo invocherà simultaneamente `on_construct` e `after_place_node`:
Per via di ciò, `place` potrebbe essere un giocatore, ma anche un'entità o `nil`.
```lua
core.register_node("miamod:mionodo", {
minetest.register_node("miamod:mionodo", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if clicker:is_player() then
core.chat_send_player(clicker:get_player_name(), "Ciao mondo!")
minetest.chat_send_player(clicker:get_player_name(), "Ciao mondo!")
end
end,
on_construct = function(pos, node)
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Il mio nodo!")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
-- controlla chi sta piazzando
if placer and placer:is_player() then
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
meta:set_string("proprietario", placer:get_player_name())
end
end,
@ -166,14 +166,14 @@ Se l'oggetto in mano possiede un richiamo `on_use`, questo verrà chiamato.
Diversamente, verrà chiamato il richiamo `on_punch` sul nodo selezionato.
Quando il giocatore tenta di scavare un nodo, viene eseguito il richiamo `on_dig` del nodo.
Di base, ciò equivale a `core.node_dig`, che controlla eventuali protezioni dell'area, usura l'oggetto, rimuove il nodo, e ne esegue il richiamo `after_dig_node`.
Di base, ciò equivale a `minetest.node_dig`, che controlla eventuali protezioni dell'area, usura l'oggetto, rimuove il nodo, e ne esegue il richiamo `after_dig_node`.
```lua
core.register_node("miamod:mionodo", {
minetest.register_node("miamod:mionodo", {
on_punch = function(pos, node, puncher, pointed_thing)
if puncher:is_player() then
core.chat_send_player(puncher:get_player_name(), "Ahia!")
minetest.chat_send_player(puncher:get_player_name(), "Ahia!")
end
end,
})

View File

@ -90,7 +90,7 @@ Gli inventari collocati nei nodi sono associati alle coordinate di un nodo speci
Il nodo deve essere stato caricato perché viene salvato [nei suoi metadati](../map/storage.html#metadata).
```lua
local inv = core.get_inventory({ type="node", pos={x=1, y=2, z=3} })
local inv = minetest.get_inventory({ type="node", pos={x=1, y=2, z=3} })
```
L'esempio in alto ottiene il *riferimento a un inventario*, comunemente definito *InvRef*.
@ -107,7 +107,7 @@ Gli inventari dei giocatori si ottengono in maniera simile, oppure usando il rif
In entrambi casi, il giocatore deve essere connesso.
```lua
local inv = core.get_inventory({ type="player", name="player1" })
local inv = minetest.get_inventory({ type="player", name="player1" })
-- oppure
local inv = player:get_inventory()
```
@ -115,14 +115,14 @@ local inv = player:get_inventory()
Gli inventari separati, infine, sono quelli non collegati né a nodi né a giocatori, e al contrario degli altri, vengono persi dopo un riavvio.
```lua
local inv = core.get_inventory({
local inv = minetest.get_inventory({
type="detached", name="nome_inventario" })
```
Un'ulteriore differenza, è che gli inventari separati devono essere creati prima di poterci accedere:
```lua
core.create_detached_inventory("inventory_name")
minetest.create_detached_inventory("inventory_name")
```
La funzione `create_detached_inventory` accetta 3 parametri, di cui solo il primo - il nome - è necessario.
@ -130,7 +130,7 @@ Il secondo parametro prende una tabella di callback, che possono essere utilizza
```lua
-- Input only detached inventory
core.create_detached_inventory("inventory_name", {
minetest.create_detached_inventory("inventory_name", {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
return count -- permette di spostare gli oggetti
end,
@ -144,9 +144,9 @@ core.create_detached_inventory("inventory_name", {
end,
on_put = function(inv, listname, index, stack, player)
core.chat_send_all(player:get_player_name() ..
minetest.chat_send_all(player:get_player_name() ..
" ha messo " .. stack:to_string() ..
" nella cassa delle donazioni da " .. core.pos_to_string(player:get_pos()))
" nella cassa delle donazioni da " .. minetest.pos_to_string(player:get_pos()))
end,
})
```

View File

@ -15,7 +15,7 @@ Queste proprietà sono fisse, uguali per tutte le istanze, tuttavia è possibile
Il concetto di nodo è stato introdotto nello scorso capitolo, ma non è mai stata data una definizione completa.
Il mondo di Minetest è una griglia 3D: un nodo è un punto di quella griglia ed è composto da un tipo (`name`) e due parametri (`param1` e `param2`).
Non farti inoltre ingannare dalla funzione `core.register_node`, in quanto è un po' fuorviante: essa non registra infatti un nuovo nodo (c'è solo una definizione di nodo), bensì un nuovo *tipo* di nodo.
Non farti inoltre ingannare dalla funzione `minetest.register_node`, in quanto è un po' fuorviante: essa non registra infatti un nuovo nodo (c'è solo una definizione di nodo), bensì un nuovo *tipo* di nodo.
I parametri sono infine usati per controllare come un nodo viene renderizzato individualmente: `param1` immagazzina le proprietà di luce, mentre il ruolo di `param2` dipende dalla proprietà `paramtype2`, la quale è situata nella definizione dei singoli tipi.
@ -51,13 +51,13 @@ Ciò è buono per quei nodi con facce in parte trasparenti come le foglie.
Puoi inoltre usare il drawtype `allfaces_optional` per permettere agli utenti di fare opt-out dal rendering più pesante, facendo comportare il nodo come se fosse di tipo normale.
```lua
core.register_node("miamod:diamante", {
minetest.register_node("miamod:diamante", {
description = "Diamante alieno",
tiles = {"miamod_diamante.png"},
groups = {cracky = 3},
})
core.register_node("default:foglie", {
minetest.register_node("default:foglie", {
description = "Foglie",
drawtype = "allfaces_optional",
tiles = {"default_foglie.png"}
@ -79,7 +79,7 @@ Questo è utile in quanto i nodi vitrei tendono a essere trasparenti, perciò pe
</figure>
```lua
core.register_node("default:obsidian_glass", {
minetest.register_node("default:obsidian_glass", {
description = "Vetro d'ossidiana",
drawtype = "glasslike",
tiles = {"default_obsidian_glass.png"},
@ -103,11 +103,11 @@ Questa opzione crea un solo bordo lungo tutto l'insieme di nodi, al posto di cre
</figure>
```lua
core.register_node("default:glass", {
minetest.register_node("default:glass", {
description = "Vetro",
drawtype = "glasslike_framed",
tiles = {"default_glass.png", "default_glass_detail.png"},
inventory_image = core.inventorycube("default_glass.png"),
inventory_image = minetest.inventorycube("default_glass.png"),
paramtype = "light",
sunlight_propagates = true, -- Sunlight can shine through block
groups = {cracky = 3, oddly_breakable_by_hand = 3},
@ -122,7 +122,7 @@ Puoi inoltre usare il *drawtype* `glasslike_framed_optional` per permettere un o
I nodi d'aria (*airlike*) non sono renderizzati e perciò non hanno texture.
```lua
core.register_node("miaaria:aria", {
minetest.register_node("miaaria:aria", {
description = "Mia Aria",
drawtype = "airlike",
paramtype = "light",
@ -172,11 +172,11 @@ Ogni tipo di liquido richiede due definizioni di nodi: una per la sorgente e l'a
```lua
-- Alcune proprietà sono state rimosse perché non
-- rilevanti per questo capitolo
core.register_node("default:water_source", {
minetest.register_node("default:water_source", {
drawtype = "liquid",
paramtype = "light",
inventory_image = core.inventorycube("default_water.png"),
inventory_image = minetest.inventorycube("default_water.png"),
-- ^ questo è necessario per impedire che l'immagine nell'inventario sia animata
tiles = {
@ -250,7 +250,7 @@ Guarda default:water_flowing nella mod default di minetest_game per un esempio c
I nodi complessi (*nodebox*) ti permettono di creare un nodo che non è cubico, bensì un insieme di più cuboidi.
```lua
core.register_node("stairs:stair_stone", {
minetest.register_node("stairs:stair_stone", {
drawtype = "nodebox",
paramtype = "light",
node_box = {
@ -281,7 +281,7 @@ Puoi usare [NodeBoxEditor](https://forum.minetest.net/viewtopic.php?f=14&t=2840)
Certe volte si vogliono avere nodi complessi che cambiano a seconda della loro posizione sul pavimento, sul muro e sul soffitto, come le torce.
```lua
core.register_node("default:sign_wall", {
minetest.register_node("default:sign_wall", {
drawtype = "nodebox",
node_box = {
type = "wallmounted",
@ -315,7 +315,7 @@ Una faccia interna appare quando le facce di due nodi complessi si sovrappongono
Puoi registrare un nodo mesh come segue:
```lua
core.register_node("miamod:meshy", {
minetest.register_node("miamod:meshy", {
drawtype = "mesh",
-- Contiene le texture di ogni materiale
@ -340,7 +340,7 @@ Al contrario del loro nome, i cartelli non rientrano nei nodi insegna bensì in
I tipi insegna tuttavia, sono comunemente usati dalle scale a pioli.
```lua
core.register_node("default:ladder_wood", {
minetest.register_node("default:ladder_wood", {
drawtype = "signlike",
tiles = {"default_ladder_wood.png"},
@ -366,7 +366,7 @@ core.register_node("default:ladder_wood", {
I nodi pianta (*plantlike*) raffigurano la loro texture in un pattern a forma di X.
```lua
core.register_node("default:papyrus", {
minetest.register_node("default:papyrus", {
drawtype = "plantlike",
-- Viene usata solo una texture
@ -391,7 +391,7 @@ I nodi fiamma (*firelike*) sono simili ai pianta, ad eccezione del fatto che son
</figure>
```lua
core.register_node("miamod:avvinghiatutto", {
minetest.register_node("miamod:avvinghiatutto", {
drawtype = "firelike",
-- Viene usata solo una texture

View File

@ -43,7 +43,7 @@ Le definizioni degli oggetti consistono in un *nome oggetto* e una *tabella di d
La tabella di definizioni contiene attributi che influenzano il comportamento dell'oggetto.
```lua
core.register_craftitem("nomemod:nomeoggetto", {
minetest.register_craftitem("nomemod:nomeoggetto", {
description = "Il Mio Super Oggetto",
inventory_image = "nomemod_nomeoggetto.png"
})
@ -72,7 +72,7 @@ Ciò è comunemente usato in due casi:
Registrare un alias è alquanto semplice.
```lua
core.register_alias("dirt", "default:dirt")
minetest.register_alias("dirt", "default:dirt")
```
Un buon modo per ricordarne il funzionamento è `da → a`, dove *da*
@ -82,7 +82,7 @@ Le mod devono inoltre assicurarsi di elaborare gli alias prima di occuparsi dire
Anche in questo caso non è difficile:
```lua
itemname = core.registered_aliases[itemname] or itemname
itemname = minetest.registered_aliases[itemname] or itemname
```
### Texture
@ -98,7 +98,7 @@ Questo perché dimensioni differenti potrebbero non essere supportate dai vecchi
## Registrare un nodo base
```lua
core.register_node("miamod:diamante", {
minetest.register_node("miamod:diamante", {
description = "Diamante alieno",
tiles = {"miamod_diamante.png"},
is_ground_content = true,
@ -116,7 +116,7 @@ Per assegnarne invece di diverse, bisogna fornire il nome di 6 texture in quest'
Ricorda che su Minetest, come nella convenzione della computer grafica 3D, +Y punta verso l'alto.
```lua
core.register_node("miamod:diamante", {
minetest.register_node("miamod:diamante", {
description = "Diamante alieno",
tiles = {
"miamod_diamante_up.png", -- y+
@ -154,7 +154,7 @@ Le ricette fisse avvengono quando gli ingredienti devono essere nella forma o se
Nell'esempio sotto, i frammenti necessitano di essere in una figura a forma di sedia per poter fabbricare appunto 99 sedie.
```lua
core.register_craft({
minetest.register_craft({
type = "shaped",
output = "miamod:diamante_sedia 99",
recipe = {
@ -170,7 +170,7 @@ Questo significa che ci *deve* essere una colonna vuota a destra della forma, al
Se invece la colonna non dovesse servire, basta ometterla in questo modo:
```lua
core.register_craft({
minetest.register_craft({
output = "miamod:diamante_sedia 99",
recipe = {
{"miamod:diamante_frammenti", "" },
@ -187,7 +187,7 @@ Il campo type non è davvero necessario per le ricette fisse, in quanto sono il
Le ricette informi sono ricette che vengono usate quando non importa dove sono posizionati gli ingredienti, ma solo che ci siano.
```lua
core.register_craft({
minetest.register_craft({
type = "shapeless",
output = "miamod:diamante 3",
recipe = {
@ -203,7 +203,7 @@ core.register_craft({
Le ricette di tipo "cottura" non vengono elaborate nella griglia di fabbricazione, bensì nelle fornaci o in qualsivoglia altro strumento di cottura che può essere trovato nelle mod.
```lua
core.register_craft({
minetest.register_craft({
type = "cooking",
output = "miamod_diamante_frammenti",
recipe = "default:coalblock",
@ -220,7 +220,7 @@ La ricetta qui sopra genera un'unità di frammenti di diamante dopo 10 secondi q
Il tipo "carburante" invece funge da accompagnamento alle ricette di cottura, in quanto definisce cosa può alimentare il fuoco.
```lua
core.register_craft({
minetest.register_craft({
type = "fuel",
recipe = "miamod:diamante",
burntime = 300,
@ -244,7 +244,7 @@ In primis, vengono utilizzati per descrivere proprietà come friabilità e infia
In secundis, possono essere usati in una ricetta al posto di un nome oggetto per permettere a qualsiasi oggetto nel gruppo di essere utilizzato.
```lua
core.register_craft({
minetest.register_craft({
type = "shapeless",
output = "miamod:diamante_qualcosa 3",
recipe = {"group:wood", "miamod:diamante"}
@ -275,7 +275,7 @@ Gli strumenti possono anche avere una durezza massima supportata per ogni tipo;
Se l'oggetto impugnato dal giocatore non ha una capacità esplicitata, verrà allora usata quella della mano.
```lua
core.register_tool("miamod:strumento", {
minetest.register_tool("miamod:strumento", {
description = "Il mio strumento",
inventory_image = "miamod_strumento.png",
tool_capabilities = {

View File

@ -44,7 +44,7 @@ I Blocchi Mappa esistenti, tuttavia, ignorano questo limite quando caricati dal
Un nodo può essere letto da un mondo fornendone la posizione:
```lua
local nodo = core.get_node({ x = 1, y = 3, z = 4 })
local nodo = minetest.get_node({ x = 1, y = 3, z = 4 })
print(dump(nodo)) --> { name=.., param1=.., param2=.. }
```
@ -55,7 +55,7 @@ Se la posizione è un decimale, verrà arrotondata alle coordinate del nodo.
* `param1` - Guarda la definizione dei nodi. È solitamente associato alla luce.
* `param2` - Guarda la definizione dei nodi.
Per vedere se un nodo è caricato si può utilizzare `core.get_node_or_nil`, che ritornerà `nil` se il nome del nodo risulta `ignore`
Per vedere se un nodo è caricato si può utilizzare `minetest.get_node_or_nil`, che ritornerà `nil` se il nome del nodo risulta `ignore`
(la funzione non caricherà comunque il nodo).
Potrebbe comunque ritornare `ignore` se un blocco contiene effettivamente `ignore`: questo succede ai limiti della mappa.
@ -67,14 +67,14 @@ Le più frequenti sono quelle per trovare i nodi.
Per esempio, mettiamo che si voglia creare un certo tipo di pianta che cresce più velocemente vicino alla pietra;
si dovrebbe controllare che ogni nodo nei pressi della pianta sia pietra, e modificarne il suo indice di crescita di conseguenza.
`core.find_node_near` ritornerà il primo nodo trovato in un dato raggio, combaciante con le informazioni passategli (nomi di nodi o gruppi).
`minetest.find_node_near` ritornerà il primo nodo trovato in un dato raggio, combaciante con le informazioni passategli (nomi di nodi o gruppi).
Nell'esempio che segue, andiamo alla ricerca di un nodo di mese nel raggio di 5 nodi:
```lua
local vel_crescita = 1
local pos_nodo = core.find_node_near(pos, 5, { "default:stone" })
local pos_nodo = minetest.find_node_near(pos, 5, { "default:stone" })
if pos_nodo then
core.chat_send_all("Nodo trovato a: " .. dump(pos_nodo))
minetest.chat_send_all("Nodo trovato a: " .. dump(pos_nodo))
vel_crescita = 2
end
```
@ -86,7 +86,7 @@ Si dovrebbe quindi usare una funzione in grado di trovare più nodi in un'area:
local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
local pos2 = vector.add(pos, { x = 5, y = 5, z = 5 })
local lista_pos =
core.find_nodes_in_area(pos1, pos2, { "default:stone" })
minetest.find_nodes_in_area(pos1, pos2, { "default:stone" })
local vel_crescita = 1 + #lista_pos
```
@ -98,7 +98,7 @@ Per ovviare a ciò, bisogna controllare l'intervallo manualmente.
local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
local pos2 = vector.add(pos, { x = 5, y = 5, z = 5 })
local lista_pos =
core.find_nodes_in_area(pos1, pos2, { "default:stone" })
minetest.find_nodes_in_area(pos1, pos2, { "default:stone" })
local vel_crescita = 1
for i=1, #lista_pos do
local delta = vector.subtract(lista_pos[i], pos)
@ -123,9 +123,9 @@ Puoi usare `set_node` per sovrascrivere nodi nella mappa.
Ogni chiamata a `set_node` ricalcolerà la luce e richiamerà i suoi callback, il che significa che `set_node` è alquanto lento quando usato su un elevato numero di nodi.
```lua
core.set_node({ x = 1, y = 3, z = 4 }, { name = "default:stone" })
minetest.set_node({ x = 1, y = 3, z = 4 }, { name = "default:stone" })
local nodo = core.get_node({ x = 1, y = 3, z = 4 })
local nodo = minetest.get_node({ x = 1, y = 3, z = 4 })
print(nodo.name) --> default:stone
```
@ -136,7 +136,7 @@ sono in verità due.
Si può impostare un nuovo nodo senza rimuoverne metadati e inventario con `swap_node`:
```lua
core.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:stone" })
minetest.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:stone" })
```
### Rimozione dei nodi
@ -146,15 +146,15 @@ Un nodo deve sempre essere presente. Per rimuoverlo, basta impostarlo uguale a `
Le seguenti due linee di codice sono equivalenti, rimuovendo in entrambi i casi il nodo:
```lua
core.remove_node(pos)
core.set_node(pos, { name = "air" })
minetest.remove_node(pos)
minetest.set_node(pos, { name = "air" })
```
Infatti, `remove_node` non fa altro che richiamare `set_node` con nome `air`.
## Caricamento blocchi
Puoi usare `core.emerge_area` per caricare i blocchi mappa.
Puoi usare `minetest.emerge_area` per caricare i blocchi mappa.
Questo comando è asincrono, ovvero i blocchi non saranno caricati istantaneamente; al contrario, verranno caricati man mano e il callback associato sarà richiamato a ogni passaggio.
```lua
@ -164,7 +164,7 @@ local pos1 = vector.subtract(pos, mezza_dimensione)
local pos2 = vector.add (pos, mezza_dimensione)
local param = {} -- dati persistenti tra un callback e l'altro
core.emerge_area(pos1, pos2, mio_callback, param)
minetest.emerge_area(pos1, pos2, mio_callback, param)
```
Minetest chiamerà la funzione locale definita qua sotto `mio_callback` ogni volta che carica un blocco, con delle informazioni sul progresso.
@ -183,12 +183,12 @@ local function mio_callback(pos, action,
-- Invia messaggio indicante il progresso
if param.blocchi_totali == param.blocchi_caricati then
core.chat_send_all("Ho finito di caricare blocchi!")
minetest.chat_send_all("Ho finito di caricare blocchi!")
else
local percentuale = 100 * param.blocchi_caricati / param.blocchi_totali
local msg = string.format("Caricamento blocchi %d/%d (%.2f%%)",
param.blocchi_caricati, param.blocchi_totali, percentuale)
core.chat_send_all(msg)
minetest.chat_send_all(msg)
end
end
```
@ -205,7 +205,7 @@ local mezza_dimensione = { x = 10, y = 10, z = 10 }
local pos1 = vector.subtract(pos, mezza_dimensione)
local pos2 = vector.add (pos, mezza_dimensione)
core.delete_area(pos1, pos2)
minetest.delete_area(pos1, pos2)
```
Questo cancellerà tutti i blocchi mappa in quell'area, anche quelli solo parzialmente selezionati.

View File

@ -43,7 +43,7 @@ Questa distinzione è resa meno chiara dal fatto che le entità sono controllate
`get_pos` e `set_pos` permettono di ottenere e impostare la posizione di un oggetto.
```lua
local giocatore = core.get_player_by_name("bob")
local giocatore = minetest.get_player_by_name("bob")
local pos = giocatore:get_pos()
giocatore:set_pos({ x = pos.x, y = pos.y + 1, z = pos.z })
```
@ -130,7 +130,7 @@ Sia la tabella di un ObjectRef che quella di un'entità forniscono modi per otte
```lua
local entita = oggetto:get_luaentity()
local oggetto = entita.object
print("L'entità si trova a " .. core.pos_to_string(oggetto:get_pos()))
print("L'entità si trova a " .. minetest.pos_to_string(oggetto:get_pos()))
```
Ci sono diversi callback disponibili da usare per le entità.
@ -142,9 +142,9 @@ function MiaEntita:on_step(dtime)
local pos_giu = vector.subtract(pos, vector.new(0, 1, 0))
local delta
if core.get_node(pos_giu).name == "air" then
if minetest.get_node(pos_giu).name == "air" then
delta = vector.new(0, -1, 0)
elseif core.get_node(pos).name == "air" then
elseif minetest.get_node(pos).name == "air" then
delta = vector.new(0, 0, 1)
else
delta = vector.new(0, 1, 0)
@ -156,7 +156,7 @@ function MiaEntita:on_step(dtime)
end
function MiaEntita:on_punch(hitter)
core.chat_send_player(hitter:get_player_name(), self.message)
minetest.chat_send_player(hitter:get_player_name(), self.message)
end
```
@ -167,14 +167,14 @@ Questo succede nella *Staticdata*, una stringa che contiene tutte le informazion
```lua
function MiaEntita:get_staticdata()
return core.write_json({
return minetest.write_json({
messaggio = self.messaggio,
})
end
function MiaEntita:on_activate(staticdata, dtime_s)
if staticdata ~= "" and staticdata ~= nil then
local data = core.parse_json(staticdata) or {}
local data = minetest.parse_json(staticdata) or {}
self:imposta_messaggio(data.messaggio)
end
end
@ -190,14 +190,14 @@ Questo significa che il suo staticdata inizialmente potrebbe essere vuoto (dato
Infine, c'è bisogno di registrare la tabella usando `register_entity`.
```lua
core.register_entity("miamod:entita", MiaEntita)
minetest.register_entity("miamod:entita", MiaEntita)
```
L'entità può essere spawnata da una mod nel seguente modo:
```lua
local pos = { x = 1, y = 2, z = 3 }
local oggetto = core.add_entity(pos, "miamod:entita", nil)
local oggetto = minetest.add_entity(pos, "miamod:entita", nil)
```
Il terzo parametro è lo staticdata inziale.

View File

@ -14,14 +14,14 @@ redirect_from:
In questo capitolo imparerai i vari modi per immagazzinare dati.
- [Metadati](#metadati)
- [Cos'è un metadato?](#cosè-un-metadato)
- [Ottenere i metadati di un oggetto](#ottenere-i-metadati-di-un-oggetto)
- [Lettura e scrittura](#lettura-e-scrittura)
- [Chiavi speciali](#chiavi-speciali)
- [Immagazzinare tabelle](#immagazzinare-tabelle)
- [Metadati privati](#metadati-privati)
- [Tabelle Lua](#tabelle-lua)
- [Storaggio Mod](#storaggio-mod)
- [Cos'è un metadato?](#cos-e-un-metadato)
- [Ottenere i metadati di un oggetto](#ottenere-i-metadati-di-un-oggetto)
- [Lettura e scrittura](#lettura-e-scrittura)
- [Chiavi speciali](#chiavi-speciali)
- [Immagazzinare tabelle](#immagazzinare-tabelle)
- [Metadati privati](#metadati-privati)
- [Tabelle Lua](#tabelle-lua)
- [Storaggio mod](#storaggio-mod)
- [Database](#database)
- [Decidere quale usare](#decidere-quale-usare)
- [Il tuo turno](#il-tuo-turno)
@ -47,7 +47,7 @@ Il dato in sé, come il tipo di un nodo o la quantità di un ItemStack, non rien
Se si conosce la posizione di un nodo, si possono ottenere i suoi metadati:
```lua
local meta = core.get_meta({ x = 1, y = 2, z = 3 })
local meta = minetest.get_meta({ x = 1, y = 2, z = 3 })
```
Quelli dei giocatori e degli ItemStack invece sono ottenuti tramite `get_meta()`:
@ -87,7 +87,7 @@ print(meta:get_string("count")) --> "3"
Questo è utile, per esempio, per mostrare lo stato o il proprietario di un nodo.
`description` è usato negli ItemStack per sovrascrivere la descrizione al passare il mouse sopra l'oggetto in un formspec (come l'inventario, li vedremo più avanti).
È possibile utilizzare `core.colorize()` per cambiarne il colore.
È possibile utilizzare `minetest.colorize()` per cambiarne il colore.
`owner` è una chiave comune, usata per immagazzinare il nome del giocatore a cui appartiene l'oggetto o il nodo.
@ -100,9 +100,9 @@ Quello in Lua tende a essere molto più veloce e corrisponde al formato usato da
```lua
local data = { username = "utente1", score = 1234 }
meta:set_string("foo", core.serialize(data))
meta:set_string("foo", minetest.serialize(data))
data = core.deserialize(meta:get_string("foo"))
data = minetest.deserialize(minetest:get_string("foo"))
```
### Metadati privati
@ -130,7 +130,7 @@ Lo spazio d'archiviazione della mod (*storage*) usa la stessa identica API dei m
Il primo infatti è per mod, e può essere ottenuto solo durante l'inizializzazione - appunto - della mod.
```lua
local memoria = core.get_mod_storage()
local memoria = minetest.get_mod_storage()
```
Nell'esempio è ora possibile manipolare lo spazio d'archiviazione come se fosse un metadato:
@ -148,10 +148,10 @@ Dovresti rendere ciò opzionale, separando il come i dati vengono salvati e il d
local backend
if use_database then
backend =
dofile(core.get_modpath("miamod") .. "/backend_sqlite.lua")
dofile(minetest.get_modpath("miamod") .. "/backend_sqlite.lua")
else
backend =
dofile(core.get_modpath("miamod") .. "/backend_storage.lua")
dofile(minetest.get_modpath("miamod") .. "/backend_storage.lua")
end
backend.get_foo("a")
@ -161,15 +161,15 @@ backend.set_foo("a", { score = 3 })
Il file `backend_storage.lua` dell'esempio (puoi nominarlo come vuoi) dovrebbe includere l'implementazione del metodo di storaggio:
```lua
local memoria = core.get_mod_storage()
local memoria = minetest.get_mod_storage()
local backend = {}
function backend.set_foo(key, value)
memoria:set_string(key, core.serialize(value))
memoria:set_string(key, minetest.serialize(value))
end
function backend.get_foo(key)
return core.deserialize(memoria:get_string(key))
return minetest.deserialize(memoria:get_string(key))
end
return backend
@ -182,7 +182,7 @@ Un ambiente non sicuro è una tabella disponibile solamente alle mod con accesso
Gli ambienti non sicuri saranno trattati più nel dettaglio nel capitolo sulla [Sicurezza](../quality/security.html).
```lua
local amb_nonsicuro = core.request_insecure_environment()
local amb_nonsicuro = minetest.request_insecure_environment()
assert(amb_nonsicuro, "Per favore aggiungi miamod a secure.trusted_mods nelle impostazioni")
local _sql = amb_nonsicuro.require("lsqlite3")
@ -214,4 +214,4 @@ Si prestano bene per i grandi ammontare di dati.
## Il tuo turno
* Crea un nodo che sparisce dopo essere stato colpito cinque volte.
(Usa `on_punch` nella definizione del nodo e `core.set_node`)
(Usa `on_punch` nella definizione del nodo e `minetest.set_node`)

View File

@ -32,7 +32,7 @@ A ogni nodo è associato un timer.
Questi timer possono essere gestiti ottenendo un oggetto NodeTimerRef (quindi un riferimento, come già visto per gli inventari).
```lua
local timer = core.get_node_timer(pos)
local timer = minetest.get_node_timer(pos)
timer:start(10.5) -- in secondi
```
@ -40,9 +40,9 @@ Quando un timer raggiunge lo zero, viene eseguito il metodo `on_timer`, che va d
`on_timer` richiede un solo parametro, ovvero la posizione del nodo.
```lua
core.register_node("porteautomatiche:porta_aperta", {
minetest.register_node("porteautomatiche:porta_aperta", {
on_timer = function(pos)
core.set_node(pos, { name = "porteautomatiche:porta_chiusa" })
minetest.set_node(pos, { name = "porteautomatiche:porta_chiusa" })
return false
end
})
@ -60,15 +60,15 @@ Potresti aver tuttavia notato una limitazione: per questioni di ottimizzazione,
Erba aliena, a scopo illustrativo del capitolo, è un tipo d'erba che ha una probabilità di apparire vicino all'acqua.
```lua
core.register_node("alieni:erba", {
minetest.register_node("alieni:erba", {
description = "Erba Aliena",
light_source = 3, -- Il nodo irradia luce. Min 0, max 14
tiles = {"alieni_erba.png"},
groups = {choppy=1},
on_use = core.item_eat(20)
on_use = minetest.item_eat(20)
})
core.register_abm({
minetest.register_abm({
nodenames = {"default:dirt_with_grass"}, -- nodo sul quale applicare l'ABM
neighbors = {"default:water_source", "default:water_flowing"}, -- nodi che devono essere nei suoi dintorni (almeno uno)
interval = 10.0, -- viene eseguito ogni 10 secondi
@ -76,7 +76,7 @@ core.register_abm({
action = function(pos, node, active_object_count,
active_object_count_wider)
local pos = {x = pos.x, y = pos.y + 1, z = pos.z}
core.set_node(pos, {name = "alieni:erba"})
minetest.set_node(pos, {name = "alieni:erba"})
end
})
```

View File

@ -13,7 +13,7 @@ cmd_online:
Per esempio, il ponte IRC permette ai giocatori di eseguire comandi senza dover entrare in gioco.
Assicurati quindi di non dar per scontato che un giocatore sia connesso.
Puoi controllare ciò tramite `core.get_player_by_name`, per vedere se ritorna qualcosa o meno.
Puoi controllare ciò tramite `minetest.get_player_by_name`, per vedere se ritorna qualcosa o meno.
cb_cmdsprivs:
level: warning
@ -44,7 +44,7 @@ Le mod possono interagire con la chat del giocatore, tra l'inviare messaggi, int
Per inviare un messaggio a tutti i giocatori connessi in gioco, si usa la funzione `chat_send_all`:
```lua
core.chat_send_all("Questo è un messaggio visualizzabile da tutti")
minetest.chat_send_all("Questo è un messaggio visualizzabile da tutti")
```
Segue un esempio di come apparirerebbe in gioco:
@ -60,7 +60,7 @@ Il messaggio appare su una nuova riga, per distinguerlo dai messaggi dei giocato
Per inviare un messaggio a un giocatore in particolare, si usa invece la funzione `chat_send_player`:
```lua
core.chat_send_player("Tizio", "Questo è un messaggio per Tizio")
minetest.chat_send_player("Tizio", "Questo è un messaggio per Tizio")
```
Questo messaggio viene mostrato esattamente come il precedente, ma solo, in questo caso, a Tizio.
@ -70,7 +70,7 @@ Questo messaggio viene mostrato esattamente come il precedente, ma solo, in ques
Per registrare un comando, per esempio `/foo`, si usa `register_chatcommand`:
```lua
core.register_chatcommand("foo", {
minetest.register_chatcommand("foo", {
privs = {
interact = true,
},
@ -160,7 +160,7 @@ Una guida più completa ai pattern è probabilmente quella su [lua-users.org](ht
Per intercettare un messaggio, si usa `register_on_chat_message`:
```lua
core.register_on_chat_message(function(name, message)
minetest.register_on_chat_message(function(name, message)
print(name .. " ha detto " .. message)
return false
end)
@ -175,10 +175,10 @@ Dovresti assicurarti, poi, che il messaggio potrebbe essere un comando che invia
o che l'utente potrebbere non avere `shout`.
```lua
core.register_on_chat_message(function(name, message)
minetest.register_on_chat_message(function(name, message)
if message:sub(1, 1) == "/" then
print(name .. " ha eseguito un comando")
elseif core.check_player_privs(name, { shout = true }) then
elseif minetest.check_player_privs(name, { shout = true }) then
print(name .. " ha detto " .. message)
else
print(name .. " ha provato a dire " .. message ..

View File

@ -123,7 +123,7 @@ function indovina.prendi_formspec(nome)
local formspec = {
"formspec_version[4]",
"size[6,3.476]",
"label[0.375,0.5;", core.formspec_escape(testo), "]",
"label[0.375,0.5;", minetest.formspec_escape(testo), "]",
"field[0.375,1.25;5.25,0.8;numero;Numero;]",
"button[1.5,2.3;3,0.8;indovina;Indovina]"
}
@ -143,10 +143,10 @@ Il metodo principale per farlo è usare `show_formspec`:
```lua
function indovina.mostra_a(nome)
core.show_formspec(nome, "indovina:gioco", indovina.prendi_formspec(nome))
minetest.show_formspec(nome, "indovina:gioco", indovina.prendi_formspec(nome))
end
core.register_chatcommand("gioco", {
minetest.register_chatcommand("gioco", {
func = function(name)
indovina.mostra_a(name)
end,
@ -180,19 +180,19 @@ Per far sì che i formspec siano utili, le informazioni devono essere ritornate
Il metodo per fare ciò è chiamato Campo di Compilazione (*formspec field submission*), e per `show_formspec` quel campo viene ottenuto usando un callback globale:
```lua
core.register_on_player_receive_fields(function(player, formname, fields)
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "indovina:gioco" then
return
end
if fields.indovina then
local p_name = player:get_player_name()
core.chat_send_all(p_name .. " ha tentato di indovinare con il numero " .. fields.numero)
minetest.chat_send_all(p_name .. " ha tentato di indovinare con il numero " .. fields.numero)
end
end)
```
La funzione data in `core.register_on_player_receive_fields` è chiamata ogni volta che un utente invia un modulo.
La funzione data in `minetest.register_on_player_receive_fields` è chiamata ogni volta che un utente invia un modulo.
La maggior parte dei callback necessiteranno di controllare il nome fornito alla funzione, e uscire se non è quello esatto; tuttavia, alcuni potrebbero necessitare di operare su più moduli, se non addirittura su tutti.
Il parametro `fields` è una tabella di tutti i valori inviati dall'utente, indicizzati per stringhe.
@ -223,7 +223,7 @@ local function prendi_contesto(nome)
return contesto
end
core.register_on_leaveplayer(function(player)
minetest.register_on_leaveplayer(function(player)
_contexts[player:get_player_name()] = nil
end)
```
@ -236,7 +236,7 @@ function indovina.mostra_a(nome)
contesto.soluzione = contesto.soluzione or math.random(1, 10)
local formspec = indovina.prendi_formspec(nome, contesto)
core.show_formspec(nome, "indovina:gioco", formspec)
minetest.show_formspec(nome, "indovina:gioco", formspec)
end
```
@ -282,11 +282,11 @@ Ci sono tre diversi modi per far sì che un formspec sia consegnato al client:
### Formspec nei nodi
`core.show_formspec` non è l'unico modo per mostrare un formspec; essi possono infatti essere aggiunti anche ai [metadati di un nodo](../map/storage.html).
`minetest.show_formspec` non è l'unico modo per mostrare un formspec; essi possono infatti essere aggiunti anche ai [metadati di un nodo](../map/storage.html).
Per esempio, questo è usato con le casse per permettere tempi più veloci d'apertura - non si ha bisogno di aspettare che il server invii il formspec della cassa al giocatore.
```lua
core.register_node("miamod:tastodestro", {
minetest.register_node("miamod:tastodestro", {
description = "Premimi col tasto destro del mouse!",
tiles = {"miamod_tastodestro.png"},
groups = {cracky = 1},
@ -295,7 +295,7 @@ core.register_node("miamod:tastodestro", {
-- Il codice che segue imposta il formspec della cassa.
-- I metadati sono un modo per immagazzinare dati nel nodo.
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
"formspec_version[4]" ..
"size[5,5]"..
@ -312,7 +312,7 @@ core.register_node("miamod:tastodestro", {
I formspec impostati in questo modo non innescano lo stesso callback.
Per far in modo di ricevere il modulo di input per i formspec nei nodi, bisogna includere una voce `on_receive_fields` al registrare il nodo.
Questo stile di callback viene innescato al premere invio in un campo, che è possibile grazie a `core.show_formspec`; tuttavia, questi tipi di moduli possono essere mostrati solo
Questo stile di callback viene innescato al premere invio in un campo, che è possibile grazie a `minetest.show_formspec`; tuttavia, questi tipi di moduli possono essere mostrati solo
tramite il premere col tasto destro del mouse su un nodo. Non è possibile farlo programmaticamente.
### Inventario del giocatore

View File

@ -79,7 +79,7 @@ Questo permette all'intero pannello di essere ancorato sulla destra della finest
Puoi creare un elemento HUD una volta ottenuto il riferimento al giocatore al quale assegnarla:
```lua
local giocatore = core.get_player_by_name("tizio")
local giocatore = minetest.get_player_by_name("tizio")
local idx = giocatore:hud_add({
hud_elem_type = "text",
position = {x = 0.5, y = 0.5},
@ -268,9 +268,9 @@ function punteggio.aggiorna_hud(giocatore)
end
end
core.register_on_joinplayer(punteggio.aggiorna_hud)
minetest.register_on_joinplayer(punteggio.aggiorna_hud)
core.register_on_leaveplayer(function(player)
minetest.register_on_leaveplayer(function(player)
hud_salvate[player:get_player_name()] = nil
end)
```

View File

@ -23,9 +23,9 @@ Per esempio, un valore di 2 sulla gravità, renderà la gravità di un utente du
Segue l'esempio di un comando di antigravità:
```lua
core.register_chatcommand("antigrav", {
minetest.register_chatcommand("antigrav", {
func = function(name, param)
local giocatore = core.get_player_by_name(name)
local giocatore = minetest.get_player_by_name(name)
giocatore:set_physics_override({
gravity = 0.1, -- imposta la gravità al 10% del suo valore originale
-- (0.1 * 9.81)

View File

@ -46,7 +46,7 @@ I privilegi non sono fatti per indicare classi o status.
Usa `register_privilege` per dichiarare un nuovo privilegio:
```lua
core.register_privilege("voto", {
minetest.register_privilege("voto", {
description = "Può votare nei sondaggi",
give_to_singleplayer = false
})
@ -59,7 +59,7 @@ core.register_privilege("voto", {
Per controllare velocemente se un giocatore ha tutti i privilegi necessari o meno:
```lua
local celo, manca = core.check_player_privs(player_or_name, {
local celo, manca = minetest.check_player_privs(player_or_name, {
interact = true,
voto = true })
```
@ -68,7 +68,7 @@ In quest'esempio, `celo` è true se il giocatore ha sia `interact` che `voto`.
Se `celo` è false, allora `manca` conterrà una tabella con i privilegi mancanti.
```lua
local celo, manca = core.check_player_privs(name, {
local celo, manca = minetest.check_player_privs(name, {
interact = true,
voto = true })
@ -82,7 +82,7 @@ end
Se non hai bisogno di controllare i privilegi mancanti, puoi inserire `check_player_privs` direttamente nel costrutto if:
```lua
if not core.check_player_privs(name, { interact=true }) then
if not minetest.check_player_privs(name, { interact=true }) then
return false, "Hai bisogno del privilegio 'interact' per eseguire quest'azione!"
end
```
@ -92,11 +92,11 @@ end
Si può accedere o modificare i privilegi di un giocatore anche se quest'ultimo non risulta online.
```lua
local privs = core.get_player_privs(name)
local privs = minetest.get_player_privs(name)
print(dump(privs))
privs.voto = true
core.set_player_privs(name, privs)
minetest.set_player_privs(name, privs)
```
I privilegi sono sempre specificati come una tabella chiave-valore, con il loro nome come chiave e true/false come valore.

View File

@ -82,7 +82,7 @@ E hai ragione! L'API di Minetest è molto incentrata sull'Osservatore, per far i
## Modello-Vista-Controllo
Nel prossimo capitolo discuteremo di come testare automaticamente il codice, e uno dei problemi che riscontreremo sarà come separare il più possibile la logica (calcoli, cosa bisognerebbe fare) dalle chiamate alle API (`core.*`, altre mod).
Nel prossimo capitolo discuteremo di come testare automaticamente il codice, e uno dei problemi che riscontreremo sarà come separare il più possibile la logica (calcoli, cosa bisognerebbe fare) dalle chiamate alle API (`minetest.*`, altre mod).
Un modo per fare ciò è pensare a:
@ -148,14 +148,14 @@ function terreno.mostra_formspec_crea(nome)
]]
end
core.register_chatcommand("/land", {
minetest.register_chatcommand("/land", {
privs = { terreno = true },
func = function(name)
land.gestore_richiesta_crea(name)
end,
})
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
terreno.gestore_invio_crea(player:get_player_name(),
fields.nome_area)
@ -191,7 +191,7 @@ Al contrario, un approccio più comune e leggermente meno rigido è quello API-V
In un mondo ideale, si avrebbero le 3 aree MVC perfettamente separate... ma siamo nel mondo reale.
Un buon compromesso è ridurre la mod in due parti:
* **API** - modello + controllo. Non ci dovrebbe essere nessun uso di `core.` nella API.
* **API** - modello + controllo. Non ci dovrebbe essere nessun uso di `minetest.` nella API.
* **Vista** - la vista, esattamente come quella spiegata sopra.
È buona norma strutturare questa parte in file separati per ogni tipo di evento.

View File

@ -40,11 +40,11 @@ Per esempio, il seguente codice presenta una vulnerabilità che permette ai gioc
```lua
local function show_formspec(name)
if not core.check_player_privs(name, { privs = true }) then
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
core.show_formspec(name, "modman:modman", [[
minetest.show_formspec(name, "modman:modman", [[
size[3,2]
field[0,0;3,1;target;Nome;]
button_exit[0,1;3,1;sub;Promuovi]
@ -52,14 +52,14 @@ local function show_formspec(name)
return true
})
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
-- MALE! Manca il controllo dei privilegi!
local privs = core.get_player_privs(fields.target)
local privs = minetest.get_player_privs(fields.target)
privs.kick = true
privs.ban = true
core.set_player_privs(fields.target, privs)
minetest.set_player_privs(fields.target, privs)
return true
end)
```
@ -67,9 +67,9 @@ end)
Aggiungi un controllo dei privilegi per ovviare:
```lua
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
if not core.check_player_privs(name, { privs = true }) then
if not minetest.check_player_privs(name, { privs = true }) then
return false
end
@ -105,7 +105,7 @@ inv:set_stack("main", 1, pila)
Il comportamento dei callback è leggermente più complicato.
```lua
core.register_on_item_eat(function(hp_change, replace_with_item,
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Un po' smangiucchiato")
-- Quasi corretto! I dati saranno persi se un altro callback annulla questa chiamata
@ -117,7 +117,7 @@ Se nessun callback cancella l'operazione, la pila sarà impostata e la descrizio
È meglio quindi fare così:
```lua
core.register_on_item_eat(function(hp_change, replace_with_item,
minetest.register_on_item_eat(function(hp_change, replace_with_item,
itemstack, user, pointed_thing)
itemstack:get_meta():set_string("description", "Un po' smangiucchiato")
user:get_inventory():set_stack("main", user:get_wield_index(),

View File

@ -19,6 +19,7 @@ Dopo aver letto questo libro, se mastichi l'inglese dai un occhio a ciò che seg
### Programmazione in Lua
* [Programmazione in Lua (PIL)](http://www.lua.org/pil/).
* [Corso accelerato su Lua](http://luatut.com/crash_course.html).
### Modellazione 3D

View File

@ -33,7 +33,7 @@ Qualsiasi utente può inviare qualsiasi formspec con i valori che preferisce qua
Segue del codice trovato realmente in una mod:
```lua
core.register_on_player_receive_fields(function(player,
minetest.register_on_player_receive_fields(function(player,
formname, fields)
for key, field in pairs(fields) do
local x,y,z = string.match(key,
@ -71,7 +71,7 @@ Minetest permette alle mod di richiedere ambienti senza limiti, dando loro acces
Riesci a individuare la vulnerabilità in questo pezzo di codice??
```lua
local ie = core.request_insecure_environment()
local ie = minetest.request_insecure_environment()
ie.os.execute(("path/to/prog %d"):format(3))
```

View File

@ -42,12 +42,12 @@ Minetest ti permette di localizzare i tuoi contenuti in tante lingue diverse, ch
### Testo formattato
Il server ha bisogno di dire ai client come tradurre il testo.
Questo accade grazie alla funzione `core.get_translator(dominiotestuale)`, che abbrevieremo con `S()`:
Questo accade grazie alla funzione `minetest.get_translator(dominiotestuale)`, che abbrevieremo con `S()`:
```lua
local S = core.get_translator("miamod")
local S = minetest.get_translator("miamod")
core.register_craftitem("miamod:oggetto", {
minetest.register_craftitem("miamod:oggetto", {
description = S("My Item"),
})
```
@ -57,7 +57,7 @@ Piuttosto che avere tutte le traduzioni di una lingua salvate nello stesso file,
È buona norma assegnare al dominio testuale lo stesso nome della mod, onde evitare conflitti tra mod diverse.
Il testo formattato può essere usato nella maggior parte dei casi dove è richiesto un testo fatto per gli esseri umani - come i formspec, i campi di definizioni di un oggetto, `infotext` ecc.
Nel caso dei formspec, tieni presente che dovrai usare la funzione di escape `core.formspec_escape` per una corretta visualizzazione.
Nel caso dei formspec, tieni presente che dovrai usare la funzione di escape `minetest.formspec_escape` per una corretta visualizzazione.
Quando il client incontra del testo formattato, come quello passato in `description`, ne andrà a cercare il corrispettivo nel file di traduzione della lingua del giocatore. Se la ricerca non avrà avuto esito positivo, ritornerà quello in inglese.
@ -95,8 +95,8 @@ Non è raro dover inserire una variabile dentro una stringa da tradurre.
Al contrario, dovresti usare il seguente sistema di formattazione:
```lua
core.register_on_joinplayer(function(player)
core.chat_send_all(S("Everyone, say hi to @1!", player:get_player_name()))
minetest.register_on_joinplayer(function(player)
minetest.chat_send_all(S("Everyone, say hi to @1!", player:get_player_name()))
end)
```
@ -130,13 +130,13 @@ local list = {
S("Potato")
}
core.register_chatcommand("find", {
minetest.register_chatcommand("find", {
func = function(name, param)
local info = core.get_player_information(name)
local info = minetest.get_player_information(name)
local lingua = info and info.language or "en"
for _, riga in ipairs(lista) do
local trad = core.get_translated_string(language, riga)
local trad = minetest.get_translated_string(language, riga)
if trad:contains(query) then
return riga
end

View File

@ -52,7 +52,7 @@ Quello che fa è cercare i file Lua con il nome che termina in `_spec`, eseguend
```lua
miamod = {}
dofile(core.get_modpath("miamod") .. "/api.lua")
dofile(minetest.get_modpath("miamod") .. "/api.lua")
```
@ -112,7 +112,7 @@ _G.minetest = {}
-- Definisce la funzione simulata
local chiamate_chat_send_all = {}
function core.chat_send_all(name, message)
function minetest.chat_send_all(name, message)
table.insert(chiamate_chat_send_all, { nome = name, messaggio = message })
end

View File

@ -13,7 +13,7 @@ layout: compress
<html>
{% endif %}
<head>
<title>{% if page.homepage %}{% else %}{{ page.title }} - {% endif %}Luanti / Minetest Modding Book</title>
<title>{% if page.homepage %}{% else %}{{ page.title }} - {% endif %}Minetest Modding Book</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="author" content="rubenwardy">
@ -22,7 +22,7 @@ layout: compress
<meta name="og:url" content="https://rubenwardy.com/minetest_modding_book{{ page.url }}">
<meta name="og:title" content="{{ page.title | escape }}">
<meta name="og:author" content="rubenwardy">
<meta name="og:site_name" content="Luanti Modding Book (formerly Minetest)">
<meta name="og:site_name" content="Minetest Modding Book">
{% if page.description %}
<meta name="og:description" content="{{ page.description | escape | strip }}">
<meta name="description" content="{{ page.description | escape | strip }}">

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 %}

View File

@ -8,7 +8,7 @@ noindex: true
<main>
<article>
<h1>Luanti Modding Book (formerly Minetest)</h1>
<h1>Minetest Modding Book</h1>
<h2>Thanks for sharing your feedback!</h2>

View File

@ -4,7 +4,7 @@ layout: none
<!doctype html>
<html>
<head>
<title>Luanti Modding Book (formerly Minetest)</title>
<title>Minetest Modding Book</title>
<meta name="og:description" content="An easy guide to learn how to create mods for Minetest">
<meta name="description" content="An easy guide to learn how to create mods for Minetest">
<link rel="canonical" href="https://rubenwardy.com/minetest_modding_book/">
@ -28,11 +28,11 @@ layout: none
</head>
<body>
<main>
<h1>Luanti Modding Book (formerly Minetest)</h1>
<h1>Minetest Modding Book</h1>
<p>An easy guide to learn how to create mods for Minetest.</p>
<p>Detecting and redirecting to the correct translation.</p>
<p>
<a href="en/index.html">View Luanti Modding Book in English</a>
<a href="en/index.html">View Minetest Modding Book in English</a>
</p>
</main>
</body>

View File

@ -6,7 +6,7 @@ root: .
<main>
<article>
<h1>Luanti Modding Book (formerly Minetest)</h1>
<h1>Minetest Modding Book</h1>
<h2>Choose a Language</h2>