Contenido generado con IA — puede contener errores.

Juego

Displays y NPCs

Objetos sólidos y cuerpos con forma de jugador, enviados por paquetes y animados por el cliente.

Tres módulos con la misma forma: ninguno crea una entidad real, los tres se dibujan directo al cliente y los tres son dueños de la vida de lo que muestran.

MóduloPunto de entradaQué dibuja
DisplaysDisplays.of(plugin)Displays de objeto, bloque, cabeza y texto que se mueven, giran y caen.
NPCsNpcs.of(plugin)Cuerpos con forma de jugador: un cadáver, una estatua, un doble.
RagdollsRagdolls.of(plugin)Un cuerpo cortado en sus seis partes, lanzado, abierto o llevado.

Los tres necesitan PacketEvents. Sin él el módulo lo dice una vez y no dibuja nada.

Casi nadie toca estas APIs

A los tres se llega desde una línea de secuencia, que es como los usa cada plugin cosmético del ecosistema. La API es para lo que la configuración no puede describir.

Por qué anima el cliente

A un display se le dice una pose y cuánto tiempo tiene para llegar, y él dibuja cada frame intermedio al framerate de quien mira. Una animación de dos segundos son unos seis paquetes por espectador, y sigue fluida en un servidor a quince ticks por segundo, porque la fluidez nunca dependió del tick.

Mover algo reenviando su posición cada tick es una animación de veinte fotogramas por segundo que empeora bajo carga — que es a lo que se parece una estela de partículas fingiendo ser un objeto.

Los displays no sustituyen a las partículas

Los displays dan peso, silueta y sombra. Las partículas dan luz, humo y ambiente. Los efectos que parecen caros son las dos cosas.

Dibujar un display desde una secuencia

Cualquier línea de forma pasa a ser una línea de display diciendo con qué se dibuja:

effects:
  # Doce espadas que caen del cielo en anillo, girando al venir.
  - '[CIRCLE] NETHERITE_SWORD;as:item;radius:2.6;points:12;from:0,9,0;to:0,0,0;spin:2;axis:x;life:0.9;face_out:true;light:15'
  # El suelo cediendo: un anillo de bloques, aplastado, creciendo hacia fuera.
  - '[CIRCLE] CRYING_OBSIDIAN;as:block;radius:0.3;points:20;size:0.1;size_to:1.4;to:0,0.2,0;life:0.5;light:15'
  # Un objeto lanzado hacia arriba, volteando, que vuelve a caer.
  - '[DISPLAY] TRIDENT;from:0,0.5,0;to:0,4,0;gravity:14;spin:3;axis:z;life:1.4;size:1.5'

Cómo se mueve

ParámetroQué hacePor defecto
life:Segundos que existe.1
from:x,y,zDónde empieza, relativo a su punto.0,0,0
to:x,y,zDónde termina.0,0,0
rise:Atajo de to:0,n,0.
gravity:Bloques por segundo al cuadrado, sumados a la línea.0; lo vanilla ronda 32
ease:in, out, in_out.lineal
spin:Vueltas en toda su vida; x,y,z voltea en tres ejes.0
axis:Sobre qué eje gira un spin de un solo número.y
orbit:Vueltas que cada punto da alrededor del ancla.0
vary:Cuánto difieren de tamaño las piezas, como fracción.0
size:Un número, o x,y,z para una placa, un pilar o una hoja.1
size_to:El tamaño con el que acaba.igual que size
tilt: roll: turn:Una rotación fija, en grados.0
face_out:Cada punto mira hacia fuera del centro.false
pull:Cuánto viaja cada punto hacia el centro; negativo lo lanza hacia fuera.0
glow:Color de contorno: un nombre, #rrggbb o un token {paleta}.ninguno
light:Nivel de luz fijo, de 0 a 15.la luz del sitio
model:Custom model data.ninguno
billboard:FIXED, VERTICAL, HORIZONTAL, CENTER.FIXED, CENTER en texto
hold:Contexto del display de objeto: 0 el modelo, 5 cabeza, 7 tirado, 8 marco.0

