Lua-Skripting: Prop- und Item-API
Diese Seite behandelt jede API, die für FreeMinecraftModels-Prop- und Item-Skripte verfügbar ist: context.prop, context.item, context.event, context.player, context.world, context.zones, context.scheduler, context.state und context.log. Wenn du neu im Skripting bist, beginne zuerst mit Erste Schritte.
context.prop
Die Prop-Tabelle liefert Informationen über die Prop-Entität und Methoden zur Steuerung ihrer Animationen. Sie wird für jeden Hook-Aufruf frisch neu erstellt.
Felder
| Feld | Typ | Hinweise |
|---|---|---|
prop.model_id | string | Der Blueprint-Modellname (z. B. "torch_01") |
prop.current_location | location-Tabelle | Die Position des Props zu dem Zeitpunkt, als der Context erstellt wurde |
Die location-Tabelle hat die Standardfelder: x, y, z, world, yaw, pitch.
Beispiel: Prop-Informationen lesen
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop spawned: " .. (context.prop.model_id or "unknown"))
local loc = context.prop.current_location
if loc then
context.log:info("Location: " .. loc.x .. ", " .. loc.y .. ", " .. loc.z)
end
end
}
prop:play_animation(name, blend, loop)
Spielt eine benannte Animation am Prop-Modell ab.
| Parameter | Typ | Standard | Hinweise |
|---|---|---|---|
name | string | erforderlich | Der Animationsname, wie in der Modelldatei definiert |
blend | boolean | true | Ob mit der aktuellen Animation überblendet werden soll |
loop | boolean | true | Ob die Animation in Schleife läuft |
Gibt true zurück, wenn die Animation gefunden und gestartet wurde, false sonst.
Beispiel
return {
api_version = 1,
on_right_click = function(context)
local success = context.prop:play_animation("open", true, false)
if not success then
context.log:warn("Animation 'open' not found on this model!")
end
end
}
prop:stop_animation()
Stoppt alle derzeit abgespielten Animationen am Prop.
Nimmt keine Parameter entgegen.
Beispiel
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
prop:hurt_visual()
Spielt die visuelle Verletzungsanimation (rotes Blinken) am Prop ab, ohne ihm tatsächlichen Schaden zuzufügen.
Nimmt keine Parameter entgegen.
Beispiel
return {
api_version = 1,
on_left_click = function(context)
-- Flash red when punched, but don't actually take damage
if context.event then
context.event.cancel()
end
context.prop:hurt_visual()
end
}
prop:pickup()
Entfernt den Prop aus der Welt und lässt ein Platzierungs-Papier-Item an seinem Standort fallen. Das fallengelassene Item kann auf einen Block rechtsgeklickt werden, um den Prop erneut zu platzieren.
Nimmt keine Parameter entgegen.
Beispiel
return {
api_version = 1,
on_right_click = function(context)
-- Let players pick up the prop by right-clicking it
context.prop:pickup()
end
}
prop:mount(player)
Setzt einen Spieler auf den ersten verfügbaren Mount-Point-Sitz am Prop. Das Modell muss Mount-Point-Bones definiert haben.
| Parameter | Typ | Hinweise |
|---|---|---|
player | entity-Tabelle | Eine Spieler-Entity-Tabelle (z. B. aus context.event.player) |
Beispiel
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
context.prop:mount(player)
end
end
}
prop:dismount(player)
Entfernt einen Spieler von seinem Mount-Point-Sitz auf dem Prop.
| Parameter | Typ | Hinweise |
|---|---|---|
player | entity-Tabelle | Eine Spieler-Entity-Tabelle |
Beispiel
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
-- Toggle mount/dismount
local passengers = context.prop:get_passengers()
for i = 1, #passengers do
if passengers[i].uuid == player.uuid then
context.prop:dismount(player)
return
end
end
context.prop:mount(player)
end
end
}
prop:get_passengers()
Gibt ein Lua-Array von Entity-Tabellen für alle aktuellen Passagiere auf dem Prop zurück.
Nimmt keine Parameter entgegen.
Beispiel
return {
api_version = 1,
on_game_tick = function(context)
local passengers = context.prop:get_passengers()
if #passengers > 0 then
context.log:info("Prop has " .. #passengers .. " passenger(s)")
end
end
}
prop:has_mount_points()
Gibt zurück, ob dieser Prop Mount-Point-Bones in seinem Modell definiert hat.
Nimmt keine Parameter entgegen. Gibt true oder false zurück.
Beispiel
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player and context.prop:has_mount_points() then
context.prop:mount(player)
end
end
}
prop:spawn_elitemobs_boss(filename, x, y, z)
Spawnt einen EliteMobs-Custom-Boss am angegebenen Standort. Erfordert, dass EliteMobs auf dem Server installiert ist.
| Parameter | Typ | Hinweise |
|---|---|---|
filename | string | Der Dateiname des Custom-Bosses (z. B. "my_boss.yml") |
x | number | X-Koordinate |
y | number | Y-Koordinate |
z | number | Z-Koordinate |
Gibt eine Living-Entity-Tabelle für den gespawnten Boss zurück, oder nil, wenn EliteMobs nicht installiert ist oder die Boss-Datei nicht existiert.
Beispiel
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local boss = context.prop:spawn_elitemobs_boss("dungeon_guardian.yml", loc.x, loc.y + 1, loc.z)
if boss then
context.log:info("Spawned boss: " .. (boss.name or "unknown"))
else
context.log:warn("Could not spawn boss -- is EliteMobs installed?")
end
end
end
}
prop:open_inventory(player, title, rows)
Öffnet eine persistente Truhen-Inventar-GUI für den Spieler. Inhalte werden im PersistentDataContainer des Props gespeichert, wenn das Inventar geschlossen wird, und beim erneuten Öffnen wiederhergestellt.
| Parameter | Typ | Standard | Hinweise |
|---|---|---|---|
player | entity-Tabelle | erforderlich | Der Spieler, dem das Inventar gezeigt werden soll |
title | string | erforderlich | Der Inventar-Titel (unterstützt &-Farbcodes) |
rows | int | 3 | Anzahl der Reihen (1-6, wobei 6 = 54 Slots = Doppeltruhe) |
Gibt true zurück, wenn das Inventar geöffnet wurde, sonst false.
prop:is_viewing_inventory(player)
Gibt zurück, ob der angegebene Spieler derzeit das Inventar dieses Props geöffnet hat.
| Parameter | Typ | Hinweise |
|---|---|---|
player | entity-Tabelle | Der zu prüfende Spieler |
Gibt true oder false zurück.
Beispiel: Schließanimation, wenn Inventar geschlossen wird
context.state["task_" .. player.uuid] = context.scheduler:run_repeating(5, 5, function(tick_context)
if not tick_context.prop:is_viewing_inventory(player) then
tick_context.prop:play_animation("close", true, false)
tick_context.scheduler:cancel(tick_context.state["task_" .. player.uuid])
end
end)
prop:place_book(player)
Nimmt das beschriebene oder beschreibbare Buch aus der Haupthand des Spielers und speichert es am Prop.
| Parameter | Typ | Hinweise |
|---|---|---|
player | entity-Tabelle | Der Spieler, der das Buch hält |
Gibt true bei Erfolg zurück.
prop:read_book(player)
Öffnet das gespeicherte Buch zum Lesen für den Spieler.
| Parameter | Typ | Hinweise |
|---|---|---|
player | entity-Tabelle | Der Spieler, dem das Buch gezeigt werden soll |
Gibt true zurück, wenn ein Buch geöffnet wurde.
prop:take_book(player)
Gibt das gespeicherte Buch in das Inventar des Spielers zurück und entfernt es vom Prop.
| Parameter | Typ | Hinweise |
|---|---|---|
player | entity-Tabelle | Der Spieler, dem das Buch gegeben werden soll |
Gibt true bei Erfolg zurück.
prop:has_book()
Gibt zurück, ob ein Buch an diesem Prop gespeichert ist. Nimmt keine Parameter entgegen.
prop:drop_inventory()
Lässt alle gespeicherten Inventarinhalte am Standort des Props als Item-Entitäten fallen und löscht dann die gespeicherten Daten. Schließt automatisch das Inventar für alle Spieler, die es derzeit ansehen.
Nimmt keine Parameter entgegen. Gibt true bei Erfolg zurück.
prop:drop_book()
Lässt das gespeicherte Buch am Standort des Props als Item-Entität fallen und löscht die gespeicherten Buchdaten.
Nimmt keine Parameter entgegen. Gibt true bei Erfolg zurück.
prop:set_persistent_data(key, value)
Speichert einen String-Wert im PersistentDataContainer des Armor-Stands des Props. Diese Daten überleben Server-Neustarts und Chunk-Entladungen.
| Parameter | Typ | Hinweise |
|---|---|---|
key | string | Ein eindeutiger Schlüsselname (intern unter fmm_lua_<key> gespeichert) |
value | string | Der zu speichernde Wert. Verwende tostring() für Zahlen und Booleans. |
Gibt true bei Erfolg zurück, false wenn der Prop keinen unterstützenden Armor-Stand hat.
prop:get_persistent_data(key)
Ruft einen zuvor mit set_persistent_data gespeicherten String-Wert ab. Gibt nil zurück, wenn der Schlüssel nicht gesetzt wurde.
| Parameter | Typ | Hinweise |
|---|---|---|
key | string | Der in set_persistent_data verwendete Schlüsselname |
Beispiel: Persistenter Umschaltzustand
return {
api_version = 1,
on_spawn = function(context)
local saved = context.prop:get_persistent_data("active")
context.state.active = saved == "true"
end,
on_right_click = function(context)
context.state.active = not context.state.active
context.prop:set_persistent_data("active", tostring(context.state.active))
end
}
context.item
Die Item-Tabelle ist nur in Item-Skripten verfügbar (nicht in Prop-Skripten). Sie liefert Informationen über das benutzerdefinierte Item und Methoden zu seiner Manipulation. Diese Tabelle wird für jeden Hook-Aufruf frisch neu erstellt.
Felder
| Feld | Typ | Hinweise |
|---|---|---|
item.id | string | Die Item-Typ-ID (die fmm_item_id aus der YML-Konfiguration) |
item:material()
Gibt den Materialnamen des Items als String zurück (z. B. "DIAMOND_SWORD", "STICK").
item:get_amount() / item:set_amount(n)
Holt oder setzt die Stack-Größe des Items.
| Parameter | Typ | Hinweise |
|---|---|---|
n | int | Die neue Stack-Menge |
item:consume(n)
Verringert die Stack-Menge des Items um n (Standard 1). Wenn die resultierende Menge 0 oder weniger ist, wird das Item aus dem Inventar des Spielers entfernt.
| Parameter | Typ | Standard | Hinweise |
|---|---|---|---|
n | int | 1 | Zu verbrauchende Menge |
item:get_uses() / item:set_uses(n)
Holt oder setzt einen benutzerdefinierten Verwendungszähler, der im PersistentDataContainer des Items gespeichert ist. Dies ist unabhängig von der Vanilla-Haltbarkeit und kann verwendet werden, um benutzerdefinierte Haltbarkeits- oder Ladungssysteme zu implementieren.
| Parameter | Typ | Hinweise |
|---|---|---|
n | int | Die neue Verwendungszahl |
item:get_name() / item:set_name(s)
Holt oder setzt den Anzeigenamen des Items. Unterstützt Farbcodes mit &.
| Parameter | Typ | Hinweise |
|---|---|---|
s | string | Der neue Anzeigename (z. B. "&b&lFrost Sword") |
item:get_lore() / item:set_lore(table)
Holt oder setzt die Lore des Items. get_lore() gibt eine Tabelle von Strings zurück (eine pro Zeile). set_lore() nimmt eine Tabelle von Strings.
| Parameter | Typ | Hinweise |
|---|---|---|
table | table | Array von Strings, eines pro Lore-Zeile |
Beispiel: Item-Skript, das Verwendungen verfolgt
return {
api_version = 1,
on_right_click = function(context)
local uses = context.item:get_uses()
if uses <= 0 then
context.player:send_message("&cThis item is out of charges!")
return
end
context.item:set_uses(uses - 1)
context.player:send_message("&aUsed! Charges remaining: " .. (uses - 1))
end
}
item:get_durability()
Gibt eine Tabelle mit den Feldern current und max zurück, die die Vanilla-Haltbarkeit des Items repräsentieren, oder nil, wenn das Item keine Haltbarkeitsleiste hat.
Beispiel
local dur = context.item:get_durability()
if dur then
context.player:send_message("Durability: " .. dur.current .. "/" .. dur.max)
end
item:get_durability_percentage()
Gibt die verbleibende Haltbarkeit als Bruchteil von 0.0 bis 1.0 zurück, oder nil, wenn das Item keine Haltbarkeitsleiste hat.
item:use_durability(amount, can_break)
Reduziert die Vanilla-Haltbarkeit des Items um einen festen Betrag.
| Parameter | Typ | Standard | Hinweise |
|---|---|---|---|
amount | int | erforderlich | Wie viele Haltbarkeitspunkte verbraucht werden sollen |
can_break | boolean | false | Wenn true, wird das Item zerstört, wenn die Haltbarkeit endet. Wenn false, stoppt die Haltbarkeit bei 1. |
item:use_durability_percentage(fraction, can_break)
Reduziert die Vanilla-Haltbarkeit des Items um einen Prozentsatz seines Maximums.
| Parameter | Typ | Standard | Hinweise |
|---|---|---|---|
fraction | number | erforderlich | Anteil der maximalen Haltbarkeit, der verbraucht werden soll (z. B. 0.1 = 10 %) |
can_break | boolean | false | Wenn true, wird das Item zerstört, wenn die Haltbarkeit endet. Wenn false, stoppt die Haltbarkeit bei 1. |
context.event
Event-Daten für den aktuellen Hook. Verfügbar in Klick-, Kampf- und Interaktions-Hooks sowohl für Prop- als auch Item-Skripte. Gibt nil zurück in Hooks, die kein zugehöriges Event haben (on_spawn, on_game_tick, on_destroy, on_zone_enter, on_zone_leave, on_equip).
Felder und Methoden
| Feld oder Methode | Typ | Hinweise |
|---|---|---|
event.player | Spieler-Entity-Tabelle | Der Spieler, der das Event ausgelöst hat. Verfügbar in on_left_click, on_right_click und on_projectile_hit (der Schütze, falls es ein Spieler war). Siehe Player-Entity-Methoden für alle Felder und Methoden. |
event.is_cancelled | boolean | Ob das Event derzeit abgebrochen ist |
event.cancel() | function | Bricht das Event ab (z. B. verhindert Schaden oder Interaktion) |
event.uncancel() | function | Hebt ein zuvor abgebrochenes Event wieder auf |
Nicht alle Events sind abbrechbar. Wenn das zugrunde liegende Bukkit-Event Cancellable nicht implementiert, sind event.cancel() und event.uncancel() nicht vorhanden und event.is_cancelled ist immer false.
Beispiel: Einen Prop unverwundbar machen
Beispiel
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Beispiel: Abbruch-Zustand prüfen
Beispiel
return {
api_version = 1,
on_left_click = function(context)
if context.event and not context.event.is_cancelled then
context.event.cancel()
context.log:info("Damage cancelled!")
end
end
}
Innerhalb geplanter Callbacks (scheduler:run_later, scheduler:run_repeating) ist context.event immer nil. Event-Modifikationen können nur während des Event-Hooks selbst stattfinden.
context.world
Dies ist die FreeMinecraftModels-/MagmaCore-World-API. Siehe context.world für die vollständige Referenz.
Alle Methoden, die auf der globalen Seite dokumentiert sind (get_block_at, set_block_at, spawn_particle, play_sound, strike_lightning, get_time, set_time, get_nearby_entities, get_nearby_players, spawn_entity, get_highest_block_y, raycast, place_temporary_block, drop_item, spawn_firework), sind in FMM verfügbar. Siehe die MagmaCore-World-API für vollständige Details zu world:raycast() (einen Strahl werfen und getroffene Entitäten/Blöcke erkennen), world:place_temporary_block() (temporärer Blockersatz) und world:spawn_firework() (Feuerwerkraketen mit benutzerdefinierten Farben und Formen spawnen). EliteMobs-Boss-Powers gehen von derselben World-Basis aus und ergänzen boss-spezifische Location-Tabellen-Methoden zum Spawnen von Bossen, Verstärkungen, fallenden Blöcken, temporären Blöcken und mehr; siehe EliteMobs Welt & Umgebung.
FMM-spezifische World-Erweiterungen
FreeMinecraftModels legt drei optionale EliteMobs-Loot-Helfer auf context.world. Sie sind immer vorhanden, geben aber jeweils false zurück und tun nichts, wenn EliteMobs nicht installiert ist:
| Methode | Hinweise |
|---|---|
world:drop_elitemobs_procedural_loot(player, level, location?) | Lässt ein prozedural generiertes EliteMobs-Item für den Spieler fallen. Gibt false zurück, wenn prozedurale Item-Drops deaktiviert sind |
world:drop_elitemobs_random_loot(player, level, location?) | Würfelt die EliteMobs-Loot-Tabellen für den Spieler auf der angegebenen Stufe aus |
world:drop_elitemobs_custom_loot(player, file, level, location?) | Lässt eine bestimmte EliteMobs-Custom-Item-Datei für den Spieler fallen. Gibt false zurück, wenn sich die Datei nicht auflösen lässt |
Die vollständigen Signaturen stehen in der Lua-API-Referenz. Das prop-seitige Gegenstück für Bosse ist prop:spawn_elitemobs_boss(...), oben dokumentiert.
Player-Entity-Methoden
Spieler-Entity-Tabellen werden von context.player, context.event.player und context.world:get_nearby_players() zurückgegeben. Die generischen MagmaCore-Hooks on_zone_enter / on_zone_leave setzen context.player und context.event.player auf den eintretenden bzw. verlassenden Spieler.
Die Entity-Tabellen, Lebewesen-Methoden, spielerspezifischen Methoden und Player-UI-Methoden, die auf der globalen Seite dokumentiert sind, sind die von FMM verwendeten MagmaCore-Tabellen. EliteMobs-Boss-Powers stellen ähnliche, aber boss-spezifische Entity-Tabellen bereit, dokumentiert in Boss & Entitäten. Siehe die MagmaCore Lua-Skript-Engine für die vollständige FMM-Referenz, die Entity-Basis-Felder, Lebewesen-Felder und -Methoden, spielerspezifische Felder und Methoden sowie Player-UI-Methoden abdeckt. Neue Spielermethoden umfassen player:get_target_entity() (Raycast-Zielerfassung), player:get_eye_location(), player:get_look_direction(), player:send_block_change() (gefälschte Blöcke pro Spieler) und player:reset_block() -- siehe Spielerspezifische Methoden für Details.
FMM-spezifische Entity-Felder
Jede Entity-Tabelle, die innerhalb eines FMM-Skripts erstellt wird, erhält diese zusätzlichen Felder automatisch (über FMMs LuaEntityEnricher):
| Feld | Typ | Hinweise |
|---|---|---|
entity.is_modeled | boolean | true, wenn diese Bukkit-Entität die zugrunde liegende Entität einer ModeledEntity ist |
entity.is_prop | boolean | true, wenn diese Entität ein Armor-Stand ist, der eine PropEntity stützt |
entity.model | Tabelle oder nil | Nur gefüllt, wenn is_modeled = true (siehe unten) |
Wenn entity.model vorhanden ist, stellt es Folgendes bereit:
| Feld / Methode | Hinweise |
|---|---|
model.model_id | Der Blueprint-Modellname (z. B. "dragon") |
model.is_dynamic | true, wenn dies eine DynamicEntity ist (an eine Lebewesen-Entität angeheftet) |
model:play_animation(name, blend, loop) | Spielt eine benannte Animation ab. Gibt true bei Erfolg zurück |
model:stop_animations() | Stoppt alle laufenden Animationen |
model:remove() | Entfernt die modellierte Entität und alle ihre Bones sofort |
on_right_click = function(context)
local player = context.event and context.event.player
if not player then return end
local target = player:get_target_entity(8)
if target and target.is_modeled then
target.model:play_animation("hurt", true, false)
end
end
EliteMobs-Entity-Felder
Wenn EliteMobs installiert ist, leitet FMM an EliteMobs' Enricher weiter, sodass dieselben Entity-Tabellen außerdem Folgendes bereitstellen:
| Feld | Typ | Hinweise |
|---|---|---|
entity.is_elite | boolean | true, wenn die Entität von EliteMobs verfolgt wird |
entity.is_custom_boss | boolean | true, wenn es eine Custom-Boss-Konfiguration ist |
entity.is_significant_boss | boolean | true für Custom-Bosse mit einem healthMultiplier > 1 (filtert benannte Trash-Mobs heraus) |
entity.elite | Tabelle oder nil | Nur gefüllt, wenn is_elite = true. Enthält level, name, health, max_health, health_multiplier, damage_multiplier, is_custom_boss, plus elite:remove() |
context.zones
Die Zones-API wird über alle Nightbreak-Plugins hinweg geteilt. Siehe context.zones für die vollständige Referenz.
context.scheduler
Die Scheduler-API wird über alle Nightbreak-Plugins hinweg geteilt. Siehe context.scheduler für die vollständige Referenz.
context.state
Die State-API wird über alle Nightbreak-Plugins hinweg geteilt. Siehe context.state für die vollständige Referenz.
context.log
Die Logging-API wird über alle Nightbreak-Plugins hinweg geteilt. Siehe context.log für die vollständige Referenz.
context.cooldowns
Die hier dokumentierte Abklingzeit-API verwendet die gemeinsame MagmaCore-/FMM-Reihenfolge, die von FreeMinecraftModels-Skripten und EliteMobs-NPC-Skripten genutzt wird: check_local(key?, duration). EliteMobs-Boss-Powers verwenden dieselbe Argumentreihenfolge mit boss-spezifischen Speichern. Die vollständige Referenz findest du unter context.cooldowns.
| Methode | Hinweise |
|---|---|
local_ready(key?) | Prüft, ob eine lokale Abklingzeit bereit ist. |
local_remaining(key?) | Gibt die verbleibenden Ticks der lokalen Abklingzeit zurück, oder 0. |
check_local(key?, duration) | Prüft und startet eine lokale Abklingzeit atomar. |
set_local(duration, key?) | Setzt eine lokale Abklingzeit ohne Prüfung. |
global_ready() | Prüft die gemeinsame globale Abklingzeit des Skript-Besitzers. |
set_global(duration) | Setzt die gemeinsame globale Abklingzeit des Skript-Besitzers. |
Verwende context.cooldowns:check_local("my_key", 40) für normale Prop- oder Item-Aktions-Abklingzeiten.
Laufzeit-Modell
Eine Laufzeit pro Skript-Instanz
Jede Prop-Entität, an die Skripte angehängt sind, erhält ihre eigene unabhängige Lua-Laufzeit-Instanz. Wenn der Prop spawnt, lädt FMM den Lua-Quellcode, wertet ihn in einer frischen Sandbox-Umgebung aus und speichert die zurückgegebene Tabelle. Wenn der Prop entfernt wird, wird die Laufzeit heruntergefahren.
Für Item-Skripte wird eine Laufzeit pro (Spieler, itemId)-Paar erstellt. Wenn ein Spieler ein benutzerdefiniertes Item ausrüstet, erstellt FMM eine Skript-Instanz für diesen Spieler und Item-Typ. Wenn das Item abgelegt wird, wird die Laufzeit heruntergefahren.
Das bedeutet:
- Lokale Variablen, die auf Dateiebene deklariert sind, sind privat für diese Skript-Instanz.
context.stateist vollständig isoliert zwischen Instanzen, selbst wenn sie dieselbe Skript-Datei teilen.
Eigentum geplanter Tasks
Alle Tasks, die durch context.scheduler erstellt werden, gehören der Laufzeit, die sie erstellt hat. Wenn ein Prop entfernt wird:
- Die Laufzeit wird heruntergefahren.
- Jeder eigene Task -- sowohl einmalige als auch wiederkehrende -- wird automatisch abgebrochen.
- Alle Zonenbeobachtungen werden gelöscht.
Cooldown-Geltungsbereich
Die geteilte Skript-Engine stellt lokale Cooldown-Helfer (local_ready, local_remaining, check_local, set_local) und globale Cooldown-Helfer (global_ready, set_global) bereit. FMM ordnet diese Speicher wie folgt zu:
| Skript-Typ | Lokaler Speicherbereich | Globaler Speicherbereich |
|---|---|---|
| Prop-Skript | Pro ScriptInstance (Prop + Skript-Datei) | Pro PropEntity (geteilt über jedes an diesen Prop gebundene Skript) |
| Item-Skript | Pro (player, itemId, scriptFile)-Tripel — bleibt über erneutes Ausrüsten erhalten, auch wenn die Skript-Instanz jedes Mal abgebaut wird, wenn das Item einen aktiven Slot verlässt | Pro Spieler (geteilt über jedes FMM-Item-Skript, das dieser Spieler ausführt) |
Da Item-Skripte bei jedem Equip/Unequip-Zyklus abgebaut und neu aufgebaut werden, werden Item-Cooldowns in einer statischen Map nach Spieler-UUID gehalten statt auf der ScriptInstance. Aus diesem Grund gilt ein Item-Cooldown weiterhin, nachdem du das Item aus der Hotbar und wieder hinein tauschst.
Diese Persistenz beschränkt sich auf die aktuelle FMM-Laufzeit. /fmm reload, das Deaktivieren des Plugins und ein Server-Neustart leeren sowohl die Item-Cooldown-Speicher als auch die globalen Prop-Cooldown-Speicher, während die Skript-Manager heruntergefahren werden.
Ausführungsbudget
Jeder Hook-Aufruf, jeder geplante Callback und die anfängliche Auswertung der Skriptdatei selbst laufen unter einem harten Ausführungsbudget. Das Budget wird innerhalb der Lua-VM durchgesetzt, greift also, während dein Code noch läuft, statt erst danach die Uhr zu prüfen.
| Limit | Wert |
|---|---|
| CPU-Zeit des aktuellen Threads | 50 Millisekunden |
| Ausgeführte Lua-Instruktionen | 250.000 |
Welches Limit zuerst erreicht wird, bricht den Aufruf mit einem Lua-Fehler ab und deaktiviert die Skript-Instanz. Die Meldungen lauten:
Lua instruction budget exceeded (250000 instruction limit)
Lua CPU-time budget exceeded (50ms current-thread CPU limit)
Da die Prüfung pro Instruktion erfolgt, kann ein while true do end den Server nicht einfrieren.
Die Zeithälfte des Budgets wird als CPU-Zeit des aktuellen Threads gemessen, nicht als Echtzeit, ein Skript wird also nicht für Zeit belastet, in der der Server-Thread verdrängt war. Auf einer JVM, auf der die CPU-Zeitmessung des aktuellen Threads nicht verfügbar ist, weicht MagmaCore auf ein bewusst großzügigeres Limit von 250 Millisekunden vergangener Zeit aus (Lua elapsed-time fallback budget exceeded (250ms fallback; current-thread CPU time unavailable)) und behält dabei dieselbe Obergrenze von 250.000 Instruktionen bei, sodass nicht terminierende Skripte in jedem Fall begrenzt bleiben.
Verschachtelte Aufrufe teilen sich ein Budget: Wenn ein Hook einen Callback aufruft, der wiederum einen weiteren aufruft, wird die gesamte Kette als eine einzige Zuteilung von 50 ms CPU-Zeit / 250.000 Instruktionen gemessen, nicht als je eine pro Aufruf.
Während der anfänglichen Auswertung einer Skriptdatei existiert noch keine Instanz, daher wird die Definition abgelehnt und gar nicht erst registriert, statt deaktiviert zu werden.
Um innerhalb des Budgets zu bleiben:
- Vermeide unbegrenzte Schleifen innerhalb von Hooks.
- Halte
on_game_tick-Handler leichtgewichtig -- sie laufen in jedem einzelnen Tick. - Verwende
context.scheduler:run_repeating(...), um Arbeit über Ticks zu verteilen.
Vollständige Hook-Referenz
Diese Tabelle listet alle Hooks auf, die in Prop- und Item-Skripten verfügbar sind.
Die Spalte context.event beschreibt die zugrunde liegende Bukkit-Event-Familie. FMMs Lua-Event-Wrapper stellt weiterhin nur event.player, event.is_cancelled, event.cancel() und event.uncancel() bereit, wo zutreffend.
Aktive Prop-Hooks (7)
| Hook | Wird ausgelöst, wenn | context.event |
|---|---|---|
on_spawn | Prop in die Welt spawnt | nil |
on_game_tick | Jeder Server-Tick (50 ms) | nil |
on_destroy | Prop entfernt wird | nil |
on_left_click | Spieler den Prop links anklickt | damage event |
on_right_click | Spieler den Prop rechts anklickt | interaction event |
on_zone_enter | Spieler eine beobachtete Zone betritt | Spieler-Akteur der Zone (context.player / context.event.player; nicht abbrechbar) |
on_zone_leave | Spieler eine beobachtete Zone verlässt | Spieler-Akteur der Zone (context.player / context.event.player; nicht abbrechbar) |
Der aktuelle Skript-Validator akzeptiert on_projectile_hit für Prop-Skripte, aber die aktuelle Laufzeit leitet Projektiltreffer noch nicht an Prop-Skripte weiter. Verwende den Item-Hook on_projectile_hit für Projektilverhalten an einem geskripteten Item, oder die Bukkit-API ModeledEntityHitByProjectileEvent für plugin-seitige Projektilbehandlung an modellierten Entitäten.
Item-Hooks (22)
| Hook | Kategorie | Wird ausgelöst, wenn | context.event |
|---|---|---|---|
on_attack_entity | Kampf | Spieler eine Entität angreift | damage event |
on_kill_entity | Kampf | Spieler eine Entität tötet | death event |
on_take_damage | Kampf | Spieler Schaden nimmt | damage event |
on_shield_block | Kampf | Spieler mit Schild blockt | damage event |
on_shoot_bow | Kampf | Spieler mit Bogen schießt | bow shoot event |
on_projectile_hit | Kampf | Projektil des Spielers trifft | projectile hit event |
on_projectile_launch | Kampf | Spieler Projektil startet | launch event |
on_right_click | Interaktion | Spieler rechtsklickt | interact event |
on_left_click | Interaktion | Spieler linksklickt | interact event |
on_shift_right_click | Interaktion | Spieler shift+rechtsklickt | interact event |
on_shift_left_click | Interaktion | Spieler shift+linksklickt | interact event |
on_interact_entity | Interaktion | Spieler eine Entität rechtsklickt | entity interact event |
on_equip | Ausrüstung | Item in aktiven Slot kommt | nil |
on_unequip | Ausrüstung | Item aktiven Slot verlässt | nil |
on_swap_hands | Ausrüstung | Tauscht Haupt-/Nebenhand | swap event |
on_drop | Ausrüstung | Spieler Item fallen lässt | drop event |
on_break_block | Werkzeug | Spieler Block bricht | block break event |
on_consume | Werkzeug | Spieler Item konsumiert | consume event |
on_item_damage | Werkzeug | Item Haltbarkeitsschaden nimmt | item damage event |
on_fish | Werkzeug | Spieler Angel benutzt | fish event |
on_death | Werkzeug | Spieler stirbt, während ausgerüstet | death event |
on_game_tick | Lebenszyklus | Jeden Tick, während ausgerüstet | nil |
Nächste Schritte
- Beispiele & Muster -- vollständige funktionierende Skripte für Props und Items mit Erläuterungen
- Fehlerbehebung -- häufige Probleme, Debugging-Tipps und eine QC-Checkliste
- Erste Schritte -- Dateistruktur, Hooks, erste Skript-Anleitung