Aller au contenu principal

Scripting Lua : Programmes de comportement

webapp_banner.jpg

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.

Choisir un programme

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 .lua placé dans n'importe quel dossier nommé modules est un module. Tout autre fichier .lua est un programme.
  • Un boss référence un programme par son chemin relatif à behaviors/, par exemple basic_melee.lua ou guards/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> ou Could not load behavior module <file> avec la raison.
  • Les ID de programme et de module utilisent l'espace de noms elitemobs, comme elitemobs:behavior/basic_melee. Les ID sont en minuscules et peuvent contenir a-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
}
}
ChampTypeRemarques
idchaîneObligatoire. ID avec espace de noms, elitemobs:... pour les fichiers de behaviors/.
revisionentier positifObligatoire.
modulestableau de chaînesFacultatif. 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, behaviorstablesFacultatif. Un programme peut déclarer les siens, au même format qu'un module.
budgettableFacultatif. Limites de planification souples. Voir Budgets.
runawaytableFacultatif. 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 :

ChampTypeRemarques
idchaîneObligatoire. ID de module avec espace de noms.
revisionentier positifObligatoire.
dependenciestableau de chaînesFacultatif. ID des autres modules dont ce module a besoin.
memoriestableFacultatif. Voir Mémoires.
sensorstableauFacultatif. Entrées ai.sensor { ... }.
behaviorstableauFacultatif. 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'
}
TypeValeur Lua
stringchaîne
booleanbooléen
integernombre entier
numbernombre
uuidchaî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
}
ChampTypeDéfautRemarques
idchaîneObligatoire.
intervalentier positif1Ticks entre deux exécutions.
sensefonctionObligatoire. 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
}
ChampTypeDéfautRemarques
idchaîneObligatoire.
priorityentier0Les nombres les plus bas sont prioritaires.
controlstableauaucunContrôles que ce comportement réserve pendant son exécution.
can_startfonctiontoujours trueDoit renvoyer true ou false.
can_continuefonctionidentique à can_startDoit renvoyer true ou false.
startfonctionaucunS'exécute une fois au démarrage du comportement.
tickfonctionObligatoire. S'exécute à chaque tick tant que le comportement est actif.
stopfonctionaucunfunction(c, reason) ; s'exécute à l'arrêt du comportement.

Cycle de vie​

  1. Tant qu'il est arrêté, le comportement vérifie can_start. Lorsque cette fonction renvoie true et que le comportement peut réserver chacun des contrôles déclarés, start s'exécute.
  2. À chaque tick d'exécution, y compris celui de son démarrage, can_continue s'exécute d'abord. Si elle renvoie false, le comportement s'arrête avec la raison completed ; sinon, tick s'exécute.
  3. stop(c, reason) reçoit l'une des raisons completed, preempted, program_replaced, entity_removed, callback_failed ou handle_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ôleAutorise
ai.controls.movec.actuator:move_to(...), c.actuator:stop_moving()
ai.controls.lookc.actuator:look_at(...)
ai.controls.jumpc.actuator:jump()
ai.controls.targetc.actuator:set_target(...), c.actuator:clear_target()
ai.controls.attackc.actuator:attack(...)
ai.controls.actionc.actions:request(...)
ai.controls.use_itemRé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éfautRemarques
callback_micros2000Un callback qui dure plus longtemps met fin aux callbacks du mob pour ce tick.
entity_micros4000Durée totale des callbacks par mob et par tick.
server_micros20000Les callbacks du mob s'arrêtent pour le tick une fois que l'ensemble des programmes Mind a utilisé ce temps.
max_callbacks128Callbacks par mob et par tick.
max_action_requests8Demandes 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éfautRemarques
cpu_micros50000Temps CPU du thread par callback.
max_instructions50000Instructions 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​