Contenido generado con IA — puede contener errores.

Juego

Recompensas, loot y economía

Lo que un jugador ganó, lo que sale de un cofre, y cuánto vale un saldo.

Recompensas

Una lista de recompensas son items, comandos y dinero con probabilidades y condiciones, editable en el juego y guardada exactamente como la guardaba ExyliaCommons.

PluginRewards rewards = Rewards.of(this);
 
rewards.give(player, config.winnerRewards(), context);
LlamadaQué hace
give(player, rewards, context)Entregar una lista entera.
give(player, reward)Una entrada.
roll(player, rewards, context)Dar lo que salió por probabilidad.
pick(rewards)Elegir sin dar — para una vista previa.
giveLater(uuid, owed)Encolar para alguien desconectado.
claim(player, callback)Entregar lo que se le debía.
editor(rewards)El editor de lista en el juego.
overflow(policy)Qué pasa cuando el inventario está lleno.
claimOnJoin(then)Vacía la cola en cada entrada, sin escribir un listener.
pending(store)Dónde se guardan las recompensas pendientes.

Desconectado no es premio perdido

giveLater escribe en un PendingRewards y claim lo vacía en la siguiente conexión del jugador. La cola se limpia antes de entregar y no después, así que un fallo a mitad de entrega no puede duplicar una recompensa la próxima vez.

Tres líneas son la cola entera, tabla y listener de entrada incluidos:

rewards = Rewards.of(this)
        .overflow(OverflowPolicy.QUEUE)
        .pending(PendingRewards.database(this))
        .claimOnJoin((player, delivery) -> messages.claimed(player, delivery.given()));

PendingRewards.database(plugin) escribe en exylia_pending_rewards en la base de datos de tu propio plugin — la que diga plugins/<Plugin>/database.yml, H2 en un archivo por defecto. ExyliaLib no tiene base de datos propia y nunca abre una. Dos plugins apuntando a la misma base comparten tabla y se distinguen por la columna que los nombra. Un jugador tiene tope de 200 lotes pendientes por plugin; pasado eso la escritura se rechaza y se dice una vez en consola: una cola es donde un bug escribe en bucle.

Sigue implementando PendingRewards a mano cuando las filas ya existen en otro sitio — ExyliaCapture y ExyliaEvents tienen cada uno su tabla, y ninguno tuvo que migrar por esto.

`keep` corre en el hilo que debía la recompensa

Escribir en la base de datos ahí mismo es un parón en el hilo principal. El store de arriba programa la escritura él solo; uno escrito a mano tiene que llamar a Tasks.of(plugin).runAsync(...) y volver. claim es lo contrario — ya está fuera del hilo principal, así que lee directo.

Desbordamiento

OverflowPolicy decide qué significa un inventario lleno: soltar a los pies, encolarlo o rechazar. Elegirlo por plugin es la gracia — un drop de mob puede caer al suelo, un premio de caja debería esperar. QUEUE necesita un pending; sin él suelta y lo dice, porque pedir encolar es pedir no perderlo.

Loot

Lo que sale de un cofre, un generador o un bloque roto:

List<LootEntry> table = Loot.parseAll(section.getStringList("loot"));
 
List<ItemStack> filled = Loot.roll(table);      // lo que llena un cofre
ItemStack single = Loot.pick(table);            // una tirada
CampoQué hace
ObjetoEl ítem, con su nombre, encantamientos y lore.
weightCuán probable es esta entrada respecto a las demás.
minAmount / maxAmountEl rango de cantidad que se sortea.
tierUna etiqueta, para que una entrada pertenezca a una banda de rareza.

Los pesos son relativos, no porcentajes: una entrada con peso 10 junto a otra con 5 sale el doble de veces, y los números no tienen que sumar nada.

Loot.editor(plugin, entries) es el editor en el juego para una.

Economía

Una sola elección de economía para todo el servidor, sobre Vault, PlayerPoints o una moneda que escribas:

Economy.balance(uuid);
Economy.has(uuid, amount);
 
Economy.charge(uuid, amount);                  // true si salió adelante
Economy.pay(uuid, amount);
 
EconomyResponse taken = Economy.withdraw(uuid, amount);
TransferResult moved  = Economy.transfer(from, to, amount);

charge y pay responden con un booleano para el caso habitual; withdraw y deposit devuelven un EconomyResponse cuando necesitas saber por qué falló. Nada lanza — un cobro que no se pudo hacer es un resultado sobre el que ramificar, no una excepción que cazar alrededor de un clic de menú.

Se soportan varias monedas: Economy.of("points") acota cada llamada a una, y Economy.currencies() lista las registradas.

Un servidor sin plugin de economía recibe un proveedor que lo dice, así que el fallo es "no hay economía instalada" y no un NoClassDefFoundError a mitad de una compra.

Formatos

La otra mitad del dinero: lo que lee un jugador, y lo que teclea un jugador.

Formats.money(1234567);          // "1.23M", o lo que haya configurado el dueño
Formats.compact(1234567);        // el mismo acortado, sin moneda
Formats.percent(0.42);
Formats.percentOf(3, 12);
Formats.date(epochMillis);
Formats.relative(epochMillis);   // "hace 3 minutos"
 
Amounts.parse("10M");            // lo que tecleó un jugador, de vuelta a número

Leer 10M del chat usa el mismo parser que la entrada amount, así que un menú, un comando y una petición por chat aceptan la misma abreviatura.

El locale está fijado a propósito

Los formatos decimales usan un locale fijo y no el de la máquina. Un servidor en España escribiría 1,50, y ese valor rompe cada scoreboard, comparación y config que lo lea de vuelta.

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