Saltar al contenido principal

Módulos de comportamiento de mascotas

Un módulo de comportamiento de mascota es un archivo Lua que le dice a las mascotas qué hacer: seguir a su dueño, desplazarse a la deriva, rodear una hoguera, picar. Cada archivo de especie de mascota lista los módulos que ejecutan sus mascotas y les da ajustes. Esta página es para los autores de criaturas que quieren cambiar un módulo o escribir uno nuevo. Para usar y ajustar los módulos incluidos, consulta Mascotas.

Los módulos usan el mismo dialecto de Lua que los programas de comportamiento de EliteMobs: ai.module, ai.behavior, ai.sensor, ai.controls, memorias con tipo y el contexto c.memory, c.perception, c.actuator y c.entity. Esa página cubre las reglas compartidas. Esta cubre lo que añaden las mascotas: los archivos de módulo, c.pet, c.settings y los límites bajo los que se ejecutan las mascotas.

Archivos​

  • Los módulos viven en plugins/FreeMinecraftModels/pet_behaviors/, en esa carpeta o en cualquier subcarpeta. Todo archivo .lua que haya allí es un módulo.
  • El nombre de un módulo es el nombre de su archivo sin .lua, en minúsculas. Solo puede usar letras, dígitos, ., _ y -. Los archivos de mascota listan los módulos por este nombre.
  • El id de un módulo debe ser fmm:pet/ seguido de su nombre, así que pet_behaviors/mine/slow_drift.lua declara id = 'fmm:pet/slow_drift'. Un módulo cuyo id no coincide con el nombre de su archivo se omite con una advertencia.
  • Cuando dos archivos comparten nombre, se carga aquel cuya ruta va primero en orden, y la consola avisa con Duplicate content filename sobre el otro. Una copia idéntica byte a byte se omite sin avisar.
  • Un archivo o carpeta que enlaza fuera de pet_behaviors/ se omite.
  • FreeMinecraftModels escribe cada uno de sus 15 módulos incluidos cuando no existe ningún archivo con ese nombre en ninguna parte de la carpeta. Uno eliminado vuelve en la siguiente carga con la versión incluida actual. Un archivo que ya está allí nunca se sobrescribe, esté editado o no, ni siquiera después de moverlo a una subcarpeta, así que conserva tus cambios, pero también pierde las actualizaciones posteriores del módulo incluido.
  • /fmm reload vuelve a leer todos los módulos y archivos de mascota, guarda las mascotas y las devuelve con los módulos nuevos. Sus memorias empiezan vacías. No necesitas subir la revision de un módulo después de editarlo.

Empieza desde una copia​

Los módulos incluidos son los mejores ejemplos: drift.lua mueve a una voladora, wander.lua camina, night_glow.lua es un único sensor y sting.lua tiene dos. Empieza por el más cercano a lo que quieres.

  1. Cópialo con un nombre nuevo, por ejemplo pet_behaviors/mine/slow_drift.lua a partir de drift.lua.
  2. Cambia su id a fmm:pet/slow_drift.
  3. Renombra sus memorias, comportamientos y sensores para que empiecen por el nombre nuevo: drift_to pasa a ser slow_drift_to, en memories y en todas las llamadas a c.memory, y el id = 'fmm:pet/drift' del comportamiento pasa a ser fmm:pet/slow_drift. Dos módulos de una misma criatura no pueden compartir un nombre de memoria, un id de comportamiento ni un id de sensor; el segundo de la lista se deja fuera con una advertencia. Renombrar permite que la copia se ejecute junto al original.
  4. Lístalo en el archivo de mascota en lugar del original: - slow_drift, o con ajustes, - slow_drift: { speed: 0.03 }.
  5. Ejecuta /fmm reload y revisa la consola.

Editar un módulo incluido en su sitio también funciona, pero cambia todas las especies que lo listan.

Un archivo de módulo​

