Saltar al contenido principal

Código de ejecución

Dale a tu plugin código que se ejecuta en el proyecto publicado: sistemas que mueven objetos, disparadores y pasos para los eventos, y ajustes para todo el proyecto.

Los paneles y los componentes personalizados funcionan en el editor. El código de ejecución funciona allí donde se reproduce el proyecto: en el proyecto publicado (en la web y en la app), en la vista previa del editor y en las pruebas de juego.

Añade código de ejecución​

Apunta runtime en el manifiesto a un archivo .ts o .js de la carpeta de tu plugin:

{
"id": "acme.spin",
"name": "Spin",
"version": "1.0.0",
"entry": "main.tsx",
"permissions": [],
"panels": [],
"components": [{ "id": "spin", "title": "Spin", "entry": "spin.tsx" }],
"runtime": "runtime/index.ts"
}

El archivo se ejecuta una vez, cuando arranca el proyecto, junto a los scripts del proyecto. Registra ahí un sistema. Un sistema se ejecuta en cada fotograma:

// runtime/index.ts
import { Collection, System } from '@was/ecs';
import { TransformComponent, frameTime, pluginComponent } from '@was/engine';

class AcmeSpinSystem extends System.from('AcmeSpinSystem') {
execute() {
const { dt } = frameTime();
const spin = pluginComponent('acme.spin/spin', this.space);
for (const e of spin.entities()) {
const t = e.getComponent(TransformComponent)!;
const r = t.$data.rotation;
t.update({ rotation: { ...r, y: r.y + (spin.props(e)!.speed as number) * dt } });
}
}
}
Collection.registerSystem(AcmeSpinSystem);

Este sistema hace girar todos los objetos que tienen el componente Spin del plugin, a la velocidad que se haya puesto en el inspector.

Usa el nombre de tu plugin en los sistemas

Todo el proyecto comparte los nombres de los sistemas. Si un nombre ya está ocupado, tu sistema no arranca, y el error dice qué nombre es. Empieza cada nombre con el de tu plugin, como AcmeSpinSystem.

Qué puede usar el código de ejecución​

El código de ejecución puede importar lo mismo que un script: @was/ecs, @was/engine, @was/utils y @was/svdt. Solo se envían el archivo de entrada y los archivos que importa con ./, hasta 1 MB en total.

No tiene página, ni DOM, ni three.js, ni React. Lee y cambia componentes, y el motor dibuja el resultado.

FunciónQué te da
frameTime(){ dt, t }: el tiempo desde el último fotograma y desde el inicio, en segundos
pluginComponent(key, space)tu componente personalizado en los objetos: para leerlo y cambiarlo
pluginEvents(id, space)para lanzar tus disparadores y responder a tus pasos
pluginSettings(id)los valores que el proyecto ha elegido para tus ajustes
pluginContext(id, space)el ctx de los scripts: entrada, física, rayos, sonido, globales, multijugador

key es <plugin id>/<component id>, como acme.spin/spin. id es el id del plugin en el manifiesto.

Tu componente​

pluginComponent(key, space) te da:

MétodoQué hace
entities()los objetos que tienen el componente
has(e)si el objeto lo tiene activado
props(e)los valores del inspector, con los valores por defecto
state(e)el estado propio del componente
setState(e, patch)cambia el estado
setProps(e, patch)cambia los valores del inspector
setEnabled(e, on)activa o desactiva el componente
add(e, props)añade el componente a un objeto
remove(e)lo quita

Los scripts obtienen lo mismo con ctx.plugin(key).

El contexto de los scripts​

pluginContext(id, space) devuelve el mismo ctx que recibe un script, para la entrada, la física, los raycasts, el audio, las globales y el multijugador. Es null hasta que arrancan los scripts del proyecto, y puede cambiar cuando cambia el mundo, así que pídelo en el momento en que lo necesites. ctx.on y ctx.tick añaden un manejador nuevo en cada llamada, así que suscríbete una sola vez por cada contexto.

Disparadores y pasos​

Un plugin con código de ejecución puede añadir sus propios disparadores y pasos al panel de eventos. Así la gente puede usarlos sin código, igual que los que vienen incluidos. Aparecen bajo el nombre de tu plugin, en los proyectos que tienen el plugin.

Decláralos en el manifiesto:

