Scripting Lua: Programas de Comportamiento
Un programa de comportamiento sustituye la IA nativa de un mob por comportamientos Lua que deciden hacia dónde se mueve, qué mira, a qué entidad apunta y cuándo ataca. EliteMobs ejecuta estos programas sobre el sistema Brain nativo de Minecraft mediante el runtime Mind de MagmaCore.
Los programas de comportamiento no son poderes Lua. Un poder Lua reacciona a eventos del jefe como on_boss_damaged_by_player; un programa de comportamiento se ejecuta cada tick y controla el movimiento del mob. Un jefe puede usar ambos: un comportamiento puede pedir a los poderes del jefe que realicen una acción mediante on_mind_action.
Define behavior en un archivo de jefe personalizado, como se describe en Crear jefes, o en el archivo de propiedades de mob del tipo de entidad. behavior: native conserva la IA vanilla. Si la versión del servidor no admite Mind nativo, EliteMobs registra Native Mind interface is unavailable on this Minecraft version. al arrancar. En ese caso, un jefe personalizado que selecciona un programa no aparece y registra Cannot spawn <boss file>: .... Un jefe cuyo behavior indica un programa inexistente o no válido falla de la misma forma en cualquier versión.
Archivos
Los archivos de comportamiento se guardan en plugins/EliteMobs/behaviors/. EliteMobs escribe estos archivos incluidos cuando faltan:
plugins/
EliteMobs/
behaviors/
basic_melee.lua
modules/
target.lua
pursuit.lua
melee.lua
wander.lua
- Un archivo
.luadentro de cualquier carpeta llamadamoduleses un módulo. Cualquier otro archivo.luaes un programa. - Un jefe hace referencia a un programa por su ruta relativa a
behaviors/, por ejemplobasic_melee.luaoguards/patrol_guard.lua. - EliteMobs carga los archivos de comportamiento cuando se inicia su servicio Mind. Un archivo que no supera la validación se omite y la consola registra
Could not load behavior <file>oCould not load behavior module <file>con el motivo. - Los ID de programas y módulos usan el espacio de nombres
elitemobs, comoelitemobs:behavior/basic_melee. Los ID van en minúsculas y pueden contenera-z,0-9,.,_y-, además de/después de los dos puntos. Dos programas no pueden compartir un ID, y cada ID de módulo debe declararlo un solo archivo. - Un espacio de nombres admite como máximo 256 módulos. Un módulo puede indicar como máximo 32 dependencias, un programa puede resolver como máximo 64 módulos y cada archivo fuente está limitado a 1.000.000 de caracteres.
Se aplican las mismas reglas de sandbox que en los demás scripts Lua. Consulta el Sandbox de Lua. Cada mob que ejecuta un programa recibe su propio entorno Lua, así que las variables locales del archivo no se comparten entre mobs.
Archivo de programa
Un archivo de programa devuelve 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
}
}
| Campo | Tipo | Notas |
|---|---|---|
id | string | Obligatorio. ID con espacio de nombres, elitemobs:... para los archivos de behaviors/. |
revision | entero positivo | Obligatorio. |
modules | array de strings | Opcional. ID de módulos cuyas memorias, sensores y comportamientos se incorporan al programa. Las dependencias se cargan antes que los módulos que las necesitan. Se rechazan los duplicados y los ciclos de dependencias. |
memories, sensors, behaviors | tablas | Opcional. Un programa puede declarar los suyos, con el mismo formato que un módulo. |
budget | tabla | Límites de planificación flexibles opcionales. Consulta Presupuestos. |
runaway | tabla | Límites estrictos opcionales por callback. Consulta Presupuestos. |
Archivo de módulo
Un archivo de módulo devuelve ai.module { ... } y agrupa memorias, sensores y comportamientos reutilizables:
| Campo | Tipo | Notas |
|---|---|---|
id | string | Obligatorio. ID de módulo con espacio de nombres. |
revision | entero positivo | Obligatorio. |
dependencies | array de strings | Opcional. Otros ID de módulo que necesita este módulo. |
memories | tabla | Opcional. Consulta Memorias. |
sensors | array | Opcional. Entradas ai.sensor { ... }. |
behaviors | array | Opcional. Entradas ai.behavior { ... }. |
sensors, behaviors, modules y dependencies deben ser arrays simples, sin huecos ni claves con nombre. Los nombres de sensores, comportamientos y memorias deben ser únicos en todos los módulos de un programa.
Memorias
Las memorias son valores con tipo que los sensores y comportamientos comparten para un mob. Declara cada una por su nombre:
memories = {
candidate = { type = 'uuid', persistent = false },
next_attack = 'integer'
}
| Tipo | Valor Lua |
|---|---|
string | string |
boolean | boolean |
integer | número entero |
number | número |
uuid | string de UUID |
position | { world = 'world', x = 0, y = 64, z = 0 } |
Un nombre sin dos puntos se coloca en el espacio de nombres del programa. persistent vale false por defecto; true marca la memoria para serializarla con el estado guardado del Mind. Lee y escribe memorias mediante c.memory:get(name), c.memory:set(name, value, ttl_ticks), c.memory:forget(name) y c.memory:contains(name). El tercer argumento de set es opcional; si se indica, el valor caduca después de ese número de ticks. Usar un nombre no declarado provoca un error.
Sensores
Un sensor recopila información, normalmente en memorias. Los sensores se ejecutan antes que los comportamientos.
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
}
| Campo | Tipo | Por defecto | Notas |
|---|---|---|---|
id | string | Obligatorio. | |
interval | entero positivo | 1 | Ticks entre ejecuciones. |
sense | función | Obligatorio. Recibe el contexto Mind. |
Los sensores no pueden usar c.actuator; llamar a un método del actuador desde un sensor provoca un error.
Comportamientos
Un comportamiento actúa sobre el mob mientras posee los controles que declara.
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
}
| Campo | Tipo | Por defecto | Notas |
|---|---|---|---|
id | string | Obligatorio. | |
priority | entero | 0 | Los números más bajos tienen preferencia. |
controls | array | ninguno | Controles que este comportamiento reserva mientras se ejecuta. |
can_start | función | siempre true | Debe devolver true o false. |
can_continue | función | igual que can_start | Debe devolver true o false. |
start | función | ninguna | Se ejecuta una vez cuando empieza el comportamiento. |
tick | función | Obligatorio. Se ejecuta cada tick mientras el comportamiento está activo. | |
stop | función | ninguna | function(c, reason); se ejecuta cuando el comportamiento se detiene. |
Ciclo de vida
- Mientras está detenido, el comportamiento comprueba
can_start. Cuando devuelvetruey el comportamiento puede reservar todos los controles declarados, se ejecutastart. - En cada tick mientras está activo, incluido el tick en que empezó, se ejecuta primero
can_continue. Si devuelvefalse, el comportamiento se detiene con el motivocompleted; si no, se ejecutatick. stop(c, reason)recibe uno de estos motivos:completed,preempted,program_replaced,entity_removed,callback_failedohandle_closed. Al detenerse, el comportamiento libera sus controles y detiene el movimiento, el objetivo o el ataque que tenía.
Un error de Lua en can_continue, start o tick detiene el comportamiento con callback_failed. Devolver algo que no sea un booleano desde can_start o can_continue es un error. La consola registra Mind <program> callback <callback> failed with ... para cada fallo.
Controles
| Control | Permite |
|---|---|
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 | Reservado; el actuador Lua no tiene ningún método de objetos. |
Cada control pertenece a un solo comportamiento activo a la vez. Un comportamiento con un número de priority más bajo quita un control a un comportamiento con un número más alto, que se detiene con el motivo preempted. No puede quitar un control que tenga un comportamiento con un número más bajo. Entre prioridades iguales, se queda el control el comportamiento cuyo id va primero en orden alfabético. Llamar a un método del actuador sin tener su control provoca un error. c.actuator:stop_all() solo detiene lo que controla el comportamiento.
En los módulos incluidos, la selección de objetivo usa prioridad 5, los ataques cuerpo a cuerpo 10, la persecución 20 y la deambulación en reposo 50, así que la persecución toma el movimiento de la deambulación en cuanto existe un objetivo.
Solicitar acciones del jefe
Un comportamiento que tiene ai.controls.action puede llamar a c.actions:request(identifier, payload). EliteMobs envía la solicitud a los poderes Lua del jefe mediante on_mind_action. El identificador debe ser una clave en minúsculas con espacio de nombres de 128 caracteres como máximo, como 'elitemobs:slam'. Los datos admiten como máximo 16 entradas con claves en minúsculas de 64 caracteres como máximo, y los valores de texto están limitados a 256 caracteres; un identificador o unos datos no válidos provocan un error. La llamada devuelve accepted, deferred o rejected; las solicitudes que superan el max_action_requests del programa en un mismo tick devuelven deferred. Consulta el contexto de acción Mind para ver el formato de los datos.
Presupuestos
budget establece límites de planificación flexibles. Cuando un mob alcanza uno en un tick, el runtime Mind omite los callbacks restantes de ese mob hasta el siguiente tick. Un callback que ya está en ejecución siempre termina.
| Clave | Por defecto | Notas |
|---|---|---|
callback_micros | 2000 | Un callback que dura más que esto termina los callbacks del mob en ese tick. |
entity_micros | 4000 | Tiempo total de callbacks por mob y tick. |
server_micros | 20000 | Los callbacks del mob se detienen en ese tick cuando todos los programas Mind juntos han usado este tiempo. |
max_callbacks | 128 | Callbacks por mob y tick. |
max_action_requests | 8 | Solicitudes de acción por mob y tick; como máximo 64. |
Todos los valores deben ser positivos, y callback_micros no puede superar entity_micros, que a su vez no puede superar server_micros.
runaway establece límites estrictos que interrumpen un solo callback:
| Clave | Por defecto | Notas |
|---|---|---|
cpu_micros | 50000 | Tiempo de CPU del hilo por callback. |
max_instructions | 50000 | Instrucciones Lua por callback. |
budget también acepta max_instructions, como en el basic_melee.lua incluido. Decláralo en budget o en runaway, no en ambos. Un callback que supera un límite de runaway falla como cualquier otro error de callback.
Próximos pasos
- Crear jefes: behavior -- seleccionar un programa para un jefe
- Referencia de la API de Lua: contexto de un programa Mind -- todos los métodos de
c.memory,c.perception,c.actuatoryc.actions - Hooks y Ciclo de Vida --
on_mind_actiony los demás hooks de poderes Lua
