Saltar al contenido principal

Shops

Menús de tienda con precios fijos, dinámicos o de trueque, stock, límites, impuestos y tres tipos de moneda.

Gratuitasv1.12Economía y crafteo
RequiereTypeWriter0.9GUI0.17+VaultopcionalPlaceholderAPIopcionalDiscordopcional

Descripción general​

Shops permite a los jugadores comprar y vender objetos desde un menú de inventario que construyes en el panel web de TypeWriter. Una tienda es una única entrada Shop Definition: contiene la lista de objetos a la venta, sus precios, la moneda, los límites, los mensajes y el layout del menú. Un jugador la abre con /tw shop <id> o desde una acción Open Shop disparada por una misión, un NPC o un botón de otro menú.

Cada objeto tiene un precio de una de estas tres formas: un precio fijo, un precio dinámico que sigue las existencias o trueque, en el que el objeto se paga con otros objetos en lugar de con dinero. Las compras y las ventas pasan por Vault, una economía de PlaceholderAPI o un saldo de puntos integrado.

El propio menú se dibuja con la extensión GUI. Colocas marcadores en un layout donde aparecen los productos (SHOP_ITEM) y botones etiquetados para paginar, cerrar y elegir cantidades, y Shops los rellena para cada jugador.

Características​

  • Precios fijos, dinámicos y en objetos: un precio único por unidad, un precio que sube a medida que bajan las existencias o una lista de objetos que entregar.
  • Trueque: priceMode ITEMS vende un artículo a cambio de uno o varios objetos, con un precio por defecto para toda la tienda y el token de lore {item_price}.
  • Tres monedas: VAULT, PLACEHOLDER (saldo leído de un placeholder de PlaceholderAPI y modificado con comandos de consola) y un saldo POINTS integrado.
  • Acciones de clic y cantidades: compra o vende 1, una pila, el máximo, todo, una cantidad personalizada desde un diálogo o una cantidad fija como 10 en un submenú.
  • Existencias, límites y reinicios: existencias por objeto, límites por jugador y globales, topes de compra y venta para toda la tienda, y reinicios con un calendario cron, por intervalo, diario, semanal o mensual.
  • Impuestos y promociones: un impuesto global, sobrescrituras de impuesto por objeto y descuentos porcentuales temporizados.
  • Menú en el panel: conjunto de layouts, submenú, objeto de relleno, lore de precios y formatos de nombre y lore por defecto.
  • Pestaña de un menú compartido: una tienda puede convertirse en una vista de un chasis de GUI mayor mediante baseMenuId.
  • Comandos de administración: listar, inspeccionar, abrir, reiniciar, editar existencias y consultar el historial de transacciones.
  • Anuncios en Discord: las transacciones se anuncian como un evento que la extensión Discord retransmite a un webhook.

Instalación​

  1. Instala la extensión GUI (versión 0.17 o posterior) y TypeWriter en un servidor Paper o Folia.
  2. Opcional, para la moneda VAULT: instala Vault y un plugin de economía que se registre en él.
  3. Opcional, para los placeholders en títulos y lore, y para la moneda PLACEHOLDER: instala PlaceholderAPI.
  4. Descarga el JAR de Shops desde las releases de GitHub (el botón del panel de resumen de arriba), colócalo en plugins/Typewriter/extensions/ y reinicia el servidor.
  5. En el panel web, crea una entrada Shop Artifact y llámala shop_artifact. Shops lee y escribe sus existencias, límites y puntos a través de esa entrada.

Primeros pasos​

Construye una pequeña tienda de armas pagada con dinero de Vault:

  1. En una página estática, añade una entrada Shop Artifact llamada shop_artifact.
  2. Añade una entrada Shop Definition. Establece title en <gold>Weapons, rows en 3 y currency en VAULT.
  3. En items, añade un objeto. Elige una espada de diamante en item, establece name en <aqua>Sword, priceMode en FIXED, fixedBuyPrice en 500 y fixedSellPrice en 100. Deja primaryAction en BUY_1 y secondaryAction en SELL_1.
  4. En layoutPool, añade un layout simple con el id main y escribe main en mainLayoutId. Añade un objeto con buttonPrefix shop_button:, buttonType SHOP_ITEM, x 1, y 1, count 7 y direction right. Esta fila de marcadores es donde aparecen los productos.
  5. Añade al layout tres objetos más con buttonPrefix shop_button: y buttonType establecido en PREV_PAGE, NEXT_PAGE y CLOSE, colocados en la fila inferior. Dale a cada uno un item y un displayName.
  6. Establece fillerItem en un panel de cristal tintado gris para que se rellenen las ranuras sin usar.
  7. Publica y ejecuta /tw shop admin list en el juego para leer el id de la tienda, y ábrela con /tw shop <id>. Para abrirla desde una misión o un NPC, añade una acción Open Shop que apunte a la tienda.