orbit: es el movimiento que una línea recta no puede expresar y el que separa una forma que aparece de una forma que está viva. vary:0.4 da a las piezas tamaños que difieren hasta en dos quintos — es un hash de la posición de cada punto, no un número al azar, así que sale igual cada vez. spin:0.5,2,1 voltea en tres ejes, porque nada lanzado en el mundo gira sobre exactamente uno.

Hacer que un movimiento aterrice

ease:in para un golpe

Retiene el movimiento y lo gasta tarde: carga y golpe, con los mismos dos números.

gravity: solo para escombros

Se suma a la línea en vez de reemplazarla, así que from:0,9,0;to:0,1,0;gravity:40 baja ocho bloques y luego cae doce más, atravesando el suelo. La mitad de gravity por el cuadrado de life es cuánto cae: un segundo en el aire quiere un 5, no un 50.

size: para dar peso

size:3,0.15,3 es un bloque aplastado en placa. Crecida desde nada es una onda de choque; estirada al revés es un pilar o una hoja.

size_to: para la llegada

Un poco más grande al impactar, o más pequeño en la carga. Es la diferencia entre un objeto que llega y un objeto que se coloca.

Una hoja se apunta con roll:, no con tilt:

El modelo de un objeto es una placa plana en su propio plano XY, mirando al sur, con la punta de una espada arriba y a la derecha. roll:135 la deja punta abajo, roll:315 punta arriba y roll:225 tumbada de punta sobre su cara. El giro va al revés que la regla de la mano derecha, así que a una hoja que sale horizontal hay que sumarle o restarle 90. face_out: y turn: se aplican después de roll: y tilt:, que es el orden que necesita un anillo. Un display de bloque es un cubo y no necesita nada de esto.

Vale la pena poner light:15 en casi todos los efectos: un display iluminado por el mundo es negro de noche, y un efecto que desaparece al anochecer es un efecto que los jugadores reportan como roto.

La API de displays

PluginDisplays displays = Displays.of(this);
 
DisplayModel blade = DisplayModel.item(new ItemStack(Material.NETHERITE_SWORD))
        .glow(0xFF6B9D)
        .light(15);
 
DisplayMotion thrown = DisplayMotion.builder()
        .life(1200)
        .from(0, 7, 0).to(0, 0, 0)
        .spin(Rotation.Axis.Z, 3)
        .build();
 
displays.show(blade, thrown, where, observers);
MétodoQué hace
show(model, motion, at, viewers)Muestra un display; se quita solo al terminar el movimiento. Devuelve un DisplayHandle, o null si nadie puede verlo o falta PacketEvents.
removeAll()Todo lo que este plugin tenga en pantalla.
active()Cuántos tiene en pantalla.
isSupported()Si se pueden mostrar displays en este servidor.

NPCs

effects:
  # La víctima, boca abajo, con lo que llevaba al morir, durante cuatro segundos.
  - '[NPC] {victim};pose:lying;life:4;equip:true'
  # De pie, girado hacia quien lo hizo, con contorno.
  - '[NPC] {victim};pose:standing;life:3;glow:{error};face:true'
ParámetroQué hacePor defecto
pose:lying, standing, crawling, sneaking o spinning.lying
life:Segundos que se queda, de 0.2 a 120.5
equip:Lleva la armadura y el arma con las que murió.true
glow:Color de contorno.ninguno
y:Altura sobre el ancla.0
face:Se gira hacia quien disparó la secuencia.true
from:x,y,z / to:x,y,zDónde aparece y dónde acaba.0,0,0
over:Segundos que dura el movimiento.0.7
ease:out, in, in_out o linear.out
gravity:Bloques por segundo al cuadrado, sumados a la línea.0
turn:Grados que gira sobre sí mismo durante el movimiento.0
pose_to: / after:Una segunda pose, y cuánto tarda en llegar.ninguna / 0.4
hurt:Parpadea en rojo al aparecer.false
spin:Grados por segundo que sigue girando, durante toda su vida.0
bob: / bob_every:Bloques que sube y baja en bucle, y cuánto dura una subida y bajada.0 / 1.6
swing:Segundos entre golpes de brazo.0
scale:Cómo de grande se dibuja, siendo 1 el tamaño de un jugador.1
hold: / offhand:Un material puesto en cada mano.el suyo
pitch:Inclinación de la cabeza en grados, negativo hacia arriba.0