Este módulo es pequeño pero completo. Por la noche la mascota se queda en un punto cercano a su ancla en lugar de desplazarse a la deriva, y cada 10 segundos desde el momento en que elige ese punto, reproduce una animación.

-- At night: settles on one spot near its anchor (its owner, or home when wild) and plays an animation now and then.
return ai.module {
id = 'fmm:pet/night_rest', revision = 1,
-- radius: blocks around the anchor. speed: blocks per tick for a flyer, at species speed 1.
settings = { radius = 3, speed = 0.04, animation = 'interact' },
memories = { night_rest_to = 'position', night_rest_retry = 'integer' },
behaviors = {
ai.behavior {
id = 'fmm:pet/night_rest', priority = 12, probe_interval = 10,
controls = { ai.controls.move, ai.controls.look },
can_start = function(c)
return c.pet.night and not c.pet.staying and c.pet.anchor ~= nil
and c.tick >= (c.memory:get('night_rest_retry') or 0)
end,
can_continue = function(c)
return c.pet.night and not c.pet.staying and c.memory:contains('night_rest_to')
end,
start = function(c)
local anchor = c.pet.anchor
local to = anchor and c.pet:rest_point(anchor, c.settings.radius)
if to ~= nil then
c.memory:set('night_rest_to', to)
else
-- Nothing fits here: look again in 5 seconds instead of every tick.
c.memory:set('night_rest_retry', c.tick + 100)
end
end,
tick = function(c)
local to = c.memory:get('night_rest_to')
if to ~= nil then c.pet:steer_to(to, c.settings.speed * c.pet.species.speed) end
end,
stop = function(c)
c.memory:forget('night_rest_to')
c.pet:stop()
end
}
},
sensors = {
ai.sensor {
id = 'fmm:pet/night_rest_animation', interval = 200,
sense = function(c)
if c.memory:contains('night_rest_to') then c.pet:play_animation(c.settings.animation) end
end
}
}
}

Un archivo de mascota lo lista entonces como - night_rest, o - night_rest: { radius: 5, animation: idle }.

CampoNotas
idObligatorio. fmm:pet/ y el nombre del archivo
revisionObligatorio. Cualquier número entero positivo
settingsOpcional. Los valores predeterminados que los archivos de mascota pueden cambiar. El tipo de cada valor predeterminado es el tipo que debe dar un archivo de mascota: un número, true/false, texto o una lista de textos. Consulta Valores de los ajustes
memoriesOpcional. Lo que el módulo recuerda para cada mascota, por nombre y tipo: integer, number, boolean, string, uuid o position. Empieza cada nombre con el nombre del módulo. Consulta Memorias
dependenciesOpcional. Ids de otros módulos de pet_behaviors/ que necesita este. Se ejecutan en todas las criaturas que listan este, con sus ajustes predeterminados salvo que el archivo de mascota también los liste
behaviorsOpcional. Entradas ai.behavior { ... }, que mueven o giran a la mascota
sensorsOpcional. Entradas ai.sensor { ... }, que nunca mueven a la mascota

Se permite código por encima de return, como funciones locales y constantes; wander.lua e idle_look.lua tienen algo.

Qué recibe un callback​

NombreQué es
c.petLa mascota, de solo lectura. Consulta c.pet
c.settingsLos ajustes de este módulo: sus valores predeterminados con los valores del archivo de mascota y de la variante por encima, como en c.settings.radius. Cada mascota tiene su propia copia, así que escribir en ella solo cambia a esa mascota
c.memoryget(name), set(name, value), forget(name) y contains(name) para los nombres de memories. Cada mascota tiene la suya
c.tickEl tick actual del juego, para temporizadores
c.perception, c.actuator, c.entityEl contexto Mind de MagmaCore, como en los programas de comportamiento de EliteMobs. c.entity es el cuerpo oculto, no el modelo. Consulta Contexto de un programa Mind. idle_look.lua usa c.perception:nearest_player(range) y c.actuator:look_at(point)

