2022-08-22 18:14:18 +03:00
|
|
|
---
|
|
|
|
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)
|
2022-08-24 12:32:15 +03:00
|
|
|
- [Anhänge](#anhänge)
|
|
|
|
- [Sie sind dran](#sie-sind-dran)
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
## Was sind Objekte, Spieler, und Entities?
|
|
|
|
|
|
|
|
Spieler und Entities sind beide Arten von Objekten. Ein Objekt ist etwas, das sich unabhängig
|
|
|
|
vom Block-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 billig 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
|
|
|
|
diese Entity erstellt, die 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 MapBlock inaktiv wird,
|
|
|
|
um ihn zu speichern, da dies zu Datenverlusten führen würde. MapBlocks 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 MapBlock 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 den *give* [privilege](../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)
|
|
|
|
```
|
|
|
|
|
2022-08-23 00:11:17 +03:00
|
|
|
### Schlagen, Damage Groups, und Armor Groups
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-23 00:11:17 +03:00
|
|
|
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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-23 00:11:17 +03:00
|
|
|
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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-23 00:11:17 +03:00
|
|
|
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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-23 00:11:17 +03:00
|
|
|
Wie anfällig ein Objekt für bestimmte Arten von Schaden ist, hängt von seiner
|
|
|
|
`armor_groups` [Objekteigenschaft](#object-properties). 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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
```lua
|
|
|
|
target:set_properties({
|
|
|
|
armor_groups = { fleshy = 90, crumbly = 50 },
|
|
|
|
})
|
|
|
|
```
|
|
|
|
|
2022-08-23 00:11:17 +03:00
|
|
|
Im obigen Beispiel erleidet das Objekt 90 % `fleshy` Schadens und 50 % des
|
|
|
|
`crumbly`-Schaden.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-23 00:11:17 +03:00
|
|
|
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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
### Beispiel für die Schadensberechnung
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
Schlagen wir das Objekt `target`:
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
```lua
|
2022-08-24 12:32:15 +03:00
|
|
|
local werkzeug_faehigkeiten = {
|
2022-08-22 18:14:18 +03:00
|
|
|
full_punch_interval = 0.8,
|
|
|
|
damage_groups = { fleshy = 5, choppy = 10 },
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
-- Dies wird nur für das abbauen von Nodes verwendet, ist aber dennoch erforderlich
|
2022-08-22 18:14:18 +03:00
|
|
|
max_drop_level=1,
|
|
|
|
groupcaps={
|
|
|
|
fleshy={times={[1]=2.5, [2]=1.20, [3]=0.35}, uses=30, maxlevel=2},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
local zeit_seit_letzten_schlag = werkzeug_faehigkeiten.full_punch_interval
|
|
|
|
target:punch(object, zeit_seit_letzten_schlag, werkzeug_faehigkeiten)
|
2022-08-22 18:14:18 +03:00
|
|
|
```
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
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`.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
```lua
|
2022-08-24 12:32:15 +03:00
|
|
|
= (5*90/100 + 10*0/100) * limit(zeit_seit_letzten_schlag / full_punch_interval, 0, 1)
|
2022-08-22 18:14:18 +03:00
|
|
|
= (5*90/100 + 10*0/100) * 1
|
|
|
|
= 4.5
|
|
|
|
```
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
Da die HP eine ganze Zahl sind, wird der Schaden auf 5 Lebenspunkte gerundet.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
## Anhänge
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
```lua
|
2022-08-24 12:32:15 +03:00
|
|
|
kind:set_attach(elternteil, knochen, position, drehung)
|
2022-08-22 18:14:18 +03:00
|
|
|
```
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
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.
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
{% include notice.html notice=page.degrad %}
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
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:
|
2022-08-22 18:14:18 +03:00
|
|
|
|
|
|
|
```lua
|
2022-08-24 12:32:15 +03:00
|
|
|
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
|
2022-08-22 18:14:18 +03:00
|
|
|
```
|
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
## Sie sind dran
|
2022-08-22 18:14:18 +03:00
|
|
|
|
2022-08-24 12:32:15 +03:00
|
|
|
* 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).
|