Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Set up JDK 21
uses: actions/setup-java@v5
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: "temurin"
java-version: "21"
cache: "gradle"

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
with:
languages: ${{ matrix.language }}
build-mode: manual
Expand All @@ -48,6 +48,6 @@ jobs:
-x test --no-daemon --no-build-cache

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
with:
category: "/language:${{ matrix.language }}"
46 changes: 46 additions & 0 deletions .github/workflows/gradle-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Gradle Package

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Validate gradle wrapper
uses: gradle/actions/wrapper-validation@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6

- name: Set up JDK 21 and 25
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: "temurin"
java-version: |
21
25
cache: "gradle"

- name: Build with Gradle
run: chmod +x gradlew && ./gradlew shadowJar -x test --no-daemon

- name: Upload PacketAPI jar
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: packetapi-build
path: build/libs/PacketAPI-*.jar
if-no-files-found: error

- name: Publish snapshot to Reposilite
if: github.event_name == 'push'
run: |
if [ -z "${REPOSILITE_USER}" ] || [ -z "${REPOSILITE_TOKEN}" ]; then
echo "Missing REPOSILITE_USER / REPOSILITE_TOKEN secrets (token name + secret)."
exit 1
fi
./gradlew publishSnapshot -x test --no-daemon
env:
REPOSILITE_USER: ${{ secrets.REPOSILITE_USER }}
REPOSILITE_TOKEN: ${{ secrets.REPOSILITE_TOKEN }}
50 changes: 49 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,52 @@
# PacketAPI
Modern access to the Minecraft protocol