c.pet​

Un punto es una tabla con x, y y z, y opcionalmente world, como c.pet.position. Un punto sin world está en el mundo de la mascota. Un punto en otro mundo cuenta como nada: los métodos responden nil, false o 0, y distance_to responde math.huge. Los puntos que devuelve c.pet siempre están en el mundo de la mascota, y uno que estaría en otro mundo se lee como nil.

  • Los métodos se llaman con dos puntos: c.pet:distance_to(point).
  • Los argumentos numéricos deben ser finitos. Los radios, profundidades, alturas, amplificadores, duraciones y demás rangos están limitados como se indica a continuación. Ningún método carga un chunk.
  • c.pet y c.pet.species son de solo lectura. Asignarles algo provoca un error; guarda los valores por mascota en c.memory.
  • Las propiedades y route_target() son una instantánea: cada una se lee una vez por tick de la mascota y permanece igual durante todos los callbacks de ese tick. c.pet:teleport_near_owner y c.pet:stop las actualizan. Un movimiento hecho de otra forma, como c.entity:teleport, se ve en el siguiente tick. speed es la excepción y siempre se lee de nuevo.
  • Cada lectura de una ubicación da una tabla nueva, que el módulo puede modificar.

Propiedades​

NombreTipoValor
wildbooltrue para una mascota salvaje, false para una con dueño
stayingboolCon la orden de quedarse
settledboolSin la orden de quedarse, y salvaje o a menos de follow.distance de su dueño
babyboolEs una cría
migratingboolVolando una ruta de migración nocturna
modelstringEl modelo de su variante. Una cría que lleva babyModel sigue leyendo su variante
positionpointDónde está su cuerpo
homepoint/nilDónde vive una mascota salvaje; nil para una mascota con dueño
anchorpoint/nilAquello alrededor de lo que merodea: su dueño, o en una mascota salvaje su hogar, o el lugar donde está cuando no tiene hogar. nil cuando el dueño está desconectado o en otro mundo
stay_anchorpoint/nilEl punto donde se le ordenó quedarse; nil cuando no tiene la orden de quedarse
owner_locationpoint/nilnil para una mascota salvaje, o cuando el dueño está desconectado, muerto o en otro mundo
owner_distancenumberBloques hasta el dueño; math.huge cuando no hay ninguno en este mundo
night, dayboolday solo con luz diurna en un mundo normal; el anochecer, el amanecer, el Nether y el End cuentan como night
rainingboolLa lluvia cae sobre la mascota, comprobado como máximo cada 10 ticks
speednumberLa velocidad actual de su cuerpo, en bloques por tick
route_cruisenumberLa velocidad de crucero de su bandada en una migración, y 0 en caso contrario
speciestableLos números del archivo de la mascota, a continuación

c.pet.species contiene:

CampoClave del archivo de mascota
idspecies
speedfollow.speed
hover_heightfloat.hoverHeight
hover_variancefloat.hoverVariance
roam_radiusfollow.roamRadius
follow_distancefollow.distance
leash_distancefollow.leashDistance
teleport_distancefollow.teleportDistance
scalescale
baby_scalebabyScale

Movimiento​

Llama a estos métodos solo desde start, tick o stop de un comportamiento, en un comportamiento cuyos controls listen lo que necesitan. Desde can_start o desde un sensor, steer_to y stop provocan un error que indica dónde les corresponde estar.

