Proyecto de Servidor Vortrium
★ En Desarrollo ★
Actualizado el: 07 Sep 2026
Mejor visto en 1024x768

▸ BIENVENIDO

Un servidor autoritativo sin una línea de código heredado.

L2V sirve al cliente retail sin modificar — revisiones de protocolo 140 y 152, con contenido High Five. El protocolo y la geodata son restricciones que heredamos; todo lo que hay detrás es nuestro. El servidor es autoritativo: el cliente envía intenciones, nunca estado.

Sin L2J, sin núcleo bifurcado, sin códec escrito a mano. Dieciocho módulos Gradle con module-info.java en todos, de modo que el compilador es lo primero que rechaza una violación de arquitectura.

Veinte reglas inviolables sostienen el diseño, y la mitad de ellas las rechaza una máquina, no una revisión.

▸ LO QUE YA FUNCIONA

un cliente real inicia sesión, entra al mundo y camina

Login y juego son dos puertos de un mismo proceso desde el primer día. Todo lo de abajo existe en el repositorio con pruebas encima; todo lo que no está abajo no existe, y el roadmap lo dice sin rodeos.

La conversación de login

El handshake heredado completo: bloque RSA de credenciales, flujo Blowfish, módulo revuelto. Contraseñas con Argon2id, límite de tasa por dirección y por cuenta, retroceso ante cada fallo.

El paso al mundo

Lista de servidores, token de sesión de un solo uso y un puerto de juego que caduca el token la primera vez que lo acepta. Las cuentas nacen de un comando, nunca del puerto.

Códec generado

Cada paquete, enum y primitiva de buffer sale de los archivos de esquema. schema.lock rompe el build si un campo se elimina, se reordena o cambia de tipo, o si un opcode se renumera.

Entrar y salir del mundo

Creación, selección y entrada de personaje contra Postgres, con plantillas y objetos iniciales del datapack — y el camino de vuelta, a la lista de personajes o a la pantalla de login.

Tick y zonas

Un platform thread por zona, un escritor, dos encuentros por tick. Un mensaje publicado en el tick N se aplica en el tick N+1, siempre.

Movimiento sobre suelo real

Movimiento resuelto celda a celda contra una rejilla de colisión convertida, mapeada en memoria fuera del heap. A* sobre la misma rejilla para las rutas.

Gestión de interés

Aparecer, moverse y desaparecer salen como CharInfo, MoveToLocation y DeleteObject, decididos por una rejilla de celdas y nunca por un barrido de la zona.

Chat y equipo

Una línea de chat y un cambio de equipo salen por el mismo tres por tres de celdas. Al público se le responde en el hilo que lo posee, no reuniéndolo en el borde.

Recoger y soltar

El cliente nombra lo que intenta alcanzar y dónde cree que está; lo segundo se descarta. La zona mide la distancia y decide cuál de dos jugadores llegó primero.

Inventario que sobrevive a un reinicio

Lo que un personaje lleva se escribe en Postgres y se lee de vuelta al entrar. El contador que da identidad a cada objeto también sobrevive a un reinicio, así que la numeración sigue en lugar de empezar de nuevo.

El dinero como saldo

La moneda es un saldo y no una fila en la bolsa, así que el dinero en el suelo dejó de leerse como dinero destruido. Y dos paquetes ya no tocan la misma bolsa en el mismo instante.

Libro mayor y transacciones

Nada puede añadirse, quitarse ni moverse sin decir adónde va el registro y por qué. Las transacciones se aplican juntas o se deshacen hacia atrás dentro de un tick.

Catálogos del datapack

El catálogo de habilidades y las tablas de atributos por clase se convierten del contenido del cliente y se cargan en el arranque en estructuras inmutables. El combate necesita ambas antes de poder escribirse.

Selección de objetivo

Un jugador puede apuntar a algo, y el servidor es quien decide a qué se apuntó. Todo aquello para lo que sirve un objetivo, daño, habilidades y muerte, sigue por delante.

Determinismo y replay

Quinientos ticks sobre sesenta y cuatro entidades, con semilla, producen el mismo hash de estado en cada ejecución; dos zonas intercambiando tráfico durante cuatrocientos ticks también.

La sonda

Instrumentación sobre cada costura que la simulación ya expone, para que un silencio deje de parecer una respuesta. No decide nada y solo se conecta en nivel de depuración.

▸ MEDIDO, NO PROMETIDO

JMH con el profiler de asignación, dentro del build
24 B
asignados por tick

Sin importar la cantidad de entidades, y cero bytes por entidad por tick. Una prueba le pregunta a la JVM y rompe el build si no es plano.

34 µs
para 1.000 caminantes

Contra un presupuesto de 60.000 µs, con el movimiento resuelto sobre una rejilla de colisión real.

100
entidades por cliente, máximo

