Scripting Lua : Programmes de comportement
Un programme de comportement remplace l'IA native d'un mob par des comportements Lua qui décident où il se déplace, ce qu'il regarde, quelle entité il cible et quand il attaque. EliteMobs exécute ces programmes sur le système Brain natif de Minecraft, via le runtime Mind de MagmaCore.
Les programmes de comportement ne sont pas des pouvoirs Lua. Un pouvoir Lua réagit aux événements du boss comme on_boss_damaged_by_player ; un programme de comportement s'exécute à chaque tick et contrôle les déplacements du mob. Un boss peut utiliser les deux : un comportement peut demander aux pouvoirs du boss d'effectuer une action via on_mind_action.
Définissez behavior dans un fichier de boss personnalisé, comme décrit dans Créer des Boss, ou dans le fichier de propriétés de mob du type d'entité. behavior: native conserve l'IA vanilla. Si la version du serveur ne prend pas en charge les Minds natifs, EliteMobs enregistre Native Mind interface is unavailable on this Minecraft version. au démarrage. Un boss personnalisé qui choisit un programme n'apparaît alors pas et enregistre Cannot spawn <boss file>: .... Un boss dont behavior désigne un programme absent ou invalide échoue de la même façon, quelle que soit la version.
Fichiers
Les fichiers de comportement se trouvent dans plugins/EliteMobs/behaviors/. EliteMobs écrit ces fichiers fournis lorsqu'ils sont absents :
plugins/
EliteMobs/
behaviors/
basic_melee.lua
modules/
target.lua
pursuit.lua
melee.lua
wander.lua
- Un fichier
.luaplacé dans n'importe quel dossier nommémodulesest un module. Tout autre fichier.luaest un programme. - Un boss référence un programme par son chemin relatif à
behaviors/, par exemplebasic_melee.luaouguards/patrol_guard.lua. - EliteMobs charge les fichiers de comportement au démarrage de son service Mind. Un fichier qui échoue à la validation est ignoré et la console enregistre
Could not load behavior <file>ouCould not load behavior module <file>avec la raison. - Les ID de programme et de module utilisent l'espace de noms
elitemobs, commeelitemobs:behavior/basic_melee. Les ID sont en minuscules et peuvent contenira-z,0-9,.,_et-, ainsi que/après les deux-points. Deux programmes ne peuvent pas partager un ID, et chaque ID de module doit être déclaré par un seul fichier. - Un espace de noms contient au maximum 256 modules. Un module peut lister au maximum 32 dépendances, un programme peut résoudre au maximum 64 modules, et chaque fichier source est limité à 1 000 000 caractères.
Les mêmes règles de sandbox que pour les autres scripts Lua s'appliquent. Consultez la Sandbox Lua. Chaque mob qui exécute un programme reçoit son propre environnement Lua : les variables locales au fichier ne sont donc pas partagées entre les mobs.
Fichier de programme
Un fichier de programme renvoie ai.program { ... } :
return ai.program {
id = 'elitemobs:behavior/basic_melee', revision = 1,
modules = {
'elitemobs:behavior/target', 'elitemobs:behavior/pursuit',
'elitemobs:behavior/melee', 'elitemobs:behavior/wander'
},
budget = {
callback_micros = 2000, entity_micros = 4000, server_micros = 5000,
max_callbacks = 20, max_instructions = 12000, max_action_requests = 2
}
}
| Champ | Type | Remarques |
|---|---|---|
id | chaîne | Obligatoire. ID avec espace de noms, elitemobs:... pour les fichiers de behaviors/. |
revision | entier positif | Obligatoire. |
modules | tableau de chaînes | Facultatif. ID des modules dont les mémoires, capteurs et comportements rejoignent le programme. Les dépendances se chargent avant les modules qui en ont besoin. Les doublons et les cycles de dépendances sont rejetés. |
memories, sensors, behaviors | tables | Facultatif. Un programme peut déclarer les siens, au même format qu'un module. |
budget | table | Facultatif. Limites de planification souples. Voir Budgets. |
runaway | table | Facultatif. Limites strictes par callback. Voir Budgets. |
Fichier de module
Un fichier de module renvoie ai.module { ... } et regroupe des mémoires, capteurs et comportements réutilisables :
| Champ | Type | Remarques |
|---|---|---|
id | chaîne | Obligatoire. ID de module avec espace de noms. |
revision | entier positif | Obligatoire. |
dependencies | tableau de chaînes | Facultatif. ID des autres modules dont ce module a besoin. |
memories | table | Facultatif. Voir Mémoires. |
sensors | tableau | Facultatif. Entrées ai.sensor { ... }. |
behaviors | tableau | Facultatif. Entrées ai.behavior { ... }. |
sensors, behaviors, modules et dependencies doivent être de simples tableaux, sans trous ni clés nommées. Les noms de capteurs, de comportements et de mémoires doivent être uniques dans l'ensemble des modules d'un programme.
Mémoires
Les mémoires sont des valeurs typées que les capteurs et comportements partagent pour un même mob. Déclarez chacune par son nom :
memories = {
candidate = { type = 'uuid', persistent = false },
next_attack = 'integer'
}
| Type | Valeur Lua |
|---|---|
string | chaîne |
boolean | booléen |
integer | nombre entier |
number | nombre |
uuid | chaîne UUID |
position | { world = 'world', x = 0, y = 64, z = 0 } |
Un nom sans deux-points est placé dans l'espace de noms du programme. persistent vaut false par défaut ; true marque la mémoire pour qu'elle soit sérialisée avec l'état sauvegardé du Mind. Lisez et écrivez les mémoires avec c.memory:get(name), c.memory:set(name, value, ttl_ticks), c.memory:forget(name) et c.memory:contains(name). Le troisième argument de set est facultatif ; s'il est fourni, la valeur expire après ce nombre de ticks. Utiliser un nom non déclaré lève une erreur.
Capteurs
Un capteur recueille des informations, généralement dans des mémoires. Les capteurs s'exécutent avant les comportements.
ai.sensor {
id = 'elitemobs:behavior/find_target', interval = 20,
sense = function(c)
local target = c.perception:nearest_player(35)
if target then c.memory:set('candidate', target.uuid, 21)
else c.memory:forget('candidate') end
end
}
| Champ | Type | Défaut | Remarques |
|---|---|---|---|
id | chaîne | Obligatoire. | |
interval | entier positif | 1 | Ticks entre deux exécutions. |
sense | fonction | Obligatoire. Reçoit le contexte Mind. |
Les capteurs ne peuvent pas utiliser c.actuator ; appeler une méthode d'actionneur depuis un capteur lève une erreur.
Comportements
Un comportement agit sur le mob tant qu'il détient les contrôles qu'il déclare.
ai.behavior {
id = 'elitemobs:behavior/attack', priority = 10,
controls = { ai.controls.attack },
can_start = function(c) return c.perception:current_target() ~= nil end,
can_continue = function(c) return c.perception:current_target() ~= nil end,
tick = function(c)
local target = c.perception:current_target()
if target then c.actuator:attack(target) end
end
}
| Champ | Type | Défaut | Remarques |
|---|---|---|---|
id | chaîne | Obligatoire. | |
priority | entier | 0 | Les nombres les plus bas sont prioritaires. |
controls | tableau | aucun | Contrôles que ce comportement réserve pendant son exécution. |
can_start | fonction | toujours true | Doit renvoyer true ou false. |
can_continue | fonction | identique à can_start | Doit renvoyer true ou false. |
start | fonction | aucun | S'exécute une fois au démarrage du comportement. |
tick | fonction | Obligatoire. S'exécute à chaque tick tant que le comportement est actif. | |
stop | fonction | aucun | function(c, reason) ; s'exécute à l'arrêt du comportement. |
Cycle de vie
- Tant qu'il est arrêté, le comportement vérifie
can_start. Lorsque cette fonction renvoietrueet que le comportement peut réserver chacun des contrôles déclarés,starts'exécute. - À chaque tick d'exécution, y compris celui de son démarrage,
can_continues'exécute d'abord. Si elle renvoiefalse, le comportement s'arrête avec la raisoncompleted; sinon,ticks'exécute. stop(c, reason)reçoit l'une des raisonscompleted,preempted,program_replaced,entity_removed,callback_failedouhandle_closed. L'arrêt libère les contrôles du comportement et interrompt le déplacement, la cible ou l'attaque qu'il détenait.
Une erreur Lua dans can_continue, start ou tick arrête le comportement avec callback_failed. Renvoyer autre chose qu'un booléen depuis can_start ou can_continue est une erreur. La console enregistre Mind <program> callback <callback> failed with ... pour chaque échec.
Contrôles
| Contrôle | Autorise |
|---|---|
ai.controls.move | c.actuator:move_to(...), c.actuator:stop_moving() |
ai.controls.look | c.actuator:look_at(...) |
ai.controls.jump | c.actuator:jump() |
ai.controls.target | c.actuator:set_target(...), c.actuator:clear_target() |
ai.controls.attack | c.actuator:attack(...) |
ai.controls.action | c.actions:request(...) |
ai.controls.use_item | Réservé ; l'actionneur Lua n'a pas de méthode pour les objets. |
Chaque contrôle appartient à un seul comportement actif à la fois. Un comportement dont le nombre priority est plus bas prend un contrôle à un comportement dont le nombre est plus élevé, qui s'arrête avec la raison preempted. Il ne peut pas prendre un contrôle détenu par un comportement dont le nombre est plus bas. À priorité égale, le comportement dont l'id vient en premier dans l'ordre alphabétique obtient le contrôle. Appeler une méthode d'actionneur sans détenir son contrôle lève une erreur. c.actuator:stop_all() n'arrête que ce que le comportement détient.
Dans les modules fournis, la sélection de cible utilise la priorité 5, les attaques de mêlée 10, la poursuite 20 et l'errance au repos 50 : la poursuite prend donc le déplacement à l'errance dès qu'une cible existe.
Demander des actions au boss
Un comportement qui détient ai.controls.action peut appeler c.actions:request(identifier, payload). EliteMobs envoie la demande aux pouvoirs Lua du boss via on_mind_action. L'identifiant doit être une clé en minuscules avec espace de noms, de 128 caractères au maximum, comme 'elitemobs:slam'. La charge utile contient au maximum 16 entrées, avec des clés en minuscules de 64 caractères au maximum, et les valeurs de type chaîne sont limitées à 256 caractères ; un identifiant ou une charge utile invalide lève une erreur. L'appel renvoie accepted, deferred ou rejected ; les demandes qui dépassent le max_action_requests du programme dans un même tick renvoient deferred. Consultez le contexte d'action Mind pour le format de la charge utile.
Budgets
budget définit des limites de planification souples. Lorsqu'un mob atteint l'une d'elles pendant un tick, le runtime Mind ignore les callbacks restants de ce mob jusqu'au tick suivant. Un callback déjà en cours se termine toujours.
| Clé | Défaut | Remarques |
|---|---|---|
callback_micros | 2000 | Un callback qui dure plus longtemps met fin aux callbacks du mob pour ce tick. |
entity_micros | 4000 | Durée totale des callbacks par mob et par tick. |
server_micros | 20000 | Les callbacks du mob s'arrêtent pour le tick une fois que l'ensemble des programmes Mind a utilisé ce temps. |
max_callbacks | 128 | Callbacks par mob et par tick. |
max_action_requests | 8 | Demandes d'action par mob et par tick ; au maximum 64. |
Toutes les valeurs doivent être positives, et callback_micros ne peut pas dépasser entity_micros, qui ne peut pas dépasser server_micros.
runaway définit des limites strictes qui interrompent un callback :
| Clé | Défaut | Remarques |
|---|---|---|
cpu_micros | 50000 | Temps CPU du thread par callback. |
max_instructions | 50000 | Instructions Lua par callback. |
budget accepte aussi max_instructions, comme dans le fichier fourni basic_melee.lua. Déclarez-le dans budget ou dans runaway, pas dans les deux. Un callback qui dépasse une limite runaway échoue comme toute autre erreur de callback.
Étapes suivantes
- Créer des Boss : behavior -- choisir un programme pour un boss
- Référence de l'API Lua : contexte d'un programme Mind -- toutes les méthodes de
c.memory,c.perception,c.actuatoretc.actions - Hooks et Cycle de Vie --
on_mind_actionet les autres hooks des pouvoirs Lua