MétodoDevuelveQué hace
steer_to(point, cruise)boolAvanza un tick hacia el punto, así que llámalo en cada tick. Necesita move y look. Una voladora vuela a cruise bloques por tick (0 a 4), frenando al llegar. Una caminante o nadadora busca una ruta hasta allí con la navegación nativa a 4 × cruise veces la velocidad de movimiento de su tipo de cuerpo, nunca por debajo de una cuarta parte de ella; un cruise de 0 la detiene y devuelve false. false cuando no puede ir allí
stop()nilDeja de moverse. Necesita move
teleport_near_owner(radius)boolColoca el cuerpo junto a su dueño, a menos de radius bloques (hasta 64), en su propio medio; para una nadadora, el agua se busca en un radio de al menos 6 bloques. Una caminante o nadadora cae al menos a un bloque del dueño. false cuando el dueño está ausente o en otro mundo, no hay ningún punto válido, o el punto no queda al menos un bloque más cerca del dueño de lo que ya está la mascota. No necesita ningún control, pero llámalo desde un comportamiento que tenga move, como hace follow_owner, para que no aparte a la mascota de otro comportamiento

Puntos y distancias​

Estos funcionan desde cualquier callback. Los que devuelven un punto devuelven nil cuando no hay ningún punto válido o el chunk no está cargado. Los radios llegan hasta 64.

MétodoDevuelveQué hace
hover_point(center, radius)point/nilUn punto de su banda de flotación a menos de radius
rest_point(center, radius)point/nilUn punto de descanso en su propio medio: la banda de flotación para una voladora, suelo firme para una caminante o un cuerpo estacionario, agua para una nadadora (a la altura de center cuando center está en el agua, y si no entre 0,5 y 2 bloques bajo la superficie), y suelo o si no agua para un cuerpo anfibio
ground_point(center, radius)point/nilUn punto de apoyo, desde unos 5 bloques por debajo hasta 4 por encima de center. nil sobre un líquido o una caída larga
water_point(center, radius, min_depth, max_depth)point/nilUn punto de nado entre las dos profundidades bajo la superficie (0 a 16)
ground_below(point, depth)number/nilLa altura de la parte superior del suelo a menos de depth bloques hacia abajo (1 a 64). Una superficie de agua o lava cuenta como suelo salvo que la especie sea AQUATIC. Sin suelo al alcance, la altura del punto menos depth
trail_point(back, height)point/nilback bloques por detrás del dueño, según hacia dónde mira, height por encima de sus pies para una especie FLYING y a la altura de sus pies en los demás casos. nil cuando el dueño está ausente o en otro mundo
distance_to(point)numberBloques desde su cuerpo
route_target()point/nilDónde quiere su ruta de migración que esté en este tick. nil cuando no está migrando o la ruta ha terminado
find_perch(height, radius)point/nilheight bloques (0 a 8) por encima de las hojas más cercanas bajo ella, hasta radius bloques (0 a 4) hacia los lados, o por encima del suelo justo debajo. Una mascota con dueño solo recibe una percha a menos de follow.distance de su dueño
nearest_campfire(radius, keep_ticks, blocks, soul_variants, height)point/nilEl bloque del fuego encendido más cercano que puede usar a menos de radius (1 a 32). blocks lista los tipos de fuego que acepta, CAMPFIRE, SOUL_CAMPFIRE o ambos, y una lista que no nombra ninguno acepta ambos; soul_variants lista los modelos que aceptan solo hogueras de almas, y todos los demás modelos aceptan entonces solo las normales. Una mascota con dueño solo acepta un fuego cuyo punto situado height bloques por encima esté a menos de follow.distance menos 1 bloques de su dueño. La búsqueda de cada chunk se conserva durante keep_ticks ticks (20 a 1200) y la comparten todas las mascotas
campfire_usable(fire, blocks, soul_variants, height)boolSi un fuego encontrado antes sigue encendido y sigue siendo adecuado

Efectos​

Estos funcionan desde cualquier callback; los sensores son el lugar habitual.