spin: es el que se usa cuando un cuerpo no debe asentarse: turn: es un giro repartido en el movimiento y luego se acaba; spin: no para nunca. Un cuerpo atrapado en un vórtice es spin:220, uno colgando en la luz es bob:0.3;spin:40, y uno que sigue golpeando a lo que lo mató es swing:0.5;hold:NETHERITE_SWORD. scale: es el atributo de escala del propio cliente, así que crece el modelo entero — 0.4 es un muñeco y 2.5 es algo para lo que la sala se queda pequeña; necesita un cliente 1.20.5, y uno más viejo ve un cuerpo de tamaño normal.

PluginNpcs npcs = Npcs.of(this);
 
NpcHandle body = npcs.show(NpcModel.of(victim)
                .wearing(victim)
                .pose(NpcPose.LYING)
                .glow(0xA33B53),
        victim.getLocation(), 4000, observers);
 
body.lookAt(killer.getLocation());

Un cuerpo se lee mejor a la mitad de la gravedad vanilla: uno real pesa más de lo que el ojo espera y va más lento de lo que dice el número. pose:lying es la pose de un jugador durmiendo, que es la única forma de dejar un cuerpo en el suelo sin un modelo propio; pose:standing con face:true es otro efecto completamente distinto: alguien que se ha parado y te está mirando.

Por qué un NPC no acepta un nombre de jugador

NpcModel.of(player) lee la textura de la conexión que este servidor ya tiene: sin consulta, sin espera, sin fallar a medias. Un nombre sería una petición a Mojang, y un efecto no puede esperarla. Una textura en base64 escrita en el archivo sí vale, y se resuelve al leer el archivo.

Un NPC siempre tiene identidad propia

Se anuncia bajo un UUID propio, nunca el del portador: una segunda entrada bajo el id de un jugador real le quita su propia skin de su propio cuerpo hasta que se reconecte. También se anuncia sin listar, así que nunca aparece en el tab junto a jugadores reales.

Ragdolls

Un cuerpo que se deshace. El jugador se corta en sus seis partes — cabeza, torso, dos brazos, dos piernas —, cada una con los colores de su propia skin, y esas partes se mueven como una sola coreografía: lanzadas, abiertas, girando, aplastadas, deletreadas en letras o llevadas enteras.

effects:
  # Reventado. Las piezas salen hacia fuera, caen, rebotan y se quedan.
  - '[RAGDOLL] {victim};intact:0.3;life:2.6;speed:4.2;up:6.4;spin:2.2;detail:2;light:15'
  # Levantado, abierto y llevado hacia arriba. No queda nada en el suelo.
  - '[RAGDOLL] {victim};pose:vortex;rise:3.0;open:0.7;turns:1.8;life:3.0;detail:2;glow:{highlight}'

La cabeza acepta {victim}, {killer} o una textura en base64, igual que [NPC]. Si lo que murió no era un jugador, la línea lo dice una vez y no dibuja nada.

Las poses

PoseQué pasaTambién se escribe
burstReventado: las piezas salen hacia fuera, caen, rebotan y se quedan. La de por defecto.
spreadSe levanta del suelo y se abre, brazos y piernas en cruz, girando despacio — y luego se suelta.starfish, open
knockedAbierto como spread y golpeado varias veces desde distintos lados.knock, batted, hit
vortexLlevado: las piezas suben en espiral hacia dentro y desaparecen arriba. No queda nada.taken, ascend, spiral
balloonLa cabeza se hincha demasiado, se tambalea y revienta. El cuerpo espera debajo.bighead, swell, pop
helicopterLos brazos se ponen planos sobre la cabeza como un rotor, el cuerpo gira al revés y se va hacia delante.chopper, rotor
planeBrazos como alas, morro arriba, inclinándose mientras sube. Con subida negativa es un picado.fly, glide, jet
flattenClavado contra el suelo y dejado plano: una mancha con forma de jugador, no un montón de bloques.pancake, squash, flat
meltSe hunde. Las piezas pierden su altura donde están y se van. Ni lanzamiento ni rebote.sink, dissolve
signLas piezas se colocan formando letras y aguantan ahí; luego se sueltan y caen.letters, spell, word
thrownEnviado a algún sitio de una pieza, dando vueltas. Sin gravedad no vuelve.launched, ejected, carried