El clic izquierdo compra una espada, el clic derecho vende una, y Shift + clic izquierdo abre el submenú de compra si has configurado uno.

Objetos mostrados, objetos vendidos

Una tienda muestra tantos productos por página como ranuras marcador SHOP_ITEM tenga, y los botones de paginación recorren el resto. Si no existe ningún marcador, el menú se abre sin ningún producto.

Cómo funciona​

Al abrirse, la tienda comprueba sus criteria de acceso, aplica un reinicio pendiente y después construye el menú para ese jugador. Un clic envía la acción al gestor de transacciones, que comprueba los límites, calcula el precio con las promociones y el impuesto, cobra el pago, entrega el objeto y registra las existencias, los contadores de límites y el historial.

Menús​

Layout y botones​

Un menú de tienda es un layout simple en el layoutPool de la Shop Definition, seleccionado con mainLayoutId. Los objetos del layout llevan un buttonPrefix de shop_button: y un buttonType:

buttonTypeFunción
SHOP_ITEMUna ranura donde se coloca un producto. Repítela con count, direction, gap y repeatY. El prefijo puede dejarse vacío para este marcador.
NEXT_PAGE, PREV_PAGERecorren las páginas de productos.
INFOEnvía las líneas de infoMessage.
CLOSECierra el menú.
BACKVuelve al menú anterior, por ejemplo desde un submenú.
BUY_1, SELL_1Compran o venden una unidad. En un submenú, BUY_1:10 y SELL_1:10 comercian con 10 unidades; vale cualquier número.
BUY_STACK, SELL_STACKComercian con una pila completa del objeto.
BUY_MAX, SELL_ALLCompran tantas unidades como sea posible o venden todo lo que coincida.
BUY_CUSTOM, SELL_CUSTOMPiden al jugador una cantidad en un diálogo.
BUY_SUBMENU, SELL_SUBMENUAbren el submenú del objeto.

Los botones distintos de SHOP_ITEM, NEXT_PAGE, PREV_PAGE, INFO, CLOSE y BACK actúan sobre el objeto que el jugador ha seleccionado, por lo que pertenecen al layout del submenú. Establece siempre el buttonPrefix en shop_button:: el prefijo por defecto pertenece a otra extensión y el botón quedaría inerte.

Submenú​

Crea un segundo layout simple en el conjunto, coloca en él los botones de cantidad y escribe su id en subMenuLayoutId. El título procede de subMenuTitle, donde {item_name} es el name del objeto. Los objetos lo abren con las acciones BUY_SUBMENU y SELL_SUBMENU, que son el Shift + clic por defecto.

Acciones de clic​

Cada objeto tiene tres ranuras de acción:

CampoValor por defectoClic por defecto
primaryActionBUY_1Clic izquierdo
secondaryActionSELL_1Clic derecho
shiftActionBUY_SUBMENUShift + clic izquierdo

Las acciones posibles son NONE, BUY_1, SELL_1, BUY_STACK, SELL_STACK, BUY_MAX, SELL_ALL, BUY_SUBMENU, SELL_SUBMENU, BUY_CUSTOM y SELL_CUSTOM. El interactionConfig de toda la tienda decide qué clic activa cada acción (comprar 1, vender 1, comprar pila, vender todo, submenú, cantidad personalizada, navegación). Cada tipo de clic solo puede ejecutar una acción por objeto, de modo que, con la configuración por defecto, varias acciones asignadas a un clic izquierdo se sustituyen entre sí: cambia interactionConfig si usas más de tres acciones.

buyMaxEnabled desactiva BUY_MAX para un objeto.

Diálogo de cantidad​

