Saltar para o conteúdo principal

Guia do MagmaCore para programadores

A referência Java gerada permite pesquisar classes, métodos e assinaturas, com a versão e o commit do código registados para cada módulo.

O MagmaCore é uma biblioteca incorporada por shading nos plugins que a utilizam. Não é um plugin de servidor autónomo e não deve aparecer em depend como se os jogadores pudessem instalar um JAR de plugin MagmaCore.

Dependência e empacotamento​

A coordenada de desenvolvimento atual é com.magmaguy:MagmaCore:2.2.0-SNAPSHOT. É publicada no repositório de releases do MagmaGuy, e não no repositório de snapshots, que contém apenas snapshots 1.x mais antigos. Os snapshots podem mudar sem alterar essa versão, e a compilação publicada não é renovada a cada lançamento de plugin, pelo que pode ser mais antiga do que o MagmaCore incorporado nos plugins atuais. A compilação publicada a 5 de outubro de 2026 inclui as APIs de atualização sem reinício e de partidas descritas abaixo. Para compilar contra alterações mais recentes ainda não publicadas, compile o MagmaCore a partir do código-fonte e publique-o no Maven Local, como descrito em Compilar um plugin após alterações à biblioteca. Registe o artefacto resolvido se precisar de compilações reproduzíveis.

Gradle Kotlin DSL
repositories {
maven("https://repo.magmaguy.com/releases")
}

dependencies {
implementation("com.magmaguy:MagmaCore:2.2.0-SNAPSHOT")
}
Maven sections
<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 declarações resolvem a dependência. Configure a tarefa de shading para a incluir no JAR final do plugin. Siga as regras de relocação de um plugin existente com as mesmas necessidades de integração e verifique as pesquisas por reflexão baseadas em strings ao alterar nomes de pacotes. A distribuição reloca org.luaj, org.reflections e javassist para com.magmaguy.shaded e exclui as classes javax.annotation usadas apenas na compilação.

Cada plugin pode ter a sua própria cópia carregada da biblioteca. Classes Java com o mesmo nome carregadas por classloaders de plugins diferentes são tipos distintos. Use os contratos explícitos entre plugins, como o serviço de poderes Lua do EliteMobs e os adaptadores do registo de localizações. Não converta um objeto MagmaCore privado de outro plugin para o tipo da sua cópia.

Módulos e responsabilidades​

MóduloResponsabilidade
coreCiclo de vida do plugin, configuração, comandos, menus, partidas, consultas de localização, scripts Lua, conteúdo Nightbreak e utilitários partilhados
nms:coreNMSManager, NMSAdapter e as interfaces EasyMinecraftGoals independentes da versão
nms:v*Implementações do contrato NMS para cada versão do servidor
distDistribuição com shading que contém o núcleo e os adaptadores ativos

Os encantamentos partilhados, ações de itens, gestão de contas, menus de configuração, catálogos e atualizações pertencem aos serviços do núcleo. Reutilize o componente responsável ao acrescentar comportamento a um plugin que use a biblioteca.

Ciclo de vida do plugin​

O ciclo de vida mínimo do núcleo segue o padrão dos plugins existentes:

CoreConsumer.java
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 inicialização faz mais do que obter um objeto utilitário. Inicializa a gestão de contas, comandos partilhados, listeners e suporte para blocos temporários. A sobrecarga createInstance(plugin, NightbreakPluginSpec) fornece os textos específicos do plugin para os comandos partilhados.

Prefira métodos que recebam explicitamente o plugin proprietário. getInstance() refere-se ao singleton da cópia carregada da biblioteca. O plugin associado é definido quando essa instância é criada. Não o use para inferir o proprietário de todos os plugins que utilizam a biblioteca.

shutdown(plugin) limpa os registos de descargas, atualização de conteúdo, inicialização e atualização desse plugin. Depois, também encerra o sistema de execução partilhado da cópia carregada. Não se limita a remover uma entrada de registo. Chame-o para a sua própria biblioteca incorporada durante o encerramento do plugin. Nunca encerre a biblioteca de outro plugin para reiniciar a integração.

Chame createInstance em onLoad para registar o proprietário do arquivo de configurações do plugin antes de outro plugin poder importar conteúdo para ele. O arquivamento usa a implementação incorporada no plugin de destino; não interprete as regras de retirada de configurações desse plugin com a sua cópia do MagmaCore.