Sus parámetros

ParámetroQué hacePor defecto
pose:Cuál de las once de arriba.burst
life:Segundos que duran las piezas.2.2
intact:Segundos que el cuerpo aguanta entero antes de que le pase nada.0.3
detail:Celdas en que se corta cada parte por eje, de 1 a 4. 1 es un color por miembro.1
size:Cómo de grande es; 1 es tamaño jugador.1
light:Nivel de luz, de 0 a 15.la del mundo
glow:Color del contorno — un nombre, #rrggbb o un token {palette}.ninguno
fade:Se encoge al final en vez de desaparecer.false
settle:Deja de girar al aterrizar.true
y:Altura sobre el ancla.0
face:Se gira hacia quien lanzó la secuencia.true
speed: up:Con qué velocidad salen las piezas, hacia fuera y hacia arriba.3.2 / 6.5
spread:Cuánto se diferencian las piezas entre sí, de 0 a 1.0.45
gravity: bounce:Bloques por segundo al cuadrado, y la velocidad que conservan al caer.26 / 0.32
spin:Vueltas por segundo.1.8
rise: open:A qué altura cuelga un cuerpo sostenido, y cuánto abre brazos y piernas.1.1 / 0.55
lift: hang: turns:Segundos que tarda en subir, segundos que cuelga y vueltas que da mientras cuelga.0.45 / 0.9 / 0.35
hits: every: force:Para knocked: cuántos golpes, segundos entre ellos y cuántos bloques lo empuja cada uno.3 / 0.32 / 0.85
swell:Para balloon: cuántas veces su tamaño alcanza la cabeza.3
squash:Para flatten: qué queda de la altura de una pieza.0.14
sign: letters:Para sign: qué deletrea el cuerpo, y cuánto mide una letra en bloques.EZ / 2.4
dir:Hacia dónde se lanza o vuela, en grados. 0 es este, 90 es sur.la orientación del ancla
PluginRagdolls ragdolls = Ragdolls.of(this);
 
ragdolls.show(RagdollModel.of(victim).detail(2).light(15),
        RagdollMotion.builder().pose(RagdollPose.VORTEX).rise(3.0).build(),
        victim.getLocation(), observers);
`detail` es el único parámetro caro de aquí

Cada parte se dibuja como una rejilla de detail × detail, así que seis partes cuestan 6 × detail² displays: detail:1 son seis, detail:2 son veinticuatro y detail:4 son noventa y seis. Dos ya se lee como un cuerpo a cualquier distancia desde la que alguien lo mire de verdad; cuatro es para un cuerpo que se queda quieto delante de la cámara.

Una pose es coreografía, no física

Todas se resuelven de antemano y se le entregan al cliente como poses, así que lo que las separa es lo que el archivo quería decir, nunca lo que el servidor podía permitirse. Aquí no se simula nada, y no se tickea nada.

Skins reales: mineskin-key

De serie, la cabeza de un ragdoll lleva la cara real del jugador, pero el resto del cuerpo se dibuja con bloques: cada pieza toma el bloque de color más parecido a esa parte de la skin. Por eso una ropa oscura se ve como un cuerpo negro hecho de bloques. Para que todo el cuerpo lleve la skin real, ExyliaLib necesita una clave de la API de MineSkin, puesta en el plugins/ExyliaLib/config.yml de la propia ExyliaLib:

plugins/ExyliaLib/config.yml
mineskin-key: 'tu-clave'
ragdoll-skin-quality: normal
ClaveQué hacePor defecto
mineskin-keyUna clave gratuita de account.mineskin.org/keys. Vacía, todos los cuerpos siguen en bloques.vacía
ragdoll-skin-qualityLo fino que se corta un cuerpo con su skin real, y por tanto cuántas subidas cuesta una skin nueva.normal
CalidadSubidas por skin nuevaCómo se veSkins nuevas por hora en el plan gratuito
high18Cubos de 4 píxeles; un cuerpo que se rompe sale en 19 piezas.unas 5
normal10Cada píxel de la skin, exacto; 11 piezas más grandes.unas 10
low5Una cabeza por parte; se pierde un tercio de las filas.unas 20
  • Se hace una vez por skin. Una skin se prepara cuando entra su dueño, se sube en segundo plano y se guarda en la base de datos del plugin que muestra los cuerpos (su database.yml, tabla exylia_ragdoll_skins). Ese servidor, o una network que comparta esa base de datos, no la vuelve a subir nunca.
  • Los límites del plan gratuito. El plan gratuito de MineSkin permite 20 subidas por minuto y 100 por hora. Pasada la hora, las subidas esperan a que se reinicie y la consola dice cuándo vuelven a empezar.
  • Nunca se espera. Una pieza cuya textura aún no ha llegado se dibuja con bloques hasta que llega.
  • Se aplica en caliente. /exylialib reload lee las dos claves, y un cambio de clave o de calidad vuelve a preparar las skins de todos los conectados.

Lo que garantizan los tres

Nada que el servidor cargueNo son entidades: ni se tickean, ni se guardan, ni están en ningún chunk, ni tienen hitbox. Dos jugadores juntos pueden ver cosas distintas.
Nada se puede quedar atrásNada más los limpiaría, así que el módulo es dueño de su vida: se van al acabar el movimiento o la vida, al desactivar el plugin o al parar el servidor. No hay un cuarto caso.
Un temporizador, no uno por objetoTodos los displays del servidor se mueven desde un único driver asíncrono.
El giro se trocea por tiEl cliente gira por el arco más corto, así que los giros se parten en sextos de vuelta; spin:3 sale bien sin que nadie lo sepa.
Trabajo con techoUn archivo que pide doscientas vueltas se limita a cuarenta y ocho poses en vez de mandar doscientos paquetes.
PacketEvents o nadaNo hay respaldo que valga la pena fingir.

El techo de lo que pueden costar los displays

plugins/ExyliaLib/displays.yml tiene dos números para todo el servidor, porque lo que se le puede mandar a un cliente es un hecho del servidor y no del plugin que lo mandó.

max-viewer-displays: 20000
max-per-effect: 128
ClaveQué limita
max-viewer-displaysPares display-espectador a la vez: un display que ven treinta jugadores cuenta como treinta. Los efectos que se pasarían se descartan antes de construir sus paquetes, así que una arena llena pierde la cola de un efecto y no su tick rate. La consola lo dice como mucho una vez por minuto. 0 quita el techo.
max-per-effectCuántos displays puede dibujar una sola forma — un points:900 escrito a mano se caza al cargar y no en el cable.

El presupuesto cuenta espectadores porque es el número que llega a la red: doscientos displays en una esquina vacía no son nada, y esos mismos doscientos con treinta jugadores alrededor son seis mil entidades en clientes que además tienen una pelea que renderizar. /exylialib reload recoge un cambio; no hace falta reiniciar.

Flags de región

Flags de WorldGuard que registra la librería, para que una región pueda rechazar efectos sin que ningún plugin dependa de WorldGuard:

FlagNegarla impide
kill-effectsQue suenen efectos de muerte donde alguien murió dentro de la región.
hit-effectsQue suenen efectos de golpe por un impacto dado dentro de la región.
arrows-effectsLos efectos de lanzamiento, estela e impacto de flechas dentro de la región.

Se registran desde el onLoad de la propia librería, porque WorldGuard cierra su registro en cuanto arranca. En un servidor sin WorldGuard cada flag permite, y una flag no registrada, un mundo que no existe o un registro que se negó responden igual: una puerta que no se puede preguntar nunca quita nada.

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