BUY_CUSTOM y SELL_CUSTOM abren un diálogo con un campo de texto. Personalízalo con buyAmountPrompt, sellAmountPrompt, amountConfirmButton, amountInputLabel, amountInputPlaceholder, amountInputWidth y amountInputMaxLength. La respuesta debe ser un número entero positivo; de lo contrario se envía invalidAmountMessage. Las comprobaciones normales de precio, límite y saldo se ejecutan cuando se confirma la cantidad.

Visualización de los objetos​

Las líneas de priceLore se añaden a cada producto, después del lore propio del objeto y de su lore. defaultNameFormat y defaultLoreFormat se aplican a los objetos que no tienen name o lore propios. En estos campos y en el name y el lore de un objeto se sustituyen los siguientes tokens; una línea que pide un precio que no existe se descarta.

TokenSe sustituye por
{item}El nombre propio del objeto.
{buy}, {sell}Precio unitario formateado. Se descarta cuando el objeto no se puede comprar o vender, cuando el precio es cero y en los objetos de trueque.
{item_price}El precio en objetos, una línea por cada objeto solicitado, como - 12 × Copper Ingot (el texto se define con itemPriceLineFormat). Se descarta en los objetos que no se pagan con objetos.
{stock}, {stock_max}Existencias actuales y máximas.
{currency}El currencySymbol.

priceFormat da forma al precio mostrado: {amount} es el número con dos decimales y {currency} el símbolo.

Precios y economía​

Modos de precio. FIXED usa fixedBuyPrice y fixedSellPrice. DYNAMIC usa dynamicPricing: el precio empieza en price (y sellPrice para las ventas) cuando las existencias están llenas y se desplaza hacia max a medida que bajan, en pasos de step de stockMax, limitado por min y max y redondeado a rounding. ITEMS es el trueque.

Trueque. Con priceMode ITEMS, enumera el coste en el itemPrice del objeto, o una sola vez para toda la tienda en defaultItemPrice. Cada línea es un objeto y un amount por unidad comprada. Todas las líneas son necesarias a la vez, y comprar varias unidades multiplica cada línea. La lista propia de un artículo sustituye a la de la tienda; nunca se suma a ella. Un objeto sin precio en ningún sitio se rechaza y se registra, nunca se regala. El pago se comprueba sobre todo el inventario antes de retirar nada, primero se comprueba que haya espacio para el objeto comprado, y los objetos del catálogo se identifican por su identidad y no solo por el material. BUY_MAX compra tantas unidades como pueda pagar el inventario. Un objeto de trueque no se puede revender por dinero. Los objetos que faltan se comunican con cannotAffordItemsMessage, donde {missing} los enumera y {amount} es la cantidad.

Monedas.

currencyComportamiento
VAULTUsa la economía registrada en Vault. Necesita el plugin Vault y un proveedor.
PLACEHOLDERLee el saldo de balancePlaceholder y lo modifica ejecutando addCommand y removeCommand desde la consola, donde se sustituyen {player} y {amount}. Deben establecerse los tres. Se entienden números como 1,250.5 y 12.5k.
POINTSUn saldo que Shops mantiene en su artefacto. Empieza en 0 y crece cuando los jugadores venden objetos; la versión publicada no tiene ningún comando para conceder puntos.

Impuestos. taxRate es un porcentaje que se añade a las compras y se resta de las ventas. Con taxMode PER_ITEM, el taxRateOverride de un objeto (0 o más) lo sustituye para ese objeto; -1 mantiene el porcentaje de la tienda.

Promociones. Una Shop Promotion aplica un descuento porcentual al precio de compra y a la recompensa de venta de una tienda, para todos los objetos o para los targetItemIndices indicados (posición en items, desde 0).

Existencias, límites y reinicios​

  • dynamicPricing.stockMax establece las existencias de un objeto. Empiezan llenas, bajan cuando los jugadores compran y suben cuando venden. 0 significa que no se hace seguimiento de existencias. Con perPlayer activado, cada jugador tiene sus propias existencias de cada objeto; un reinicio rellena las de todos. Mientras una tienda está abierta, defaultRefreshTicks (y el refreshTicks de un objeto) hacen que se redibuje cuando cambian las existencias mostradas, de modo que se ven las compras de otros jugadores. El guiSlot de un objeto lo fija en una casilla concreta, y sellAllEnabled desactiva su acción de vender todo. Detalles en Shop Definition.
  • playerLimit y globalLimit limitan cuántas unidades de un objeto puede comprar un jugador, o todos juntos, por ciclo de reinicio. globalPlayerLimit, globalBuyLimit y globalSellLimit limitan toda la tienda; 0 significa ilimitado. limitReachedMessage se envía cuando se alcanza un tope.
  • reset restablece las existencias y borra los contadores de límites. Las políticas son none, cron (una expresión como 0 0 * * *), interval (segundos), daily, weekly (el día 1 es el lunes) y monthly. Las horas usan la zona horaria del servidor. La primera comprobación de un ciclo se produce cuando se abre la tienda, y también se ejecuta una comprobación cada minuto.
  • criteria restringe el acceso a la tienda y envía criteriaFailMessage cuando no se cumplen. Un objeto cuyos propios criteria no se cumplen se muestra como lockedItem y no se puede comprar.

