Scripting Lua : API Prop et Objet
Cette page couvre toutes les API disponibles aux scripts de prop et d'objet de FreeMinecraftModels : context.prop, context.item, context.event, context.player, context.world, context.zones, context.scheduler, context.state, context.cooldowns et context.log. Si le scripting est nouveau pour vous, commencez d'abord par Premiers pas.
context.prop
La table prop fournit des informations sur l'entité prop et des méthodes pour contrôler ses animations. FMM met cette table en cache par prop pour des raisons de performance ; les champs tels que current_location sont paresseux/vivants, si bien que leur lecture reflète toujours l'état actuel du prop.
Champs
| Champ | Type | Notes |
|---|---|---|
prop.model_id | string | Le nom de modèle blueprint (par ex. "torch_01") |
prop.current_location | table de location | La position actuelle du prop. C'est un champ vivant/paresseux, pas un instantané pris une seule fois. |
La table de location a les champs standard : x, y, z, world, yaw, pitch.
Exemple : lecture des infos du prop
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)
Joue une animation nommée sur le modèle du prop.
| Paramètre | Type | Défaut | Notes |
|---|---|---|---|
name | string | requis | Le nom de l'animation tel que défini dans le fichier de modèle |
blend | boolean | true | Si on doit fondre avec l'animation en cours |
loop | boolean | true | Si l'animation boucle |
Retourne true si l'animation a été trouvée et démarrée, false sinon.
Exemple
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()
Arrête toutes les animations actuellement en cours sur le prop.
Ne prend aucun paramètre.
Exemple
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
prop:hurt_visual()
Joue l'animation visuelle de blessure (flash de teinte rouge) sur le prop sans lui infliger de dégâts réels.
Ne prend aucun paramètre.
Exemple
return {
api_version = 1,
on_left_click = function(context)
-- Flash rouge quand frappé, mais ne pas prendre de dégâts
if context.event then
context.event.cancel()
end
context.prop:hurt_visual()
end
}
prop:pickup()
Retire le prop du monde et drop un objet de placement en papier à sa position. L'objet droppé peut être clic-droit sur un bloc pour replacer le prop.
Ne prend aucun paramètre et ne retourne rien. Le retrait et le drop sont mis en file d'attente sur le thread principal de Bukkit.
Exemple
return {
api_version = 1,
on_right_click = function(context)
-- Laisse les joueurs ramasser le prop en cliquant droit dessus
context.prop:pickup()
end
}
prop:mount(player)
Monte un joueur sur le premier siège de point de monture disponible sur le prop. Le modèle doit avoir des os de point de monture définis.
| Paramètre | Type | Notes |
|---|---|---|
player | entity table | Une table d'entité joueur (par ex. depuis context.player ou context.event.player) |
Retourne true lorsque le joueur a été trouvé, que le prop possède des points de monture et que l'action de montée a été mise en file d'attente. Retourne false lorsque ces références de base ne sont pas valides. Un retour true ne prouve pas qu'un siège était finalement disponible au moment où l'action en file d'attente s'est exécutée.
Exemple
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)
Démonte un joueur de son siège de point de monture sur le prop.
| Paramètre | Type | Notes |
|---|---|---|
player | entity table | Une table d'entité joueur |
Retourne true lorsque le joueur a été trouvé, que le prop possède un gestionnaire de montures et que la vérification de démontage a été mise en file d'attente. Retourne false lorsque ces références de base ne sont pas valides.
Exemple
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
-- Bascule monter/démonter
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()
Retourne un array Lua de tables d'entité pour tous les passagers actuels sur le prop.
Ne prend aucun paramètre.
Exemple
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()
Retourne si ce prop a des os de point de monture définis dans son modèle.
Ne prend aucun paramètre. Retourne true ou false.
Exemple
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)
Fait apparaître un boss personnalisé EliteMobs à la position donnée. Nécessite qu'EliteMobs soit installé sur le serveur.
| Paramètre | Type | Notes |
|---|---|---|
filename | string | Le nom de fichier du boss personnalisé (par ex. "my_boss.yml") |
x | number | Coordonnée X |
y | number | Coordonnée Y |
z | number | Coordonnée Z |
Retourne une table d'entité vivante pour le boss apparu, ou nil si EliteMobs n'est pas installé ou si le fichier de boss n'existe pas.
Exemple
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)
Ouvre une GUI d'inventaire coffre persistante pour le joueur. Le contenu est sauvegardé dans le PersistentDataContainer du prop lorsque l'inventaire est fermé, et restauré lors de la réouverture.
| Paramètre | Type | Défaut | Notes |
|---|---|---|---|
player | entity table | requis | Le joueur à qui montrer l'inventaire |
title | string | requis | Le titre de l'inventaire (supporte les codes de couleur &) |
rows | int | 3 | Nombre de rangées (1-6, où 6 = 54 slots = double coffre) |
Retourne true si les références prop/joueur étaient valides et que l'action d'ouverture a été mise en file d'attente, false sinon. Le nombre de rangées est ramené dans l'intervalle 1-6 avant la création de l'inventaire.
prop:is_viewing_inventory(player)
Retourne si le joueur donné a actuellement l'inventaire de ce prop ouvert.
| Paramètre | Type | Notes |
|---|---|---|
player | entity table | Le joueur à vérifier |
Retourne true ou false.
Exemple : animation de fermeture lorsque l'inventaire est fermé
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)
Prend le livre écrit ou inscriptible de la main principale du joueur et le stocke sur le prop.
| Paramètre | Type | Notes |
|---|---|---|
player | entity table | Le joueur tenant le livre |
Retourne true si les références prop/joueur étaient valides et que l'action a été mise en file d'attente. L'action différée sur le thread principal ne place un livre que si le joueur tient un livre inscriptible ou écrit et que le prop n'en possède pas déjà un.
prop:read_book(player)
Ouvre le livre stocké en lecture pour le joueur.
| Paramètre | Type | Notes |
|---|---|---|
player | entity table | Le joueur à qui montrer le livre |
Retourne true si les références prop/joueur étaient valides et que l'action de lecture a été mise en file d'attente. Cela ne garantit pas qu'un livre était effectivement stocké.
prop:take_book(player)
Retourne le livre stocké dans l'inventaire du joueur et le retire du prop.
| Paramètre | Type | Notes |
|---|---|---|
player | entity table | Le joueur à qui donner le livre |
Retourne true si les références prop/joueur étaient valides et que l'action de récupération a été mise en file d'attente. Cela ne garantit pas qu'un livre était effectivement stocké.
prop:has_book()
Retourne si un livre est stocké sur ce prop. Ne prend aucun paramètre.
prop:drop_inventory()
Drop tout le contenu d'inventaire stocké à la position du prop sous forme d'entités d'objet, puis efface les données stockées. Ferme automatiquement l'inventaire pour tous les joueurs qui le consultent actuellement.
Ne prend aucun paramètre. Retourne true si le prop possède un armor stand support valide et que l'action de drop a été mise en file d'attente. Cela ne garantit pas que des objets étaient effectivement stockés.
prop:drop_book()
Drop le livre stocké à la position du prop sous forme d'entité d'objet et efface les données du livre stocké.
Ne prend aucun paramètre. Retourne true si le prop possède un armor stand support valide et que l'action de drop a été mise en file d'attente. Cela ne garantit pas qu'un livre était effectivement stocké.
prop:set_persistent_data(key, value)
Stocke une valeur chaîne sur le PersistentDataContainer de l'armor stand du prop. Ces données survivent aux redémarrages serveur et aux déchargements de chunks.
| Paramètre | Type | Notes |
|---|---|---|
key | string | Un nom de clé unique (stocké sous fmm_lua_<key> en interne) |
value | string | La valeur à stocker. Utilisez tostring() pour les nombres et booléens. |
Retourne true en cas de succès, false si le prop n'a pas d'armor stand support.
prop:get_persistent_data(key)
Récupère une valeur chaîne précédemment stockée avec set_persistent_data. Retourne nil si la clé n'a pas été définie.
| Paramètre | Type | Notes |
|---|---|---|
key | string | Le nom de clé utilisé dans set_persistent_data |
Exemple : état de bascule persistant
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
La table item est disponible uniquement dans les scripts d'objet (pas dans les scripts de prop). Elle fournit des informations sur l'objet personnalisé et des méthodes pour le manipuler. Cette table est reconstruite à neuf à chaque appel de hook.
Les méthodes d'écriture d'objet telles que set_amount, consume, set_uses, set_name, set_lore et les utilitaires de consommation de durabilité mettent leur mutation en file d'attente sur le thread principal de Bukkit et retournent nil. Les méthodes de lecture retournent l'état de l'objet équipé correspondant au moment où elles s'exécutent.
Champs
| Champ | Type | Notes |
|---|---|---|
item.id | string | L'ID de type d'objet (le fmm_item_id depuis la config YML) |
item:material()
Retourne le nom du matériau de l'objet sous forme de chaîne (par ex. "DIAMOND_SWORD", "STICK").
item:get_amount() / item:set_amount(n)
Obtient ou définit la taille de stack de l'objet. set_amount(n) met le changement en file d'attente et retourne nil.
| Paramètre | Type | Notes |
|---|---|---|
n | int | La nouvelle quantité de stack |
item:consume(n)
Met en file d'attente une décrémentation de la quantité de stack de l'objet de n (défaut 1). Si la quantité résultante est 0 ou moins, l'objet est retiré de l'inventaire du joueur. Retourne nil.
| Paramètre | Type | Défaut | Notes |
|---|---|---|---|
n | int | 1 | Quantité à consommer |
item:get_uses() / item:set_uses(n)
Obtient ou définit un compteur d'utilisations personnalisé stocké dans le PersistentDataContainer de l'objet. C'est indépendant de la durabilité vanilla et peut être utilisé pour implémenter des systèmes de durabilité ou de charge personnalisés. set_uses(n) met le changement en file d'attente et retourne nil.
| Paramètre | Type | Notes |
|---|---|---|
n | int | Le nouveau compte d'utilisations |
item:get_name() / item:set_name(s)
Obtient ou définit le nom d'affichage de l'objet. Supporte les codes de couleur avec &. set_name(s) met le changement en file d'attente et retourne nil.
| Paramètre | Type | Notes |
|---|---|---|
s | string | Le nouveau nom d'affichage (par ex. "&b&lFrost Sword") |
item:get_lore() / item:set_lore(table)
Obtient ou définit le lore de l'objet. get_lore() retourne une table de chaînes (une par ligne). set_lore() prend une table de chaînes, met le changement en file d'attente et retourne nil.
| Paramètre | Type | Notes |
|---|---|---|
table | table | Array de chaînes, une par ligne de lore |
Exemple : script d'objet qui suit les utilisations
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()
Retourne une table avec les champs current et max représentant la durabilité vanilla de l'objet, ou nil si l'objet n'a pas de barre de durabilité.
Exemple
local dur = context.item:get_durability()
if dur then
context.player:send_message("Durability: " .. dur.current .. "/" .. dur.max)
end
item:get_durability_percentage()
Retourne la durabilité restante sous forme de fraction 0.0 à 1.0, ou nil si l'objet n'a pas de barre de durabilité.
item:use_durability(amount, can_break)
Met en file d'attente une réduction de la durabilité vanilla d'un montant fixe et retourne nil.
| Paramètre | Type | Défaut | Notes |
|---|---|---|---|
amount | int | requis | Combien de points de durabilité consommer |
can_break | boolean | false | Si true, l'objet est détruit lorsque la durabilité s'épuise. Si false, la durabilité s'arrête à 1. |
item:use_durability_percentage(fraction, can_break)
Met en file d'attente une réduction de la durabilité vanilla d'un pourcentage de son maximum et retourne nil.
| Paramètre | Type | Défaut | Notes |
|---|---|---|---|
fraction | number | requis | Fraction de la durabilité max à consommer (par ex. 0.1 = 10%) |
can_break | boolean | false | Si true, l'objet est détruit lorsque la durabilité s'épuise. Si false, la durabilité s'arrête à 1. |
context.event
Données d'événement pour le hook actuel. Disponible dans les hooks de clic, de combat, d'interaction et les hooks de zone génériques, pour les scripts de prop et d'objet. Retourne nil dans les hooks qui n'ont ni événement associé ni acteur joueur (on_spawn, on_game_tick, on_destroy, on_equip).
Les tables de référence des hooks ci-dessous nomment le type d'événement Bukkit sous-jacent à titre indicatif. Le wrapper Lua n'expose malgré tout que les champs et méthodes listés ici.
Champs et méthodes
| Champ ou méthode | Type | Notes |
|---|---|---|
event.player | player entity table | Le joueur qui a déclenché l'événement ou franchi la limite d'une zone générique surveillée. Disponible dans les hooks de prop on_left_click, on_right_click, on_zone_enter et on_zone_leave, ainsi que dans les hooks d'objet provoqués par un joueur. Voir Méthodes d'entité joueur pour tous les champs et méthodes. |
event.is_cancelled | boolean | L'état d'annulation au moment où le contexte a été construit. Ce champ n'est pas rafraîchi après un appel à cancel() ou uncancel(). |
event.cancel() | function | Annule l'événement (par ex. empêche les dégâts ou l'interaction) |
event.uncancel() | function | Dé-annule un événement précédemment annulé |
cancel et uncancel ignorent ce qu'on leur passe : context.event.cancel() et context.event:cancel() se comportent donc de façon identique. Les scripts pré-configurés livrés avec FMM utilisent la forme avec deux-points ; cette page utilise la forme avec point. Aucune n'est plus correcte que l'autre.
Tous les événements ne sont pas annulables. Si l'événement Bukkit sous-jacent n'implémente pas Cancellable, ou si le hook est un hook de zone générique sans événement Bukkit derrière lui, event.cancel() et event.uncancel() ne seront pas présents et event.is_cancelled sera toujours false.
Considérez event.is_cancelled comme un instantané de l'état initial. Si votre propre script appelle event.cancel() ou event.uncancel(), conservez votre propre indicateur local si vous avez besoin de vous souvenir de ce changement plus loin dans le même hook.
La table d'événement actuelle de FMM n'expose pas les champs spécifiques à Bukkit tels que target, block, projectile ou item. Utilisez context.player, context.event.player, player:get_target_entity(range), context.world:raycast(...) ou les requêtes d'entités proches lorsque vous avez besoin de contexte supplémentaire.
Exemple : rendre un prop invulnérable
Exemple
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Exemple : vérification de l'état d'annulation
Exemple
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
}
À l'intérieur des callbacks programmés (scheduler:run_later, scheduler:run_repeating), context.event est toujours nil. La modification d'événement ne peut se produire que pendant le hook d'événement lui-même.
context.world
Il s'agit de l'API world de FreeMinecraftModels/MagmaCore. Voir context.world pour la référence complète.
Toutes les méthodes documentées sur la page globale (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) sont disponibles dans FMM. Voir l'API world MagmaCore pour tous les détails sur world:raycast() (lance un rayon et détecte les entités/blocs touchés), world:place_temporary_block() (remplacement temporaire de bloc) et world:spawn_firework() (fait apparaître des fusées de feu d'artifice avec couleurs et formes personnalisées). Les pouvoirs de boss d'EliteMobs partent de la même base world et ajoutent des méthodes de table de location spécifiques aux boss pour faire apparaître des boss, des renforts, des blocs tombants, des blocs temporaires et plus encore ; voir EliteMobs Monde & Environnement.
Ajouts world spécifiques à FMM
FreeMinecraftModels superpose trois aides de butin EliteMobs optionnelles à context.world. Elles sont toujours présentes, mais chacune retourne false et ne fait rien lorsqu'EliteMobs n'est pas installé :
| Méthode | Notes |
|---|---|
world:drop_elitemobs_procedural_loot(player, level, location?) | Fait tomber un objet EliteMobs généré procéduralement pour le joueur. Retourne false lorsque les drops d'objets procéduraux sont désactivés |
world:drop_elitemobs_random_loot(player, level, location?) | Lance les tables de butin d'EliteMobs pour le joueur au niveau indiqué |
world:drop_elitemobs_custom_loot(player, file, level, location?) | Fait tomber un fichier d'objet personnalisé EliteMobs précis pour le joueur. Retourne false lorsque le fichier ne se résout pas |
Les signatures complètes se trouvent dans la Référence de l'API Lua. L'équivalent côté prop pour les boss est prop:spawn_elitemobs_boss(...), documenté ci-dessus.
Méthodes d'entité joueur
Les tables d'entité joueur sont retournées depuis context.player, context.event.player et context.world:get_nearby_players(). Les hooks MagmaCore génériques on_zone_enter / on_zone_leave définissent context.player et context.event.player sur le joueur qui entre ou qui sort.
Les tables d'entité, méthodes d'entité vivante, méthodes spécifiques aux joueurs et méthodes d'UI joueur documentées sur la page globale sont les tables MagmaCore utilisées par FMM. Les pouvoirs de boss d'EliteMobs exposent des tables d'entité similaires mais spécifiques aux boss, documentées dans Boss & Entités. Voir le moteur de scripting Lua MagmaCore pour la référence FMM complète couvrant les champs de base d'entité, les champs et méthodes d'entité vivante, les champs et méthodes spécifiques aux joueurs, et les méthodes d'UI joueur. Les nouvelles méthodes joueur incluent player:get_target_entity() (ciblage par raycast), player:get_eye_location(), player:get_look_direction(), player:send_block_change() (faux blocs par joueur) et player:reset_block() -- voir Méthodes spécifiques aux joueurs pour les détails.
Champs d'entité spécifiques à FMM
Chaque table d'entité construite à l'intérieur d'un script FMM obtient automatiquement ces champs supplémentaires (via le LuaEntityEnricher de FMM) :
| Champ | Type | Notes |
|---|---|---|
entity.is_modeled | boolean | true si cette entité Bukkit est l'entité sous-jacente d'un ModeledEntity |
entity.is_prop | boolean | true si cette entité est un armor stand supportant un PropEntity |
entity.model | table or nil | Renseigné uniquement lorsque is_modeled = true (voir ci-dessous) |
Lorsque entity.model est présent, il expose :
| Champ / Méthode | Notes |
|---|---|
model.model_id | Le nom de modèle blueprint (par ex. "dragon") |
model.is_dynamic | true s'il s'agit d'un DynamicEntity (attaché à une entité vivante) |
model:play_animation(name, blend, loop) | Joue une animation nommée. blend et loop valent false par défaut sur le pont de modèle d'entité. Retourne true en cas de succès |
model:stop_animations() | Arrête toutes les animations en cours |
model:remove() | Supprime immédiatement l'entité modélisée et tous ses os |
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
Champs d'entité EliteMobs
Lorsqu'EliteMobs est installé, FMM transfère à l'enricher d'EliteMobs afin que les mêmes tables d'entité exposent également :
| Champ | Type | Notes |
|---|---|---|
entity.is_elite | boolean | true si l'entité est suivie par EliteMobs |
entity.is_custom_boss | boolean | true s'il s'agit d'une configuration de boss personnalisé |
entity.is_significant_boss | boolean | true pour les boss personnalisés avec un healthMultiplier > 1 (filtre les mobs nommés sans importance) |
entity.elite | table or nil | Renseigné uniquement lorsque is_elite = true. Contient level, name, health, max_health, health_multiplier, damage_multiplier, is_custom_boss, plus elite:remove() |
context.zones
Il s'agit de l'API zones de FreeMinecraftModels/MagmaCore. Voir context.zones pour la référence complète. Les pouvoirs de boss d'EliteMobs utilisent une table context.zones différente, avec des définitions de zone natives d'EliteMobs ; voir EliteMobs Zones & Ciblage.
context.scheduler
L'API scheduler documentée ici est le scheduler MagmaCore utilisé par les scripts de FreeMinecraftModels et les scripts de PNJ d'EliteMobs. Les noms de style EliteMobs (run_after, run_every et cancel_task) sont des alias sur le scheduler partagé : les deux conventions de nommage fonctionnent donc. Les pouvoirs de boss exposent les mêmes alias via leur contexte spécifique aux boss. Voir context.scheduler pour la référence FMM complète.
context.state
L'API state est partagée par les scripts de FreeMinecraftModels, les pouvoirs de boss d'EliteMobs et les scripts de PNJ d'EliteMobs. Voir context.state pour la référence complète.
context.log
L'API de logging documentée ici est le logger de FreeMinecraftModels/MagmaCore (info, warn, error). Les scripts de PNJ d'EliteMobs utilisent le même logger ; les pouvoirs de boss d'EliteMobs exposent info, warn et debug. Voir context.log pour la référence complète.
context.cooldowns
L'API de cooldown documentée ici suit l'ordre partagé MagmaCore/FMM utilisé par les scripts de FreeMinecraftModels et les scripts de PNJ d'EliteMobs : check_local(key?, duration). Les pouvoirs de boss d'EliteMobs utilisent le même ordre d'arguments avec des stores de sauvegarde spécifiques aux boss. Voir context.cooldowns pour la référence complète.
| Méthode | Notes |
|---|---|
local_ready(key?) | Vérifie si un cooldown local est prêt. |
local_remaining(key?) | Retourne le nombre de ticks restants du cooldown local, ou 0. |
check_local(key?, duration) | Vérifie et démarre un cooldown local de façon atomique. |
set_local(duration, key?) | Définit un cooldown local sans vérification. |
global_ready() | Vérifie le cooldown global partagé du propriétaire du script. |
set_global(duration) | Définit le cooldown global partagé du propriétaire du script. |
Utilisez context.cooldowns:check_local("my_key", 40) pour les cooldowns d'action normaux de prop ou d'objet.
Modèle runtime
Un runtime par instance de script
Chaque entité prop qui a des scripts attachés obtient sa propre instance Lua runtime indépendante. Lorsque le prop apparaît, FMM charge la source Lua, l'évalue dans un environnement sandboxé frais, et stocke la table retournée. Lorsque le prop est retiré, le runtime est arrêté.
Pour les scripts d'objet, un runtime est créé par paire (joueur, itemId). Lorsqu'un joueur équipe un objet personnalisé, FMM crée une instance de script pour ce joueur et ce type d'objet. Lorsque l'objet est déséquipé, le runtime est arrêté.
Cela signifie :
- Les variables locales déclarées à l'échelle du fichier sont privées à cette instance de script.
context.stateest complètement isolé entre les instances, même si elles partagent le même fichier de script.
Propriété des tâches programmées
Toutes les tâches créées via context.scheduler appartiennent au runtime qui les a créées. Lorsqu'un prop est retiré :
- Le runtime est arrêté.
- Toute tâche possédée -- à coup unique et répétitive -- est automatiquement annulée.
- Toutes les surveillances de zone sont effacées.
Portée des cooldowns
Le moteur de scripting partagé expose des utilitaires de cooldown local (local_ready, local_remaining, check_local, set_local) et des utilitaires de cooldown global (global_ready, set_global). FMM délimite ces stores comme suit :
| Type de script | Portée du store local | Portée du store global |
|---|---|---|
| Script de prop | Par ScriptInstance (prop + fichier de script) | Par PropEntity (partagé entre tous les scripts liés à ce prop) |
| Script d'objet | Par triplet (player, itemId, scriptFile) — persiste à travers les réÉquipements même si l'instance de script est démontée à chaque fois que l'objet quitte un slot actif | Par joueur (partagé entre tous les scripts d'objet FMM que ce joueur exécute) |
Comme les scripts d'objet sont démontés et reconstruits à chaque cycle équipement/déséquipement, les cooldowns d'objet sont conservés dans une map statique indexée par UUID de joueur plutôt que de vivre sur le ScriptInstance. C'est pourquoi un cooldown d'objet s'applique toujours après que vous ayez échangé l'objet hors de la hotbar et de retour.
Cette persistance est limitée au runtime FMM courant. /fmm reload, la désactivation du plugin et le redémarrage du serveur effacent à la fois les stores de cooldown d'objet et les stores de cooldown global de prop lors de l'arrêt des gestionnaires de scripts.
Budget d'exécution
Chaque invocation de hook, chaque callback planifié et l'évaluation initiale du fichier de script lui-même s'exécutent sous un budget d'exécution strict. Le budget est appliqué à l'intérieur de la VM Lua, il s'applique donc pendant que votre code s'exécute encore plutôt que de se contenter de vérifier l'horloge après coup.
| Limite | Valeur |
|---|---|
| Temps CPU du thread courant | 50 millisecondes |
| Instructions Lua exécutées | 250 000 |
La première limite atteinte interrompt l'appel avec une erreur Lua et désactive l'instance de script. Les messages sont :
Lua instruction budget exceeded (250000 instruction limit)
Lua CPU-time budget exceeded (50ms current-thread CPU limit)
Comme la vérification a lieu à chaque instruction, un while true do end ne peut pas figer le serveur.
La partie temporelle du budget est mesurée en temps CPU du thread courant, et non en temps réel : un script n'est donc pas facturé pour le temps pendant lequel le thread serveur a été déprogrammé. Sur une JVM où la mesure du temps CPU du thread courant n'est pas disponible, MagmaCore retombe sur une limite délibérément plus généreuse de 250 millisecondes de temps écoulé (Lua elapsed-time fallback budget exceeded (250ms fallback; current-thread CPU time unavailable)) tout en conservant le même plafond de 250 000 instructions, de sorte que les scripts qui ne terminent pas restent bornés dans les deux cas.
Les appels imbriqués partagent un seul budget : si un hook invoque un callback qui en invoque un autre, toute la chaîne est mesurée comme une unique allocation de 50 ms de CPU / 250 000 instructions, et non une allocation chacun.
Pendant l'évaluation initiale d'un fichier de script, il n'existe pas encore d'instance : la définition est donc rejetée et jamais enregistrée, plutôt que désactivée.
Pour rester dans le budget :
- Évitez les boucles non bornées à l'intérieur des hooks.
- Gardez les gestionnaires
on_game_ticklégers -- ils s'exécutent chaque tick unique. - Utilisez
context.scheduler:run_repeating(...)pour répartir le travail sur les ticks.
Référence complète des hooks
Cette table liste tous les hooks disponibles à travers les scripts de prop et d'objet.
La colonne context.event décrit la famille d'événements Bukkit sous-jacente. Le wrapper d'événement Lua de FMM n'expose malgré tout que event.player, event.is_cancelled, event.cancel() et event.uncancel(), le cas échéant.
Hooks de prop actifs (7)
| Hook | Se déclenche quand | context.event |
|---|---|---|
on_spawn | Le prop apparaît dans le monde | nil |
on_game_tick | Chaque tick serveur (50ms) | nil |
on_destroy | Le prop est retiré | nil |
on_left_click | Le joueur clique gauche sur le prop | événement de dégâts |
on_right_click | Le joueur clique droit sur le prop | événement d'interaction |
on_zone_enter | Un joueur entre dans une zone surveillée | acteur joueur de zone (context.player / context.event.player ; non annulable) |
on_zone_leave | Un joueur quitte une zone surveillée | acteur joueur de zone (context.player / context.event.player ; non annulable) |
Le validateur de script actuel accepte on_projectile_hit pour les scripts de prop, mais le runtime actuel ne transmet pas encore les impacts de projectile aux scripts de prop. Utilisez le on_projectile_hit d'objet pour un comportement de projectile lié à un objet scripté, ou l'API Bukkit ModeledEntityHitByProjectileEvent pour gérer les projectiles sur les entités modélisées côté plugin.
Hooks d'objet (22)
| Hook | Catégorie | Se déclenche quand | context.event |
|---|---|---|---|
on_attack_entity | Combat | Le joueur attaque une entité | événement de dégâts |
on_kill_entity | Combat | Le joueur tue une entité | événement de mort |
on_take_damage | Combat | Le joueur subit des dégâts | événement de dégâts |
on_shield_block | Combat | Le joueur bloque avec bouclier | événement de dégâts |
on_shoot_bow | Combat | Le joueur tire à l'arc | événement de tir d'arc |
on_projectile_hit | Combat | Projectile du joueur touche | événement de coup de projectile |
on_projectile_launch | Combat | Le joueur lance un projectile | événement de lancement |
on_right_click | Interaction | Le joueur clique droit | événement d'interaction |
on_left_click | Interaction | Le joueur clique gauche | événement d'interaction |
on_shift_right_click | Interaction | Le joueur shift+clic droit | événement d'interaction |
on_shift_left_click | Interaction | Le joueur shift+clic gauche | événement d'interaction |
on_interact_entity | Interaction | Le joueur clique droit sur entité | événement d'interaction d'entité |
on_equip | Équipement | L'objet entre dans un slot actif | nil |
on_unequip | Équipement | L'objet quitte un slot actif | nil |
on_swap_hands | Équipement | Échange main principale/secondaire | événement d'échange |
on_drop | Équipement | Le joueur jette l'objet | événement de drop |
on_break_block | Utilité | Le joueur casse un bloc | événement de cassage de bloc |
on_consume | Utilité | Le joueur consomme l'objet | événement de consommation |
on_item_damage | Utilité | L'objet subit des dégâts de durabilité | événement de dégâts d'objet |
on_fish | Utilité | Le joueur utilise canne à pêche | événement de pêche |
on_death | Utilité | Le joueur meurt pendant qu'équipé | événement de mort |
on_game_tick | Cycle de vie | Chaque tick tant qu'équipé | nil |
Étapes suivantes
- Exemples et patterns -- scripts complets fonctionnels pour props et objets avec explications
- Dépannage -- problèmes courants, conseils de débogage et checklist QC
- Premiers pas -- structure de fichier, hooks, première marche pas à pas
/fmm reload annule les tâches et délais appartenant aux scripts avant leur reconstruction. Les tâches partagées comprennent run_after, run_every et cancel_task ; le monde fournit raycast, place_temporary_block et drop_item.