Modern, versioned access to the Minecraft protocol through **direct NMS** (`CraftPlayer.getHandle()`, `ServerPlayer.connection.send`). Menu/container packets live in [PacketUxUi](https://github.com/OPmasterLEO/PacketUxUi); sign input lives in [SignGUI](https://github.com/OPmasterLEO/SignGUI). This library does **not** inject Netty handlers.

[![Codacy Badge](https://app.codacy.com/project/badge/Grade/d8e7bc74da0d4ce29142f3ac5886a98e)](https://app.codacy.com/gh/OPmasterLEO/MasterPacketAPI/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)

## What it is

- Per-version paperweight adapters (1.16 → 26.2) sharing one NMS implementation when the packet layout does not break
- Typed `PacketWrap` around raw `net.minecraft.network.protocol.Packet` handles
- Custom Bukkit events (`PacketSendEvent`, `NmsPlayerJoinEvent`, `NmsSwingEvent`, `NmsUnknownEntityInteractEvent`) with NMS player handles
- Folia / Paper / Canvas region-safe schedulers
- No duplication of PacketUxUi window click / open / set-slot / cursor / book packets

## Send a packet

```java
import net.opmasterleo.packet.PacketAPI;
import net.kyori.adventure.text.Component;

PacketAPI api = PacketAPI.get();
Object handle = api.adapter().players().handle(player); // ServerPlayer
api.packets().setHealth(player, 20f, 20, 5f);
api.packets().systemChat(player, Component.text("hello"), false);
```

Listen without touching Netty:

```java
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();
}
```

## Build / publish

```bash
./gradlew shadowJar
./gradlew publish # Reposilite releases
./gradlew publishSnapshot # Reposilite snapshots
```
10 changes: 4 additions & 6 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@ java {
withSourcesJar()
withJavadocJar()
toolchain {
languageVersion.set(JavaLanguageVersion.of(25))
languageVersion.set(JavaLanguageVersion.of(21))
}
}

dependencies {
api(project(":nms-api"))
compileOnly("io.papermc.paper:paper-api:26.2.build.+")
compileOnly("io.netty:netty-transport:4.2.16.Final")
compileOnly("io.netty:netty-handler:4.2.16.Final")
compileOnly("net.kyori:adventure-api:5.2.0")
compileOnly("net.kyori:adventure-text-serializer-plain:5.2.0")
compileOnly("io.papermc.paper:paper-api:${property("paperApiVersion")}")
compileOnly("net.kyori:adventure-api:4.17.0")
compileOnly("net.kyori:adventure-text-serializer-plain:4.17.0")
testImplementation(platform("org.junit:junit-bom:6.1.2"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
package org.mastersmp.packet;
package net.opmasterleo.packet;

import java.util.Objects;

import org.bukkit.plugin.java.JavaPlugin;

import org.mastersmp.packet.channel.PacketChannels;
import org.mastersmp.packet.channel.PacketListenerBus;
import org.mastersmp.packet.component.Components;
import org.mastersmp.packet.item.Items;
import org.mastersmp.packet.menu.Menus;
import org.mastersmp.packet.nms.AdapterLoader;
import org.mastersmp.packet.nms.NmsAdapter;
import org.mastersmp.packet.packet.Packets;
import org.mastersmp.packet.schedule.Schedulers;
import org.mastersmp.packet.world.Chunks;
import org.mastersmp.packet.world.Dimensions;
import org.mastersmp.packet.world.Entities;
import org.mastersmp.packet.world.Levels;
import org.mastersmp.packet.world.Worlds;
import net.opmasterleo.packet.component.Components;
import net.opmasterleo.packet.item.Items;
import net.opmasterleo.packet.menu.Menus;
import net.opmasterleo.packet.nms.AdapterLoader;
import net.opmasterleo.packet.nms.NmsAdapter;
import net.opmasterleo.packet.packet.Packets;
import net.opmasterleo.packet.schedule.Schedulers;
import net.opmasterleo.packet.world.Chunks;
import net.opmasterleo.packet.world.Dimensions;
import net.opmasterleo.packet.world.Entities;
import net.opmasterleo.packet.world.Levels;
import net.opmasterleo.packet.world.Worlds;

public final class PacketAPI {

Expand All @@ -26,8 +24,6 @@ public final class PacketAPI {
private final JavaPlugin plugin;
private final NmsAdapter adapter;
private final Schedulers schedulers;
private final PacketChannels channels;
private final PacketListenerBus listeners;
private final Packets packets;
private final Items items;
private final Menus menus;
Expand All @@ -42,8 +38,6 @@ private PacketAPI(JavaPlugin plugin, NmsAdapter adapter) {
this.plugin = plugin;
this.adapter = adapter;
this.schedulers = new Schedulers(plugin);
this.channels = new PacketChannels(adapter, schedulers);
this.listeners = new PacketListenerBus(channels, adapter);
this.packets = new Packets(adapter);
this.items = new Items(adapter);
this.menus = new Menus(adapter);
Expand Down Expand Up @@ -75,8 +69,6 @@ public static boolean isReady() {
}

public void shutdown() {
listeners.clear();
channels.uninjectAll();
schedulers.shutdown();
if (instance == this) {
instance = null;
Expand All @@ -95,14 +87,6 @@ public Schedulers schedulers() {
return schedulers;
}

public PacketChannels channels() {
return channels;
}

public PacketListenerBus listeners() {
return listeners;
}

public Packets packets() {
return packets;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.mastersmp.packet.component;
package net.opmasterleo.packet.component;

import net.kyori.adventure.text.Component;
import org.mastersmp.packet.nms.ComponentBridge;
import org.mastersmp.packet.nms.NmsAdapter;
import net.opmasterleo.packet.nms.ComponentBridge;
import net.opmasterleo.packet.nms.NmsAdapter;

public final class Components {

Expand Down
44 changes: 44 additions & 0 deletions api/src/main/java/net/opmasterleo/packet/event/NmsPlayerEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package net.opmasterleo.packet.event;

import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.ApiStatus;

/**
* Parent for NMS player lifecycle events. Handle is {@code ServerPlayer} / {@code EntityPlayer}.
*/
public abstract class NmsPlayerEvent extends Event {

private static final HandlerList HANDLER_LIST = new HandlerList();

private final Player player;
private final Object playerHandle;
Comment on lines +12 to +16

@ApiStatus.Internal
protected NmsPlayerEvent(Player player, Object playerHandle) {
super(false);
this.player = player;
this.playerHandle = playerHandle;
}

public Player getPlayer() {
return player;
}

/**
* NMS {@code ServerPlayer} / {@code EntityPlayer} from {@code CraftPlayer.getHandle()}.
*/
public Object getPlayerHandle() {
return playerHandle;
}

@Override
public HandlerList getHandlers() {
return HANDLER_LIST;
}

public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.opmasterleo.packet.event;

import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;

/**
* Fired after a player joins, with the NMS {@code ServerPlayer} handle already resolved.
*/
public final class NmsPlayerJoinEvent extends NmsPlayerEvent {

@ApiStatus.Internal
public NmsPlayerJoinEvent(Player player, Object playerHandle) {
super(player, playerHandle);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.opmasterleo.packet.event;

import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;

/**
* Fired when a player quits, with the NMS {@code ServerPlayer} handle when still available.
*/
public final class NmsPlayerQuitEvent extends NmsPlayerEvent {

@ApiStatus.Internal
public NmsPlayerQuitEvent(Player player, Object playerHandle) {
super(player, playerHandle);
}
}
61 changes: 61 additions & 0 deletions api/src/main/java/net/opmasterleo/packet/event/NmsSwingEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package net.opmasterleo.packet.event;

import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.ApiStatus;
import net.opmasterleo.packet.nms.packet.Hand;

/**
* NMS-oriented wrap of CraftBukkit/Paper swing animation. Avoids Netty intercept of
* {@code ServerboundSwingPacket}.
*/
public final class NmsSwingEvent extends Event implements Cancellable {

private static final HandlerList HANDLER_LIST = new HandlerList();

private final Player player;
private final Object playerHandle;
private final Hand hand;
private boolean cancelled;

@ApiStatus.Internal
public NmsSwingEvent(Player player, Object playerHandle, Hand hand) {
super(false);
this.player = player;
this.playerHandle = playerHandle;
this.hand = hand;
}

public Player getPlayer() {
return player;
}

public Object getPlayerHandle() {
return playerHandle;
}

public Hand getHand() {
return hand;
}

@Override
public boolean isCancelled() {
return cancelled;
}

@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}

@Override
public HandlerList getHandlers() {
return HANDLER_LIST;
}

public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
}
Loading
Loading