Contenido generado con IA — puede contener errores.

Juego

Secuencias

Efectos coreografiados escritos en configuración: cada token, cada forma y los parámetros que mueven un display.

Una secuencia es coreografía escrita como una lista de textos — un anillo de fuego, un sonido, una pausa, una explosión, en ese orden. Se compila una vez y se lanza muchas.

PluginSequences sequences = Sequences.of(this);
Sequence onKill = sequences.compile(config.getStringList("effects"), "ember_burst");
 
sequences.play(onKill, SequenceTarget.at(victim.getLocation()).by(killer));
effects:
  - '[CIRCLE] FLAME;radius:1.5;points:24'
  - '[SOUND] ENTITY_BLAZE_DEATH;1.5;0.8'
  - '[DELAY] 0.15'
  - '[EXPLOSION]'

¿Secuencias o efectos?

Lo que tienesUsa
Un título, un sonido, una partícula, declarados en un recordEffects
Una lista de cosas en orden, con pausas, formas y objetosesto

El sonido de apertura de un menú es un EffectConfig. Un espectáculo de cien líneas es una Sequence.

La sintaxis

Cada línea es un token entre corchetes, una cabecera y parámetros separados por ;:

- '[CIRCLE] NETHERITE_SWORD;as:item;radius:3;points:12;from:0,10,0;ease:in'

(0,0,0) es el ancla donde se lanzó la secuencia. La Y positiva es arriba.

Tokens

TokenArgumentos
[DELAY] 0.15Segundos de espera antes de la línea siguiente.
[PARTICLE] FLAMEcount: offset:x,y,z speed: y: color: size: block:
[SOUND] NOMBRE;volumen;tonoTambién volume: pitch:. Sirve la clave propia de un resource pack.
[LIGHTNING]volume: pitch: — destello, chispas y trueno. Sin rayo real, sin fuego, sin daño.
[EXPLOSION]count: y:
[FIREWORK]color: fade: type: trail: flicker: power:
[BLOCK_BREAK] STONEcount: offset: y:
[POTION] speed;100;1También duration: amplifier:
[TITLE] título;subtítulo;in;stay;outTiempos en segundos.
[ACTION_BAR] texto
[MESSAGE] textoUna línea de chat. <center> funciona como en cualquier otro sitio.
[COMMAND] give {player} …{player} {world} {x} {y} {z}
[DISPLAY] NETHERITE_SWORDUn display — ver Displays y NPCs.
[NPC] {victim}Un cuerpo donde ocurrió — misma página.
[RAGDOLL] {victim}Ese cuerpo deshaciéndose, en once poses — misma página.

Formas

Veinticinco, y todas se pueden dibujar con partículas o con displays:

CIRCLE SPHERE DOME CUBE LINE RIBBON SCATTER BEAM SPIRAL DOUBLE_HELIX TORNADO STAR CAGE DISC VORTEX WAVE CROSS GALAXY TORUS BURST PYRAMID RING_PULSE WINGS ARCH CLAW

FormaSus parámetros
CIRCLE, SPHERE, DOMEradius points
BEAMheight points
SPIRALheight radius turns points
DOUBLE_HELIXheight radius turns points strands
TORNADOheight radius top_radius turns points
STARradius spikes inner points
CAGEradius height columns points
DISCradius rings points
VORTEXradius turns points
WAVElength amplitude frequency arms angle points
CROSSradius arms angle points
GALAXYradius turns arms points
TORUSradius tube segments tube_segments
BURSTradius beams angle points
PYRAMIDbase height points
RING_PULSEradius rings spacing points
WINGSspan arch depth dir points
ARCHradius arc dir points
CLAWradius claws spread curve dir drop points
CUBEwidth points edges
LINElength dir climb points
RIBBONradius points waves amplitude
SCATTERradius height points seed floor

CUBE dice width y LINE dice climb en vez de size y rise porque, en una línea de display, esas dos palabras ya significan la escala del modelo y dónde termina.

Toda forma acepta además y: scale: color: size: count: ticks: interval: rotate: face:. ticks:1 dibuja la forma entera en un frame; más la reparte en el tiempo, que es lo que hace que una espiral parezca trazarse. SCATTER acepta seed, así que sus puntos al azar son los mismos puntos al azar cada vez.

color: acepta un token de paleta

color:{primary} sigue colors.yml como todo lo que lee un jugador. #rrggbb y R,G,B también valen. Una partícula DUST sin color se dibuja blanca — visible y obviamente mal, en vez de invisible en silencio.

Dibujado con algo que no son partículas

Cualquier línea de forma pasa a ser una forma de display entities diciendo de qué está hecha:

- '[CIRCLE] NETHERITE_SWORD;as:item;radius:2.6;points:12;from:0,9,0;spin:2;axis:x;face_out:true'
as:La cabecera de la línea es
itemUn nombre de objeto, NETHERITE_SWORD.
blockUn bloque, o un estado completo como oak_stairs[facing=east].
headUna textura en base64, o {killer} / {victim} para una cara.
textLa propia línea, con el formato de siempre.

La geometría, la animación, la rotación y quién lo ve no cambian, porque una forma nunca supo con qué se dibujaba. Los parámetros de movimiento — life, from, to, ease, gravity, spin, orbit, pull, size_to, roll, glow, light y demás — están en Displays y NPCs.

Repetir una línea a compás

