KSPlaceholder es un motor de placeholders diseñado para servidores complejos donde múltiples plugins exponen tokens (%kseco_saldo%, %ksprotect_region%, %kschunk_progreso%, etc.). Ofrece un registro por namespace con separación clara entre claves exactas y prefijos dinámicos, caché por token con TTL, y un puente automático a PlaceholderAPI para no obligar a los usuarios a instalar los dos.
Características
- Namespaces separados — cada plugin registra sus tokens bajo su propio prefijo (kseco_, ksprotect_, kschunk_). Cero colisiones.
- Claves exactas + prefijos dinámicos — resuelve %plugin_saldo% como clave exacta o %plugin_top:5% como prefijo con argumento.
- Caché por token con TTL configurable — evita re-cálculos costosos. Cada namespace decide su política (o desactiva).
- Fallback — cuando ninguna clave/prefijo casa, un handler global de la expansión decide.
- Integración transparente con PlaceholderAPI — si PAPI está cargado, KSPlaceholder registra un puente automático. Los tokens %plugin_x% funcionan igual desde ambos motores.
- Herramientas de debug — /ksp list, /ksp info, /ksp parse, /ksp cache para diagnosticar qué namespace responde a qué.
- Async-safe — los resolvers deben ser puros (sin I/O). El motor puede resolver desde cualquier hilo.
- Descarga KSPlaceholder-1.0.0.jar.
- Coloca el JAR en plugins/.
- Coloca KSCore.jar.
- Opcional: PlaceholderAPI.jar — KSPlaceholder se autopuentea.
- Arranca el servidor.
Requisitos
Requisito Versión mínima
Servidor Paper 1.21+ (api-version 26.2)
Java 21
KSCore 1.0-SNAPSHOT o superior
Dependencias
Plugin Tipo Rol
KSCore Requerida Framework
PlaceholderAPI Opcional Puente bidireccional automático
Comandos
Todos requieren permiso ksp.admin.
Comando Descripción
/ksp list Namespaces registrados con conteo de tokens
/ksp info <namespace> Detalles: claves exactas, prefijos dinámicos, fallback, TTL de caché
/ksp parse <texto> Resuelve el texto sobre ti (solo jugador)
/ksp test <jugador> <texto> Resuelve sobre un jugador online
/ksp reload Recarga config y catálogos internos
/ksp cache stats [ns] Estadísticas de la caché (global o por namespace)
/ksp cache clear [ns] Vacía la caché
Aliases: /ksplaceholder
Permisos
Permiso Default Descripción
ksp.admin op Todos los comandos administrativos
Uso desde otro plugin
Añade la dependencia soft en tu paper-plugin.yml:
Code (YAML):
dependencies:
server:
KSPlaceholder:
load : BEFORE
required : false
Y en tu build.gradle.kts :
compileOnly ( "studio.kuraky:ksplaceholder-api:1.0.0" )
server:
KSPlaceholder:
load : BEFORE
required : false
Y en tu build.gradle.kts :
compileOnly ( "studio.kuraky:ksplaceholder-api:1.0.0" )
La API vive en un módulo independiente. Otros plugins pueden compilar contra ella sin arrastrar KSCore.
Registrar una expansión
Code (Java):
import
studio.kuraky.ksPlaceholder.api.KSP
;
import java.time.Duration ;
KSP. expansion ( "miplugin" )
// Clave exacta: %miplugin_nombre%
. add ( "nombre", p -> "Hola" )
// Otra clave exacta: %miplugin_nivel%
. add ( "nivel", p -> nivelDe (p ) )
// Prefijo dinámico: %miplugin_top:5%
. dynamic ( "top", (p, arg ) -> top ( Integer. parseInt (arg ) ) )
// Fallback si nada coincide
. fallback ( (p, params ) -> "?" )
// Caché con TTL
. cache (Duration. ofSeconds ( 3 ) )
. register ( ) ;
import java.time.Duration ;
KSP. expansion ( "miplugin" )
// Clave exacta: %miplugin_nombre%
. add ( "nombre", p -> "Hola" )
// Otra clave exacta: %miplugin_nivel%
. add ( "nivel", p -> nivelDe (p ) )
// Prefijo dinámico: %miplugin_top:5%
. dynamic ( "top", (p, arg ) -> top ( Integer. parseInt (arg ) ) )
// Fallback si nada coincide
. fallback ( (p, params ) -> "?" )
// Caché con TTL
. cache (Duration. ofSeconds ( 3 ) )
. register ( ) ;
Code (Java):
// Sustituir tokens en un texto
String linea = KSP. parse (player, "Bienvenido %player_name% — nivel %miplugin_nivel%" ) ;
// Lista de líneas
List <String > lore = KSP. parse (player, List. of ( "Línea 1", "Nivel: %miplugin_nivel%" ) ) ;
// Un token aislado
Object valor = KSP. value (player, "miplugin", "top:1" ) ;
String linea = KSP. parse (player, "Bienvenido %player_name% — nivel %miplugin_nivel%" ) ;
// Lista de líneas
List <String > lore = KSP. parse (player, List. of ( "Línea 1", "Nivel: %miplugin_nivel%" ) ) ;
// Un token aislado
Object valor = KSP. value (player, "miplugin", "top:1" ) ;
Code (Java):
- El resolver corre en el hilo que llame a parse. Puede ser el hilo del servidor, pero también uno async (por ejemplo, desde KSBoard que resuelve el scoreboard en async).
- Nunca consultes BD ni hagas I/O en el resolver. Cachea el valor en memoria y devuélvelo desde ahí.
- Devolver null significa "este placeholder no aplica". El motor pasa a la siguiente variante (prefijo más corto, fallback) o deja el token intacto.
- El resultado se formatea después. Números decimales se recortan a la escala configurada, Boolean se traduce por el motor, el resto pasa por String.valueOf. No llames a String.valueOf manualmente.
Cuando el motor ve %namespace_algo%:
- Busca namespace en el registro.
- Intenta clave exacta algo (registrada con .add).
- Si no, prefijo dinámico más largo que coincida (registrado con .dynamic).
- Si tampoco, .fallback de la expansión.
- Si nadie responde, deja %namespace_algo% en el texto — otro motor (como PAPI) puede intentarlo.
Si PlaceholderAPI está cargado:
- Todos los tokens KS también funcionan bajo el motor PAPI: %kseco_saldo% en un plugin que sólo entienda PAPI se resuelve correctamente.
- Todos los tokens PAPI (%player_*%, %server_*%, expansiones instaladas) también funcionan bajo KSP.
Debug
Situaciones típicas:
"Mi token %miplugin_x% no se resuelve".
/ksp list
/ksp info miplugin
/ksp parse "%miplugin_x%"
Comprueba que:
- El namespace aparece en list.
- La clave x aparece en info.
- El resolver no está devolviendo null (si devuelve null, el motor deja el token intacto).
/ksp cache clear miplugin
Fuerza recomputación. Si el problema persiste, el TTL puede ser demasiado alto:
.cache(Duration.ofSeconds(1)) // en lugar de 30 o similar
Rendimiento
- Registro con HashMap — lookup O(1) por namespace.
- Caché con ConcurrentHashMap<(uuid, ns, key), (valor, expira)> — segura desde cualquier hilo.
- El puente PAPI usa reflexión sólo una vez al arrancar; llamadas subsiguientes son directas.
Quick facts
- Edition: Minecraft Java
- File type: .jar
- Minecraft version listed: 26.2
- How to install: Install the matching mod loader (Forge, Fabric or NeoForge) for your Minecraft version. → Download the .jar. → Put it in the .minecraft/mods folder and launch that loader profile.
- Where to get it: Opens on Spigot — not every file is mirrored on our own servers.
Install steps are the general flow for this file type — How to install Minecraft Java mods & modpacks walks through it step by step.
KSPlaceholder is a free Minecraft Java mod. Compatible with Minecraft 26.2. Downloaded 5 times (via Spigot). Download it and open it directly in the game.