Lua-Skripting: Fehlerbehebung
Diese Seite behandelt häufige Probleme, die beim Schreiben oder Debuggen von FreeMinecraftModels-Prop-Skripten auftreten können, sowie Tipps für die Arbeit mit dem System der verzögerten Konfigurationserzeugung. Wenn du nach funktionierenden Beispielen suchst, siehe Beispiele & Muster. Wenn du gerade erst anfängst, siehe Erste Schritte.
Häufige Probleme
1. Konfigurationsdatei wird nicht geladen / Skript nicht angehängt
Symptom: Der Prop spawnt, reagiert aber nicht auf Klicks oder andere Hooks.
Ursachen und Lösungen:
-
Keine
.yml-Konfigurationsdatei existiert noch. FMM erzeugt die Konfiguration verzögert beim ersten Prop-Spawn. Beim ersten Mal, wenn ein Modell gespawnt wird, erstellt FMM die.yml-Konfiguration asynchron mit Standardwerten (aktiviert, keine Skripte). Du musst die generierte Konfiguration bearbeiten, um deine Skriptdateinamen hinzuzufügen, und dann den Prop erneut spawnen. -
Die Konfiguration hat
isEnabled: false. Öffne die.yml-Datei neben der Modelldatei und setzeisEnabled: true. -
Die
scripts:-Liste ist leer. Füge deine Skriptdateinamen hinzu:isEnabled: true
scripts:
- my_script.lua -
Der
.yml-Dateiname stimmt nicht mit dem Modelldateinamen überein. Die Konfiguration muss denselben Basisnamen wie die Modelldatei haben. Zum Beispiel brauchttorch_01.fmmodeleinetorch_01.ymlim selben Verzeichnis.
2. Skriptdatei nicht gefunden
Symptom: Konsole zeigt: [FMM Scripts] Script 'my_script.lua' not found in scripts/ folder
Ursachen und Lösungen:
-
Falsches Verzeichnis. Skriptdateien müssen in
plugins/FreeMinecraftModels/scripts/sein, nicht neben der Modelldatei. -
Dateinamen-Abweichung. Der Name in der
.yml-Konfiguration muss exakt mit dem Dateinamen imscripts/-Ordner übereinstimmen, einschließlich Groß-/Kleinschreibung und der.lua-Endung. -
Datei nicht vorhanden. Überprüfe nochmals, ob die
.lua-Datei tatsächlich imscripts/-Ordner existiert.
3. Skript wird überhaupt nicht geladen
Symptom: Kein Konsolenfehler, aber keine Hooks feuern.
Überprüfe die Serverkonsole auf Lua-Syntaxfehler beim Start. Die häufigsten Ursachen sind:
- Fehlendes
endzum Schließen einer Funktion oder einesif-Blocks - Nicht übereinstimmende Klammern
- Fehlendes Komma zwischen Hook-Definitionen in der zurückgegebenen Tabelle
- Datei endet nicht mit
.lua
Wenn ein Lua-Fehler vorliegt, gibt die Konsole einen [Lua]-Fehlerblock mit Dateiname, Zeilennummer und einer Beschreibung aus.
4. Hook wird nie ausgelöst
Symptom: Das Skript wird geladen (du siehst die [FMM Scripts] Bound script-Nachricht), aber ein bestimmter Hook wird nie ausgelöst.
Überprüfe, ob der Hook-Name exakt so geschrieben ist wie in der Hook-Referenz aufgeführt. Häufige Fehler:
| Falscher Name | Korrekter Name |
|---|---|
on_click | on_right_click oder on_left_click |
on_interact | on_right_click |
on_hit | on_left_click |
on_tick | on_game_tick |
on_remove | on_destroy |
on_arrow_hit | on_projectile_hit |
Überprüfe auch, ob der Prop tatsächlich eine darunterliegende Armor-Stand-Entity hat. Einige Prop-Konfigurationen erzeugen möglicherweise keine anklickbare Entity.
5. Timeout / Ausführungsbudget überschritten
Symptom: Die Konsole zeigt eine von zwei Nachrichten.
Ein Aufruf, der das In-VM-Budget überschritten hat, wird mitten in der Ausführung abgebrochen:
Lua execution budget exceeded (50ms or 250000 instructions)
Ein Aufruf, der zwar zurückkehrte, insgesamt aber zu lange dauerte, wird nachträglich abgefangen:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
Jeder Hook, jeder Callback und jede Dateiauswertung darf höchstens 250,000 Lua-Instruktionen ausführen oder 50 ms laufen, je nachdem, was zuerst eintritt, und verschachtelte Aufrufe teilen sich eine einzige Zuteilung. Das Skript hat zu viel Arbeit in einem einzelnen Hook-Aufruf erledigt. Häufige Ursachen:
- Zu viele Entities in
on_game_tickdurchiterieren - Zu viele Partikel pro Tick erstellen
- Aufwändige Schleifen ohne Verteilung der Arbeit über Ticks
Lösung: Schwere Arbeit hinter einen state-basierten Cooldown verschieben oder scheduler:run_repeating() mit einem vernünftigen Intervall anstelle von on_game_tick verwenden.
6. context.event ist nil in einem Klick-Hook
Das sollte normalerweise nicht für on_left_click und on_right_click passieren, aber schütze immer mit:
if context.event then
context.event.cancel()
end
Innerhalb von Scheduler-Callbacks ist context.event immer nil -- das ist erwartetes Verhalten. Event-Modifikation kann nur innerhalb des Event-Hooks selbst erfolgen.
7. Animation wird nicht abgespielt
Symptom: play_animation() gibt false zurück, oder es passiert nichts Sichtbares.
Ursachen und Lösungen:
-
Falscher Animationsname. Der Name muss exakt mit dem übereinstimmen, was in der Modelldatei definiert ist. Überprüfe deine
.bbmodel- oder.fmmodel-Datei auf den korrekten Animationsnamen. -
Modell hat keine Animationen. Nicht alle Modelle haben Animationen. Überprüfe, ob die Modelldatei tatsächlich Animationsdaten enthält.
-
Spieler sind nicht in Ressourcenpaket-Reichweite. Die Animation ist serverseitig, aber Spieler brauchen das FMM-Ressourcenpaket geladen, um das Modell überhaupt zu sehen.
8. Partikel erscheinen nicht
- Überprüfe, ob der Partikelname ein gültiger Bukkit
ParticleEnum-Wert in GROSSBUCHSTABEN ist:"FLAME", nicht"flame". - Überprüfe, ob die Position in einem geladenen Chunk ist. Wenn keine Spieler in der Nähe sind, kann der Chunk entladen sein.
- Überprüfe, ob
countmindestens 1 ist. - Einige Partikel (wie
DUST) benötigen spezifische Zusatzdaten, die das Basis-spawn_particle()möglicherweise nicht unterstützt. Verwende Standard-Partikel wieFLAME,HEART,HAPPY_VILLAGER,NOTE,ENCHANT, etc.
9. Sound wird nicht abgespielt
- Überprüfe, ob der Soundname eine gültige Bukkit
SoundEnum-Konstante in GROSSBUCHSTABEN ist. Beispiel:"BLOCK_NOTE_BLOCK_HARP", nicht"block.note_block.harp". - Überprüfe, ob die Positionskoordinaten korrekt sind (nicht alles Nullen oder NaN).
- Überprüfe, ob die Lautstärke größer als 0 ist.
10. State setzt sich unerwartet zurück
context.state ist pro Prop-Instanz und bleibt für die Lebensdauer des Props bestehen. Wenn State sich scheinbar zurücksetzt:
- Der Prop könnte entfernt und erneut gespawnt worden sein (jeder Spawn erstellt eine neue Instanz).
- Du liest möglicherweise State in einem Scheduler-Callback mit der falschen Context-Variable. Verwende immer den eigenen Context-Parameter des Callbacks.
11. Die os-Bibliothek ist nicht verfügbar
Symptom: Das Skript stürzt mit einem Fehler wie attempt to index nil (os) ab.
Die os-Bibliothek ist vollständig aus der Lua-Sandbox entfernt. Du kannst weder os.time(), os.clock() noch irgendeine andere os-Funktion verwenden.
Lösung: Verwende context.world:get_time() für die Weltzeit oder verfolge die verstrichene Zeit manuell über State-Flags und Tick-Zähler in on_game_tick. Für Abklingzeiten ist context.cooldowns:check_local(key, ticks) vorzuziehen.
12. Item-Skript wird nicht aktiviert
Symptom: Das benutzerdefinierte Item ist in der Hand des Spielers, aber es werden keine Item-Hooks ausgelöst.
Ursachen und Lösungen:
-
Kein
material:-Feld in der YML-Konfiguration. Item-Skripte funktionieren nur bei Modellen, in deren Konfigurationmaterial:gesetzt ist. Ohne dieses Feld behandelt FMM das Modell als Prop, nicht als benutzerdefiniertes Item. -
Fehlender
fmm_item_id-PDC-Schlüssel. Das Item im Inventar des Spielers muss den PersistentDataContainer-Schlüsselfmm_item_idbesitzen. Items, die über Vanilla-Befehle oder Drittanbieter-Plugins beschafft wurden, können dieses Tag verlieren. Verwende/fmm giveitem <id>oder das Admin-Menü, um ein korrekt getaggtes Item zu erhalten. -
Skript-Dateiname nicht in der Konfiguration aufgeführt. Prüfe, ob die
.yml-Konfiguration des Items den Skript-Dateinamen in derscripts:-Liste enthält, genau wie bei Props.
13. Item-Skript wird aktiviert und sofort wieder deaktiviert
Symptom: Du siehst in der Konsole, wie das Skript in schneller Folge gebunden und gelöst wird, oder on_equip wird ausgelöst und unmittelbar danach on_unequip.
Ursache: Die Verfolgung des Item-Anlegens reagiert auf Slot-Wechsel-Events. Wenn du dir ein Item per Befehl gibst und es in einem nicht aktiven Slot landet, oder wenn sich dein aktiver Slot während der Vergabe ändert, kann der Equip-/Unequip-Zyklus in schneller Folge feuern.
Lösung: Wechsle nach /fmm giveitem <id> manuell in den Inventarslot, der das Item enthält. Das Skript aktiviert sich anhand des aktuell ausgewählten Slots, nicht nur danach, ob das Item im Inventar liegt.
14. Hook feuert, aber das Skript stürzt bei Entity-Methoden ab
Symptom: Ein Hook wie on_shift_right_click funktioniert, aber das Skript stürzt innerhalb eines geplanten Callbacks mit Fehlern wie attempt to call nil ab, wenn entity:damage() oder entity:push() aufgerufen wird.
Ursache: context.world:get_nearby_entities() gibt ALLE Entities in Reichweite zurück, einschließlich nicht-lebender Entities (Armor Stands, fallengelassene Items, Erfahrungskugeln, Area-Effect-Clouds). Diese Entities haben keine Living-Entity-Methoden wie damage(), push() oder add_potion_effect().
Lösung: Sichere Aufrufe immer mit if entity.damage then ab, bevor du Living-Entity-Methoden aufrufst:
local entities = context.world:get_nearby_entities(x, y, z, radius)
for _, entity in ipairs(entities) do
if entity.damage then
-- Safe to call living entity methods
entity:damage(5.0)
entity:push(0, 0.5, 0)
end
end
15. Nur im Event vorhandene Daten fehlen in geplanten Callbacks
Symptom: Daten aus dem Klick-/Kampf-Event fehlen innerhalb eines scheduler:run_later()- oder scheduler:run_repeating()-Callbacks.
Ursache: Geplante Callbacks erhalten einen frischen Context und behalten weder das ursprüngliche Bukkit-Event noch den generischen Zonen-Akteur. context.event ist in Callbacks immer nil. Item-Skripte können context.player weiterhin über den Item-Besitzer auflösen, solange das Skript aktiv ist, aber Prop-Skripte erhalten das Top-Level-context.player nur während spielergetriebener Hooks wie Klicks und Zonen-Ein-/Austritt. Prop-Skripte sollten den Spieler während des ursprünglichen Hooks aus context.player oder context.event.player festhalten, wenn sie ihn später brauchen.
Lösung: Verwende den frischen Context des Callbacks für normalen Item-/Welt-/State-Zugriff. Wenn du den exakten Spieler oder die Entity aus dem ursprünglichen Event brauchst, halte sie vor dem Planen fest und prüfe, dass sie noch gültig sind.
on_right_click = function(context)
local clicked_player = context.player or (context.event and context.event.player)
context.scheduler:run_later(20, function(later_context)
-- Item scripts can use later_context.player here.
-- Prop scripts should use a captured player when they need the clicker.
local player = later_context.player or clicked_player
if player and player.is_valid then
player:send_message("&aDelayed message!")
end
end)
end
Wie die verzögerte Konfigurationserzeugung funktioniert
Das Verständnis des verzögerten Konfigurationssystems hilft, Verwirrung bei der Einrichtung neuer Props zu vermeiden:
-
Erster Spawn: Wenn ein Prop spawnt und keine begleitende
.yml-Datei existiert, erstellt FMM die Konfiguration asynchron. Das bedeutet, die Datei wird in einem Hintergrund-Thread geschrieben und ist nicht sofort verfügbar. -
Standardwerte: Die generierte Konfiguration hat
isEnabled: trueund eine leerescripts: []-Liste. -
Keine Skripte beim ersten Spawn: Da die Konfiguration erstellt wird, nachdem der Prop bereits gespawnt hat (und keine Skripte auflistet), wird der Prop bei seinem ersten Spawn keine Skripte angehängt haben.
-
Bearbeiten und erneut spawnen: Nachdem FMM die Konfiguration erstellt hat, bearbeitest du sie, um deine Skriptdateinamen hinzuzufügen. Beim nächsten Spawn des Props werden Skripte geladen.
-
Konfigurationsort: Die
.yml-Datei wird im selben Verzeichnis wie die Modelldatei erstellt, mit demselben Basisnamen. Zum Beispiel:- Modell:
plugins/FreeMinecraftModels/models/fountain.fmmodel - Konfiguration:
plugins/FreeMinecraftModels/models/fountain.yml
- Modell:
- Modell in
models/platzieren - Skript in
scripts/platzieren - Den Prop einmal spawnen (generiert die
.yml) - Die
.ymlbearbeiten undscripts: [my_script.lua]hinzufügen - Den Prop erneut spawnen -- Skript ist jetzt aktiv
Fehlermeldungen lesen
Wenn in einem Lua-Prop-Skript etwas schiefgeht, gibt die Konsole einen [Lua]-Fehlerblock aus. Diese Meldungen sagen dir genau, welche Datei, welche Zeile, welcher Hook und was schiefgelaufen ist, in verständlicher Sprache.
Ein typischer Fehler sieht so aus:
[Lua] Error in 'my_door.lua' at line 12 during 'on_right_click':
[Lua] -> You tried to call a method or function that doesn't exist.
[Lua] -> Check the method name for typos, or make sure you're using ':' (colon) for method calls, not '.' (dot).
[Lua] -> Script has been disabled for this entity to prevent further errors.
Das System übersetzt häufige Lua-Fehler in verständliche Sprache:
| Roher Lua-Fehler | Was die Konsole dir sagt |
|---|---|
attempt to call nil | Du hast versucht, eine Methode oder Funktion aufzurufen, die nicht existiert. Prüfe auf Tippfehler und : vs . Verwendung. |
index expected, got nil | Du hast versucht, auf ein Feld von etwas zuzugreifen, das nil ist. Prüfe, ob vorheriger Code es initialisiert hat. |
attempt to index | Du hast versucht, auf eine Eigenschaft eines nil- oder ungültigen Werts zuzugreifen. |
bad argument | Eine Funktion hat den falschen Argumenttyp erhalten. Die Nachricht zeigt den erwarteten vs. tatsächlichen Typ. |
| Timeout | Dein Skript brauchte Xms in 'hook_name' (Limit: 50ms) -- Skript deaktiviert, um Lag zu verhindern. |
Lies immer die vollständige [Lua]-Fehlermeldung, bevor du in den Code eintauchst. Sie zeigt dir normalerweise direkt die Lösung.
Gehe nicht davon aus, dass undokumentierte Methoden existieren
Die FMM-Lua-API stellt einen bestimmten Satz von Methoden bereit. Gehe nicht davon aus, dass Kurzformen oder alternative Namen existieren. Häufige Fehler:
context.prop:get_location()-- existiert nicht. Verwendecontext.prop.current_location(ein Feld, keine Methode).context.prop:set_animation("open")-- existiert nicht. Verwendecontext.prop:play_animation("open", true, true).context.event:setCancelled(true)-- existiert nicht. Verwendecontext.event.cancel().context.cooldowns:check_local(...)-- existiert nicht in FMM. Verwendecontext.statemitscheduler:run_later()für Cooldowns.context.player-- existiert nicht in FMM-Prop-Skripten. Verwendecontext.world:get_nearby_players(), um Spieler in der Nähe des Props zu finden.context.boss-- existiert nicht. Das ist EliteMobs. Verwendecontext.propin FMM.
Im Zweifelsfall prüfe die Prop-API-Seite. Wenn es dort nicht dokumentiert ist, existiert es nicht.
Debug-Tipps
1. Verwende context.log:info() großzügig
Füge Log-Nachrichten bei jedem Schritt beim Debuggen hinzu:
on_right_click = function(context)
context.log:info("Right click received!")
context.log:info("Event present: " .. tostring(context.event ~= nil))
context.log:info("State is_open: " .. tostring(context.state.is_open))
end
2. Überprüfe die Konsole beim Start
FMM protokolliert [FMM Scripts] Bound script 'X' to prop 'Y' für jede erfolgreiche Bindung. Wenn du diese Nachricht nicht siehst, wurde die Konfiguration oder das Skript nicht geladen.
3. Überprüfe den Modelldateipfad
Die .yml-Konfiguration muss ein Geschwister der Modelldatei sein (gleiches Verzeichnis, gleicher Basisname). Überprüfe dies durch:
- Modelldateipfad:
plugins/FreeMinecraftModels/models/my_model.fmmodel - Konfigurationsdateipfad:
plugins/FreeMinecraftModels/models/my_model.yml
4. Teste Hooks einzeln
Wenn du ein komplexes Skript erstellst, beginne damit, jeden Hook isoliert zu testen. Füge jeweils einen Hook hinzu und überprüfe, ob er feuert, bevor du zum nächsten übergehst.
5. Prüfe auf Tippfehler in Hook-Namen
Der häufigste Grund, warum ein Hook nicht feuert, ist ein falsch geschriebener Hook-Name. Das Skript wird ohne Fehler geladen, aber die falsch geschriebene Hook-Funktion wird während der Validierung abgelehnt.
Anfänger-Lernpfad
Wenn du dieses System von Grund auf lernen möchtest, funktioniert dieser Lernpfad gut:
- Schreibe eine Datei mit nur
api_version = 1undon_spawn, das eine Nachricht protokolliert. - Füge das Skript zu einer Prop-Konfiguration hinzu und überprüfe, ob die Log-Nachricht erscheint.
- Füge
on_right_clickhinzu und protokolliere, wenn der Prop angeklickt wird. - Füge
on_left_clickmitcontext.event.cancel()für Unverwundbarkeit hinzu. - Spiele eine Animation bei Rechtsklick ab.
- Füge einen Sound bei Rechtsklick hinzu.
- Füge State und Umschaltverhalten hinzu.
- Füge eine Zonenüberwachung für Näherungserkennung hinzu.
- Gehe erst dann zu komplexen Multi-Hook-Skripten mit Schedulern über.
Jeder Schritt baut auf dem vorherigen auf, und du kannst in jeder Phase testen.
Nächste Schritte
- Erste Schritte -- Dateistruktur, Hooks, erste Skript-Erklärung, Kopier-Vorlagen
- Prop-API -- vollständige API-Referenz
- Beispiele & Muster -- vollständige funktionierende Skripte, die du studieren und anpassen kannst