Para um arranque por fases, startInitialization aceita trabalho assíncrono, trabalho síncrono e callbacks de sucesso e de falha. Arquiva os ficheiros de configuração que correspondam a formatos retirados antes de executar a inicialização assíncrona. Mantenha as operações sobre mundos e entidades Bukkit na fase síncrona. Trabalho assíncrono demorado deve consultar isShutdownRequested(plugin) entre fases. getInitializationState e isPluginReady expõem o estado do gestor de inicialização.

Atualizações do plugin sem reinício​

NightbreakPluginBootstrap.registerStandardCommands regista applypluginupdate juntamente com os outros subcomandos partilhados. Este instala uma atualização transferida desativando o plugin, substituindo o seu jar e voltando a ativá-lo na mesma sessão do servidor, pelo que onDisable tem de cancelar tarefas, remover o registo dos listeners e libertar todas as referências que manteriam vivo o classloader antigo. Os plugins ativos cuja classe principal esteja em com.magmaguy. e que dependam do seu, diretamente ou por soft-depend, são recarregados com ele. Qualquer outro plugin que dependa do seu faz com que a substituição seja recusada e peça um reinício. Consulte Aplicar atualizações sem reiniciar para a perspetiva do dono do servidor.

Se parte do plugin não puder ser recarregada no local, chame NightbreakPluginHotSwap.requireRestartForUpdates(plugin, reason) antes de as verificações de atualização começarem e passe false como segundo argumento de NightbreakPluginUpdater.setAutoDownloadConfigDefault, para que config.yml não ofereça applyPluginUpdatesWithoutRestart. O plugin continua a ser recarregado com o jar atual quando um plugin de que depende é substituído. NightbreakPluginUpdater.onPluginUpdateDownloaded(plugin, listener) executa um listener na thread de transferência depois de uma atualização validada chegar à pasta update.

NMS e entidades por pacotes​

Inicialize NMS apenas se o plugin precisar dele, usando NMSManager.initializeAdapter(plugin) de com.magmaguy.easyminecraftgoals. Verifique NMSManager.isEnabled() antes de usar comportamento dependente do adaptador. A inicialização pode falhar ou encontrar uma versão de servidor não suportada.

A distribuição inclui estas famílias de adaptadores:

AdaptadorVersões de Minecraft
v1_21_R31.21.4
v1_21_R41.21.5
v1_21_R51.21.6, 1.21.7, 1.21.8
v1_21_R61.21.9, 1.21.10
v1_21_R7_spigot, v1_21_R7_paper1.21.11, com implementações separadas para Spigot e Paper
v2626.1 e a família atual de adaptadores 26.x

A seleção de um adaptador não garante compatibilidade com todas as versões futuras do servidor. O seletor de execução em NMSManager determina se o servidor instalado pode carregar um adaptador. Versões anteriores à 1.21.4 estão fora do conjunto atual.

O EasyMinecraftGoals gere as entidades que existem apenas através de pacotes, a sua visibilidade, o encaminhamento das interações e os utilitários de movimento e procura de caminhos. Estas não são entidades normais do mundo. Gira-as através da API responsável e limpe os objetos criados pelo seu plugin enquanto o adaptador ainda estiver disponível.

Consultas de localização e proteção​

com.magmaguy.magmacore.location.LocationQueryRegistry disponibiliza consultas sobre masmorras e proteção de regiões, incluindo isInAnyDungeon, isInAnyProtectedRegion e canBuild.

Registe fornecedores personalizados com registerDungeonLocator ou registerProtectionProvider e remova o mesmo fornecedor quando o proprietário for desativado. O registo inclui adaptadores para plugins existentes e descobre fornecedores de masmorras entre plugins sem exigir que todos partilhem um classloader do MagmaCore.

Escolha a consulta correspondente à ação. Estar fora de uma masmorra não equivale a ter permissão para construir nesse local. Execute as consultas que acedem ao Bukkit ou a plugins de proteção na thread do servidor.

Partidas​

O ciclo de vida das partidas encontra-se em com.magmaguy.magmacore.match. Chame MatchCore.enable(plugin) uma vez durante a ativação, depois estenda Match, passe ao seu construtor um MatchSettings obtido de MatchSettings.builder() e chame open() quando a subclasse terminar a construção. A lógica de jogo fica nos hooks protegidos, como onJoin, onStart, onDeath e onLeave. MagmaCore.shutdown(plugin) destrói as partidas restantes do plugin.

O núcleo não emite eventos Bukkit próprios. Chama a MatchApi definida nas definições, pelo que é o seu plugin que decide que eventos expor. Uma callback cancelável veta o passo devolvendo false ou lançando uma exceção. A cópia de cada plugin só acompanha as suas próprias partidas; um marcador de metadados do jogador, magmacore_match, indica às outras cópias que o jogador já está numa partida.