Comandos​

Subcomandos de /typewriter, que normalmente se escribe como /tw.

ComandoDescripción
/tw shop <shop>Abre una tienda para ti. Requiere typewriter.shop.open.
/tw shop adminLista los comandos de administración. Requiere typewriter.shop.admin.
/tw shop admin listLista las tiendas cargadas con su id, nombre, número de objetos y número de conjuntos.
/tw shop admin info <shop>Muestra la definición de una tienda y sus objetos con su índice.
/tw shop admin open <shop> [target]Abre una tienda para un jugador.
/tw shop admin refresh [target]Vuelve a dibujar la tienda abierta de un jugador.
/tw shop admin close [target]Cierra la tienda abierta de un jugador.
/tw shop admin reset <shop>Restablece ahora las existencias y los límites.
/tw shop admin stock <shop> <item> getMuestra las existencias del objeto en ese índice.
/tw shop admin stock <shop> <item> set <amount>Establece las existencias. También add y remove.
/tw shop admin history [target]Muestra las últimas 10 transacciones de un jugador desde el último reinicio.

<shop> es el id de la entrada, que se completa con la tecla Tab. <item> es la posición del objeto en los items de la tienda, empezando en 0.

Textos editables​

Ningún texto que se muestra en el juego está fijado en el código. Tres tipos de texto se pueden cambiar sin recompilar nada.

Lo que lee un jugador al comerciar es un campo de la Shop Definition: purchaseMessage, sellMessage, cannotAffordMessage, limitReachedMessage, priceLore y los demás descritos arriba.

Los textos de precio, los iconos de tendencia y las líneas de pool son campos de la entrada a la que pertenecen. Su valor por defecto es el texto que la extensión siempre mostró.

CampoEntradaPor defectoUso
trendUpIconShop Definition<red>▲</red>El placeholder trend_icon de un objeto cuyo precio subió desde la última compra o venta.
trendDownIconShop Definition<green>▼</green>El mismo placeholder cuando el precio bajó.
trendStableIconShop Definition<gray>●</gray>El mismo placeholder cuando el precio no cambió, o cuando no se conoce un precio anterior.
itemPriceLineFormatShop Definition- {amount} × {name}Una línea del token de lore {item_price}, por cada objeto que pide un precio en objetos. {amount} es la cantidad y {name} el nombre del objeto.
unknownItemNameShop Definitionunknown itemEl nombre de un objeto de precio cuyo nombre propio no se puede leer, en {item_price} y en la lista de objetos que faltan.
missingItemFormatShop Definition{amount} × {name}Un elemento de la lista {missing} de cannotAffordItemsMessage. {amount} es la cantidad que falta.
missingItemSeparatorShop Definition, Lo que va entre dos elementos de la lista {missing}.
defaultItemNameShop DefinitionItemEl {item_name} de subMenuTitle para un objeto que no tiene name.
noPriceTextShop Definition—Se muestra en lugar de un número donde un precio en objetos no lo tiene: los placeholders buy_price y sell_price, y {price} en el mensaje de inventario lleno de un objeto así.
cooldownFormatShop Definition{d}d:{h}h:{m}m:{s}sEl patrón del placeholder cooldown cuando el placeholder no indica ninguno. {d} días, {h}, {m}, {s} rellenados a 2 dígitos.
limitedLoreShop Pool<yellow>Limited: <red>{limit}La última línea de lore de un objeto limitado del pool. {limit} es la cantidad disponible.
unlimitedLoreShop Pool<yellow>UnlimitedLa última línea de lore de un objeto del pool sin límite.