MétodoDevuelveQué hace
set_glow(light, lantern_bone, animation)nilIlumina los huesos de display del modelo a light (0 a 15), para jugadores de Java. Un modelo con un hueso llamado lantern_bone también repite animation. Los dos últimos son opcionales
clear_glow()nilVuelve a la luz del mundo, terminando esa animación
scale_toward(target, span, ticks, elapsed)nilLleva gradualmente el tamaño del cuerpo hacia target veces su tamaño base. Un cambio completo de 1 a span tarda ticks (al menos 2); elapsed son los ticks desde la última llamada. Multiplicadores de 0.1 a 16
sting_contacts(on, effect, duration, amplifier, damage, cooldown)numberPica a los jugadores cuyo contacto alcanzó el modelo de una mascota salvaje en el último segundo, nunca a uno en modo Creativo o Espectador, y devuelve cuántos. Borra los contactos incluso cuando on es false. Las mascotas con dueño no registran contactos
sting_enemies(reach, effect, duration, amplifier, damage, cooldown)numberPica a los mobs hostiles a menos de reach bloques (0 a 4) de la hitbox del modelo, nunca a jugadores ni mascotas, y devuelve cuántos
drizzle(depth, chance)boolCuando la mascota flota quieta sobre un cultivo a menos de depth bloques (1 a 8), muestra partículas de agua y da una probabilidad chance (0 a 1) de que el cultivo crezca una etapa. true cuando está sobre un cultivo
owner_effect(effect, duration, amplifier, range)boolDa al dueño el efecto de poción durante duration ticks (1 a 6000) cuando está a menos de range bloques, sin partículas. Un efecto que el dueño ya tiene, al menos igual de fuerte y de igual o mayor duración, se deja como está. false cuando el dueño está ausente, en otro mundo o fuera de rango, o el efecto no existe
play_animation(name)boolReproduce una vez una de las animaciones del modelo. false cuando el modelo no la tiene

Para ambas picaduras, effect es un nombre de efecto de poción o NONE, duration está en ticks (1 a 6000), amplifier 0 es el nivel I (hasta 255), damage está en medios corazones y cooldown son los ticks (al menos 1) antes de que esta mascota pueda picar de nuevo a la misma víctima. Una picadura muestra chispas y reproduce un sonido de picadura de abeja, y un adulto reproduce su animación attack. Un nombre de efecto de poción que no existe genera una advertencia una vez por especie y nombre, y no aplica nada.

Comportamientos y sensores​

  • Un comportamiento mueve o gira a la mascota. Lista los controles que necesita, ai.controls.move y ai.controls.look para las llamadas de movimiento de c.pet, y solo un comportamiento tiene un control a la vez. Mientras está detenido, MagmaCore pregunta a su can_start. Cuando devuelve true y los controles están libres, los toma y ejecuta start, después tick en cada tick mientras can_continue devuelve true (sin can_continue, decide can_start), y por último stop. Consulta Ciclo de vida.
  • El número de priority más bajo va primero. Un comportamiento quita los controles a uno en ejecución con un número más alto, cuyo stop se ejecuta entonces. El 12 del ejemplo lo mantiene por detrás de seguir y de quedarse y lo pone por delante de desplazarse y flotar, pero también por delante de campfire, así que una mascota que lista ambos nunca visita una hoguera por la noche. Un número por encima de 15 dejaría ganar al fuego.
  • Un comportamiento solo compite por los controles que lista. idle_look solo toma look, así que se ejecuta mientras ningún comportamiento tenga la mirada; todos los comportamientos de movimiento incluidos toman también look, así que moverse siempre gana a este.
  • Un archivo de mascota no puede cambiar una prioridad. Para reordenar, copia el módulo y cambia el número.
  • probe_interval es opcional, en ticks: mientras el comportamiento está detenido, can_start se consulta solo cada esa cantidad de ticks, con una fase propia para cada mascota. Ahorra tiempo de servidor cuando hay muchas mascotas fuera, a costa de que el comportamiento empiece con hasta esa cantidad de ticks de retraso. Su valor por defecto es 1 y por encima de 200 cuenta como 200. Un comportamiento en ejecución sigue ejecutándose en cada tick.
  • Un sensor nunca mueve a la mascota. Ejecuta sense en el primer tick en que se procesa el cuerpo de la mascota, y después cada interval ticks con una fase propia de la mascota, sea lo que sea lo que estén haciendo los comportamientos. El brillo, el hinchado, las picaduras, la llovizna y los efectos para el dueño son sensores.

