Crear un cerebro
Un .oabrain que juega un asiento de ordenador: la carpeta, cada clave del manifiesto, las etiquetas, los niveles, la visión total, dónde corre el script, las asignaciones y qué pasa cuando se detiene.
Este capítulo resume docs/brains/oabrain-standard.md, docs/brains/authoring.md y docs/playing-with-brains.md. Esos documentos son el texto normativo.
Qué es un cerebro
El jugador de ordenador del propio motor sigue por defecto y sigue en el motor. Un cerebro juega un asiento de ordenador, y solo un asiento que un jugador le asignó. Un identificador de cerebro vacío es ese jugador de ordenador integrado. Un asiento sin cerebro, un cerebro que no encaja y un cerebro que se detiene los juega todos ese mismo jugador. Classic está escrito en Lua y juega como lo hace ese jugador. Es la documentación de ese jugador, no un sustituto.
Solo la máquina que sienta al jugador de ordenador ejecuta el script, así que los demás jugadores no necesitan tener nada instalado. Sus máquinas reflejan las unidades del asiento. Una grabación reproducida no ejecuta el script. Un cerebro es fuente Lua y datos. No tiene código nativo, ni archivo, ni red, ni reloj. La visión total es una bandera del manifiesto. Un cerebro puede ponerla, puede jugar con ella en una partida en red, y el asiento muestra la bandera.
El paquete
Un cerebro es un archivo .oabrain, o la carpeta a la que se descomprime ese archivo. El manifiesto es el YAML estricto que usa un perfil de mod: un documento, un mapeo de nivel superior, sin anclas ni escalares de bloque. En la raíz del paquete está oabrain.yaml. A su lado, un archivo es uno de estos. Un archivo fuera de esa lista se rechaza.
my-brain.oabrainel archivo que recibe un jugador├─ oabrain.yamlobligatorio el manifiesto, como mucho 256 KiB├─ brain.luael script de entrada. El nombre por defecto es brain.lua. entry nombra otro, y ese archivo tiene que estar en el paquete├─ lua/más fuente Lua. require solo lee estos archivos. Cada parte se compone de letras minúsculas, dígitos y _├─ nets/una red que nombra el manifiesto, nets/ y un nombre que acaba en .oann├─ data/una tabla de datos, a una sola carpeta de profundidad: .csv, .tdf, .json o .txt├─ icon.pngla imagen, solo cuando icon la nombra. Sin esa clave el archivo queda fuera├─ README.mduna nota en la raíz. El juego no la carga└─ LICENSEla licencia en la raíz. El nombre licence, y un readme en una subcarpeta, quedan fueraLa comparación no distingue mayúsculas de minúsculas en las letras ASCII, salvo donde el estándar dice que los bytes tienen que coincidir. brain.lua queda fuera cuando entry nombra otro archivo. Un archivo Lua es como mucho 1 MiB. El icono es un PNG cuadrado, cada lado como mucho 256 píxeles, como mucho 256 KiB. OA instala un cerebro en Brains/ y el identificador del manifiesto.
El manifiesto
El lector reúne cada regla rota y deja el manifiesto sin cambios cuando se rompe alguna. Una clave que el estándar no lista se rechaza. Una clave de perfil pertenece a un mod. Una clave de mutador se rechaza como clave de mutador. Entrecomilla una versión, porque un 1.0 suelto es un número, y entrecomilla una estrella, porque una estrella suelta es un alias de YAML.
| Clave | Obligatorio | Qué hace |
|---|---|---|
oabrain | sí | El formato. El entero 1. 1.0 y un 1 entre comillas se rechazan. |
id | sí | Kebab-case en minúsculas, de 1 a 64 bytes. Sin guion al inicio, al final ni doble. El nombre de la carpeta bajo Brains/. |
name | sí | De 1 a 64 bytes, sin carácter de control. El nombre que ven los jugadores. |
version | sí | Entre comillas, de una a tres partes, una versión de mutador, como "2.0". Un número suelto se rechaza. 2, 2.0 y 2.0.0 se comparan como iguales. |
author | sí | Un mapeo. name es obligatorio, de 1 a 128 bytes. email es opcional. |
description | sí | Obligatorio, de 1 a 2.000 bytes. Se permite un salto de línea. Cualquier otro carácter de control se rechaza. La primera línea, cortada a 200 bytes, es el resumen. |
homepage | no | Una dirección http o https. |
icon | no | Solo icon.png, la imagen en la raíz del paquete. Cualquier otra cosa se rechaza. |
tags | sí | De 1 a 4 de las nueve etiquetas de abajo, ninguna repetida. |
works-with | sí | De 1 a 32 condiciones, sin identificador repetido. Un asterisco significa cualquier mod y el juego base, y entonces es la única entrada. ta-3.1c significa el juego base sin mod. Cualquier otro identificador es un mod, con un rango de versión opcional. |
requires | no | Solo engine y expansions. engine es un rango, entre comillas cuando empieza por un signo de mayor que. expansions es de 1 a 16 identificadores de bundle. Un cerebro no puede requerir un mutador. |
levels | sí | De 1 a 6 niveles. Cada mapeo es exactamente id, name y difficulty. |
fullAwareness | no | true o false. Si falta, es false. Un true entre comillas se rechaza. |
networks | no | De 1 a 16, cada uno exactamente id, file y sha256. file es nets/ y un nombre que acaba en .oann. sha256 son 64 dígitos hexadecimales en minúsculas, entre comillas. |
options | no | Como mucho 16, las reglas de opciones del mutador. Un interruptor es true o false, un número es un número y una elección es su texto. me.options las lee. |
strings | no | Como mucho 16 idiomas. Un idioma puede llevar name, description, options, labels y levels. |
entry | no | Un archivo Lua en la raíz del paquete, con nombre de letras minúsculas, dígitos y _. Si falta, es brain.lua. |
Las nueve etiquetas
Una etiqueta es una de estas nueve, comparada byte a byte. Más de cuatro, cuando la regla compartida de etiquetas ya ha pasado, es un problema propio. Una etiqueta que no es una de las nueve se rechaza.
| Clave |
|---|
classic |
economy |
rush |
turtle |
air |
naval |
learned |
teaching |
experimental |
Niveles y dificultad
levels es una lista de 1 a 6 mapeos. Cada uno es exactamente id, name y difficulty, todos obligatorios. id es kebab-case en minúsculas, de 1 a 32 bytes, y ningún id se repite. name es de 1 a 64 bytes, sin carácter de control. difficulty es easy, medium o hard, byte a byte.
Esos tres nombres son los valores 0, 1 y 2. Un asiento que elige el nivel usa ese valor como sus reglas de ingresos, la misma dificultad que el juego ya usa.
Visión total
fullAwareness es true o false. Si falta, es false. Un cerebro con la bandera ve unidades que un asiento en la niebla no vería, como lo hace el jugador de ordenador integrado, y sus comprobaciones de sitio no necesitan un jugador que coloca. La bandera se permite en una partida en red. La Biblioteca muestra Ve todas las unidades del mapa, como el jugador de ordenador de Total Annihilation. La bandera es la del propio manifiesto. No la concede el identificador del paquete, y no es una de las cosas que solo se dan a Classic.
Dónde corre un cerebro
Solo la máquina que sienta al jugador de ordenador necesita el paquete, y solo esa máquina ejecuta el script. Un asiento es un jugador de ordenador de esta máquina. Un asiento humano se rechaza. game.mode es skirmish, campaign o network.
| Situación | Qué corre |
|---|---|
| Escaramuza | Cada asiento de ordenador que juega esta máquina, cuando un jugador le puso un cerebro. Un identificador vacío es el jugador de ordenador integrado. |
| Misión de campaña | El asiento de campaña sigue el cerebro por defecto que puso el jugador. Una misión no ignora ese valor por defecto. |
| Partida en red | La máquina dueña del asiento de ordenador ejecuta el cerebro, visión total incluida. Las demás máquinas no. |
| Partida guardada cargada después | La partida guardada nombra cada asiento. El estándar dice qué pasa cuando falta el paquete o la versión difiere. |
| Grabación reproducida | La grabación guarda el texto de los cerebros. La reproducción aplica los paquetes grabados. No sienta un cerebro y no llama a sus hooks. |
| Deathmatch o torneo | El lanzamiento no sienta a ningún jugador de ordenador. |
El cerebro que juega un asiento no es una entrada del hash de la simulación. Dos partidas que solo difieren en qué cerebro está sentado conservan el mismo hash del estado de la partida. Los valores hack ai.* del mod forman parte del perfil de mod que cubre ese hash, así que siguen llegando a cada máquina.
Las asignaciones de la ejecución
Un cerebro corre como Lua en un aislamiento. Dos cerebros no comparten módulos, ni globales, ni asignaciones. El script no tiene archivo, ni reloj, ni entorno, ni proceso, ni red. Cada fragmento se carga como texto. pcall y xpcall no pueden mantener viva una fase agotada. Un turno es una llamada con cargo al banco, en el punto del controlador del asiento, tras el barrido de unidades. Las órdenes que da un hook tienen efecto en el siguiente tick.
| Asignación | Valor |
|---|---|
| Instrucciones en load, fits, start, save y report | 50,000,000 |
| Instrucciones que añade un tick | 2,000,000 |
| Ticks que puede guardar el banco, incluido el tick actual | 30, así que el saldo abre en 60,000,000 |
| Memoria de Lua | 64 MiB (67,108,864 bytes). No se reinicia entre fases. |
| Memoria de red | 64 MiB, aparte del tope de Lua |
| Tiempo real, una fase que no es un turno, en milisegundos | 10,000 |
| Tiempo real, un turno, en milisegundos | 250 |
| Una cadena, en bytes | 65,536 |
Cuando un cerebro falla
Un cerebro se detiene por un error en un hook o en un temporizador, una asignación de instrucciones agotada, el respaldo de tiempo real, el tope de memoria de Lua, una cadena de más de 65.536 bytes, o una carga que el asiento rechaza. Un turno fallido cierra el aislamiento y quita los hooks antes de que ese turno vuelva. El turno que falla cuenta igual como jugado. El siguiente tick de órdenes no tiene hooks, así que lo toma el jugador de ordenador integrado. Un cerebro que se rechaza, que no arranca o que no encaja nunca tiene hooks, así que ese jugador juega desde el principio. El aviso usa el nombre del manifiesto y el motivo, cortado a 160 bytes:
- `{brain} stopped ({reason}); the engine plays this seat on`
- `{brain} could not start ({reason}); the engine plays this seat`
- `{brain} does not fit this game ({reason}); the engine plays this seat`
Cuando el asiento no tiene un motivo propio, el motivo es the brain could not be seated. A un jugador derrotado simplemente ya no se le llama. El aislamiento se cierra con la partida.