Las 24 más cercanas actualizadas cada tick, el resto cada quinto — haga lo que haga un asedio.

140 Mbit
para 3.000 jugadores

Donde un broadcast sin gestión cuesta 380. El cuello de botella real es la gestión de interés, no el tick.

▸ POR QUÉ NO PARTIR DE L2J

L2J hizo posibles dos décadas de servidores privados. También es la razón por la que la mayoría no se puede razonar. Nada de esto es un fork, un port ni una limpieza de él.

01

Acumulado, no diseñado

Veinte años de parches sobre un núcleo que ya era ingeniería inversa. El comportamiento vive en casos especiales y no en un modelo que alguien pueda enunciar.

02

Un códec escrito a mano

Aquí el códec se genera desde un esquema versionado y un lock file, así que un campo que se mueve en silencio es un build roto en lugar de un cliente dibujando lo que no es.

03

Locks y estado global

Un escritor por zona, ningún estado estático mutable, ningún lock en la simulación — los tres rechazados por ArchUnit, no por convención.

04

Nada que repetir

El tiempo y la aleatoriedad inyectados hacen la simulación determinista, así que un fallo de concurrencia se reproduce en vez de discutirse.

▸ ARQUITECTURA

las dependencias apuntan en una sola dirección

El sistema de módulos impone la dirección. El dominio no sabe nada de Netty, JDBC, Postgres ni de un paquete; el game server es el único módulo que conoce a todos los demás.

                   domain  <----- (nothing beyond the JDK)
                      ^
  collision ----------|
  datapack -----------|
                      |
                    world
                      ^
  protocol ---> net --|---> journal
                      |
                persistence
                      ^
                game-server   (composition root)
DIECIOCHO MÓDULOS
vortrium-bom
vortrium-protocol-schema
vortrium-protocol
vortrium-domain
vortrium-collision
vortrium-geodata
vortrium-content
vortrium-datapack
vortrium-world
vortrium-journal
vortrium-persistence
vortrium-net
vortrium-ops
vortrium-probe
vortrium-testkit
vortrium-conformance
vortrium-login-server
vortrium-game-server
edge funcionando

Netty y framing

Handshake, cifrado, framing y despacho en el event loop, fijo al número de núcleos. Virtual threads solo para trabajo de borde que bloquea, nunca para lógica de juego.

protocol funcionando

Esquema y códec

Records bajo una interfaz sellada, despacho exhaustivo por construcción. Nueve de las diez formas que exige un formato de cable heredado — incluidos recuentos que el cable nunca lleva y spans que el propio códec mide.

simulation en marcha

Tick, zonas, interés

Almacenamiento columnar de entidades en vez de un array de objetos, mapas primitivos, una free list de slots. Ninguna asignación por entidad por tick.

domain inicial

Reglas puras

Daño, habilidades, validación de inventario, curvas de experiencia. Sin reloj de pared, sin random global, sin entrada ni salida — y sin dependencia más allá del JDK.

collision en marcha

Suelo convertido

El cliente retail High Five no trae geodata alguna, así que la rejilla se convierte offline desde un conjunto de geodata del mismo mundo. El servidor mapea el suelo y nunca lo inventa.

durability diseñado

Journal y outbox

Snapshots write behind para lo que puede perderse; un registro append only con fsync para lo que no. La confirmación de un evento irreversible espera al journal.

observability funcionando

Sonda

Instrumentación que envuelve las costuras que la simulación ya expone, registra una línea y delega. Conectada solo en nivel de depuración, no decide nada, y solo depende de ella la composition root.

▸ VEINTE REGLAS INVIOLABLES

Una regla sin quien la haga cumplir es una sugerencia, y una sugerencia no sobrevive a seis meses de prisa. Cada regla nombra el mecanismo que rechaza la violación, y dice honestamente si ya existe.

10
automatizadas
Una máquina rechaza la violación antes de que el commit termine.
8
parciales
Mitad automatizada; las notas nombran la mitad que no lo está.
2
pendientes
Sostenidas por revisión hasta que exista el código que cada una protege.
01 Ninguna entrada o salida en el hilo del tick parcial
02 Un único escritor por zona auto
03 El dominio no depende de nada más que del JDK auto
04 El servidor es autoritativo; cada paquete es una intención pendiente
05 Cero asignación en el camino caliente en régimen auto
06 Determinismo: el tiempo y la aleatoriedad se inyectan auto
07 Ningún estado estático mutable auto
08 El códec se genera, nunca se escribe a mano auto
09 Ninguna lectura de base de datos en el runtime del juego parcial
10 El tráfico entre zonas es solo mensajes auto
11 El datapack es inmutable en runtime auto
12 Un paquete inválido cierra la conexión auto
13 Ninguna optimización sin medición parcial
14 Las preview features quedan fuera de los módulos de producción auto
15 Toda mutación de objeto emite un evento de libro mayor parcial
16 Una transacción de objetos es atómica dentro de un tick parcial
17 La colisión se convierte de una fuente, nunca se autora parcial
18 Ningún broadcast sin gestión de interés parcial
19 Ningún buffer por conexión sin límite parcial
20 Un evento irreversible pasa por fsync antes de confirmarse pendiente

