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);| Llamada | Qué 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.
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| Campo | Qué hace |
|---|---|
| Objeto | El ítem, con su nombre, encantamientos y lore. |
weight | Cuán probable es esta entrada respecto a las demás. |
minAmount / maxAmount | El rango de cantidad que se sortea. |
tier | Una 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úmeroLeer 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.
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