repeat: y every: funcionan en cualquier línea; una forma acepta además turn_each:.

- '[CIRCLE] NETHERITE_SWORD;as:item;radius:3;points:6;repeat:5;every:0.1;turn_each:12'

Cinco anillos a una décima de segundo, cada uno doce grados más girado — en vez de cinco copias de una línea con cuatro pausas intercaladas.

Formas propias

sequences.shape("heart", args -> {
    List<Vector> points = new ArrayList<>();
    double size = args.number("size", 1.0);
    for (int i = 0; i < args.atLeastOne("points", 60); i++) {
        double t = i / 60.0 * Math.PI * 2;
        points.add(new Vector(size * Math.pow(Math.sin(t), 3),
                size * (13 * Math.cos(t) - 5 * Math.cos(2 * t)) / 16, 0));
    }
    return points;
});

Una forma dice dónde, nunca qué. El color, la animación, la rotación, la escala, as: y la visibilidad vienen gratis, y por eso una forma nueva es un bucle que devuelve vectores en vez de otra copia del código de dibujo. Se llama una sola vez, al compilar.

Lanzarla

SequenceRun run = sequences.play(sequence, SequenceTarget.at(location)
        .by(killer)
        .on(victim)
        .visibleTo((observer, source) -> settings.seesEffects(observer)));
 
run.cancel();
En el targetQué fija
at(location) / of(player)El ancla.
by(player)Quién lo causó — lo que leen {killer}, face: y [COMMAND].
on(entity)A quién le pasó — lo que lee {victim}.
onlyTo(player)Un solo espectador, que es como se muestra una preview.
visibleTo(predicate)Quién puede percibirlo, preguntado una vez por frame.

durationMillis() dice cuánto dura una secuencia sin lanzarla, animación incluida — que es como una preview sabe cuándo devolver al jugador.

Efectos que pueden sonar o no

Una secuencia dice qué pasa. Un EffectEntry dice si pasa, para quién y cuándo:

EffectEntry crit = EffectEntry.of(List.of(
                "[SOUND] ENTITY_PLAYER_ATTACK_CRIT;1;1.4",
                "[PARTICLE] CRIT;count:20"))
        .name("Critical hit")
        .chance(25.0)
        .condition("%player_level% >= 10")
        .nearby(12.0)
        .build();
CampoSignifica
linesLo que suena.
name, iconLo que muestra un editor.
chanceEl porcentaje de probabilidad de sonar.
condition, permissionPara quién puede sonar.
priorityMayor va primero; a igual prioridad, el orden escrito.
delayTicksCuánto después del disparo empieza esta entrada — las de al lado suenan a su hora.
radius0 o menos es solo el jugador del que trata; un número son todos a esa distancia; EffectEntry.WHOLE_WORLD es el mundo entero.

El permiso y la condición se comprueban antes del dado: quién puede ver algo no depende de la suerte. Las entradas se compilan la primera vez que suenan y se cachean por sus propias líneas, y una condición rota se avisa una vez y no una por lanzamiento.

EffectCodec.encode / decode las guardan, y decode lee además las filas de ExyliaCommons, traduciendo su tipo a la línea que reproduce lo mismo.

Editarlas en el juego

sequences.editor(mine.breakEffects())
         .title("{primary}&lBREAK EFFECTS")
         .onSave(edited -> mines.save(mine, edited))
         .open(player);

Dos niveles de la pantalla de editor: las entradas y, dentro de una, sus líneas como lista propia. Una línea se añade eligiendo qué reproduce, buscando cuál en el registro del propio servidor y rellenando solo los campos que ese token lee — a un círculo se le pide su radio; a unas alas, su envergadura. Los campos en blanco no se escriben, así que una línea construida a clics es la misma línea corta que alguien habría escrito a mano.

Las condiciones viven detrás del botón WHEN IT PLAYS, y las dos mitades se guardan o se descartan juntas. Un token que la librería no reconoce se sigue dibujando, se sigue editando como texto y vuelve exactamente como estaba escrito.

Contratos

Compilada una vezNombres, números y trigonometría se resuelven al compilar. Lanzarla es aritmética y paquetes.
Una línea mala cuesta su líneaSe avisa por Debug nombrando la secuencia; el resto suena igual.
Nunca alcanza al eventoUn efecto de muerte no puede cancelar una muerte.
Correcta en FoliaCorre en el hilo dueño de la ubicación, a través de Tasks.
Las secuencias instantáneas no agendan nadaSin pausas ni animación se reproduce en el tick de la llamada.
Cancelableplay devuelve un SequenceRun.
Nada sobrevive a su pluginDesactivar un plugin cancela sus runs antes de liberar el scheduler.
Un sonido que este servidor no tiene se avisa

Un sonido renombrado se pasaba como una clave que no es clave: no sonaba nada y nada decía por qué. Ahora cuesta una línea de consola nombrando el efecto. Un nombre con punto o dos puntos se deja en paz, porque el sonido propio de un resource pack legítimamente no está en el registro.

Previews

Previews.of(this).show(player, sequence, () -> menu.open(player));

Sube a un jugador a un trozo de cielo vacío, le lanza la secuencia solo a él y lo devuelve exactamente donde estaba — el callback corre termine como termine. La altura del escenario, la separación, la distancia y la red de seguridad son una sección PreviewSettings que un plugin puede anidar en su propia config.

¿Falta algo en esta página? Dínoslo en Discord