AxinMenuGUI
Crea menús GUI completamente configurables para tu servidor VintageStory — sin escribir código.
AxinMenuGUI es un mod de menús interactivos para VintageStory que permite a los administradores construir menús complejos y multipágina mediante ficheros JSON. Sin programar, sin reiniciar el servidor.
Inspirado en GUIPlus (Minecraft/Spigot), diseñado desde cero para la API de VintageStory y la metodología AXIN.
/amenu reload.{player}, {stats.deaths}, {ranking.position} y más en cualquier texto del menú.axinmenugui: listos para usar en cualquier botón./artp) con validación de terreno.menusClick.json.📋 Requisitos
| Requisito | Valor |
|---|---|
| VintageStory | 1.21.x+ |
| Versión actual | 0.9.5 |
| Tipo de mod | Universal (cliente y servidor) |
| Dependencias | Ninguna (mod standalone) |
AxinMenuGUI renderiza GUI en el cliente. Debe estar instalado en el cliente además del servidor.
Inicio rápido
Instala AxinMenuGUI y crea tu primer menú en minutos.
📥 Instalación
- Copia
AxinMenuGUI_v0.9.5.zipen la carpetaMods/del servidor. - Reinicia el servidor. Se generan los ficheros de configuración y menús de ejemplo.
- Verifica en los logs:
[AxinMenuGUI] Alias registrado: /menu → 'ejemplo' - Entra al juego y escribe
/menupara ver el menú de ejemplo.
📂 Ficheros generados
ModConfig/AxinMenuGUI/
├── config.json # Configuración global (idioma, killPoints, ranking, RTP, market)
├── adminteleports.json # Puntos ATP guardados con /atp set (auto-generado)
├── menus/ # Tus ficheros JSON de menú
│ ├── ejemplo.json # Menú índice con submenús (/menu)
│ ├── ejemplo_jugador.json
│ ├── ejemplo_stats.json
│ ├── ejemplo_temas.json # 13 escenas, un tema por pestaña (/temas)
│ ├── ejemplo_tp.json # Panel de teleport admin (ATP, RTP, waypoints)
│ └── ...
├── playerdata/ # Stats por jugador (auto-generado)
│ └── {uid}.json
├── bank/ # Snapshots de Banks por jugador (auto-generado)
│ └── {uid}.json
├── missions/ # Configuración de misiones (auto-generado)
│ └── killranking.json
└── marketlog/ # Log persistente de transacciones de mercado (auto-generado)
└── market_log_{fecha}.json
🎯 Tu primer menú
hola.json{
"id": "hola",
"title": "Mi primer menú",
"theme": "dark-red",
"rows": 3,
"commandAlias": "hola",
"scenes": {
"0": {
"items": {
"saludo": {
"slot": 13,
"item": "axinmenugui:menuicon-star",
"name": "Hola, {player}!",
"lore": ["Clic para saludar"],
"clickEvents": {
"msg": { "type": "message", "message": "¡Bienvenido, {player}!" }
}
}
}
}
}
}
Guarda el fichero en ModConfig/AxinMenuGUI/menus/ y ejecuta /amenu reload. Luego /hola para abrir el menú.
Comandos y permisos
Todos los comandos disponibles en AxinMenuGUI.
| Comando | Permiso | Descripción |
|---|---|---|
/amenu open <id> [jugador] | chat | Abre un menú. Con jugador: requiere controlserver. |
/amenu reload | controlserver | Recarga todos los JSONs y re-registra alias. |
/amenu list | controlserver | Lista los menús cargados. |
/amenu info <id> | controlserver | Detalle de un menú. |
/amenu player <nombre> | controlserver | Stats del jugador + ranking. |
/amenu ranking | chat | Muestra el ranking público. |
/amenu click open <id> | controlserver | Modo vinculación: el siguiente clic derecho en un bloque lo vincula al menú indicado. |
/amenu click delete | controlserver | Modo desvinculación: el siguiente clic derecho en un bloque elimina su vínculo de menú. |
/<alias> | chat | Abre el menú con ese commandAlias. |
Tras ejecutar /amenu click open <id> o /amenu click delete, el jugador entra en modo de selección. El siguiente clic derecho sobre cualquier bloque confirma la operación. Los vínculos se guardan en ModConfig/AxinMenuGUI/menusClick.json.
🏪 Mercado global (/market)
El mercado P2P permite a los jugadores publicar y comprar ofertas. Todos los subcomandos requieren privilegio chat.
| Comando | Descripción |
|---|---|
/market | Alias directo: abre el menú principal del mercado. |
/amenu market | Ídem: abre el menú principal del mercado. |
/amenu market buy | Abre la vista de compra (explorar y comprar ofertas). |
/amenu market browse [página] | Lista ofertas agrupadas por tipo de ítem (paginada). |
/amenu market detail <itemCode> | Muestra todos los vendedores de un ítem concreto con precio y cantidad. |
/amenu market sell | Sin argumentos: abre la GUI de venta personalizada (wizard interactivo). |
/amenu market sell <item> <cant> <precioItem> <precioCant> | Venta rápida: publica la oferta directamente con todos los parámetros. |
/amenu market cancel <offerId> | Cancela tu oferta activa; devuelve los ítems restantes al inventario. |
/amenu market myoffers | Muestra tu lista de ofertas activas. |
/amenu market collect | Cobra las ganancias pendientes generadas por ventas completadas. |
/amenu market list | Lista todas las ofertas activas en formato texto (chat). |
Al ejecutar /amenu market sell sin argumentos, se inicia un asistente paso a paso por chat: (1) selecciona qué ítem vender del inventario en la GUI, (2) escribe o selecciona el ítem de pago, (3) escribe la cantidad de pago por unidad. Escribe cancel en cualquier momento para salir. El wizard expira por inactividad según marketSellWizardTimeoutSeconds en config.json.
⚡ Teleport administrativo (ATP)
Gestiona puntos de teletransporte guardados en el servidor. Todos requieren privilegio controlserver.
| Comando | Descripción |
|---|---|
/atp set <nombre> | Guarda tu posición actual como punto ATP con ese nombre. |
/atp setat <nombre> <x> <y> <z> | Guarda un ATP en coordenadas explícitas. |
/atp go <nombre> | Teleport al punto ATP guardado. |
/atp del <nombre> | Elimina un punto ATP. |
/atp list | Lista todos los puntos ATP guardados. |
/atp info <nombre> | Muestra coordenadas y metadatos del punto ATP. |
🌀 Teletransporte aleatorio (RTP)
Teletransporta al jugador a una posición aleatoria segura. Requiere privilegio controlserver.
| Comando | Descripción |
|---|---|
/artp | RTP con radio mínimo y máximo definidos en config.json. |
/artp <min> <max> | RTP con radio explícito. Acepta enteros o sufijo k (ej. /artp 5k 10k). |
La verificación de claims solo comprueba el punto exacto de aterrizaje (limitación de la API de VintageStory). Las story zones se aproximan por distancia al spawn. Verificado en mundo plano; se recomienda prueba adicional en mundos con relieve.
Output de /amenu player
[AxinMenuGUI] Stats: elYandrack
timeRealSeconds: 77 (1m 17s)
timeGameDays: 0.00
deaths: 0
mobKillsAll: 4
mobKillsHostile: 3
mobKillsHostilePoints: 22.5
playerKills: 0
ranking.position: #1
Configuración global
El fichero config.json se genera automáticamente al primer inicio.
ModConfig/AxinMenuGUI/config.json{
"language": "en",
"rankingSize": 10,
"rankingField": "mobKillsHostilePoints",
"killPoints": {
"drifter-normal": 0.5,
"drifter-deep": 2.0,
"drifter-tainted": 4.0,
"drifter-corrupt": 8.0,
"drifter-nightmare": 14.0,
"drifter-double-headed": 20.0
// ... 29 mobs en total
},
"randomTeleport": {
"defaultMin": 5000,
"defaultMax": 10000,
"maxAttempts": 40,
"claimMargin": 128,
"storyZoneMargin": 256,
"forbidWater": true,
"requireTwoAirBlocks": true
},
"saveIntervalSeconds": 30,
"rankingCacheSeconds": 60,
"marketLogRetentionDays": 30,
"marketLogFlushSeconds": 30,
"marketSellWizardTimeoutSeconds": 60
}
| Campo | Default | Descripción |
|---|---|---|
language | en | Idioma del mod: en, es, fr, de, pt-br, ru |
rankingSize | 10 | Número de jugadores en el ranking |
rankingField | mobKillsHostilePoints | Campo por el que se ordena: mobKillsHostilePoints, deaths, playerKills… |
saveIntervalSeconds | 30 | Intervalo entre flush automático de player stats a disco. Mínimo 5. |
rankingCacheSeconds | 60 | Duración del caché de ranking en segundos. |
killPoints | — | Puntos por tipo de mob hostil. Lookup progresivo: wolf-male-adult → wolf-male → wolf. |
🏪 Bloque market
| Campo | Default | Descripción |
|---|---|---|
marketLogRetentionDays | 30 | Días de histórico de marketlog/ a conservar. Los archivos más antiguos se purgan automáticamente. |
marketLogFlushSeconds | 30 | Intervalo en segundos entre flush de la cola de log de mercado a disco. Mínimo 5. |
marketSellWizardTimeoutSeconds | 60 | Segundos de inactividad antes de cancelar un wizard de venta personalizada activo. |
🌀 Bloque randomTeleport
Configuración del teletransporte aleatorio (/artp y click event randomTeleport).
| Campo | Default | Descripción |
|---|---|---|
randomTeleport.defaultMin | 5000 | Radio mínimo por defecto al usar /artp sin argumentos. |
randomTeleport.defaultMax | 10000 | Radio máximo por defecto al usar /artp sin argumentos. |
randomTeleport.maxAttempts | 40 | Intentos máximos antes de cancelar la búsqueda de posición segura. |
randomTeleport.claimMargin | 128 | Margen de claims. Limitación de API: solo se comprueba el punto exacto de aterrizaje, no el perímetro. |
randomTeleport.storyZoneMargin | 256 | Distancia mínima al spawn como proxy de story zones. No equivale a detección real de zonas de historia. |
randomTeleport.forbidWater | true | Rechaza agua u otros líquidos como suelo de aterrizaje. |
randomTeleport.requireTwoAirBlocks | true | Exige dos bloques de aire libres (pies y cabeza) en el punto de destino. |
Estructura del GUI
Anatomía completa de un menú JSON.
mi_menu.json{
"id": "mi_menu",
"title": "Mi Menú",
"theme": "dark-red",
"rows": 3,
"commandAlias": "menu",
"commandAliasTarget": "OPTIONAL",
"permission": "",
"openTriggers": [],
"scenes": {
"0": {
"delay": 0,
"theme": "parchment",
"items": {
"boton1": {
"slot": 13,
"item": "axinmenugui:menuicon-star",
"amount": 1,
"name": "Hola, {player}!",
"lore": ["Primera línea", "Segunda línea"],
"hideOnFail": false,
"clickEvents": {
"ev1": { "type": "message", "message": "¡Hola!" }
},
"conditions": {},
"conditionFailMessage": ""
}
}
}
}
}
| Campo del menú | Tipo | Descripción |
|---|---|---|
id | string | ID único del menú (requerido) |
title | string | Título mostrado en la barra del GUI |
theme | string | Tema visual del menú (ver sección Temas) |
rows | int | Filas del grid (1–6) |
commandAlias | string | Alias de comando para abrir el menú |
commandAliasTarget | string | OPTIONAL · REQUIRED · DISABLED |
permission | string | Privilegio VS requerido (vacío = todos) |
| Campo del ítem | Tipo | Descripción |
|---|---|---|
slot | int | Posición 0-indexed (9 columnas) |
item | string | Código VS o axinmenugui:menuicon-* |
amount | int | Cantidad visual |
name | string | Nombre. Admite tokens y VTML. |
lore | string[] | Tooltip. Admite tokens y VTML. |
hideOnFail | bool | true = ocultar si condición falla |
Escenas y navegación
Un menú puede tener múltiples escenas (páginas). Cada escena puede tener su propio tema visual.
🗂 Múltiples escenas
"scenes": {
"0": { "theme": "dark-red", "items": { ... } },
"1": { "theme": "dark-blue", "items": { ... } },
"2": { /* sin theme → hereda el del menú */ "items": { ... } }
}
🧭 Click events de navegación
| Type | Descripción |
|---|---|
nextScene | Avanza a la escena siguiente |
previousScene | Retrocede a la escena anterior |
openGui | Abre otro menú (submenú). Se registra en el historial. |
back | Vuelve al menú anterior del historial. |
closeGui | Cierra el menú activo. |
🔗 Patrón submenús con back
// En el menú índice:
"sub_stats": {
"slot": 13,
"item": "axinmenugui:menuicon-trophy",
"name": "Estadísticas",
"clickEvents": {
"open": { "type": "openGui", "guiId": "ejemplo_stats" }
}
}
// En ejemplo_stats.json:
"volver": {
"slot": 17,
"item": "axinmenugui:menuicon-back",
"name": "← Volver",
"clickEvents": {
"back": { "type": "back" }
}
}
Temas visuales
14 temas Cairo para personalizar completamente el aspecto de tus menús.
🖼 Cómo aplicar un tema
Añade el campo "theme" al menú y/o a cada escena:
{
"id": "mi_menu",
"theme": "dark-red", // tema por defecto del menú
"scenes": {
"0": { "theme": "parchment", "items": { ... } }, // sobreescribe el del menú
"1": { "items": { ... } } // hereda "dark-red"
}
}
ejemplo_temas.json tiene 13 escenas, una por tema. Abre con /temas para ver todos en acción.🎨 Temas disponibles (14)
📐 Diferencias entre variantes
| Variante | BorderW | CornerR | Efecto |
|---|---|---|---|
Original (dark-red, etc.) | 4px | 8px | Marco fino, esquinas redondeadas |
Cofre (dark-red-2, etc.) | 7–8px | 2px | Marco grueso con bisel automático, esquinas cuadradas. Estilo cofre VS. |
glass | 1px | 6px | Completamente transparente. Solo cuadrícula y título visibles. |
-2 activan automáticamente un bisel (highlight de borde) cuando el mod detecta BorderW > 4. Este efecto no requiere configuración adicional.Click Events
Acciones que se ejecutan al hacer clic en un botón del menú.
| Type | Estado | Descripción |
|---|---|---|
message | ✅ RUN | Envía un mensaje al jugador. Admite tokens. |
closeGui | ✅ RUN | Cierra el menú activo. |
openGui | ✅ RUN | Abre otro menú. Guarda el menú actual en historial. |
back | ✅ RUN | Vuelve al menú anterior del historial. |
nextScene | ✅ RUN | Avanza a la escena siguiente. |
previousScene | ✅ RUN | Retrocede a la escena anterior. |
playerCommand | ✅ RUN | Ejecuta un comando como el jugador. |
consoleCommand | ✅ RUN | Ejecuta un comando de servidor (sin límite de permisos). |
giveItem | ✅ RUN | Da ítems al jugador. |
takeItem | ✅ IMPL | Quita ítems del inventario. |
buyItem | ✅ IMPL | Compra: verifica coste + consume + entrega. |
sellItem | ✅ IMPL | Venta: verifica ítem + consume + entrega currency. |
setVariable | ✅ IMPL | Modifica un field del jugador (set/add/subtract/multiply/divide). |
teleport | ✅ RUN | Teletransporta al jugador a coordenadas fijas. |
teleportSaved | ✅ RUN | Teleport a un punto ATP guardado por nombre. |
randomTeleport | ✅ RUN | Teletransporte aleatorio seguro con validación de terreno. |
Ejemplos de uso
// message
"ev": { "type": "message", "message": "Hola {player}, estás en {pos}" }
// openGui (submenú)
"ev": { "type": "openGui", "guiId": "mi_submenu" }
// back
"ev": { "type": "back" }
// consoleCommand
"ev": { "type": "consoleCommand", "commands": ["/tp {player} 0 150 0"] }
// giveItem
"ev": { "type": "giveItem", "itemCode": "game:ingot-iron", "quantity": 5 }
// setVariable
"ev": { "type": "setVariable", "field": "puntos", "op": "add", "value": 10 }
// teleport — coordenadas fijas separadas por coma
"ev": { "type": "teleport", "location": "0,150,0" }
// teleportSaved — usa un punto ATP guardado con /atp set
"ev": { "type": "teleportSaved", "target": "spawn" }
// randomTeleport — radios explícitos (0,0 usa defaults de config.json)
"ev": { "type": "randomTeleport", "radiusMin": 1000, "radiusMax": 5000 }
Condiciones
Muestra u oculta botones según el estado del jugador.
| Type | Estado | Parámetros |
|---|---|---|
hasPrivilege | ✅ RUN | privilege: string |
hasPrivilegeLevel | ✅ IMPL | minLevel: int |
hasItem | ✅ IMPL | itemCode, quantity |
hasRole | ✅ IMPL | roleCode: string |
playerDataCompare | ✅ IMPL | field, op, value |
cooldownActive | ✅ IMPL | id, duration |
"conditions": {
"es-admin": { "type": "hasPrivilege", "privilege": "controlserver", "inverted": false }
},
"hideOnFail": true,
"conditionFailMessage": "Solo administradores."
Iconos del mod
58 iconos pixel art 32×32 incluidos en AxinMenuGUI. Úsalos en cualquier botón de tus menús.
En el campo "item" de cualquier ítem, usa el prefijo axinmenugui:menuicon- seguido del nombre del icono.
Ejemplo: "item": "axinmenugui:menuicon-star"
🧭 Navegación
ℹ UI / Información
🛒 Tienda / Economía
👤 Social / Admin / Roles
✨ Decorativos / Misc
💡 Cómo añadir iconos propios
Puedes añadir tus propios iconos al mod creando los ficheros necesarios:
- Coloca el PNG (32×32, fondo transparente, estilo pixel art) en:
assets/axinmenugui/textures/item/menuicon-MINOMBRE.png - Crea el fichero de itemtype en:
assets/axinmenugui/itemtypes/menuicon-MINOMBRE.json - El contenido del JSON del itemtype es:
menuicon-MINOMBRE.json{
"code": "menuicon-MINOMBRE",
"class": "Item",
"maxStackSize": 1,
"texture": { "base": "axinmenugui:item/menuicon-MINOMBRE" }
}
texture es OBLIGATORIOVintageStory no infiere la textura desde el código del ítem. Sin este campo el slot aparece negro aunque el PNG exista.
- Reinicia el servidor. Usa el icono con:
"item": "axinmenugui:menuicon-MINOMBRE"
Player Data y Stats
Variables persistentes por jugador: stats automáticos, campos personalizados, cooldowns.
📊 Stats automáticos
El mod trackea automáticamente al entrar, morir y matar entidades:
| Campo | Descripción |
|---|---|
deaths | Número de veces que ha muerto |
mobKillsAll | Total de mobs asesinados |
mobKillsHostile | Mobs hostiles asesinados |
mobKillsHostilePoints | Puntos acumulados (escala en config.json) |
playerKills | Jugadores asesinados |
timeRealSeconds | Tiempo real en el servidor (segundos) |
timeGameDays | Días de juego vividos |
🎯 Puntos por mob
Los puntos se calculan con lookup progresivo: wolf-male-adult → prueba wolf-male → prueba wolf. Configúralos en config.json.
📋 Ranking
El ranking se calcula automáticamente sobre el campo rankingField (por defecto mobKillsHostilePoints). Se refresca con caché de 30 segundos.
Tokens / Placeholders
Variables dinámicas que puedes usar en cualquier campo de texto del menú.
| Token | Descripción |
|---|---|
{player} | Nombre del jugador |
{uid} | UID único del jugador |
{pos} | Posición X,Y,Z actual |
{gamemode} | Modo de juego actual |
{world} | Nombre del mundo |
{var:campo} | Field personalizado del jugador |
{stats.deaths} | Número de muertes |
{stats.mobKillsAll} | Total mobs asesinados |
{stats.mobKillsHostile} | Mobs hostiles asesinados |
{stats.mobKillsHostilePoints} | Puntos por kills hostiles |
{stats.playerKills} | Jugadores asesinados |
{stats.timeReal} | Tiempo real formateado (Xh Ym) |
{stats.timeGame} | Tiempo in-game (X.X días) |
{ranking.position} | Posición en el ranking |
{ranking.value} | Valor del campo de ranking |
{ranking.top} | Ranking completo formateado |
{ranking.top3} | Top 3 formateado |
{ranking.topN} | Top N formateado |
Chat Fetcher
Solicita input al jugador vía chat. Fase 3
Modos de apertura
Formas de abrir un menú en AxinMenuGUI.
| Trigger | Estado | Descripción |
|---|---|---|
/amenu open <id> | ✅ RUN | Comando directo de admin. |
commandAlias | ✅ RUN | Alias por menú: /menu, /temas, etc. |
| Block Click Trigger | ✅ RUN | Clic derecho en un bloque vinculado. Configuración guardada en menusClick.json. |
| Menús ATP/RTP | ✅ RUN | Menús con click events de teleport o ATP, accesibles por alias propio. |
| Ítem especial | Fase 2 — pendiente | Clic derecho en un ítem configurado (Bloque 2.7). |
| Hotkey | Fase 3 | Tecla configurable (ClientSide). |
| onJoin | Fase 3 | Al conectarse al servidor. |
| claimZone | Fase 3 (opcional) | Al entrar en una zona con flag. |
Menús de ejemplo incluidos
8 menús se generan automáticamente al instalar el mod.
A partir de la v0.7.2, los menús de ejemplo oficiales se sobreescriben en cada recarga del mod para mantenerse al día. Tus menús propios (con IDs distintos) nunca se ven afectados.
| ID | Alias | Descripción |
|---|---|---|
ejemplo | /menu | Índice con submenús navegables (openGui + back). Incluye acceso al panel TP si eres admin. |
ejemplo_jugador | — | Datos del jugador: nombre, pos, modo, UID |
ejemplo_stats | — | Estadísticas completas + ranking |
ejemplo_tienda | — | Tienda demo con giveItem (solo admins) |
ejemplo_admin | — | Panel admin: reload, list, info, open |
ejemplo_temas | /temas | 13 escenas, 1 por tema visual. Todo en 1 JSON. |
ejemplo_multitema | /multitema | Demo de theme por escena (7 temas en 1 menú) |
ejemplo_tp | — | Panel de teleport admin: lista ATP, RTP con distintos radios, waypoints personales (solo admins) |
Navegación del menú principal
/menu → ejemplo.json (índice)
├── Sobre ti → ejemplo_jugador.json [← Volver]
├── Estadísticas → ejemplo_stats.json [← Volver]
├── Tienda → ejemplo_tienda.json
├── Panel Admin → ejemplo_admin.json (oculto si no es admin)
└── Teleport TP → ejemplo_tp.json (oculto si no es admin)
Roadmap
Plan de desarrollo por fases del mod.
teleport (coordenadas) · ✅ ATP: /atp set|setat|go|del|list|info y click event teleportSaved · ✅ RTP: /artp y click event randomTeleport
AxinMenuGUI vs GUIPlus
Diferencias y equivalencias entre los dos sistemas.
| GUIPlus (Minecraft) | AxinMenuGUI (VintageStory) | Nota |
|---|---|---|
| YAML | JSON | Estándar en VS |
| Inventario Chest | GuiDialog con grid configurable | VS no tiene chest como GUI nativa |
| Temas de color limitados | 14 temas Cairo personalizables | ✅ Sistema propio completo |
§ color codes | VTML — <font color="#FF8C00">texto</font> | ✅ Verificado en GuiDialog |
| Vault / economy | Player Data numérico + stats | No hay economy nativa en VS |
| PlaceholderAPI | Sistema de tokens {token} | 18+ tokens incluyendo stats y ranking |
| LuckPerms | Roles nativos VS (hasRole, hasPrivilegeLevel) | API nativa VS |
| Skull textures | 58 iconos pixel art propios | Dominio axinmenugui: |
| BungeeCord | No aplica | VS es standalone |
| In-game editor | Fase 4 | Primero config 100% por JSON |
Mercado Global P2P
Permite a los jugadores publicar ofertas de venta y comprar ítems de otros jugadores. Las transacciones usan escrow automático.
🚀 Cómo acceder
Usa el comando /market o /amenu market para abrir el menú principal. No requiere permisos especiales.
🛒 Flujo de compra
- Abre el mercado con
/market. - Selecciona Comprar para ver ítems disponibles agrupados por tipo.
- Selecciona un ítem para ver los vendedores, precio y cantidad disponible.
- Haz clic en la oferta que quieras comprar. El sistema verificará que puedes pagar (inventario + Treasury + Bank cerrados).
- Si la compra prospera, los ítems aparecen en tu inventario y el vendedor recibe una notificación.
El sistema cobra en este orden: (1) inventario del jugador, (2) Treasury cerrada, (3) Banks cerrados. No es necesario tener el pago en el inventario si tienes saldo en Treasury o Bank.
💰 Flujo de venta — venta rápida
Para publicar una oferta directamente sin GUI:
/amenu market sell <itemCode> <cantidad> <precioItem> <precioCantidad>
Ejemplo: vender 10 lingotes de hierro a 2 engranajes oxidados cada uno
/amenu market sell game:ingot-iron 10 game:gear-rusty 2
Los ítems se retiran inmediatamente del inventario y quedan en escrow hasta ser comprados o cancelados.
🧙 Flujo de venta — asistente personalizado
Para iniciar el wizard interactivo, ejecuta /amenu market sell sin argumentos. Se abre la GUI de tu inventario y el proceso es guiado por chat:
- Haz clic en el ítem de tu inventario que quieres vender.
- Si tienes más de 1 unidad, escribe por chat la cantidad a vender.
- Selecciona en la GUI (o escribe por chat en formato
dominio:codigo) el ítem que pides como precio. - Escribe por chat la cantidad de ese ítem que pides por cada unidad vendida.
- La oferta se publica y los ítems pasan a escrow.
cancel para salirEn cualquier paso del wizard puedes escribir cancel por chat para cancelar. El wizard también expira automáticamente por inactividad según marketSellWizardTimeoutSeconds en config.json (default 60s).
📋 Gestión de ofertas
| Acción | Comando |
|---|---|
| Ver mis ofertas activas | /amenu market myoffers |
| Cancelar una oferta | /amenu market cancel <offerId> — devuelve ítems restantes |
| Cobrar ganancias pendientes | /amenu market collect |
| Listar todas las ofertas (texto) | /amenu market list |
Cuando alguien compra tu oferta, el pago queda en cola hasta que uses /amenu market collect. El vendedor recibe una notificación in-game si está conectado.
📦 Estado de una oferta
| Estado | Significado |
|---|---|
active | La oferta está disponible para compra. |
sold | Toda la cantidad fue comprada. |
cancelled | Cancelada por el vendedor; ítems devueltos. |
📝 Log de transacciones
Todas las transacciones quedan registradas en ModConfig/AxinMenuGUI/marketlog/. Los archivos se rotan diariamente y se purgan automáticamente pasados marketLogRetentionDays días (default 30).
| Acción en log | Descripción |
|---|---|
SELL_PUBLISHED | Oferta publicada por un vendedor. |
SELL_FILLED | Parte o toda la oferta fue comprada (par con BUY_FILLED, mismo TxId). |
BUY_FILLED | Compra realizada por un comprador. |
OFFER_CANCELLED | Oferta cancelada por el vendedor. |
EARNINGS_COLLECTED | Vendedor cobró sus ganancias pendientes. |
Bank (bloque)
Cofre especial crafteable que actúa como fuente de pago secundaria en el Mercado Global.
📐 Qué es el Bank
El Bank es un bloque de almacenamiento similar a un cofre. La diferencia clave es que el Mercado Global usa automáticamente los ítems del Bank como fuente de pago cuando el inventario del jugador no es suficiente, siempre que el Bank esté cerrado en el momento de la transacción.
Un Bank abierto (interfaz activa) no se usa como fuente de pago. Solo los Banks cerrados contribuyen al saldo disponible para compras en el mercado. El snapshot se sincroniza 5 segundos después de cerrar el inventario.
🔨 Crafteo
El Bank se craftea con planchas de madera (cualquier tipo), clavos metálicos y piedra tallada. La receta exacta está disponible en el Handbook del juego buscando "Bank".
🏗 Colocación y uso
- Coloca el Bank en el mundo como cualquier cofre.
- Ábrelo con clic derecho para guardar ítems.
- Al cerrarlo, el servidor sincroniza el contenido en
ModConfig/AxinMenuGUI/bank/{uid}.json. - Cuando realices una compra en el mercado, el sistema sumará automáticamente el saldo de todos tus Banks cerrados al calcular si puedes pagar.
📊 Múltiples Banks
Un jugador puede tener varios Banks colocados. El servicio los identifica por su posición en el mundo. Todos los Banks cerrados de un mismo jugador contribuyen al saldo total disponible para el mercado.
🗂 Persistencia
Los snapshots se guardan en ModConfig/AxinMenuGUI/bank/{uid}.json, uno por jugador, con la lista de Banks y su contenido en el momento del último cierre.
KillRanking Missions
Recompensa automática y única cuando un jugador cruza un umbral de puntos de ranking de kills hostiles.
📄 Fichero de configuración
Se genera automáticamente en ModConfig/AxinMenuGUI/missions/killranking.json con valores de ejemplo. Se recarga con /amenu reload.
missions/killranking.json{
"DocVersion": "0.1",
"RankingBonus": {
"10": {
"message": "¡Has alcanzado 10 puntos de ranking!",
"all_message": "{player} ha alcanzado 10 puntos de ranking.",
"give": { "type": "item", "code": "game:gear-rusty", "amount": 1 },
"command": "/amenu ranking"
},
"50": {
"message": "¡Leyenda! 50 puntos de ranking.",
"all_message": "{player} ha alcanzado 50 puntos de ranking.",
"give": { "type": "item", "code": "game:ingot-iron", "amount": 5 },
"command": null
}
}
}
📋 Campos de un hito
| Campo | Tipo | Descripción |
|---|---|---|
| Clave (número) | double | Umbral de mobKillsHostilePoints que activa el hito. |
message | string | Mensaje privado al jugador. Admite placeholders {player}, {stats.*}, {ranking.*}. |
all_message | string | Mensaje broadcast a todos los jugadores conectados. Admite los mismos placeholders. |
give.type | string | Tipo de recompensa. Por ahora solo "item". |
give.code | string | Código del ítem a entregar (e.g. game:gear-rusty). |
give.amount | int | Cantidad del ítem a entregar. |
command | string | Comando de servidor a ejecutar cuando se cruza el hito. Admite placeholders. null = ninguno. |
⚙ Comportamiento
- Cada hito se concede exactamente una vez por jugador, aunque los puntos bajen y vuelvan a subir.
- La verificación ocurre en el momento del kill, sin I/O adicional (todo en memoria).
- Los umbrales se evalúan de menor a mayor; si un jugador sube varios umbrales de golpe, recibe todos.
- Las recompensas no concedidas (
give: null) se omiten sin error. - El estado "ya concedido" persiste en
playerdata/{uid}.jsony sobrevive a reloads y reinicios.
Puedes añadir nuevos umbrales o modificar las recompensas y ejecutar /amenu reload sin reiniciar el servidor. Los hitos ya concedidos no se revierten.