▸ ROADMAP

ninguna fecha prometida

La cifra de arriba es el roadmap ponderado por fase, no una suposición sobre el juego. Combate, habilidades, NPC y misiones todavía no existen: casi todo lo terminado es la máquina que tendrá que sostenerlos.

LEYENDA
hecho
en marcha
sin empezar
01

Fundación y conformidad

Reparto en módulos, descriptores de módulo, quality gate, las reglas como pruebas.

hecho
02

Protocolo y generador de códec

Lenguaje de esquema, códec generado, schema.lock, fuzzing a cincuenta mil frames por dirección.

hecho
03

Servidor de login

Handshake, Argon2id, límite de tasa, directorio de mundos, paso de sesión, comando de cuenta.

hecho
04

Runtime del mundo

Bucle de tick, zonas, barreras, almacenamiento columnar, replay determinista.

hecho
05

Entrar y caminar

Ciclo de vida del personaje, caminata con colisión, pathfinding, vista con gestión de interés, chat y equipo.

hecho
06

Objetos y durabilidad

Inventario, moneda y persistencia están en pie; el journal con fsync detrás de ellos todavía no.

en marcha
07

El mundo entero

Un conversor que hace streaming de tres mil regiones, en vez de los tiles que caben en una ejecución.

siguiente
08

Combate y habilidades

El catálogo de habilidades y las tablas de atributos por clase cargan en el arranque y un jugador puede apuntar. Las fórmulas High Five, el daño, la muerte y la inteligencia de los NPC siguen por delante.

inicial
09

Sistemas y endgame

Clanes, asedios, olimpiada, instancias, misiones.

sin empezar
10

Carga y endurecimiento

Enjambre de bots contra la premisa de coste, revisión de exploits, herramientas de operación.

en marcha

▸ LICENCIAS

abierto para colaborar, cerrado para explotar

L2V no es open source y no va a serlo. El código es privado, y la licencia es nominal, intransferible y revocable. Lo que le pasó a L2J no fue ser gratuito; fue que nadie podía decir que no. Aquí alguien puede.

QUÉ TERMINA UNA LICENCIA
  1. Redistribuir el código o un binario, a quien sea, al precio que sea.
  2. Mantener un fork. Un cambio sube al upstream, o queda privado y termina con la licencia.
  3. Vender cualquier cosa que altere el balance de combate.
  4. Exhibir el sello de verificado con un core modificado.
  5. Dejar un exploit conocido sin parchear después de que la corrección salió.
Colaborador
leer el código y cambiarlo
US$ 9 al mes
o US$ 90 al año
  • El repositorio privado: leerlo y abrir un pull request contra él.
  • Revisión de quienes escribieron las reglas que tu propuesta tiene que pasar.
  • Las discusiones de diseño, y voto en cada RFC.
  • El datapack convertido y las builds internas, para ejecutar lo que cambiaste.
Fundador
ganado, no vendido
ganado
los primeros veinte parches integrados
  • Todo lo del colaborador, para siempre, sin la cuota.
  • Se da por un parche de fondo ya integrado. No hay forma de comprarlo.
  • Una licencia de operador no comercial, incluida.
  • Tu nombre queda en los créditos pase lo que pase con el proyecto después.
Operador
un servidor, sin vender nada
US$ 180 al año
un servidor, sin monetización de ningún tipo
  • Ejecutar un servidor público. Sin donaciones, sin tienda, sin vender nada.
  • El sello de build verificada, y un puesto en el directorio de servidores.
  • Parches de seguridad el mismo día que los reciben los colaboradores.
  • Las herramientas de conversión del mundo sobre el que corre tu servidor.
Comercial
un servidor, y cobrar por él
US$ 150 al mes
hasta 300 jugadores; US$ 400 hasta 1.000; por encima, negociado
  • Todo lo anterior, más el derecho a aceptar donaciones y a vender.
  • Precio por pico de jugadores simultáneos, que informa tu propio servidor.
  • Respuesta en un día hábil, y releases antes de que sean públicas.
  • Nada de lo que vendas puede alterar el balance de combate. Eso está en la licencia.

Los precios son de lista. Brasil, América Latina y la CIS pagan una tarifa regional; pídela. Las licencias se emiten a mano, una conversación cada vez.

Dónde está escrito el diseño

La referencia de arquitectura es la fuente de verdad, no un resumen del código — cuando las dos discrepan, una de ellas es un bug y el pull request dice cuál. vortrium-conformance es la mitad ejecutable de las reglas. El repositorio es privado mientras el trabajo de protocolo se asienta.