Configuración
Archivos YAML declarados como records de Java, generados a partir de ellos, y migrados cuando cambian de forma.
El record es la fuente de verdad. El archivo YAML es salida, no entrada: se genera a partir del constructor sin argumentos del record, comentarios incluidos, y se lee de vuelta a la misma forma.
ConfigFile<Settings> settings = Configs.define(this, "config", Settings.class).load();
int pool = settings.get().database().poolSize();Declarar un archivo
public record Storage(
@Comment("Conexiones abiertas. Regla rápida: núcleos × 2.")
@Key("pool-size")
int poolSize,
@Comment("Dónde viven los datos de jugador.")
String host) {
/** Los valores con los que se genera el archivo. */
public Storage() {
this(10, "localhost");
}
}| Anotación | Qué hace |
|---|---|
@Key("otro-nombre") | La clave YAML difiere del nombre del componente. |
@Comment("…") | Se escribe encima del valor en el archivo. Repetible — varias líneas, en orden. |
Los records anidados se convierten en secciones anidadas, así que la estructura del archivo es el árbol de records.
Son lo que lee el dueño del servidor en vez de tu documentación. Di qué cambia el valor, en qué unidad
y en qué rango — Segundos que un jugador sigue marcado tras recibir un golpe, no duración del tag.
Leer y escribir
| Llamada | Qué hace |
|---|---|
get() | La instantánea actual. Un acceso a campo, nunca un reparseo. |
reload() | Relee el archivo. Devuelve los problemas; lista vacía significa limpio. |
onReload(consumer) | Se ejecuta tras cada recarga correcta. |
save() | Escribe la instantánea actual en disco. |
update(operador) | Cambiar y persistir en un paso. |
issues() | Problemas de la última carga. |
schema() | Una descripción de solo lectura del tipo del record. |
settings.update(actual -> actual.withHost("10.0.0.5"));Versiones y migraciones
Un archivo recibe un marcador config-version en cuanto declaras una versión, y las migraciones llevan
un archivo antiguo hacia adelante en el primer arranque tras actualizar:
config = Configs.define(this, "config", Settings.class)
.version(3)
.migration(1, MIGRATION_FROM_1)
.migration(2, MIGRATION_FROM_2)
.load();Los pasos se ejecutan en orden, por muy atrasado que esté el archivo. Una migración se construye con cuatro operaciones:
| Operación | Qué hace |
|---|---|
Migration.rename(de, a) | Mueve un valor a una ruta nueva. Un origen ausente se deja en paz. |
Migration.remove(ruta) | Borra una clave. |
Migration.transform(ruta, reescritura) | Reescribe el valor en el sitio. Se salta si la clave no está. |
Migration.all(pasos…) | Varias de las anteriores como una sola migración. |
public static final Migration MIGRATION_FROM_1 = Migration.all(
Migration.rename("combat.combat-actionbar.text",
"combat.combat-actionbar.action-bar.text"),
Migration.remove("combat.combat-actionbar.update-interval"));Una clave que ningún record declara se elimina al cargar. Eso es lo que mantiene los archivos limpios entre actualizaciones — y es exactamente por lo que reestructurar una sección sin migración tira en silencio lo que el dueño del servidor hubiera escrito ahí. Renombra en el record y migra en el mismo commit.
transform es la herramienta correcta cuando lo que cambió es el significado de un valor y no su
sitio — un token renombrado, un número que estaba en ticks y ahora va en segundos. Reescribe lo que hay
en vez de reemplazarlo con el valor por defecto, así que las palabras y los colores del dueño
sobreviven.
Bloques que nombra el dueño
Un componente declarado Map<String, V> es una sección cuyas claves elige el dueño del servidor —
mundos, regiones, materiales — en vez de claves que decidió el código:
public record Limits(
@Comment("Multiplicador por mundo. Añade los mundos que tenga este servidor.")
Map<String, Double> worlds,
Map<String, Item> items) {
public Limits() {
this(Map.of("world", 7.0), Map.of("ender-pearl", new Item()));
}
public record Item(double cooldown, int maxUses) {
public Item() { this(14.0, 1); }
}
}worlds:
arena: 2.5
survival: 9.0
items:
ender-pearl:
cooldown: 14.0
max-uses: 1V puede ser una hoja — texto, número, booleano, enum, lista — o un record, que se convierte en un
bloque por entrada. La clave tiene que ser String; un Map de Map se rechaza, así que anida un
record y el bloque interior tendrá nombre, comentarios y valores por defecto propios.
| Nada de dentro se poda | Las claves son del dueño. Las claves dentro de un record siguen siendo del código y se podan normal. |
| Las entradas del constructor son ejemplos | Se escriben una vez, al generar el archivo. Una entrada que el dueño borró se queda borrada, y un bloque vaciado se queda vacío. |
| Una entrada inventada hereda los defaults del record | Para lo que no haya escrito. |
| Una entrada ilegible cuesta esa entrada | Se avisa en su propia ruta; el resto carga. |
| Se conserva el orden de inserción | El archivo no se reordena en cada guardado. |
Secciones que no hacen nada
Un record que implementa Sparse decide por sí mismo si tiene algo que decir. Mientras isEmpty()
responda true, la sección no se escribe en el archivo, leerla de vuelta no dice nada y no vuelve
a aparecer en la siguiente carga; un bloque vacío que escribió una versión anterior se elimina en el
siguiente guardado.
Eso es lo que evita que un efecto con una sola boss bar escriba además un título, una action bar, un sonido, una partícula y un firework vacíos, cada uno con un comentario por clave. Solo vale para secciones cuyos valores por defecto están vacíos por naturaleza — una con valores reales tiene que quedarse en el archivo, o nadie se entera de que existe.
Claves desconocidas
Cualquier clave que ningún record declare se elimina al cargar y se reporta una vez como
UNKNOWN_KEY. Es una operación de un solo sentido, así que una sección que se está retirando a
propósito merece una nota en el código diciéndolo.
Recargar todo lo de un plugin
List<ConfigIssue> issues = Configs.reloadAll(this);Cada ConfigIssue dice qué archivo, qué ruta y qué estaba mal. Un valor malo cuesta ese valor, no el
archivo: el resto carga y el valor por defecto rellena el hueco.
¿Falta algo en esta página? Dínoslo en Discord