Los módulos incluidos usan:

MóduloPrioridadprobe_intervalinterval del sensor
migrate110
stay54
follow_owner104
campfire1510
day_perch1810
rain_bloom19104 (hinchado)
drift, wander, swim2010
hover304
idle_look3010
night_glow40
sting4 (jugadores), 10 (mobs)
crop_drizzle20
owner_effect20

Reglas​

  • Llama a steer_to y stop solo desde start, tick o stop de un comportamiento, en un comportamiento que liste los controles que necesitan.
  • Guarda el estado por mascota en c.memory, declarado en memories, con nombres que empiecen por el nombre del módulo.
  • No escribas en c.pet; asignarle algo provoca un error.
  • Mantén los callbacks cortos. Todas las mascotas se ejecutan bajo estos límites fijos, que los módulos y los archivos de mascota no pueden cambiar:
LímiteValor
Un callback1,5 ms
Los callbacks de una mascota en un tick3 ms, como máximo 32 callbacks
Los callbacks de todas las mascotas en un tick10 ms
Tiempo de CPU de un callback, límite estricto20 ms
Instrucciones Lua de un callback, límite estricto20.000

Cuando una mascota alcanza uno de los tres primeros límites, sus callbacks restantes esperan al siguiente tick. Un callback que supera un límite estricto se detiene y falla como un error. Consulta Presupuestos.

Cuando algo va mal​

Nada de lo siguiente detiene el servidor ni a las demás criaturas. Busca en la consola pet behavior, pet_behaviors y .pet.yml para encontrar estas advertencias.

  • Un módulo no se carga. Un módulo que no compila, cuyo id no coincide con el nombre de su archivo, o cuyo nombre de archivo tiene otros caracteres se omite con una advertencia que nombra el archivo, y la línea en el caso de un error de Lua. Todos los demás módulos se cargan igualmente.
  • Un archivo de mascota nombra un módulo que no existe. La advertencia nombra el archivo de mascota y sugiere el nombre de módulo más parecido cuando hay uno a una o dos letras de distancia. La criatura se carga sin él. Cuando el módulo existe pero no se pudo cargar, la advertencia remite a la advertencia sobre su archivo.
  • Un ajuste es incorrecto. Un ajuste que el módulo no tiene, o un valor del tipo equivocado, se notifica con el nombre del archivo de mascota, y el valor predeterminado se mantiene. Consulta Valores de los ajustes.
  • Dos módulos chocan. Cuando dos módulos de una misma criatura declaran el mismo nombre de memoria, id de comportamiento o id de sensor, la criatura conserva el primero de la lista y se ejecuta sin el otro, con una advertencia.
  • Un callback falla mientras las mascotas se ejecutan. Se registra una vez por programa, callback y tipo de fallo hasta la siguiente recarga. Los programas se llaman fmm:pet/creature/<species>/<variant>, y los callbacks por el id de su comportamiento o sensor, como fmm:pet/drift.tick. Un comportamiento que falla se detiene, o no se inicia, y se reintenta desde el siguiente tick; mientras siga fallando, es posible que no se ejecuten los comportamientos con números de prioridad más altos que mueven o giran a la mascota. Un sensor que falla se ejecuta de nuevo en su siguiente intervalo.
  • Una llamada a c.pet falla dentro de FreeMinecraftModels. La causa se registra una vez por especie y llamada, con su traza de pila, y el callback falla con c.pet:<method> failed; the server log has the cause.
  • Un nombre de efecto de poción no existe. Se avisa una vez por especie y nombre, y la llamada no aplica ningún efecto.

Tras una corrección, ejecuta /fmm reload.