Guide développeur MagmaCore
La référence Java générée permet de rechercher les classes, méthodes et signatures. La version des sources et le commit utilisés sont indiqués pour chaque module.
MagmaCore est une bibliothèque intégrée dans le JAR des plugins qui l'utilisent par shading. Ce n'est pas un plugin serveur autonome : ne l'ajoutez pas à depend comme si les joueurs pouvaient installer un JAR de plugin MagmaCore.
Dépendance et packaging
Les coordonnées de développement actuelles sont com.magmaguy:MagmaCore:2.2.0-SNAPSHOT. Elles sont publiées dans le dépôt releases de MagmaGuy, et non dans le dépôt de snapshots, qui ne contient que d'anciens snapshots 1.x. Un snapshot peut changer sans que cette chaîne de version ne change, et le build publié n'est pas actualisé à chaque version d'un plugin : il peut donc être plus ancien que le MagmaCore intégré aux plugins actuels. Le build publié le 5 octobre 2026 inclut les API de mise à jour sans redémarrage et de parties décrites ci-dessous. Pour compiler avec des changements plus récents non publiés, construisez MagmaCore depuis les sources et publiez-le dans Maven Local, comme indiqué dans Recompiler un consommateur après modification de la bibliothèque. Conservez une trace de l'artefact résolu si vous avez besoin de builds reproductibles.
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>
Ces déclarations permettent de résoudre la dépendance. Configurez la tâche de shading de votre build pour l'inclure dans le JAR final du plugin. Suivez les règles de relocation d'un plugin existant ayant les mêmes besoins d'intégration et vérifiez les recherches réflexives basées sur des chaînes lorsque vous changez les noms de packages. La distribution relocalise org.luaj, org.reflections et javassist sous com.magmaguy.shaded et exclut les classes javax.annotation utilisées uniquement à la compilation.
Chaque plugin peut charger sa propre copie de la bibliothèque. Deux classes Java de même nom, chargées par des chargeurs de classes de plugins distincts, sont des types différents. Utilisez les contrats explicites entre plugins, comme le service de pouvoirs Lua d'EliteMobs ou les adaptateurs du registre de localisations. Ne convertissez pas un objet MagmaCore privé d'un autre plugin vers le type de votre propre copie.
Modules et responsabilités
| Module | Responsabilité |
|---|---|
core | Cycle de vie des plugins, configuration, commandes, menus, parties, requêtes de localisation, scripts Lua, contenu Nightbreak et utilitaires partagés |
nms:core | NMSManager, NMSAdapter et interfaces EasyMinecraftGoals indépendantes de la version |
nms:v* | Implémentations du contrat NMS propres aux versions du serveur |
dist | Distribution assemblée par shading, contenant le cœur et les adaptateurs actifs |
Les enchantements partagés, les actions d'objets, la gestion du compte, les menus de configuration, les catalogues et les mises à jour relèvent des services du cœur. Réutilisez le composant responsable lorsque vous ajoutez un comportement à un plugin consommateur.
Cycle de vie du plugin
Le cycle de vie minimal du cœur suit le modèle des plugins existants :
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);
}
}
Cette initialisation ne se limite pas à obtenir un objet utilitaire. Elle initialise la gestion du compte, les commandes partagées, les écouteurs et la prise en charge des blocs temporaires. La surcharge createInstance(plugin, NightbreakPluginSpec) fournit les textes des commandes partagées propres au plugin.
Préférez les méthodes qui prennent explicitement le plugin propriétaire en argument. getInstance() désigne le singleton de la copie chargée de la bibliothèque ; le plugin demandeur est fixé à la création de cette instance. Ne l'utilisez pas pour déduire le propriétaire de tous les consommateurs.
shutdown(plugin) supprime les enregistrements du téléchargeur, du rafraîchissement de contenu, de l'initialisation et des mises à jour de ce plugin, puis arrête également l'environnement d'exécution partagé de la copie chargée. Son action ne se limite pas au retrait d'une entrée de registre. Appelez cette méthode pour votre propre bibliothèque intégrée lors de l'arrêt de votre plugin ; n'arrêtez jamais la bibliothèque d'un autre plugin pour réinitialiser votre intégration.
Appelez createInstance depuis onLoad afin d'enregistrer le propriétaire des archives de configuration du plugin avant qu'un autre plugin puisse importer du contenu pour lui. L'archivage passe par l'implémentation intégrée au plugin cible ; n'interprétez pas ses règles de retrait de configuration avec votre copie de MagmaCore.
Pour un démarrage en plusieurs phases, startInitialization accepte du travail asynchrone, du travail synchrone et des callbacks de réussite et d'échec. Il archive les fichiers de configuration correspondant à un format retiré avant de lancer l'initialisation asynchrone. Réservez les opérations Bukkit sur les mondes et les entités à la phase synchrone. Un travail asynchrone long doit vérifier isShutdownRequested(plugin) entre ses phases. getInitializationState et isPluginReady exposent l'état du gestionnaire d'initialisation.
Mises à jour du plugin sans redémarrage
NightbreakPluginBootstrap.registerStandardCommands enregistre applypluginupdate avec les autres sous-commandes partagées. Cette commande installe une mise à jour téléchargée en désactivant votre plugin, en remplaçant son jar puis en le réactivant dans la même session du serveur : onDisable doit donc annuler les tâches, désenregistrer les écouteurs et libérer toute référence qui maintiendrait en vie l'ancien chargeur de classes. Les plugins activés dont la classe principale se trouve sous com.magmaguy. et qui dépendent du vôtre, en depend ou en softdepend, sont rechargés avec lui. Tout autre plugin dépendant du vôtre fait refuser le remplacement, qui demande alors un redémarrage. Consultez Appliquer les mises à jour sans redémarrage pour le point de vue de l'administrateur du serveur.
Si une partie de votre plugin ne peut pas être rechargée sur place, appelez NightbreakPluginHotSwap.requireRestartForUpdates(plugin, reason) avant le début des vérifications de mise à jour, et passez false comme second argument de NightbreakPluginUpdater.setAutoDownloadConfigDefault afin que config.yml ne propose pas applyPluginUpdatesWithoutRestart. Le plugin est tout de même rechargé avec son jar actuel lorsqu'un plugin dont il dépend est remplacé. NightbreakPluginUpdater.onPluginUpdateDownloaded(plugin, listener) exécute un écouteur sur le thread de téléchargement une fois qu'une mise à jour validée a atteint le dossier update.
NMS et entités par paquets
Initialisez NMS uniquement si votre plugin en a besoin, avec NMSManager.initializeAdapter(plugin) de com.magmaguy.easyminecraftgoals. Vérifiez NMSManager.isEnabled() avant d'utiliser un comportement dépendant d'un adaptateur. L'initialisation peut échouer ou rencontrer une version de serveur non prise en charge.
La distribution contient les familles d'adaptateurs suivantes :
| Adaptateur | Versions 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, implémentations Spigot/Paper distinctes |
v26 | 26.1 et famille actuelle d'adaptateurs 26.x |
La sélection d'un adaptateur ne garantit pas la compatibilité avec toutes les futures versions du serveur. Le sélecteur d'exécution de NMSManager détermine si le serveur installé peut charger un adaptateur. Les versions antérieures à 1.21.4 ne font pas partie de l'ensemble actuel d'adaptateurs.
EasyMinecraftGoals gère les entités qui n'existent que par paquets, leur visibilité, le routage de leurs interactions et les utilitaires de déplacement et de recherche de chemin. Ce ne sont pas des entités ordinaires du monde. Gérez-les via leur API responsable et nettoyez les objets créés par votre plugin tant que l'adaptateur est encore disponible.
Requêtes de localisation et de protection
com.magmaguy.magmacore.location.LocationQueryRegistry expose des requêtes sur les donjons et les protections de régions, notamment isInAnyDungeon, isInAnyProtectedRegion et canBuild.
Enregistrez les fournisseurs personnalisés avec registerDungeonLocator ou registerProtectionProvider, puis désenregistrez le même fournisseur à la désactivation de son propriétaire. Le registre contient des adaptateurs pour les plugins existants et découvre les fournisseurs de donjons entre plugins sans imposer aux consommateurs un même chargeur de classes MagmaCore.
Choisissez la requête correspondant à l'action. Être en dehors d'un donjon ne signifie pas avoir la permission de construire à cet endroit. Exécutez sur le thread du serveur les requêtes qui utilisent Bukkit ou des plugins de protection.
Parties
Le cycle de vie des parties se trouve dans com.magmaguy.magmacore.match. Appelez MatchCore.enable(plugin) une fois pendant l'activation, puis étendez Match, transmettez à son constructeur un MatchSettings obtenu avec MatchSettings.builder(), et appelez open() une fois la construction de votre sous-classe terminée. La logique de jeu se place dans les hooks protégés tels que onJoin, onStart, onDeath et onLeave. MagmaCore.shutdown(plugin) détruit les parties restantes du plugin.
Le cœur ne déclenche aucun événement Bukkit de lui-même. Il appelle le MatchApi défini dans les paramètres : c'est donc votre plugin qui décide des événements à exposer. Un callback annulable met son veto à l'étape en renvoyant false ou en levant une exception. La copie de chaque plugin ne suit que ses propres parties ; un marqueur de métadonnées du joueur, magmacore_match, indique aux autres copies qu'un joueur participe déjà à une partie.
MatchSettings.builder().permission(...) définit la permission dont un joueur a besoin pour rejoindre. Redéfinissez hasJoinPermission(player) pour décider joueur par joueur, par exemple pour laisser entrer le staff sans elle. Un participant qui part parce qu'il est mort (LeaveReason.DIED) est soigné à pleine santé avant d'être déplacé hors de la partie : si un bonus de santé maximale est retiré à la sortie, sa santé reste ainsi au maximum. Les autres sorties en cours de partie conservent les dégâts subis, et les joueurs encore présents à la fin de la partie sont soignés. Ces deux comportements sont plus récents que la version publiée le 5 octobre 2026.
Les anciennes classes de parties de com.magmaguy.magmacore.instance, dont MatchInstance, ont été supprimées. InstanceProtector y reste et est enregistré par MagmaCore.enableWorldProtections(plugin).
Hôtes Lua Mind
MagmaCore compile des programmes Mind écrits en Lua pour les plugins hôtes. Le format des scripts est décrit dans Programmes de comportement. Un hôte crée son propre LuaMindModuleRegistry, ouvre un propriétaire pour son espace de noms avec openOwner(namespace), enregistre les modules avec le registerModule du propriétaire, et obtient un LuaMindDefinition grâce au validateProgram du propriétaire. Chaque appel à instantiate sur la définition construit un programme neuf, avec son propre environnement Lua, pour une entité. Les hooks ci-dessous sont plus récents que le build publié le 5 octobre 2026.
- Inspecter un module.
LuaMindModuleRegistry.inspectModule(sourceName, source)lit l'id, la révision, les dépendances et les valeurs par défaut desettingsd'un module sans l'enregistrer.LuaMindModuleDescriptor.settings()contient des valeursDouble,Boolean,StringouList<String>. MagmaCore ne transmet pas les réglages aux scripts. Un hôte qui veut des valeurs par créature fusionne les siennes par-dessus ces valeurs par défaut et les expose, comme les familiers de FreeMinecraftModels le font avecc.settings. - Étendre les contextes de callback.
LuaMindDefinition.instantiate(LuaMindContextExtension)ajoute vos champs à la table de contexte de chaque callback.extend(table, context, contribution)reçoit la table avant que Lua ne la voie, leMindContextdu callback, et l'id du module qui a déclaré le callback, ou l'id propre du programme. Elle s'exécute sur le thread serveur dans le budget d'exécution du callback : son temps CPU compte donc dans lecpu_microsdu programme, et une exception fait échouer le callback. Ajoutez des champs avecrawset, ou avecLuaTableSupport.lazyField, qui conserve le__indexexistant de la table pour toutes les autres clés. Ne remplacez ni la métatable de la table ni son__index, car les sections intégrées sont lues à travers eux, et n'écrasez pastick,generation,entity,memory,perception,actuatorniactions. Lire une section intégrée depuisextendla construit pour ce callback. Passez une extension distincte à chaque appel àinstantiatelorsqu'elle contient un état propre à chaque entité. - Intervalle de sondage. Un comportement Java peut redéfinir
MindBehavior.probeInterval(), l'équivalent duprobe_intervalde Lua, pour n'interrogercanStartque tous les N ticks tant qu'il est arrêté. La valeur doit aller de 1 àMindBehavior.MAX_PROBE_INTERVAL(200) ;MindProgramrefuse les autres valeurs. La valeur par défaut de 1 interroge à chaque tick. UnMindSensordétecte au premier tick où son corps est actualisé, puis tous lesintervalTicks()ticks selon une phase propre à chaque entité. - Vol.
MindActuator.steerFlight(Vector), qui figurait déjà dans ce build, fait voler un corpsFLYINGselon cette vitesse pendant un tick et nécessite les réservations MOVE et LOOK. Son plafond et lesteer_flightde Lua sont nouveaux :MindActuator.MAX_FLIGHT_SPEEDvaut 4 blocs par tick, et une vitesse supérieure y est ramenée.RouteFlighty plafonne aussi sa vitesse : une route réglée à plus de 80 blocs par seconde vole donc à 80.
Recompiler un consommateur après modification de la bibliothèque
Utilisez le JDK 21 et publiez MagmaCore dans Maven Local avec ./gradlew publishToMavenLocal, ou .\gradlew.bat publishToMavenLocal sous Windows. Vérifiez que le plugin consommateur résout ce dépôt et la version voulue, puis reconstruisez son JAR avec shading. Remplacer une bibliothèque dans Maven Local ne met pas à jour un plugin déjà compilé.
Consultez l'index développeur pour les API des plugins installés. Ces intégrations utilisent généralement provided ou compileOnly ; le contrat de bibliothèque intégrée de MagmaCore est différent.