"triggers": [
{ "id": "reached", "title": "Reached a point",
"params": { "point": { "type": "number", "default": -1, "any": -1, "label": "Point" } } }
],
"steps": [
{ "id": "pause", "title": "Pause",
"params": { "seconds": { "type": "number", "default": 0, "min": 0 } } }
]
  • Los ids van en kebab-case. El nombre completo es <plugin id>:<id>, como acme.patrol:reached.
  • params usa los tipos de campo de defineProps: number, string, boolean, color, select, entity y resource. El panel dibuja un formulario para ellos.
  • Los params de un disparador sirven de filtro. Un evento configurado para el punto 2 solo se ejecuta cuando el disparador se lanza con point: 2. Un param vacío, o con su valor any, deja pasar todos los lanzamientos.

Lanza los disparadores y responde a los pasos desde tu código de ejecución:

import { pluginEvents } from '@was/engine';

class AcmePatrolSystem extends System.from('AcmePatrolSystem') {
events = pluginEvents('acme.patrol', this.space);
off = this.events.onStep<{ seconds: number }>('pause', (targets, params) => {
// detén los objetos de `targets` durante params.seconds
});

execute() {
// cuando un guardia llega a un punto:
// this.events.fire('reached', guard, { point: 2 });
}

dispose() {
this.off();
}
}
  • fire(id, object, payload) ejecuta los eventos que usan este disparador en ese objeto y en los objetos que tiene por encima. Sin objeto, se lanza en todas partes. Los scripts lo oyen con ctx.on('acme.patrol:reached', payload => …).
  • onStep(id, handler) se ejecuta cuando un evento ejecuta tu paso. Un script también puede ejecutarlo, con ctx.step('acme.patrol:pause', { seconds: 2 }). Suscríbete una sola vez y llama a la función que te devuelve en dispose().
  • Si se quita el plugin de un proyecto, sus disparadores ya no se lanzan nunca y sus pasos se saltan.

Ajustes del proyecto​

Algunos valores son de todo el proyecto: un tempo, una dificultad, un color. Decláralos en settings: hasta 24 campos de los tipos number, string, boolean, color y select.

"settings": {
"tempo": { "type": "number", "default": 1, "min": 0, "label": "Tempo" }
}

La gente los configura en Project settings, en una sección con el nombre de tu plugin.

  • El código de ejecución los lee con pluginSettings<{ tempo: number }>('acme.patrol'). Recibes todos los campos: el valor del proyecto o el valor por defecto. Los valores están listos antes de que se ejecute tu archivo de entrada y no cambian mientras se reproduce el proyecto.
  • Un proyecto publicado usa los valores con los que se publicó.
  • Tu panel los lee y los cambia con editor.pluginSettings.get() y editor.pluginSettings.set({ tempo: 2 }). Para eso necesita el permiso settings:write.

Cómo llega el código a un proyecto​

El código de ejecución solo se ejecuta en los proyectos a los que se ha añadido el plugin.

  • Al añadir el plugin, la versión queda fijada. El proyecto se queda con el código que tenía el plugin en ese momento. Las vistas previas, las pruebas de juego y las publicaciones ejecutan ese código, aunque después publiques uno más nuevo.
  • Actualizar es decisión del proyecto. Cuando hay código más nuevo, el plugin muestra update available en el panel Plugins. Update in project pasa el proyecto a esa versión.
  • Tus propios proyectos siguen tus cambios. Si añadiste tu propio plugin a un proyecto, el proyecto ejecuta cada versión que guardas.
  • Una publicación conserva su código. Un proyecto publicado ejecuta el código con el que se publicó, hasta que se vuelve a publicar.

Los títulos, las descripciones y las etiquetas de los disparadores, los pasos y los ajustes pueden salir de tus archivos de idioma, escritos como ${…}.

Plugins solo para suscriptores​

El código de ejecución de un plugin llega a todos los que abren el proyecto publicado, y cualquiera puede leerlo en su navegador. Esto también vale para un plugin Subscribers only. La suscripción decide quién puede añadir el plugin a un proyecto, actualizarlo y publicar con él. No oculta el código.

Si termina la suscripción, un proyecto que usa el plugin no se puede volver a publicar. Renueva la suscripción o quita el plugin. Un proyecto que ya está publicado sigue funcionando.

Para desarrolladores​

  • El código de ejecución se ejecuta en el worker de scripts del proyecto, junto con los scripts del proyecto.
  • La versión que guarda un proyecto es una huella de los archivos de ejecución, los disparadores, los pasos y los ajustes. Si la huella cambia, aparece update available.

Siguiente: Atajos de teclado: las teclas que agilizan la edición.