Modern, versioned access to the Minecraft protocol through direct NMS (CraftPlayer.getHandle(), ServerPlayer.connection.send). Menu/container packets live in PacketUxUi; sign input lives in SignGUI. Optional Netty intercept uses an instance-scoped injection path that refuses to silently overwrite another PacketAPI copy.
- Per-version paperweight adapters (1.16 → 26.2) sharing one NMS implementation when the packet layout does not break
- Typed
PacketWraparound rawnet.minecraft.network.protocol.Packethandles - Packet domains, cases, and exemptions so PacketAPI does not fight companion libraries (SignGUI, PacketUxUi)
PacketSendEvent/PacketReceiveEventplus NMS player events (NmsPlayerJoinEvent,NmsSwingEvent, …)- Expanded facades:
packets,players,connections,metadata,protocol,classifier,cases - Folia / Paper / Canvas region-safe schedulers
- Ownership-aware
PacketListenerBus.ensureInjected(single inject entry point) that detects foreign shaded copies via pipeline markers and backs off instead of hijacking - No duplication of PacketUxUi window click / open / set-slot / cursor / book packets
Latest release: 1.0.2 — hosted on Reposilite.
Maven (pom.xml):
<repositories>
<repository>
<id>mastersmp-releases</id>
<url>http://repo.mastersmp.net/releases</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.opmasterleo</groupId>
<artifactId>PacketAPI</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>Gradle (Groovy) (build.gradle):
repositories {
maven {
name = "mastersmp-releases"
url = uri("http://repo.mastersmp.net/releases")
isAllowInsecureProtocol = true
}
}
dependencies {
implementation("net.opmasterleo:PacketAPI:1.0.2")
}Gradle (Kotlin DSL) (build.gradle.kts):
repositories {
maven {
name = "mastersmp-releases"
url = uri("http://repo.mastersmp.net/releases")
isAllowInsecureProtocol = true
}
}
dependencies {
implementation("net.opmasterleo:PacketAPI:1.0.2")
}import net.opmasterleo.packet.PacketAPI;
import net.opmasterleo.packet.PacketAPIConfig;
import net.opmasterleo.packet.event.PacketReceiveEvent;
import net.opmasterleo.packet.event.PacketSendEvent;
import net.opmasterleo.packet.packet.OwnedPacketPolicy;
import net.opmasterleo.packet.packet.PacketExemption;
import net.opmasterleo.packet.packet.PacketExemptions;
import net.kyori.adventure.text.Component;
PacketAPI api = PacketAPI.bootstrap(plugin, PacketAPIConfig.builder()
.autoInjectOnJoin(true)
.registerExemption(PacketExemption.builder("MyMenus")
.domains(net.opmasterleo.packet.packet.PacketDomain.UI_CONTAINER)
.nameContains("OpenScreen")
.build())
.build());
api.packets().setHealth(player, 20f, 20, 5f);
api.packets().keepAlive(player, System.currentTimeMillis());
api.cases().when(packet, view -> {
if (view.isUiOwned()) return;
if (view.isEntityLifecycle()) { /* ... */ }
});
@EventHandler
public void onReceive(PacketReceiveEvent event) {
if (event.getDomain() == net.opmasterleo.packet.packet.PacketDomain.UI_SIGN) {
return; // SignGUI owns this path
}
}Built-in exemptions (disable with respectExemptionsOnSend(false)):
PacketExemptions.SIGN_GUI— sign editor packetsPacketExemptions.PACKET_UX_UI— menus, containers, slots, books, cursors
Listen without touching Netty:
import net.opmasterleo.packet.event.PacketSendEvent;
import net.opmasterleo.packet.event.NmsPlayerJoinEvent;
@EventHandler
public void onPacket(PacketSendEvent event) {
if (event.getPacketName().contains("SetHealth")) {
event.setCancelled(true);
}
}
@EventHandler
public void onJoin(NmsPlayerJoinEvent event) {
Object serverPlayer = event.getPlayerHandle();
}Optional Netty filters (single entry point — never call low-level inject helpers):
api.listeners().addOutbound(player, (viewer, packet) -> OutboundPacketResult.keep());
// Conflict / ownership probe for status/debug:
InjectionProbe.Result probe = api.detectInjectionConflicts(player);
String status = api.injectionStatus(player);./gradlew shadowJar
./gradlew publish # Reposilite releases
./gradlew publishSnapshot # Reposilite snapshots