MatchSettings.builder().permission(...) define a permissão de que um jogador precisa para entrar. Substitua hasJoinPermission(player) para decidir jogador a jogador, por exemplo para deixar entrar sem ela os membros da equipa do servidor. Um participante que sai por ter morrido (LeaveReason.DIED) recupera a vida toda antes de ser retirado, para que um bónus de vida máxima removido na saída mantenha a proporção completa. As outras saídas durante a partida mantêm o dano, e os jogadores ainda na partida quando esta termina recuperam a vida. Os dois comportamentos são mais recentes do que a build publicada a 5 de outubro de 2026.

As classes de partidas antigas em com.magmaguy.magmacore.instance, incluindo MatchInstance, foram removidas. InstanceProtector permanece nesse pacote e é registado por MagmaCore.enableWorldProtections(plugin).

Hosts Lua Mind​

O MagmaCore compila programas Mind escritos em Lua para os plugins anfitriões. O formato dos scripts está descrito em Programas de comportamento. Um anfitrião cria o seu próprio LuaMindModuleRegistry, abre um proprietário para o seu espaço de nomes com openOwner(namespace), regista módulos com o registerModule do proprietário e obtém um LuaMindDefinition a partir do validateProgram do proprietário. Cada chamada a instantiate na definição constrói um programa novo, com o seu próprio ambiente Lua, para uma entidade. Os hooks abaixo são mais recentes do que a compilação publicada a 5 de outubro de 2026.

  • Inspecionar um módulo. LuaMindModuleRegistry.inspectModule(sourceName, source) lê o ID, a revisão, as dependências e as predefinições de settings de um módulo sem o registar. LuaMindModuleDescriptor.settings() contém valores Double, Boolean, String ou List<String>. O MagmaCore não entrega as definições aos scripts. Um anfitrião que queira valores por criatura combina os seus sobre estas predefinições e expõe-nos, como as mascotes do FreeMinecraftModels fazem com c.settings.
  • Estender os contextos dos callbacks. LuaMindDefinition.instantiate(LuaMindContextExtension) acrescenta os seus campos à tabela de contexto de cada callback. extend(table, context, contribution) recebe a tabela antes de o Lua a ver, o MindContext do callback e o ID do módulo que declarou o callback, ou o ID do próprio programa. É executado na thread do servidor, dentro do orçamento de execução do callback, pelo que o seu tempo de CPU conta para o cpu_micros do programa e uma exceção faz o callback falhar. Acrescente campos com rawset, ou com LuaTableSupport.lazyField, que mantém o __index existente da tabela para todas as outras chaves. Não substitua a metatabela da tabela nem o seu __index, porque as secções incorporadas são lidas através deles, e não substitua tick, generation, entity, memory, perception, actuator nem actions. Ler uma secção incorporada a partir de extend constrói-a para esse callback. Passe uma extensão separada a cada chamada a instantiate quando ela guarda estado por entidade.
  • Intervalo de verificação. Um comportamento Java pode substituir MindBehavior.probeInterval(), o equivalente do probe_interval do Lua, para chamar canStart a cada N ticks enquanto está parado. Tem de ir de 1 a MindBehavior.MAX_PROBE_INTERVAL (200); o MindProgram recusa outros valores. A predefinição 1 pergunta a cada tick. Um MindSensor deteta no primeiro tick em que o seu corpo é processado e depois a cada intervalTicks() ticks, numa fase própria de cada entidade.
  • Voo. MindActuator.steerFlight(Vector), que já estava nessa compilação, faz voar um corpo FLYING por essa velocidade durante um tick e precisa das reservas MOVE e LOOK. São novos o seu limite e o steer_flight do Lua: MindActuator.MAX_FLIGHT_SPEED é 4 blocos por tick, e uma velocidade superior é reduzida a esse valor. RouteFlight também limita aí a sua velocidade, pelo que uma rota definida acima de 80 blocos por segundo voa a 80.

Compilar um plugin após alterações à biblioteca​

Use JDK 21 e publique o MagmaCore no Maven Local com ./gradlew publishToMavenLocal, ou .\gradlew.bat publishToMavenLocal no Windows. Confirme que o plugin que usa a biblioteca resolve esse repositório e a versão pretendida, e volte a compilar o seu JAR com shading. Substituir uma biblioteca no Maven Local não atualiza um plugin já compilado.

Consulte o índice para programadores para APIs de plugins instalados. Essas integrações usam normalmente provided ou compileOnly. O MagmaCore segue o contrato de uma biblioteca incorporada.