Usa %typewriter_shop:<shop>:<n>:trend_icon% en el lore de un objeto para mostrar el icono. %typewriter_shop:<shop>:<n>:trend% devuelve up, down, stable o unknown, y estas cuatro palabras son fijas porque las condiciones las comparan.

Lo que responden los comandos /tw shop, incluidos los comandos /tw shop admin, es un snippet de TypeWriter. Abre plugins/Typewriter/snippets.yml, busca la clave bajo content.shop, cambia el valor y ejecuta /tw reload. La extensión registra todos sus snippets con su texto por defecto al iniciarse, así que aparecen en el archivo tras el primer arranque. Si mantienes los valores por defecto, nada cambia.

Las respuestas son MiniMessage y se envían sin el prefijo de Typewriter, así que el color de una respuesta forma parte de su texto. Un {name} en un texto se sustituye por el valor indicado en la tabla; un placeholder que no existe se queda tal cual, y un valor nunca se vuelve a examinar en busca de placeholders. Un valor que viene de tus páginas (el nombre de una tienda, el nombre de un jugador, el título de un inventario) se muestra tal como está escrito: sus etiquetas nunca se interpretan. El registro de la consola del servidor sigue en inglés.

Snippet (bajo content.shop.)Por defectoPlaceholders
help<gold>Shop commands:</gold> <yellow>/tw shop <id></yellow> to open a shop, <yellow>/tw shop admin</yellow> for operator tools.ninguno
unknown_shop_errorUnknown shop: {shop} (texto sin formato){shop} (lo que se escribió)
admin.helpla lista de comandos de administración, uno por líneaninguno
admin.unknown_shop<red>Unknown shop: {shop}{shop}
admin.list_empty<yellow>No shop definitions are currently loaded.ninguno
admin.list_header<gold>Loaded shops ({count}):{count}
admin.list_line<white>- {id} | {name} | items={items} | pools={pools}{id}, {name}, {items}, {pools}
admin.opened<green>Opened {shop} for {player}.{shop}, {player}
admin.refreshed<green>Refreshed the shop session for {player}.{player}
admin.closed<green>Closed the shop session for {player}.{player}
admin.reset<green>Reset runtime stock and limits for {shop}.{shop}
admin.history_header<gold>Recent transactions for {player} ({count}):{player}, {count}
admin.history_empty<yellow>No transactions recorded in the current runtime.ninguno
admin.history_line<white>{time} | {type} | {shop}[{index}] | amount={amount} | price={price}{time}, {type}, {shop}, {index}, {amount}, {price}
admin.info_title<gold>=== Shop {shop} ==={shop}
admin.info_name<white>Name: {name}{name}
admin.info_inventory_title<white>Title: {title}{title}
admin.info_currency<white>Currency: {currency} | rows={rows}{currency}, {rows}
admin.info_items<white>Items: {items} direct | pools={pools} | access criteria={criteria}{items}, {pools}, {criteria}
admin.info_reset<white>Reset policy: {policy}{policy}
admin.info_item<white>[{index}] {name} | buy={buy} sell={sell} | playerLimit={playerLimit} globalLimit={globalLimit} | item criteria={criteria}{index}, {name}, {buy}, {sell}, {playerLimit}, {globalLimit}, {criteria}
admin.info_item_unnamed<unnamed> (texto sin formato)ninguno; es el {name} de un objeto sin nombre
admin.stock_unlimited<yellow>{shop}[{index}] uses unlimited stock.{shop}, {index}
admin.stock_value<green>{shop}[{index}] stock: {stock}/{max}.{shop}, {index}, {stock}, {max}
admin.stock_out_of_range<red>Stock must stay between 0 and {max}.{max}
admin.stock_updated<green>{shop}[{index}] stock set to {stock}/{max}.{shop}, {index}, {stock}, {max}
admin.unknown_item<red>Unknown direct item index {index} in {shop}.{index}, {shop}

unknown_shop_error es un error de comando, que el juego muestra en rojo mientras el jugador escribe: es texto sin formato, sin MiniMessage.

Permisos​

PermisoConcede
typewriter.shop.open/tw shop <shop>. Concedido a todos por defecto.
typewriter.shop.adminTodos los comandos /tw shop admin. Solo para operadores por defecto.

Placeholders​

Placeholders de PlaceholderAPI, con la expansión typewriter. <shop> es el nombre o el id de la entrada de la tienda y <n> la posición del objeto en items, desde 0.

