Guía de MagmaCore para desarrolladores
La referencia Java generada permite buscar clases, métodos y firmas, e indica la versión y el commit del código fuente de cada módulo.
MagmaCore es una biblioteca que se incluye dentro del JAR de los plugins que la usan. No es un plugin de servidor independiente y no debe aparecer en depend como si los jugadores pudieran instalar un JAR de plugin de MagmaCore.
Dependencia y empaquetado
La coordenada de desarrollo actual es com.magmaguy:MagmaCore:2.2.0-SNAPSHOT. Se publica en el repositorio de releases de MagmaGuy, no en el de snapshots, que solo contiene snapshots antiguos de la serie 1.x. Los snapshots pueden cambiar sin que cambie esa cadena de versión, y la compilación publicada no se actualiza con cada versión de los plugins, así que puede ser más antigua que el MagmaCore integrado en los plugins actuales. La compilación publicada el 5 de octubre de 2026 incluye las API de actualizaciones sin reinicio y de partidas descritas más abajo. Para compilar contra cambios más recientes aún sin publicar, compila MagmaCore desde el código fuente y publícalo en Maven Local, como se describe en Compilar un plugin tras modificar la biblioteca. Registra el artefacto resuelto cuando necesites compilaciones reproducibles.
repositories {
maven("https://repo.magmaguy.com/releases")
}
dependencies {
implementation("com.magmaguy:MagmaCore:2.2.0-SNAPSHOT")
}
<repositories>
<repository>
<id>magmaguy-releases</id>
<url>https://repo.magmaguy.com/releases</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>MagmaCore</artifactId>
<version>2.2.0-SNAPSHOT</version>
</dependency>
</dependencies>
Estas declaraciones resuelven la dependencia. Configura la tarea de empaquetado de dependencias de tu compilación para incluirla en el JAR final del plugin. Sigue las reglas de reubicación de un plugin existente con las mismas necesidades de integración y comprueba las búsquedas por reflexión basadas en cadenas al cambiar nombres de paquetes. La distribución reubica org.luaj, org.reflections y javassist en com.magmaguy.shaded y omite las clases de compilación de javax.annotation.
Cada plugin puede cargar su propia copia de la biblioteca. Las clases Java con el mismo nombre procedentes de distintos cargadores de clases de plugins son tipos diferentes. Usa los contratos explícitos entre plugins, como el servicio de poderes Lua de EliteMobs y los adaptadores del registro de ubicaciones. No conviertas un objeto privado de MagmaCore de otro plugin al tipo de tu propia copia.
Módulos y responsabilidades
| Módulo | Responsabilidad |
|---|---|
core | Ciclo de vida del plugin, configuración, comandos, menús, partidas, consultas de ubicación, scripting Lua, contenido de Nightbreak y utilidades compartidas |
nms:core | NMSManager, NMSAdapter e interfaces de EasyMinecraftGoals independientes de la versión |
nms:v* | Implementaciones del contrato NMS para cada versión del servidor |
dist | Distribución empaquetada que contiene el núcleo y los adaptadores activos |
Los encantamientos compartidos, las acciones de objetos, la gestión de cuentas, los menús de configuración, los catálogos y las actualizaciones pertenecen a los servicios del núcleo. Reutiliza el componente responsable al añadir funciones a un plugin que consuma la biblioteca.
Ciclo de vida del plugin
El ciclo de vida mínimo del núcleo sigue el patrón de los plugins que ya lo usan:
package example;
import com.magmaguy.magmacore.MagmaCore;
import org.bukkit.plugin.java.JavaPlugin;
public final class CoreConsumer extends JavaPlugin {
@Override
public void onLoad() {
MagmaCore.createInstance(this);
}
@Override
public void onEnable() {
MagmaCore.onEnable(this);
}
@Override
public void onDisable() {
MagmaCore.shutdown(this);
}
}
Esta inicialización tiene efectos más allá de obtener un objeto de utilidades. Inicializa la gestión de cuentas, los comandos compartidos, los listeners y el soporte de bloques temporales. La sobrecarga createInstance(plugin, NightbreakPluginSpec) proporciona los textos de los comandos compartidos específicos del plugin.
Prefiere los métodos que reciben explícitamente el plugin propietario. getInstance() hace referencia al singleton de la copia cargada de la biblioteca, cuyo plugin solicitante se establece al crear esa instancia. No debe usarse para deducir la propiedad de todos los plugins que consumen la biblioteca.
shutdown(plugin) elimina los registros del descargador, el actualizador de contenido, la inicialización y el actualizador de ese plugin, y después también cierra el entorno de ejecución compartido de la copia cargada. No se limita a eliminar una entrada de un registro. Llámalo para tu propia biblioteca integrada durante el cierre de tu plugin; nunca cierres la biblioteca de otro plugin para reiniciar tu integración.
Llama a createInstance desde onLoad para registrar el propietario del archivo de configuraciones del plugin antes de que otro plugin pueda importar contenido para él. El archivado se ejecuta mediante la propia implementación de MagmaCore incluida en el plugin de destino; no interpretes sus reglas de retirada con tu copia de MagmaCore.
Para un arranque por fases, startInitialization acepta trabajo asíncrono, trabajo síncrono y callbacks de éxito y fallo. Archiva los archivos de configuración que coincidan con formatos retirados antes de ejecutar el trabajo de inicialización asíncrono. Mantén las operaciones de mundos y entidades de Bukkit en la fase síncrona. El trabajo asíncrono prolongado debe comprobar isShutdownRequested(plugin) entre fases. getInitializationState e isPluginReady exponen el estado del gestor de inicialización.
Actualizaciones de plugins sin reinicio
NightbreakPluginBootstrap.registerStandardCommands registra applypluginupdate junto con los demás subcomandos compartidos. Instala una actualización descargada deshabilitando tu plugin, sustituyendo su JAR y volviendo a habilitarlo en la misma sesión del servidor, así que onDisable debe cancelar las tareas, eliminar el registro de los listeners y liberar cualquier referencia que mantendría vivo el cargador de clases antiguo. Los plugins habilitados cuya clase principal está bajo com.magmaguy. y que dependen del tuyo mediante depend o softdepend se recargan con él. Cualquier otro plugin que dependa del tuyo hace que el cambio se rechace y pida un reinicio. Consulta Aplicar actualizaciones sin reiniciar para la parte del propietario del servidor.
Si una parte de tu plugin no puede recargarse en caliente, llama a NightbreakPluginHotSwap.requireRestartForUpdates(plugin, reason) antes de que empiecen las comprobaciones de actualizaciones y pasa false como segundo argumento de NightbreakPluginUpdater.setAutoDownloadConfigDefault para que config.yml no ofrezca applyPluginUpdatesWithoutRestart. El plugin sigue recargándose con su JAR actual cuando se cambia un plugin del que depende. NightbreakPluginUpdater.onPluginUpdateDownloaded(plugin, listener) ejecuta un listener en el hilo de descarga cuando una actualización validada llega a la carpeta update.
NMS y entidades de paquetes
Inicializa NMS solo si tu plugin lo necesita, mediante NMSManager.initializeAdapter(plugin) de com.magmaguy.easyminecraftgoals. Comprueba NMSManager.isEnabled() antes de usar funciones que dependan del adaptador. La llamada de inicialización puede fallar o encontrar una versión de servidor no compatible.
La distribución incluye las siguientes familias de adaptadores:
| Adaptador | Versiones de Minecraft |
|---|---|
v1_21_R3 | 1.21.4 |
v1_21_R4 | 1.21.5 |
v1_21_R5 | 1.21.6, 1.21.7, 1.21.8 |
v1_21_R6 | 1.21.9, 1.21.10 |
v1_21_R7_spigot, v1_21_R7_paper | 1.21.11, implementaciones separadas de Spigot/Paper |
v26 | 26.1 y la familia actual de adaptadores 26.x |
La selección de adaptadores no garantiza la compatibilidad general con futuras versiones del servidor. El selector de ejecución de NMSManager determina si el servidor instalado puede cargar un adaptador. Las versiones anteriores a 1.21.4 quedan fuera del conjunto actual de adaptadores.
EasyMinecraftGoals gestiona las entidades que solo existen mediante paquetes, su visibilidad, el enrutamiento de sus interacciones y las utilidades de movimiento y búsqueda de rutas. No son entidades normales del mundo. Gestiónalas mediante su API responsable y elimina los objetos que cree tu plugin mientras el adaptador siga disponible.
Consultas de ubicación y protección
com.magmaguy.magmacore.location.LocationQueryRegistry expone consultas de mazmorras y protección de regiones, incluidas isInAnyDungeon, isInAnyProtectedRegion y canBuild.
Registra proveedores personalizados con registerDungeonLocator o registerProtectionProvider; elimina el registro del mismo proveedor al deshabilitar su propietario. El registro incluye adaptadores para plugins existentes y descubre proveedores de mazmorras de otros plugins sin exigir que compartan un único cargador de clases de MagmaCore.
Comprueba la consulta que corresponda a la acción. Estar fuera de una mazmorra no equivale a tener permiso de construcción en una ubicación. Ejecuta las consultas que accedan a Bukkit o a plugins de protección en el hilo del servidor.
Partidas
El ciclo de vida de las partidas está en com.magmaguy.magmacore.match. Llama una vez a MatchCore.enable(plugin) durante la habilitación, después extiende Match, pasa a su constructor un MatchSettings creado con MatchSettings.builder() y llama a open() cuando tu subclase termine de construirse. La lógica del juego va en los hooks protegidos, como onJoin, onStart, onDeath y onLeave. MagmaCore.shutdown(plugin) destruye las partidas que le queden al plugin.
El núcleo no emite eventos de Bukkit propios. Llama a la MatchApi indicada en la configuración, así que tu plugin decide qué eventos expone. Un callback cancelable veta el paso devolviendo false o lanzando una excepción. La copia de cada plugin solo registra sus propias partidas; un marcador en los metadatos del jugador, magmacore_match, indica a las demás copias que el jugador ya está en una.
MatchSettings.builder().permission(...) establece el permiso que necesita un jugador para unirse. Sobrescribe hasJoinPermission(player) para decidirlo jugador por jugador, por ejemplo para dejar entrar al staff sin él. Un participante que se va porque murió (LeaveReason.DIED) recupera toda la salud antes de que lo saquen, de modo que un bonus de salud máxima retirado en la salida conserva la proporción completa. Las demás salidas durante la partida conservan su daño, y los jugadores que siguen en la partida cuando termina se curan. Ambos comportamientos son posteriores a la compilación publicada el 5 de octubre de 2026.
Se han eliminado las clases de partidas antiguas de com.magmaguy.magmacore.instance, incluida MatchInstance. InstanceProtector sigue ahí y lo registra MagmaCore.enableWorldProtections(plugin).
Anfitriones de Lua Mind
MagmaCore compila programas Mind escritos en Lua para los plugins anfitriones. El formato de los scripts se describe en Programas de Comportamiento. Un anfitrión crea su propio LuaMindModuleRegistry, abre un propietario para su espacio de nombres con openOwner(namespace), registra módulos con el registerModule del propietario y obtiene un LuaMindDefinition del validateProgram del propietario. Cada llamada a instantiate sobre la definición construye un programa nuevo, con su propio entorno Lua, para una entidad. Los hooks siguientes son posteriores a la compilación publicada el 5 de octubre de 2026.
- Inspeccionar un módulo.
LuaMindModuleRegistry.inspectModule(sourceName, source)lee el id, la revisión, las dependencias y los valores predeterminados desettingsde un módulo sin registrarlo.LuaMindModuleDescriptor.settings()contiene valoresDouble,Boolean,StringoList<String>. MagmaCore no entrega los ajustes a los scripts. Un anfitrión que quiera valores por criatura combina los suyos sobre estos valores predeterminados y los expone, como hacen las mascotas de FreeMinecraftModels conc.settings. - Ampliar los contextos de callback.
LuaMindDefinition.instantiate(LuaMindContextExtension)añade tus campos a la tabla de contexto de cada callback.extend(table, context, contribution)recibe la tabla antes de que Lua la vea, elMindContextdel callback y el id del módulo que declaró el callback, o el id propio del programa. Se ejecuta en el hilo del servidor dentro del presupuesto de ejecución del callback, así que su tiempo de CPU cuenta para elcpu_microsdel programa y una excepción hace fallar el callback. Añade campos conrawset, o conLuaTableSupport.lazyField, que conserva el__indexexistente de la tabla para cualquier otra clave. No reemplaces la metatabla de la tabla ni su__index, porque las secciones integradas se leen a través de ellos, y no sobrescribastick,generation,entity,memory,perception,actuatorniactions. Leer una sección integrada desdeextendla construye para ese callback. Pasa una extensión distinta a cada llamada ainstantiatecuando contenga estado por entidad. - Intervalo de sondeo. Un comportamiento Java puede sobrescribir
MindBehavior.probeInterval(), el equivalente deprobe_intervalen Lua, para llamar acanStartcada N ticks mientras está detenido. Debe estar entre 1 yMindBehavior.MAX_PROBE_INTERVAL(200);MindProgramrechaza otros valores. El valor por defecto de 1 consulta en cada tick. UnMindSensordetecta en el primer tick en que se procesa su cuerpo y después cadaintervalTicks()ticks, con una fase propia por entidad. - Vuelo.
MindActuator.steerFlight(Vector), que ya estaba en esa compilación, hace volar un cuerpoFLYINGcon esa velocidad durante un tick y necesita las reservas de control MOVE y LOOK. Son nuevos su límite y elsteer_flightde Lua:MindActuator.MAX_FLIGHT_SPEEDes de 4 bloques por tick, y una velocidad mayor se reduce hasta ese valor.RouteFlighttambién limita ahí su velocidad, así que una ruta configurada a más de 80 bloques por segundo vuela a 80.
Compilar un plugin tras modificar la biblioteca
Usa JDK 21 y publica MagmaCore en Maven Local con ./gradlew publishToMavenLocal, o .\gradlew.bat publishToMavenLocal en Windows. Asegúrate de que el plugin resuelva ese repositorio y la versión prevista, y después vuelve a compilar su JAR con las dependencias integradas. Sustituir una biblioteca en Maven Local no actualiza un plugin ya compilado.
Consulta el índice para desarrolladores para las API de plugins instalados. Esas integraciones normalmente usan provided o compileOnly; el contrato de biblioteca integrada de MagmaCore es distinto.