Saltar al contenido principal

Scripting Lua: Programas de Comportamiento

webapp_banner.jpg

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.

Seleccionar un programa

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 .lua dentro de cualquier carpeta llamada modules es un módulo. Cualquier otro archivo .lua es un programa.
  • Un jefe hace referencia a un programa por su ruta relativa a behaviors/, por ejemplo basic_melee.lua o guards/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> o Could not load behavior module <file> con el motivo.
  • Los ID de programas y módulos usan el espacio de nombres elitemobs, como elitemobs:behavior/basic_melee. Los ID van en minúsculas y pueden contener a-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
}
}
CampoTipoNotas
idstringObligatorio. ID con espacio de nombres, elitemobs:... para los archivos de behaviors/.
revisionentero positivoObligatorio.
modulesarray de stringsOpcional. 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, behaviorstablasOpcional. Un programa puede declarar los suyos, con el mismo formato que un módulo.
budgettablaLímites de planificación flexibles opcionales. Consulta Presupuestos.
runawaytablaLí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:

CampoTipoNotas
idstringObligatorio. ID de módulo con espacio de nombres.
revisionentero positivoObligatorio.
dependenciesarray de stringsOpcional. Otros ID de módulo que necesita este módulo.
memoriestablaOpcional. Consulta Memorias.
sensorsarrayOpcional. Entradas ai.sensor { ... }.
behaviorsarrayOpcional. 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'
}
TipoValor Lua
stringstring
booleanboolean
integernúmero entero
numbernúmero
uuidstring 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
}
CampoTipoPor defectoNotas
idstringObligatorio.
intervalentero positivo1Ticks entre ejecuciones.
sensefunciónObligatorio. 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
}
CampoTipoPor defectoNotas
idstringObligatorio.
priorityentero0Los números más bajos tienen preferencia.
controlsarrayningunoControles que este comportamiento reserva mientras se ejecuta.
can_startfunciónsiempre trueDebe devolver true o false.
can_continuefunciónigual que can_startDebe devolver true o false.
startfunciónningunaSe ejecuta una vez cuando empieza el comportamiento.
tickfunciónObligatorio. Se ejecuta cada tick mientras el comportamiento está activo.
stopfunciónningunafunction(c, reason); se ejecuta cuando el comportamiento se detiene.

Ciclo de vida​

  1. Mientras está detenido, el comportamiento comprueba can_start. Cuando devuelve true y el comportamiento puede reservar todos los controles declarados, se ejecuta start.
  2. En cada tick mientras está activo, incluido el tick en que empezó, se ejecuta primero can_continue. Si devuelve false, el comportamiento se detiene con el motivo completed; si no, se ejecuta tick.
  3. stop(c, reason) recibe uno de estos motivos: completed, preempted, program_replaced, entity_removed, callback_failed o handle_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​

ControlPermite
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_itemReservado; 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.

ClavePor defectoNotas
callback_micros2000Un callback que dura más que esto termina los callbacks del mob en ese tick.
entity_micros4000Tiempo total de callbacks por mob y tick.
server_micros20000Los callbacks del mob se detienen en ese tick cuando todos los programas Mind juntos han usado este tiempo.
max_callbacks128Callbacks por mob y tick.
max_action_requests8Solicitudes 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:

ClavePor defectoNotas
cpu_micros50000Tiempo de CPU del hilo por callback.
max_instructions50000Instrucciones 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​