PlaceholderDevuelve
%typewriter_shop:<shop>:name%Nombre de la entrada.
%typewriter_shop:<shop>:entryid%Id de la entrada.
%typewriter_shop:<shop>:cooldown%Tiempo hasta el próximo reinicio, por defecto con el formato 0d:00h:00m:00s (el campo cooldownFormat de la tienda; las versiones anteriores usaban j para los días). Añade un formato tras un guion bajo, por ejemplo cooldown_{h}h{m}m, usando {d}, {h}, {m} y {s}.
%typewriter_shop:<shop>:<n>:buy_price%Precio de compra del objeto; el noPriceText de la tienda (— por defecto) en los objetos de trueque.
%typewriter_shop:<shop>:<n>:sell_price%Precio de venta del objeto; el noPriceText de la tienda (— por defecto) en los objetos de trueque.
%typewriter_shop:<shop>:<n>:stock%Existencias actuales.
%typewriter_shop:<shop>:<n>:stock_max%Existencias máximas.
%typewriter_shop:<shop>:<n>:has_promotion%true cuando se aplica una promoción al objeto.

Integración​

  • GUI: Shops abre sus menús a través del servicio de sesiones de GUI, por lo que gui:back, los sonidos, los chasis extendidos y baseMenuId se comportan como en cualquier otro menú. Establece baseMenuId en una base compartida Open GUI, añade views y la tienda se convierte en una pestaña: contentX, contentY, contentColumns y contentRows colocan los productos dentro de la base.
  • Discord: tras cada compra o venta, Shops dispara un ShopTransactionEvent. Cuando la extensión Discord está instalada y la tienda define notificationWebhookId, una entrada Shop Notification da formato al anuncio.
  • Sonidos: buySound, sellSound y deniedSound se reproducen según el resultado correspondiente.

Entradas​

6 entradas, generadas a partir del código fuente de la extensión.

Acciones1
Artefactos1
Manifiestos4

Resolución de problemas​

El menú se abre pero no muestra ningún producto. El layout no tiene ningún marcador SHOP_ITEM, mainLayoutId no coincide con el id de ningún layout de layoutPool, o el layout no es un layout simple. Los productos solo aparecen en las ranuras marcador.

Un botón no hace nada. Su buttonPrefix no es shop_button:, o su buttonType está mal escrito (los tipos van en mayúsculas). Un botón de paginación o de cierre también necesita el prefijo; solo SHOP_ITEM tolera un prefijo vacío.

La tienda dice "No economy available". Con VAULT, falta Vault o su proveedor de economía. Con PLACEHOLDER, uno de balancePlaceholder, addCommand o removeCommand está vacío. Con un objeto de trueque, el mensaje también aparece cuando no se ha definido ni itemPrice ni defaultItemPrice, y la consola registra el id de la tienda y el número del objeto.

Las existencias y los límites se pierden al reiniciar, o nunca se guardan. Debe existir una entrada Shop Artifact cuyo id o nombre sea shop_artifact.

No se puede vender un objeto. Su precio de venta es cero (los objetos de trueque siempre lo tienen), sellEnabled está desactivado, o el jugador no tiene suficientes objetos que coincidan. Solo cuentan los objetos con un tipo de objeto y datos idénticos.

La consola avisa de que un artículo no se puede mostrar o se ha movido. Un objeto con guiSlot ocupa un marcador SHOP_ITEM. Cuando los objetos fijados ocupan todos los marcadores, los demás objetos se colocan en las casillas libres de la zona de contenido; si no queda ninguna casilla libre, el objeto no se muestra. Añade marcadores SHOP_ITEM o libera una casilla.

Los objetos de itemPools aparecen pero no se pueden comprar. En esta versión, las acciones de compra y venta solo gestionan las entradas de items; los objetos de los conjuntos se muestran después de ellas.

Los límites nunca se reinician. reset es none. Elige una política o usa /tw shop admin reset <shop>.

/tw shop <id> dice que la tienda es desconocida. El comando toma el id de la entrada, no el título. Usa /tw shop admin list.

Extensiones relacionadas​

  • GUI: layouts, sesiones y el mecanismo de marcadores que usan los menús de tienda.
  • Discord: anuncia las transacciones de la tienda en un webhook.
  • Quest Codex: usa la misma idea de chasis para los menús de misiones.