diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 134a929..a6a723e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -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 @@ -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 }}" diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml new file mode 100644 index 0000000..66d1a1b --- /dev/null +++ b/.github/workflows/gradle-publish.yml @@ -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 }} diff --git a/README.md b/README.md index 0b90172..d88c63c 100644 --- a/README.md +++ b/README.md @@ -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 +``` diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 151bff9..e8f4142 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -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") diff --git a/api/src/main/java/org/mastersmp/packet/PacketAPI.java b/api/src/main/java/net/opmasterleo/packet/PacketAPI.java similarity index 70% rename from api/src/main/java/org/mastersmp/packet/PacketAPI.java rename to api/src/main/java/net/opmasterleo/packet/PacketAPI.java index 9de5601..8c31358 100644 --- a/api/src/main/java/org/mastersmp/packet/PacketAPI.java +++ b/api/src/main/java/net/opmasterleo/packet/PacketAPI.java @@ -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 { @@ -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; @@ -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); @@ -75,8 +69,6 @@ public static boolean isReady() { } public void shutdown() { - listeners.clear(); - channels.uninjectAll(); schedulers.shutdown(); if (instance == this) { instance = null; @@ -95,14 +87,6 @@ public Schedulers schedulers() { return schedulers; } - public PacketChannels channels() { - return channels; - } - - public PacketListenerBus listeners() { - return listeners; - } - public Packets packets() { return packets; } diff --git a/api/src/main/java/org/mastersmp/packet/component/Components.java b/api/src/main/java/net/opmasterleo/packet/component/Components.java similarity index 80% rename from api/src/main/java/org/mastersmp/packet/component/Components.java rename to api/src/main/java/net/opmasterleo/packet/component/Components.java index b02219b..3ab2cae 100644 --- a/api/src/main/java/org/mastersmp/packet/component/Components.java +++ b/api/src/main/java/net/opmasterleo/packet/component/Components.java @@ -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 { diff --git a/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerEvent.java b/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerEvent.java new file mode 100644 index 0000000..7ce4d6f --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerEvent.java @@ -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; + + @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; + } +} diff --git a/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerJoinEvent.java b/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerJoinEvent.java new file mode 100644 index 0000000..7b5cdaa --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerJoinEvent.java @@ -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); + } +} diff --git a/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerQuitEvent.java b/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerQuitEvent.java new file mode 100644 index 0000000..4f529b5 --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/event/NmsPlayerQuitEvent.java @@ -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); + } +} diff --git a/api/src/main/java/net/opmasterleo/packet/event/NmsSwingEvent.java b/api/src/main/java/net/opmasterleo/packet/event/NmsSwingEvent.java new file mode 100644 index 0000000..07b7183 --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/event/NmsSwingEvent.java @@ -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; + } +} diff --git a/api/src/main/java/net/opmasterleo/packet/event/NmsUnknownEntityInteractEvent.java b/api/src/main/java/net/opmasterleo/packet/event/NmsUnknownEntityInteractEvent.java new file mode 100644 index 0000000..8728d7b --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/event/NmsUnknownEntityInteractEvent.java @@ -0,0 +1,80 @@ +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; +import net.opmasterleo.packet.nms.packet.InteractAction; + +/** + * NMS-oriented wrap of Paper {@code PlayerUseUnknownEntityEvent} (fake-entity interact) + * without injecting into the Netty pipeline. + */ +public final class NmsUnknownEntityInteractEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Player player; + private final Object playerHandle; + private final int entityId; + private final InteractAction action; + private final Hand hand; + private boolean cancelled; + + @ApiStatus.Internal + public NmsUnknownEntityInteractEvent( + Player player, + Object playerHandle, + int entityId, + InteractAction action, + Hand hand + ) { + super(false); + this.player = player; + this.playerHandle = playerHandle; + this.entityId = entityId; + this.action = action; + this.hand = hand; + } + + public Player getPlayer() { + return player; + } + + public Object getPlayerHandle() { + return playerHandle; + } + + public int getEntityId() { + return entityId; + } + + public InteractAction getAction() { + return action; + } + + 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; + } +} diff --git a/api/src/main/java/net/opmasterleo/packet/event/PacketEvent.java b/api/src/main/java/net/opmasterleo/packet/event/PacketEvent.java new file mode 100644 index 0000000..dec3fc5 --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/event/PacketEvent.java @@ -0,0 +1,79 @@ +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.PacketWrap; + +/** + * Parent event for NMS packet traffic sent through PacketAPI. + * Listen to this to capture every packet event, or to {@link PacketSendEvent} only. + */ +public abstract class PacketEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Player player; + private final Object playerHandle; + private Object packet; + private boolean cancelled; + + @ApiStatus.Internal + protected PacketEvent(Player player, Object packet, Object playerHandle) { + super(false); + this.player = player; + this.packet = packet; + this.playerHandle = playerHandle; + } + + public Player getPlayer() { + return player; + } + + /** + * NMS {@code ServerPlayer} / {@code EntityPlayer}. + */ + public Object getPlayerHandle() { + return playerHandle; + } + + /** + * Raw NMS packet ({@code net.minecraft.network.protocol.Packet}). + */ + public Object getPacket() { + return packet; + } + + public void setPacket(Object packet) { + this.packet = packet; + } + + public PacketWrap wrap() { + return packet == null ? null : PacketWrap.of(packet); + } + + public String getPacketName() { + return packet == null ? "null" : packet.getClass().getSimpleName(); + } + + @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; + } +} diff --git a/api/src/main/java/net/opmasterleo/packet/event/PacketSendEvent.java b/api/src/main/java/net/opmasterleo/packet/event/PacketSendEvent.java new file mode 100644 index 0000000..760ccd1 --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/event/PacketSendEvent.java @@ -0,0 +1,30 @@ +package net.opmasterleo.packet.event; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.ApiStatus; + +/** + * Fired immediately before PacketAPI sends an NMS packet via {@code ServerPlayer.connection.send}. + */ +public final class PacketSendEvent extends PacketEvent { + + @ApiStatus.Internal + public PacketSendEvent(Player player, Object packet, Object playerHandle) { + super(player, packet, playerHandle); + } + + /** + * Dispatches only when listeners are registered — skips plugin-manager work on the hot path. + * + * @return the event after call, or {@code null} when nobody is listening + */ + public static PacketSendEvent callIfListened(Player player, Object packet, Object playerHandle) { + if (PacketEvent.getHandlerList().getRegisteredListeners().length == 0) { + return null; + } + PacketSendEvent event = new PacketSendEvent(player, packet, playerHandle); + Bukkit.getPluginManager().callEvent(event); + return event; + } +} diff --git a/api/src/main/java/org/mastersmp/packet/item/Items.java b/api/src/main/java/net/opmasterleo/packet/item/Items.java similarity index 94% rename from api/src/main/java/org/mastersmp/packet/item/Items.java rename to api/src/main/java/net/opmasterleo/packet/item/Items.java index 21dab05..6146e91 100644 --- a/api/src/main/java/org/mastersmp/packet/item/Items.java +++ b/api/src/main/java/net/opmasterleo/packet/item/Items.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.item; +package net.opmasterleo.packet.item; import java.util.List; import java.util.Map; @@ -10,8 +10,8 @@ import org.bukkit.potion.PotionType; import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.ItemBridge; -import org.mastersmp.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.ItemBridge; +import net.opmasterleo.packet.nms.NmsAdapter; public final class Items { diff --git a/api/src/main/java/org/mastersmp/packet/menu/Menus.java b/api/src/main/java/net/opmasterleo/packet/menu/Menus.java similarity index 90% rename from api/src/main/java/org/mastersmp/packet/menu/Menus.java rename to api/src/main/java/net/opmasterleo/packet/menu/Menus.java index 217b96b..207072a 100644 --- a/api/src/main/java/org/mastersmp/packet/menu/Menus.java +++ b/api/src/main/java/net/opmasterleo/packet/menu/Menus.java @@ -1,10 +1,10 @@ -package org.mastersmp.packet.menu; +package net.opmasterleo.packet.menu; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.mastersmp.packet.nms.MenuBridge; -import org.mastersmp.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.MenuBridge; +import net.opmasterleo.packet.nms.NmsAdapter; public final class Menus { diff --git a/api/src/main/java/org/mastersmp/packet/packet/PacketTypeCache.java b/api/src/main/java/net/opmasterleo/packet/packet/PacketTypeCache.java similarity index 93% rename from api/src/main/java/org/mastersmp/packet/packet/PacketTypeCache.java rename to api/src/main/java/net/opmasterleo/packet/packet/PacketTypeCache.java index c717a11..2d3697a 100644 --- a/api/src/main/java/org/mastersmp/packet/packet/PacketTypeCache.java +++ b/api/src/main/java/net/opmasterleo/packet/packet/PacketTypeCache.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.packet; +package net.opmasterleo.packet.packet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/api/src/main/java/net/opmasterleo/packet/packet/Packets.java b/api/src/main/java/net/opmasterleo/packet/packet/Packets.java new file mode 100644 index 0000000..adc4ae3 --- /dev/null +++ b/api/src/main/java/net/opmasterleo/packet/packet/Packets.java @@ -0,0 +1,168 @@ +package net.opmasterleo.packet.packet; + +import java.util.List; +import java.util.UUID; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +import net.kyori.adventure.text.Component; +import net.opmasterleo.packet.event.PacketSendEvent; +import net.opmasterleo.packet.nms.MetadataBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.PlayerBridge; +import net.opmasterleo.packet.nms.packet.PacketViews; +import net.opmasterleo.packet.nms.packet.PacketWrap; + +/** + * High-level send facade. Constructs NMS packets in the version adapter and writes them through + * {@code ServerPlayer.connection.send} — never Netty. Menu/container/sign packets are not sent + * here (PacketUxUi / SignGUI). + */ +public final class Packets { + + private final PlayerBridge players; + private final PacketBridge packets; + private final MetadataBridge metadata; + private final PacketTypeCache types = new PacketTypeCache(); + + public Packets(NmsAdapter adapter) { + this.players = adapter.players(); + this.packets = adapter.packets(); + this.metadata = adapter.metadata(); + } + + public PacketWrap wrap(Object nmsPacket) { + return PacketWrap.of(nmsPacket); + } + + public String classify(Object nmsPacket) { + if (nmsPacket == null) { + return "Unknown"; + } + return types.getOrCompute(nmsPacket.getClass(), type -> packets.classify(nmsPacket)); + } + + public void send(Player player, Object nmsPacket) { + if (player == null || nmsPacket == null) { + return; + } + Object outgoing = nmsPacket; + PacketSendEvent event = PacketSendEvent.callIfListened(player, nmsPacket, players.handle(player)); + if (event != null) { + if (event.isCancelled()) { + return; + } + outgoing = event.getPacket(); + if (outgoing == null) { + return; + } + } + players.send(player, outgoing); + } + + public void sendAll(Player player, Object... nmsPackets) { + if (nmsPackets == null) { + return; + } + for (Object packet : nmsPackets) { + send(player, packet); + } + } + + public Object handle(Player player) { + return players.handle(player); + } + + public void spawnTextDisplay(Player player, PacketViews.TextDisplaySpec spec) { + Object add = packets.addTextDisplay(spec); + PacketViews.TextDisplayStyle style = spec.style(); + Object data; + try { + data = packets.setEntityData(spec.entityId(), metadata.textDisplayValues(style)); + } catch (RuntimeException ignored) { + send(player, add); + return; + } + try { + send(player, packets.rebuildBundle(List.of(add, data))); + } catch (RuntimeException ignored) { + send(player, add); + send(player, data); + } + } + + public void destroyEntities(Player player, int... entityIds) { + send(player, packets.removeEntities(entityIds)); + } + + public void setEntityData(Player player, int entityId, List metadataEntries) { + send(player, packets.setEntityData(entityId, metadataEntries)); + } + + public void blockEvent(World world, int x, int y, int z, Object blockType, int type, int data) { + Object packet = packets.blockEvent(x, y, z, blockType, type, data); + for (Player player : world.getPlayers()) { + send(player, packet); + } + } + + public void blockUpdate(Player player, int x, int y, int z, Object nmsBlockState) { + send(player, packets.blockUpdate(x, y, z, nmsBlockState)); + } + + public void setHealth(Player player, float health, int food, float saturation) { + send(player, packets.setHealth(health, food, saturation)); + } + + public void setExperience(Player player, float progress, int totalXp, int level) { + send(player, packets.setExperience(progress, totalXp, level)); + } + + public void systemChat(Player player, Component message, boolean overlay) { + send(player, packets.systemChat(message, overlay)); + } + + public void actionBar(Player player, Component message) { + send(player, packets.actionBar(message)); + } + + public void tabList(Player player, Component header, Component footer) { + send(player, packets.tabList(header, footer)); + } + + public void title(Player player, Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { + send(player, packets.titleTimes(fadeIn, stay, fadeOut)); + send(player, packets.subtitleText(subtitle)); + send(player, packets.titleText(title)); + } + + public void clearTitle(Player player, boolean resetTimes) { + send(player, packets.clearTitles(resetTimes)); + } + + public void playerInfoRemove(Player player, List profileIds) { + send(player, packets.playerInfoRemove(profileIds)); + } + + public void playerInfoAdd(Player viewer, Object nmsServerPlayer) { + send(viewer, packets.playerInfoAdd(nmsServerPlayer)); + } + + public void setEquipment(Player player, int entityId, List slots) { + send(player, packets.setEquipment(entityId, slots)); + } + + public void entityVelocity(Player player, int entityId, double vx, double vy, double vz) { + send(player, packets.entityVelocity(entityId, vx, vy, vz)); + } + + public void gameEvent(Player player, int eventId, float value) { + send(player, packets.gameEvent(eventId, value)); + } + + public PacketBridge nms() { + return packets; + } +} diff --git a/api/src/main/java/org/mastersmp/packet/schedule/AdvancedScheduler.java b/api/src/main/java/net/opmasterleo/packet/schedule/AdvancedScheduler.java similarity index 97% rename from api/src/main/java/org/mastersmp/packet/schedule/AdvancedScheduler.java rename to api/src/main/java/net/opmasterleo/packet/schedule/AdvancedScheduler.java index 32caf8e..d7ecce1 100644 --- a/api/src/main/java/org/mastersmp/packet/schedule/AdvancedScheduler.java +++ b/api/src/main/java/net/opmasterleo/packet/schedule/AdvancedScheduler.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.schedule; +package net.opmasterleo.packet.schedule; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -130,7 +130,7 @@ public TaskHandle runAsyncLater(Runnable task, long delay, TimeUnit unit) { return workers.schedule(task, delay, unit); } - public TaskHandle runOffNetty(Entity entity, Runnable task) { + public TaskHandle runOnEntityThread(Entity entity, Runnable task) { if (Bukkit.isPrimaryThread() || isOwnedByCurrentRegion(entity)) { task.run(); return TaskHandle.noop(); @@ -138,7 +138,7 @@ public TaskHandle runOffNetty(Entity entity, Runnable task) { return runEntity(entity, task); } - public TaskHandle runOffNetty(Location location, Runnable task) { + public TaskHandle runOnRegionThread(Location location, Runnable task) { if (Bukkit.isPrimaryThread() || isOwnedByCurrentRegion(location)) { task.run(); return TaskHandle.noop(); diff --git a/api/src/main/java/org/mastersmp/packet/schedule/AsyncWorkerPool.java b/api/src/main/java/net/opmasterleo/packet/schedule/AsyncWorkerPool.java similarity index 98% rename from api/src/main/java/org/mastersmp/packet/schedule/AsyncWorkerPool.java rename to api/src/main/java/net/opmasterleo/packet/schedule/AsyncWorkerPool.java index 6405f7f..5c1b077 100644 --- a/api/src/main/java/org/mastersmp/packet/schedule/AsyncWorkerPool.java +++ b/api/src/main/java/net/opmasterleo/packet/schedule/AsyncWorkerPool.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.schedule; +package net.opmasterleo.packet.schedule; import java.util.Objects; import java.util.concurrent.CompletableFuture; diff --git a/api/src/main/java/org/mastersmp/packet/schedule/DirectScheduler.java b/api/src/main/java/net/opmasterleo/packet/schedule/DirectScheduler.java similarity index 98% rename from api/src/main/java/org/mastersmp/packet/schedule/DirectScheduler.java rename to api/src/main/java/net/opmasterleo/packet/schedule/DirectScheduler.java index cbd9276..0741ee6 100644 --- a/api/src/main/java/org/mastersmp/packet/schedule/DirectScheduler.java +++ b/api/src/main/java/net/opmasterleo/packet/schedule/DirectScheduler.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.schedule; +package net.opmasterleo.packet.schedule; import java.util.Objects; diff --git a/api/src/main/java/org/mastersmp/packet/schedule/FastScheduler.java b/api/src/main/java/net/opmasterleo/packet/schedule/FastScheduler.java similarity index 82% rename from api/src/main/java/org/mastersmp/packet/schedule/FastScheduler.java rename to api/src/main/java/net/opmasterleo/packet/schedule/FastScheduler.java index bb8e4a9..cf170fd 100644 --- a/api/src/main/java/org/mastersmp/packet/schedule/FastScheduler.java +++ b/api/src/main/java/net/opmasterleo/packet/schedule/FastScheduler.java @@ -1,17 +1,15 @@ -package org.mastersmp.packet.schedule; +package net.opmasterleo.packet.schedule; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import org.bukkit.entity.Entity; import org.bukkit.plugin.Plugin; -import io.netty.channel.Channel; -import org.mastersmp.packet.channel.ChannelOps; - public final class FastScheduler { private final AdvancedScheduler advanced; @@ -40,16 +38,12 @@ public void coalesceEntity(Entity entity, Runnable task) { } } - public void coalesceEventLoop(Channel channel, Runnable task) { - Objects.requireNonNull(channel, "channel"); - Objects.requireNonNull(task, "task"); - ChannelOps.runInEventLoop(channel, task); - } - public void shutdown() { globalFlushHandle.cancel(); globalQueue.clear(); globalFlushScheduled.set(false); + ENTITY_QUEUES.clear(); + ENTITY_FLAGS.clear(); } private void flushGlobal() { @@ -103,8 +97,8 @@ private AtomicBoolean entityFlushFlags(Entity entity) { return ENTITY_FLAGS.computeIfAbsent(key, k -> new AtomicBoolean()); } - private static final java.util.concurrent.ConcurrentHashMap> ENTITY_QUEUES = - new java.util.concurrent.ConcurrentHashMap<>(); - private static final java.util.concurrent.ConcurrentHashMap ENTITY_FLAGS = - new java.util.concurrent.ConcurrentHashMap<>(); + private static final ConcurrentHashMap> ENTITY_QUEUES = + new ConcurrentHashMap<>(); + private static final ConcurrentHashMap ENTITY_FLAGS = + new ConcurrentHashMap<>(); } diff --git a/api/src/main/java/org/mastersmp/packet/schedule/PlatformDetect.java b/api/src/main/java/net/opmasterleo/packet/schedule/PlatformDetect.java similarity index 97% rename from api/src/main/java/org/mastersmp/packet/schedule/PlatformDetect.java rename to api/src/main/java/net/opmasterleo/packet/schedule/PlatformDetect.java index 1204c57..78dd8aa 100644 --- a/api/src/main/java/org/mastersmp/packet/schedule/PlatformDetect.java +++ b/api/src/main/java/net/opmasterleo/packet/schedule/PlatformDetect.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.schedule; +package net.opmasterleo.packet.schedule; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; diff --git a/api/src/main/java/org/mastersmp/packet/schedule/Schedulers.java b/api/src/main/java/net/opmasterleo/packet/schedule/Schedulers.java similarity index 97% rename from api/src/main/java/org/mastersmp/packet/schedule/Schedulers.java rename to api/src/main/java/net/opmasterleo/packet/schedule/Schedulers.java index 1a3166a..55c8b9c 100644 --- a/api/src/main/java/org/mastersmp/packet/schedule/Schedulers.java +++ b/api/src/main/java/net/opmasterleo/packet/schedule/Schedulers.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.schedule; +package net.opmasterleo.packet.schedule; import java.util.Objects; diff --git a/api/src/main/java/org/mastersmp/packet/schedule/TaskHandle.java b/api/src/main/java/net/opmasterleo/packet/schedule/TaskHandle.java similarity index 98% rename from api/src/main/java/org/mastersmp/packet/schedule/TaskHandle.java rename to api/src/main/java/net/opmasterleo/packet/schedule/TaskHandle.java index f8b759b..b537f08 100644 --- a/api/src/main/java/org/mastersmp/packet/schedule/TaskHandle.java +++ b/api/src/main/java/net/opmasterleo/packet/schedule/TaskHandle.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.schedule; +package net.opmasterleo.packet.schedule; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/api/src/main/java/org/mastersmp/packet/world/Chunks.java b/api/src/main/java/net/opmasterleo/packet/world/Chunks.java similarity index 71% rename from api/src/main/java/org/mastersmp/packet/world/Chunks.java rename to api/src/main/java/net/opmasterleo/packet/world/Chunks.java index 1116720..86c83c6 100644 --- a/api/src/main/java/org/mastersmp/packet/world/Chunks.java +++ b/api/src/main/java/net/opmasterleo/packet/world/Chunks.java @@ -1,9 +1,9 @@ -package org.mastersmp.packet.world; +package net.opmasterleo.packet.world; import org.bukkit.Chunk; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.WorldBridge; public final class Chunks { diff --git a/api/src/main/java/org/mastersmp/packet/world/Dimensions.java b/api/src/main/java/net/opmasterleo/packet/world/Dimensions.java similarity index 74% rename from api/src/main/java/org/mastersmp/packet/world/Dimensions.java rename to api/src/main/java/net/opmasterleo/packet/world/Dimensions.java index 884d6a4..42df13a 100644 --- a/api/src/main/java/org/mastersmp/packet/world/Dimensions.java +++ b/api/src/main/java/net/opmasterleo/packet/world/Dimensions.java @@ -1,9 +1,9 @@ -package org.mastersmp.packet.world; +package net.opmasterleo.packet.world; import org.bukkit.World; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.WorldBridge; public final class Dimensions { diff --git a/api/src/main/java/org/mastersmp/packet/world/Entities.java b/api/src/main/java/net/opmasterleo/packet/world/Entities.java similarity index 69% rename from api/src/main/java/org/mastersmp/packet/world/Entities.java rename to api/src/main/java/net/opmasterleo/packet/world/Entities.java index 824c623..24ba0f3 100644 --- a/api/src/main/java/org/mastersmp/packet/world/Entities.java +++ b/api/src/main/java/net/opmasterleo/packet/world/Entities.java @@ -1,9 +1,9 @@ -package org.mastersmp.packet.world; +package net.opmasterleo.packet.world; import org.bukkit.entity.Entity; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.WorldBridge; public final class Entities { diff --git a/api/src/main/java/org/mastersmp/packet/world/Levels.java b/api/src/main/java/net/opmasterleo/packet/world/Levels.java similarity index 72% rename from api/src/main/java/org/mastersmp/packet/world/Levels.java rename to api/src/main/java/net/opmasterleo/packet/world/Levels.java index a401ca5..46b96d6 100644 --- a/api/src/main/java/org/mastersmp/packet/world/Levels.java +++ b/api/src/main/java/net/opmasterleo/packet/world/Levels.java @@ -1,9 +1,9 @@ -package org.mastersmp.packet.world; +package net.opmasterleo.packet.world; import org.bukkit.World; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.WorldBridge; public final class Levels { diff --git a/api/src/main/java/org/mastersmp/packet/world/Worlds.java b/api/src/main/java/net/opmasterleo/packet/world/Worlds.java similarity index 85% rename from api/src/main/java/org/mastersmp/packet/world/Worlds.java rename to api/src/main/java/net/opmasterleo/packet/world/Worlds.java index 95daad1..7174f37 100644 --- a/api/src/main/java/org/mastersmp/packet/world/Worlds.java +++ b/api/src/main/java/net/opmasterleo/packet/world/Worlds.java @@ -1,11 +1,11 @@ -package org.mastersmp.packet.world; +package net.opmasterleo.packet.world; import java.util.stream.Stream; import org.bukkit.World; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.WorldBridge; public final class Worlds { diff --git a/api/src/main/java/org/mastersmp/packet/channel/ChannelOps.java b/api/src/main/java/org/mastersmp/packet/channel/ChannelOps.java deleted file mode 100644 index 5c5d100..0000000 --- a/api/src/main/java/org/mastersmp/packet/channel/ChannelOps.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.mastersmp.packet.channel; - -import java.util.ArrayList; -import java.util.List; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.util.AttributeKey; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; - -public final class ChannelOps { - - private ChannelOps() { - } - - public static ChannelHandler get(Channel channel, String name) { - if (channel == null || name == null) { - return null; - } - try { - return channel.pipeline().get(name); - } catch (Throwable ignored) { - return null; - } - } - - public static void remove(Channel channel, String name) { - if (channel == null || name == null) { - return; - } - try { - if (channel.pipeline().get(name) != null) { - channel.pipeline().remove(name); - } - } catch (Throwable ignored) { - } - } - - public static void remove(Channel channel, Class type) { - removeAll(channel, type); - } - - public static void removeAll(Channel channel, Class type) { - if (channel == null || type == null) { - return; - } - try { - List toRemove = new ArrayList<>(); - for (String name : channel.pipeline().names()) { - ChannelHandler handler = channel.pipeline().get(name); - if (handler != null && type.isInstance(handler)) { - toRemove.add(name); - } - } - for (String name : toRemove) { - channel.pipeline().remove(name); - } - } catch (Throwable ignored) { - } - } - - public static List pipelineNames(Channel channel) { - if (channel == null) { - return List.of(); - } - try { - return new ArrayList<>(channel.pipeline().names()); - } catch (Throwable ignored) { - return List.of(); - } - } - - public static void runInEventLoop(Channel channel, Runnable task) { - if (channel == null || task == null) { - return; - } - if (channel.eventLoop().inEventLoop()) { - task.run(); - return; - } - channel.eventLoop().execute(task); - } - - public static void runInEventLoop(Channel channel, Runnable task, GenericFutureListener> listener) { - if (channel == null || task == null) { - return; - } - if (channel.eventLoop().inEventLoop()) { - task.run(); - return; - } - channel.eventLoop().submit(task).addListener(listener); - } - - public static void runCoalesced(Channel channel, AttributeKey gate, Runnable task) { - if (channel == null || gate == null || task == null) { - return; - } - runInEventLoop(channel, () -> { - if (Boolean.TRUE.equals(channel.attr(gate).get())) { - return; - } - channel.attr(gate).set(true); - channel.eventLoop().execute(() -> { - try { - task.run(); - } finally { - channel.attr(gate).set(false); - } - }); - }); - } -} diff --git a/api/src/main/java/org/mastersmp/packet/channel/OutboundPacketResult.java b/api/src/main/java/org/mastersmp/packet/channel/OutboundPacketResult.java deleted file mode 100644 index cfea698..0000000 --- a/api/src/main/java/org/mastersmp/packet/channel/OutboundPacketResult.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.mastersmp.packet.channel; - -import java.util.Objects; - -public final class OutboundPacketResult { - - private static final OutboundPacketResult KEEP = new OutboundPacketResult(Kind.KEEP, null); - private static final OutboundPacketResult DROP = new OutboundPacketResult(Kind.DROP, null); - - private final Kind kind; - private final Object replacement; - - private OutboundPacketResult(Kind kind, Object replacement) { - this.kind = kind; - this.replacement = replacement; - } - - public static OutboundPacketResult keep() { - return KEEP; - } - - public static OutboundPacketResult drop() { - return DROP; - } - - public static OutboundPacketResult replace(Object packet) { - return new OutboundPacketResult(Kind.REPLACE, Objects.requireNonNull(packet, "packet")); - } - - public Kind kind() { - return kind; - } - - public Object replacement() { - return replacement; - } - - public enum Kind { - KEEP, - DROP, - REPLACE - } -} diff --git a/api/src/main/java/org/mastersmp/packet/channel/PacketChannels.java b/api/src/main/java/org/mastersmp/packet/channel/PacketChannels.java deleted file mode 100644 index de1d049..0000000 --- a/api/src/main/java/org/mastersmp/packet/channel/PacketChannels.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.mastersmp.packet.channel; - -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -import org.bukkit.entity.Player; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import org.mastersmp.packet.nms.ConnectionBridge; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.schedule.Schedulers; - -public final class PacketChannels { - - private static final String[] DEFAULT_OUTBOUND_BEFORE = { - "packet_handler", - "encoder", - "outbound_config" - }; - - private static final String[] DEFAULT_INBOUND_BEFORE = { - "packet_handler", - "inbound_config" - }; - - private final ConnectionBridge connection; - private final Schedulers schedulers; - private final Map knownChannels = new ConcurrentHashMap<>(); - - public PacketChannels(NmsAdapter adapter, Schedulers schedulers) { - this.connection = adapter.connection(); - this.schedulers = Objects.requireNonNull(schedulers, "schedulers"); - } - - public Channel channel(Player player) { - if (player == null) { - return null; - } - Channel channel = connection.channel(player); - if (channel != null) { - knownChannels.put(player.getUniqueId(), channel); - } - return channel; - } - - public boolean isActive(Player player) { - Channel channel = channel(player); - return channel != null && channel.isActive(); - } - - public void injectOutbound(Player player, String name, ChannelHandler handler) { - inject(player, name, handler, true); - } - - public void injectInbound(Player player, String name, ChannelHandler handler) { - inject(player, name, handler, false); - } - - public void uninject(Player player, String name) { - if (player == null || name == null) { - return; - } - Channel channel = channel(player); - if (channel == null) { - return; - } - ChannelOps.runInEventLoop(channel, () -> ChannelOps.remove(channel, name)); - } - - public void uninject(Player player, Class handlerClass) { - if (player == null || handlerClass == null) { - return; - } - Channel channel = channel(player); - if (channel == null) { - return; - } - ChannelOps.runInEventLoop(channel, () -> ChannelOps.remove(channel, handlerClass)); - } - - public void runOnEventLoop(Channel channel, Runnable task) { - ChannelOps.runInEventLoop(channel, task); - } - - public void uninjectAll() { - for (Channel channel : knownChannels.values()) { - if (channel == null) { - continue; - } - ChannelOps.runInEventLoop(channel, () -> { - for (String name : ChannelOps.pipelineNames(channel)) { - if (name.startsWith("packetapi_")) { - ChannelOps.remove(channel, name); - } - } - }); - } - knownChannels.clear(); - } - - private void inject(Player player, String name, ChannelHandler handler, boolean outbound) { - Objects.requireNonNull(name, "name"); - Objects.requireNonNull(handler, "handler"); - if (player == null) { - return; - } - Runnable install = () -> { - Channel channel = channel(player); - if (channel == null) { - return; - } - ChannelOps.runInEventLoop(channel, () -> installNow(channel, name, handler, outbound)); - }; - if (schedulers.isOwnedByCurrentRegion(player)) { - install.run(); - } else { - schedulers.advanced().runEntity(player, install); - } - } - - private void installNow(Channel channel, String name, ChannelHandler handler, boolean outbound) { - ChannelOps.remove(channel, name); - String[] anchors = outbound ? DEFAULT_OUTBOUND_BEFORE : DEFAULT_INBOUND_BEFORE; - for (String anchor : anchors) { - if (ChannelOps.get(channel, anchor) != null) { - channel.pipeline().addBefore(anchor, name, handler); - return; - } - } - for (String anchor : connection.injectBeforeNames()) { - if (ChannelOps.get(channel, anchor) != null) { - channel.pipeline().addBefore(anchor, name, handler); - return; - } - } - if (ChannelOps.get(channel, "decoder") != null) { - channel.pipeline().addAfter("decoder", name, handler); - } - } -} diff --git a/api/src/main/java/org/mastersmp/packet/channel/PacketDirection.java b/api/src/main/java/org/mastersmp/packet/channel/PacketDirection.java deleted file mode 100644 index 803e579..0000000 --- a/api/src/main/java/org/mastersmp/packet/channel/PacketDirection.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.mastersmp.packet.channel; - -public enum PacketDirection { - CLIENTBOUND, - SERVERBOUND -} diff --git a/api/src/main/java/org/mastersmp/packet/channel/PacketFilter.java b/api/src/main/java/org/mastersmp/packet/channel/PacketFilter.java deleted file mode 100644 index 50b5a69..0000000 --- a/api/src/main/java/org/mastersmp/packet/channel/PacketFilter.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mastersmp.packet.channel; - -import org.bukkit.entity.Player; - -@FunctionalInterface -public interface PacketFilter { - - OutboundPacketResult filter(Player viewer, PacketView packet); -} diff --git a/api/src/main/java/org/mastersmp/packet/channel/PacketListenerBus.java b/api/src/main/java/org/mastersmp/packet/channel/PacketListenerBus.java deleted file mode 100644 index 055f71d..0000000 --- a/api/src/main/java/org/mastersmp/packet/channel/PacketListenerBus.java +++ /dev/null @@ -1,222 +0,0 @@ -package org.mastersmp.packet.channel; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.bukkit.entity.Player; - -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.packet.PacketTypeCache; - -public final class PacketListenerBus { - - private final PacketChannels channels; - private final NmsAdapter adapter; - private final PacketTypeCache typeCache = new PacketTypeCache(); - private final List globalOutbound = new CopyOnWriteArrayList<>(); - private final List globalInbound = new CopyOnWriteArrayList<>(); - private final Map> playerOutbound = new ConcurrentHashMap<>(); - private final Map> playerInbound = new ConcurrentHashMap<>(); - private final Map injected = new ConcurrentHashMap<>(); - - public PacketListenerBus(PacketChannels channels, NmsAdapter adapter) { - this.channels = channels; - this.adapter = adapter; - } - - public void addOutbound(PacketFilter filter) { - globalOutbound.add(Objects.requireNonNull(filter, "filter")); - } - - public void addOutbound(Player player, PacketFilter filter) { - playerOutbound - .computeIfAbsent(player.getUniqueId(), id -> new CopyOnWriteArrayList<>()) - .add(Objects.requireNonNull(filter, "filter")); - ensureInjected(player); - } - - public void addInbound(InboundListener listener) { - globalInbound.add(Objects.requireNonNull(listener, "listener")); - } - - public void addInbound(Player player, InboundListener listener) { - playerInbound - .computeIfAbsent(player.getUniqueId(), id -> new CopyOnWriteArrayList<>()) - .add(Objects.requireNonNull(listener, "listener")); - ensureInjected(player); - } - - public void removeOutbound(PacketFilter filter) { - globalOutbound.remove(filter); - for (List list : playerOutbound.values()) { - list.remove(filter); - } - } - - public void removeInbound(InboundListener listener) { - globalInbound.remove(listener); - for (List list : playerInbound.values()) { - list.remove(listener); - } - } - - public void clear(Player player) { - if (player == null) { - return; - } - UUID id = player.getUniqueId(); - playerOutbound.remove(id); - playerInbound.remove(id); - String name = injected.remove(id); - if (name != null) { - channels.uninject(player, name); - } - } - - public void clear() { - globalOutbound.clear(); - globalInbound.clear(); - playerOutbound.clear(); - playerInbound.clear(); - injected.clear(); - typeCache.clear(); - } - - public void ensureInjected(Player player) { - if (player == null) { - return; - } - String name = "packetapi_filter_" + player.getUniqueId(); - channels.injectOutbound(player, name, new FilterHandler(player)); - injected.put(player.getUniqueId(), name); - } - - private OutboundPacketResult applyOutbound(Player player, PacketView view) { - OutboundPacketResult result = OutboundPacketResult.keep(); - PacketView current = view; - for (PacketFilter filter : globalOutbound) { - result = filter.filter(player, current); - if (result.kind() == OutboundPacketResult.Kind.DROP) { - return result; - } - if (result.kind() == OutboundPacketResult.Kind.REPLACE) { - current = current.withHandle(result.replacement()); - result = OutboundPacketResult.keep(); - } - } - List personal = playerOutbound.get(player.getUniqueId()); - if (personal != null) { - for (PacketFilter filter : personal) { - result = filter.filter(player, current); - if (result.kind() == OutboundPacketResult.Kind.DROP) { - return result; - } - if (result.kind() == OutboundPacketResult.Kind.REPLACE) { - current = current.withHandle(result.replacement()); - result = OutboundPacketResult.keep(); - } - } - } - if (current.handle() != view.handle()) { - return OutboundPacketResult.replace(current.handle()); - } - return OutboundPacketResult.keep(); - } - - private boolean applyInbound(Player player, PacketView view) { - for (InboundListener listener : globalInbound) { - if (!listener.onInbound(player, view)) { - return false; - } - } - List personal = playerInbound.get(player.getUniqueId()); - if (personal != null) { - for (InboundListener listener : personal) { - if (!listener.onInbound(player, view)) { - return false; - } - } - } - return true; - } - - private String classify(Object packet) { - return typeCache.getOrCompute(packet.getClass(), type -> adapter.packets().classify(packet)); - } - - @FunctionalInterface - public interface InboundListener { - boolean onInbound(Player player, PacketView packet); - } - - private final class FilterHandler extends ChannelDuplexHandler { - - private final Player player; - - private FilterHandler(Player player) { - this.player = player; - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - if (msg == null) { - super.write(ctx, msg, promise); - return; - } - String name = classify(msg); - if ("Bundle".equals(name) || name.endsWith("BundlePacket")) { - List parts = adapter.packets().unwrapBundle(msg); - if (parts != null && !parts.isEmpty()) { - List rebuilt = new ArrayList<>(parts.size()); - for (Object part : parts) { - PacketView view = new PacketView(part, classify(part), PacketDirection.CLIENTBOUND); - OutboundPacketResult result = applyOutbound(player, view); - switch (result.kind()) { - case DROP -> { - } - case REPLACE -> rebuilt.add(result.replacement()); - case KEEP -> rebuilt.add(part); - } - } - if (rebuilt.isEmpty()) { - promise.setSuccess(); - return; - } - msg = adapter.packets().rebuildBundle(rebuilt); - } - } else { - PacketView view = new PacketView(msg, name, PacketDirection.CLIENTBOUND); - OutboundPacketResult result = applyOutbound(player, view); - switch (result.kind()) { - case DROP -> { - promise.setSuccess(); - return; - } - case REPLACE -> msg = result.replacement(); - case KEEP -> { - } - } - } - super.write(ctx, msg, promise); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg != null) { - PacketView view = new PacketView(msg, classify(msg), PacketDirection.SERVERBOUND); - if (!applyInbound(player, view)) { - return; - } - } - super.channelRead(ctx, msg); - } - } -} diff --git a/api/src/main/java/org/mastersmp/packet/channel/PacketView.java b/api/src/main/java/org/mastersmp/packet/channel/PacketView.java deleted file mode 100644 index a741b2b..0000000 --- a/api/src/main/java/org/mastersmp/packet/channel/PacketView.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.mastersmp.packet.channel; - -import java.util.Objects; - -public final class PacketView { - - private final Object handle; - private final String name; - private final PacketDirection direction; - - public PacketView(Object handle, String name, PacketDirection direction) { - this.handle = Objects.requireNonNull(handle, "handle"); - this.name = Objects.requireNonNull(name, "name"); - this.direction = Objects.requireNonNull(direction, "direction"); - } - - public Object handle() { - return handle; - } - - public String name() { - return name; - } - - public PacketDirection direction() { - return direction; - } - - public PacketView withHandle(Object replacement) { - return new PacketView(replacement, name, direction); - } -} diff --git a/api/src/main/java/org/mastersmp/packet/event/NMSPacketEvent.java b/api/src/main/java/org/mastersmp/packet/event/NMSPacketEvent.java deleted file mode 100644 index 92dc207..0000000 --- a/api/src/main/java/org/mastersmp/packet/event/NMSPacketEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.mastersmp.packet.event; - -/** - * Base class for NMS-level packet events. - */ -public abstract class NMSPacketEvent { - - private final Object nmsPacket; - private final Object playerHandle; - private boolean cancelled; - - protected NMSPacketEvent(Object nmsPacket, Object playerHandle) { - this.nmsPacket = nmsPacket; - this.playerHandle = playerHandle; - this.cancelled = false; - } - - /** - * Gets the raw NMS packet object. - * @return The NMS packet (net.minecraft.network.protocol.Packet) - */ - public Object getNmsPacket() { - return nmsPacket; - } - - /** - * Gets the player's NMS handle (ServerPlayer). - * @return The ServerPlayer instance - */ - public Object getPlayerHandle() { - return playerHandle; - } - - /** - * Gets the packet class name for identification. - * @return The simple class name of the packet - */ - public String getPacketName() { - return nmsPacket != null ? nmsPacket.getClass().getSimpleName() : "null"; - } - - /** - * Checks if the packet send should be cancelled. - * @return true if cancelled - */ - public boolean isCancelled() { - return cancelled; - } - - /** - * Sets whether to cancel the packet send. - * @param cancelled true to cancel - */ - public void setCancelled(boolean cancelled) { - this.cancelled = cancelled; - } -} diff --git a/api/src/main/java/org/mastersmp/packet/event/NMSPacketReceiveEvent.java b/api/src/main/java/org/mastersmp/packet/event/NMSPacketReceiveEvent.java deleted file mode 100644 index b6bbaee..0000000 --- a/api/src/main/java/org/mastersmp/packet/event/NMSPacketReceiveEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.mastersmp.packet.event; - -/** - * Fired when an NMS packet is received from a player. - */ -public class NMSPacketReceiveEvent extends NMSPacketEvent { - - public NMSPacketReceiveEvent(Object nmsPacket, Object playerHandle) { - super(nmsPacket, playerHandle); - } - - /** - * Gets the packet type by stripping common prefixes. - * @return Clean packet type name - */ - public String getPacketType() { - String name = getPacketName(); - if (name.startsWith("Clientbound")) { - return name.substring("Clientbound".length()); - } - if (name.startsWith("Serverbound")) { - return name.substring("Serverbound".length()); - } - if (name.startsWith("PacketPlayOut")) { - return name.substring("PacketPlayOut".length()); - } - if (name.startsWith("PacketPlayIn")) { - return name.substring("PacketPlayIn".length()); - } - return name; - } -} diff --git a/api/src/main/java/org/mastersmp/packet/event/NMSPacketSendEvent.java b/api/src/main/java/org/mastersmp/packet/event/NMSPacketSendEvent.java deleted file mode 100644 index a132066..0000000 --- a/api/src/main/java/org/mastersmp/packet/event/NMSPacketSendEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.mastersmp.packet.event; - -/** - * Fired when an NMS packet is about to be sent to a player. - */ -public class NMSPacketSendEvent extends NMSPacketEvent { - - public NMSPacketSendEvent(Object nmsPacket, Object playerHandle) { - super(nmsPacket, playerHandle); - } - - /** - * Gets the packet type by stripping common prefixes. - * @return Clean packet type name - */ - public String getPacketType() { - String name = getPacketName(); - if (name.startsWith("Clientbound")) { - return name.substring("Clientbound".length()); - } - if (name.startsWith("Serverbound")) { - return name.substring("Serverbound".length()); - } - if (name.startsWith("PacketPlayOut")) { - return name.substring("PacketPlayOut".length()); - } - if (name.startsWith("PacketPlayIn")) { - return name.substring("PacketPlayIn".length()); - } - return name; - } -} diff --git a/api/src/main/java/org/mastersmp/packet/packet/Packets.java b/api/src/main/java/org/mastersmp/packet/packet/Packets.java deleted file mode 100644 index 8c30c2c..0000000 --- a/api/src/main/java/org/mastersmp/packet/packet/Packets.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.mastersmp.packet.packet; - -import java.util.List; - -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.PacketBridge; -import org.mastersmp.packet.nms.PlayerBridge; - -public final class Packets { - - private final PlayerBridge players; - private final PacketBridge packets; - - public Packets(NmsAdapter adapter) { - this.players = adapter.players(); - this.packets = adapter.packets(); - } - - public void send(Player player, Object nmsPacket) { - players.send(player, nmsPacket); - } - - public void spawnTextDisplay( - Player player, - int entityId, - double x, - double y, - double z, - Component text, - int lineWidth, - int backgroundColor, - byte textOpacity, - boolean seeThrough - ) { - Object add = packets.createAddTextDisplay( - entityId, x, y, z, text, lineWidth, backgroundColor, textOpacity, seeThrough - ); - players.send(player, add); - } - - public void destroyEntities(Player player, int... entityIds) { - players.send(player, packets.createRemoveEntities(entityIds)); - } - - public void setEntityData(Player player, int entityId, List metadataEntries) { - players.send(player, packets.createSetEntityData(entityId, metadataEntries)); - } - - public void blockEvent(World world, int x, int y, int z, Object blockType, int type, int data) { - Object packet = packets.createBlockEvent(world, x, y, z, blockType, type, data); - for (Player player : world.getPlayers()) { - players.send(player, packet); - } - } - - public void sendContainerSetSlot(Player player, int containerId, int stateId, int slot, ItemStack item) { - players.send(player, packets.createContainerSetSlot(containerId, stateId, slot, item)); - } -} diff --git a/build.gradle.kts b/build.gradle.kts index bc3b31c..e651376 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { val pluginVersion: String by project allprojects { - group = "org.mastersmp.packet" + group = "net.opmasterleo.packet" version = pluginVersion repositories { @@ -47,7 +47,7 @@ dependencies { nmsBuckets.forEach { bucket -> implementation(project(":nms:$bucket")) } - compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT") + compileOnly("io.papermc.paper:paper-api:${property("paperApiVersion")}") } java { @@ -73,7 +73,7 @@ tasks.shadowJar { ) mergeServiceFiles() manifest { - attributes["Automatic-Module-Name"] = "org.mastersmp.packet" + attributes["Automatic-Module-Name"] = "net.opmasterleo.packet" attributes["Implementation-Title"] = "PacketAPI" attributes["Implementation-Version"] = project.version attributes["paperweight-mappings-namespace"] = "mojang" @@ -182,6 +182,13 @@ tasks.named("publishApiPublicationToReposiliteSnapshotsRepository").configure { onlyIf { publishingSnapshot } } +tasks.named("publishAllPublicationsToReposiliteReleasesRepository").configure { + onlyIf { !publishingSnapshot } +} +tasks.named("publishAllPublicationsToReposiliteSnapshotsRepository").configure { + onlyIf { publishingSnapshot } +} + tasks.named("publish").configure { group = "publishing" description = "Publish fat jar to Reposilite releases" diff --git a/gradle.properties b/gradle.properties index b105278..ed20e59 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,5 @@ org.gradle.caching=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4g -Xms512m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -Dfile.encoding=UTF-8 -pluginVersion=1.0.0 +pluginVersion=1.0.1 +paperApiVersion=1.21.4-R0.1-SNAPSHOT diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 diff --git a/nms-api/build.gradle.kts b/nms-api/build.gradle.kts index e33e41f..f6ef358 100644 --- a/nms-api/build.gradle.kts +++ b/nms-api/build.gradle.kts @@ -10,10 +10,16 @@ java { } dependencies { - compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT") - compileOnly("io.netty:netty-transport:4.1.115.Final") + 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") +} + +tasks.test { + useJUnitPlatform() } tasks.compileJava { diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/AdapterLoader.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/AdapterLoader.java similarity index 99% rename from nms-api/src/main/java/org/mastersmp/packet/nms/AdapterLoader.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/AdapterLoader.java index dfbfcb2..d8b338a 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/AdapterLoader.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/AdapterLoader.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; import java.util.Collections; import java.util.HashMap; diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/ComponentBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/ComponentBridge.java similarity index 86% rename from nms-api/src/main/java/org/mastersmp/packet/nms/ComponentBridge.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/ComponentBridge.java index adba70c..04c17f2 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/ComponentBridge.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/ComponentBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; import net.kyori.adventure.text.Component; diff --git a/nms-api/src/main/java/net/opmasterleo/packet/nms/ConnectionBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/ConnectionBridge.java new file mode 100644 index 0000000..cf67003 --- /dev/null +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/ConnectionBridge.java @@ -0,0 +1,24 @@ +package net.opmasterleo.packet.nms; + +import org.bukkit.entity.Player; + +/** + * Direct NMS connection access ({@code ServerGamePacketListenerImpl} / {@code PlayerConnection}). + * Does not expose Netty; packet I/O goes through {@link PlayerBridge#send}. + */ +public interface ConnectionBridge { + + /** + * NMS {@code Connection} / {@code NetworkManager}. + */ + Object connection(Player player); + + /** + * NMS {@code ServerGamePacketListenerImpl} / {@code PlayerConnection}. + */ + Object listener(Player player); + + int latency(Player player); + + boolean accepting(Player player); +} diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/ItemBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/ItemBridge.java similarity index 98% rename from nms-api/src/main/java/org/mastersmp/packet/nms/ItemBridge.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/ItemBridge.java index 3b64e40..b3136e4 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/ItemBridge.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/ItemBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; import java.util.List; import java.util.Map; diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/MenuBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/MenuBridge.java similarity index 98% rename from nms-api/src/main/java/org/mastersmp/packet/nms/MenuBridge.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/MenuBridge.java index 3c7584e..22340fe 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/MenuBridge.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/MenuBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/MetadataBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/MetadataBridge.java similarity index 56% rename from nms-api/src/main/java/org/mastersmp/packet/nms/MetadataBridge.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/MetadataBridge.java index c95ad6e..cff3ab7 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/MetadataBridge.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/MetadataBridge.java @@ -1,8 +1,9 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; import java.util.List; import net.kyori.adventure.text.Component; +import net.opmasterleo.packet.nms.packet.PacketViews; public interface MetadataBridge { @@ -12,13 +13,17 @@ public interface MetadataBridge { Object dataValue(int id, Object value); - List textDisplayValues( + List textDisplayValues(PacketViews.TextDisplayStyle style); + + default List textDisplayValues( Component text, int lineWidth, int backgroundColor, byte textOpacity, boolean seeThrough - ); + ) { + return textDisplayValues(new PacketViews.TextDisplayStyle(text, lineWidth, backgroundColor, textOpacity, seeThrough)); + } int nextEntityId(); } diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/MetadataIds.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/MetadataIds.java similarity index 86% rename from nms-api/src/main/java/org/mastersmp/packet/nms/MetadataIds.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/MetadataIds.java index 4acd71e..c8fb6e1 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/MetadataIds.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/MetadataIds.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; public final class MetadataIds { diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/NmsAdapter.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/NmsAdapter.java similarity index 85% rename from nms-api/src/main/java/org/mastersmp/packet/nms/NmsAdapter.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/NmsAdapter.java index 319c4d2..72060ac 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/NmsAdapter.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/NmsAdapter.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; public interface NmsAdapter { @@ -18,8 +18,6 @@ public interface NmsAdapter { ComponentBridge components(); - PacketWrapper wrapper(); - default MetadataBridge metadata() { return UnsupportedMetadata.INSTANCE; } @@ -47,13 +45,7 @@ public Object dataValue(int id, Object value) { } @Override - public java.util.List textDisplayValues( - net.kyori.adventure.text.Component text, - int lineWidth, - int backgroundColor, - byte textOpacity, - boolean seeThrough - ) { + public java.util.List textDisplayValues(net.opmasterleo.packet.nms.packet.PacketViews.TextDisplayStyle style) { throw new UnsupportedOperationException("metadata"); } diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/NmsUnsupportedException.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/NmsUnsupportedException.java similarity index 88% rename from nms-api/src/main/java/org/mastersmp/packet/nms/NmsUnsupportedException.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/NmsUnsupportedException.java index 2049eb7..206f217 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/NmsUnsupportedException.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/NmsUnsupportedException.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; public final class NmsUnsupportedException extends RuntimeException { diff --git a/nms-api/src/main/java/net/opmasterleo/packet/nms/PacketBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/PacketBridge.java new file mode 100644 index 0000000..ba9d6d8 --- /dev/null +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/PacketBridge.java @@ -0,0 +1,162 @@ +package net.opmasterleo.packet.nms; + +import java.util.List; +import java.util.UUID; + +import net.kyori.adventure.text.Component; +import net.opmasterleo.packet.nms.packet.Hand; +import net.opmasterleo.packet.nms.packet.InteractAction; +import net.opmasterleo.packet.nms.packet.PacketViews; +import net.opmasterleo.packet.nms.packet.PlayerActionType; + +/** + * Direct NMS packet factory. Menu/container/sign packets are owned by PacketUxUi / SignGUI + * and are not duplicated. Methods without a default must be implemented for every era; + * the rest throw unless that protocol layout exists on the running version. + */ +public interface PacketBridge { + + String classify(Object packet); + + int entityId(Object packet); + + List unwrapBundle(Object packet); + + default boolean clientbound(Object packet) { + if (packet == null) { + return false; + } + String name = packet.getClass().getSimpleName(); + return name.startsWith("Clientbound") || name.startsWith("PacketPlayOut"); + } + + default Object rebuildBundle(List packets) { + throw unsupported("bundle"); + } + + default Object addEntity(PacketViews.AddEntitySpec spec) { + throw unsupported("addEntity"); + } + + default Object addTextDisplay(PacketViews.TextDisplaySpec spec) { + throw unsupported("addTextDisplay"); + } + + Object removeEntities(int... entityIds); + + default Object setEntityData(int entityId, List metadataEntries) { + throw unsupported("setEntityData"); + } + + default Object entityVelocity(int entityId, double vx, double vy, double vz) { + throw unsupported("entityVelocity"); + } + + default Object entityEvent(Object nmsEntity, byte event) { + throw unsupported("entityEvent"); + } + + default Object animate(Object nmsEntity, int action) { + throw unsupported("animate"); + } + + default Object rotateHead(Object nmsEntity, float yaw) { + throw unsupported("rotateHead"); + } + + default Object setCamera(Object nmsEntity) { + throw unsupported("setCamera"); + } + + default Object setPassengers(Object nmsVehicle) { + throw unsupported("setPassengers"); + } + + default Object collectItem(int collectedId, int collectorId, int amount) { + throw unsupported("collectItem"); + } + + default Object setEquipment(int entityId, List slots) { + throw unsupported("setEquipment"); + } + + default Object blockUpdate(int x, int y, int z, Object nmsBlockState) { + throw unsupported("blockUpdate"); + } + + Object blockEvent(int x, int y, int z, Object nmsBlock, int type, int data); + + default Object blockDestruction(int entityId, int x, int y, int z, int progress) { + throw unsupported("blockDestruction"); + } + + default Object gameEvent(int eventId, float value) { + throw unsupported("gameEvent"); + } + + default Object setTime(long gameTime, long dayTime) { + throw unsupported("setTime"); + } + + Object setHealth(float health, int food, float saturation); + + default Object setExperience(float progress, int totalXp, int level) { + throw unsupported("setExperience"); + } + + default Object systemChat(Component message, boolean overlay) { + throw unsupported("systemChat"); + } + + default Object actionBar(Component message) { + throw unsupported("actionBar"); + } + + default Object tabList(Component header, Component footer) { + throw unsupported("tabList"); + } + + default Object titleText(Component title) { + throw unsupported("titleText"); + } + + default Object subtitleText(Component subtitle) { + throw unsupported("subtitleText"); + } + + default Object titleTimes(int fadeIn, int stay, int fadeOut) { + throw unsupported("titleTimes"); + } + + default Object clearTitles(boolean resetTimes) { + throw unsupported("clearTitles"); + } + + default Object playerInfoRemove(List profileIds) { + throw unsupported("playerInfoRemove"); + } + + default Object playerInfoAdd(Object nmsServerPlayer) { + throw unsupported("playerInfoAdd"); + } + + default Object keepAlive(long id) { + throw unsupported("keepAlive"); + } + + default Object disconnect(Component reason) { + throw unsupported("disconnect"); + } + + default PacketViews.InteractView interact(Object packet) { + return new PacketViews.InteractView(entityId(packet), InteractAction.UNKNOWN, Hand.MAIN_HAND); + } + + default PacketViews.PlayerActionView playerAction(Object packet) { + return new PacketViews.PlayerActionView(PlayerActionType.UNKNOWN, null); + } + + private static NmsUnsupportedException unsupported(String packet) { + return new NmsUnsupportedException("Packet '" + packet + "' is not available on this Minecraft version"); + } +} diff --git a/nms-api/src/main/java/net/opmasterleo/packet/nms/PlayerBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/PlayerBridge.java new file mode 100644 index 0000000..113c654 --- /dev/null +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/PlayerBridge.java @@ -0,0 +1,32 @@ +package net.opmasterleo.packet.nms; + +import org.bukkit.entity.Player; + +/** + * Direct {@code ServerPlayer} / {@code EntityPlayer} access via CraftBukkit {@code CraftPlayer}. + */ +public interface PlayerBridge { + + /** + * NMS player handle ({@code ServerPlayer} / {@code EntityPlayer}). + */ + Object handle(Player player); + + /** + * Send an NMS packet through {@code ServerPlayer.connection.send} / {@code PlayerConnection.sendPacket}. + */ + void send(Player player, Object nmsPacket); + + boolean isConnected(Player player); + + default int entityId(Player player) { + return -1; + } + + /** + * NMS {@code ServerLevel} / {@code WorldServer} the player is in. + */ + default Object level(Player player) { + return null; + } +} diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/ProtocolProbe.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/ProtocolProbe.java similarity index 98% rename from nms-api/src/main/java/org/mastersmp/packet/nms/ProtocolProbe.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/ProtocolProbe.java index 6bd0f3f..ad39a67 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/ProtocolProbe.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/ProtocolProbe.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; public final class ProtocolProbe { diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/RandomBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/RandomBridge.java similarity index 88% rename from nms-api/src/main/java/org/mastersmp/packet/nms/RandomBridge.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/RandomBridge.java index 8e499db..f9f5fc9 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/RandomBridge.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/RandomBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; import java.util.Collection; import java.util.Map; @@ -42,11 +42,12 @@ default T pickWeighted(Map weights) { } default T pickWeighted(Collection> weights) { - return this.pickWeighted(weights.stream().collect(java.util.stream.Collectors.toMap( + Map map = weights.stream().collect(java.util.stream.Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, Integer::sum, java.util.LinkedHashMap::new - ))); + )); + return pickWeighted(map); } } diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/WorldBridge.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/WorldBridge.java similarity index 97% rename from nms-api/src/main/java/org/mastersmp/packet/nms/WorldBridge.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/WorldBridge.java index a8854f9..076874b 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/WorldBridge.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/WorldBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms; +package net.opmasterleo.packet.nms; import java.util.stream.Stream; diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/BlockPosView.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/BlockPosView.java similarity index 55% rename from nms-api/src/main/java/org/mastersmp/packet/nms/packet/BlockPosView.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/packet/BlockPosView.java index 6d1994c..f17ae6e 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/BlockPosView.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/BlockPosView.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.packet; +package net.opmasterleo.packet.nms.packet; public record BlockPosView(int x, int y, int z) { } diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/Hand.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/Hand.java similarity index 53% rename from nms-api/src/main/java/org/mastersmp/packet/nms/packet/Hand.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/packet/Hand.java index 0dcd8f7..7fd31b8 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/Hand.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/Hand.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.packet; +package net.opmasterleo.packet.nms.packet; public enum Hand { MAIN_HAND, diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/InteractAction.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/InteractAction.java similarity index 66% rename from nms-api/src/main/java/org/mastersmp/packet/nms/packet/InteractAction.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/packet/InteractAction.java index 6196cf8..d606df8 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/InteractAction.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/InteractAction.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.packet; +package net.opmasterleo.packet.nms.packet; public enum InteractAction { ATTACK, diff --git a/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PacketViews.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PacketViews.java new file mode 100644 index 0000000..50a7aea --- /dev/null +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PacketViews.java @@ -0,0 +1,87 @@ +package net.opmasterleo.packet.nms.packet; + +import java.util.UUID; + +import net.kyori.adventure.text.Component; + +/** + * Version-agnostic views / construction specs for packets whose layout breaks across versions. + * Menu/container/sign packets are owned by PacketUxUi / SignGUI and are not duplicated here. + */ +public final class PacketViews { + + private PacketViews() { + } + + public record EquipmentEntry(String slot, Object nmsItem) { + } + + public record InteractView(int entityId, InteractAction action, Hand hand) { + } + + public record PlayerActionView(PlayerActionType action, BlockPosView pos) { + } + + public record Vec3d(double x, double y, double z) { + public static final Vec3d ZERO = new Vec3d(0, 0, 0); + } + + public record EntityPose(double x, double y, double z, float pitch, float yaw) { + public EntityPose at(double x, double y, double z) { + return new EntityPose(x, y, z, pitch, yaw); + } + } + + /** + * Spec for {@code ClientboundAddEntityPacket} / {@code PacketPlayOutSpawnEntity}. + */ + public record AddEntitySpec( + int entityId, + UUID uuid, + EntityPose pose, + Object nmsEntityType, + int data, + Vec3d velocity, + double headYaw + ) { + public AddEntitySpec { + if (uuid == null) { + uuid = UUID.randomUUID(); + } + if (pose == null) { + pose = new EntityPose(0, 0, 0, 0f, 0f); + } + if (velocity == null) { + velocity = Vec3d.ZERO; + } + } + } + + public record TextDisplayStyle( + Component text, + int lineWidth, + int backgroundColor, + byte textOpacity, + boolean seeThrough + ) { + public TextDisplayStyle { + if (text == null) { + text = Component.empty(); + } + } + } + + /** + * Spec for spawning a text display (add-entity + metadata). + */ + public record TextDisplaySpec(int entityId, Vec3d pos, TextDisplayStyle style) { + public TextDisplaySpec { + if (pos == null) { + pos = Vec3d.ZERO; + } + if (style == null) { + style = new TextDisplayStyle(Component.empty(), 200, 0x40000000, (byte) -1, false); + } + } + } +} diff --git a/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PacketWrap.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PacketWrap.java new file mode 100644 index 0000000..793f30b --- /dev/null +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PacketWrap.java @@ -0,0 +1,60 @@ +package net.opmasterleo.packet.nms.packet; + +import java.util.Objects; + +/** + * Zero-copy handle around a raw NMS packet. Stable packets are not given per-version wrapper + * classes — use this plus {@link net.opmasterleo.packet.nms.PacketBridge#classify}. + */ +public final class PacketWrap { + + public enum Direction { + CLIENTBOUND, + SERVERBOUND, + UNKNOWN + } + + private final Object handle; + private final String type; + private final Direction direction; + + public PacketWrap(Object handle, String type, Direction direction) { + this.handle = Objects.requireNonNull(handle, "handle"); + this.type = type == null ? handle.getClass().getSimpleName() : type; + this.direction = direction == null ? Direction.UNKNOWN : direction; + } + + public static PacketWrap of(Object handle) { + Objects.requireNonNull(handle, "handle"); + String simple = handle.getClass().getSimpleName(); + Direction direction; + if (simple.startsWith("Clientbound") || simple.startsWith("PacketPlayOut")) { + direction = Direction.CLIENTBOUND; + } else if (simple.startsWith("Serverbound") || simple.startsWith("PacketPlayIn")) { + direction = Direction.SERVERBOUND; + } else { + direction = Direction.UNKNOWN; + } + return new PacketWrap(handle, simple, direction); + } + + public Object handle() { + return handle; + } + + public String type() { + return type; + } + + public Direction direction() { + return direction; + } + + public boolean clientbound() { + return direction == Direction.CLIENTBOUND; + } + + public PacketWrap withHandle(Object replacement) { + return new PacketWrap(replacement, type, direction); + } +} diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/PlayerActionType.java b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PlayerActionType.java similarity index 82% rename from nms-api/src/main/java/org/mastersmp/packet/nms/packet/PlayerActionType.java rename to nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PlayerActionType.java index 9f1e170..dbfe68d 100644 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/PlayerActionType.java +++ b/nms-api/src/main/java/net/opmasterleo/packet/nms/packet/PlayerActionType.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.packet; +package net.opmasterleo.packet.nms.packet; public enum PlayerActionType { START_DESTROY_BLOCK, diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/ConnectionBridge.java b/nms-api/src/main/java/org/mastersmp/packet/nms/ConnectionBridge.java deleted file mode 100644 index ec958ca..0000000 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/ConnectionBridge.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.mastersmp.packet.nms; - -import org.bukkit.entity.Player; - -import io.netty.channel.Channel; - -public interface ConnectionBridge { - - Channel channel(Player player); - - Object connection(Player player); - - Object gamePacketListener(Player player); - - String[] injectBeforeNames(); -} diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/PacketBridge.java b/nms-api/src/main/java/org/mastersmp/packet/nms/PacketBridge.java deleted file mode 100644 index 57f0297..0000000 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/PacketBridge.java +++ /dev/null @@ -1,263 +0,0 @@ -package org.mastersmp.packet.nms; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; - -import org.bukkit.World; -import org.bukkit.block.BlockFace; -import org.bukkit.inventory.ItemStack; - -import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.packet.BlockPosView; -import org.mastersmp.packet.nms.packet.Hand; -import org.mastersmp.packet.nms.packet.InteractAction; -import org.mastersmp.packet.nms.packet.PacketViews; -import org.mastersmp.packet.nms.packet.PlayerActionType; - -public interface PacketBridge { - - String classify(Object packet); - - int entityId(Object packet); - - List unwrapBundle(Object packet); - - Object rebuildBundle(List packets); - - Object createAddTextDisplay( - int entityId, - double x, - double y, - double z, - Component text, - int lineWidth, - int backgroundColor, - byte textOpacity, - boolean seeThrough - ); - - Object createRemoveEntities(int... entityIds); - - Object createSetEntityData(int entityId, List metadataEntries); - - Object createBlockEvent(World world, int x, int y, int z, Object blockType, int type, int data); - - Object createContainerSetSlot(int containerId, int stateId, int slot, ItemStack item); - - Object createSetHealth(float health, int food, float saturation); - - default int interactEntityId(Object packet) { - return entityId(packet); - } - - default InteractAction interactAction(Object packet) { - return InteractAction.UNKNOWN; - } - - default PacketViews.InteractView interact(Object packet) { - return new PacketViews.InteractView(interactEntityId(packet), interactAction(packet), Hand.MAIN_HAND, Optional.empty()); - } - - default PlayerActionType playerAction(Object packet) { - return PlayerActionType.UNKNOWN; - } - - default BlockPosView playerActionPos(Object packet) { - return null; - } - - default PacketViews.PlayerActionView playerActionView(Object packet) { - return new PacketViews.PlayerActionView(playerAction(packet), playerActionPos(packet), BlockFace.SELF); - } - - default Hand useItemHand(Object packet) { - return Hand.MAIN_HAND; - } - - default BlockPosView useItemOnPos(Object packet) { - return null; - } - - default BlockFace useItemOnFace(Object packet) { - return BlockFace.SELF; - } - - default PacketViews.UseItemOnView useItemOn(Object packet) { - return new PacketViews.UseItemOnView(useItemHand(packet), useItemOnPos(packet), useItemOnFace(packet)); - } - - default Optional soundPath(Object packet) { - return Optional.empty(); - } - - default double soundX(Object packet) { - return 0; - } - - default double soundY(Object packet) { - return 0; - } - - default double soundZ(Object packet) { - return 0; - } - - default double particleX(Object packet) { - return 0; - } - - default double particleY(Object packet) { - return 0; - } - - default double particleZ(Object packet) { - return 0; - } - - default int entityEventId(Object packet) { - return -1; - } - - default boolean systemChatOverlay(Object packet) { - return false; - } - - default PacketViews.ExplodeView explode(Object packet) { - return null; - } - - default List entityDataValues(Object packet) { - return List.of(); - } - - default int dataValueId(Object dataValue) { - return -1; - } - - default Object dataValueValue(Object dataValue) { - return null; - } - - default List equipmentSlots(Object packet) { - return List.of(); - } - - default int equipmentEntityId(Object packet) { - return entityId(packet); - } - - default float packetHealth(Object packet) { - return 0f; - } - - default int packetFood(Object packet) { - return 0; - } - - default float packetSaturation(Object packet) { - return 0f; - } - - default int vehicleId(Object packet) { - return -1; - } - - default int[] passengerIds(Object packet) { - return new int[0]; - } - - default int linkSourceId(Object packet) { - return -1; - } - - default int linkDestId(Object packet) { - return -1; - } - - default Set playerInfoActions(Object packet) { - return Set.of(); - } - - default List playerInfoEntries(Object packet) { - return List.of(); - } - - default List playerInfoRemoveIds(Object packet) { - return List.of(); - } - - default PacketViews.SuggestionsView commandSuggestions(Object packet) { - return null; - } - - default Collection teamPlayers(Object packet) { - return List.of(); - } - - default PacketViews.ScoreView setScore(Object packet) { - return null; - } - - default PacketViews.ObjectiveView setObjective(Object packet) { - return null; - } - - default PacketViews.OpenScreenView openScreen(Object packet) { - return null; - } - - default int containerCloseId(Object packet) { - return -1; - } - - default PacketViews.ContainerSlotView containerSetSlot(Object packet) { - return null; - } - - default PacketViews.ContainerContentView containerSetContent(Object packet) { - return null; - } - - default Object cursorItem(Object packet) { - return null; - } - - default Object createDataValue(int id, Object value) { - throw new UnsupportedOperationException("createDataValue"); - } - - default Object createSetEquipment(int entityId, List slots) { - throw new UnsupportedOperationException("createSetEquipment"); - } - - default Object createPlayerInfoUpdate(Set actions, List entries) { - throw new UnsupportedOperationException("createPlayerInfoUpdate"); - } - - default Object createExplode(PacketViews.ExplodeView view) { - throw new UnsupportedOperationException("createExplode"); - } - - default Object withExplosionParticle(Object explodePacket, Object particle) { - throw new UnsupportedOperationException("withExplosionParticle"); - } - - default Object createContainerSetSlotNms(int containerId, int stateId, int slot, Object nmsItem) { - throw new UnsupportedOperationException("createContainerSetSlotNms"); - } - - default Object createContainerSetContent(int containerId, int stateId, List items, Object carried) { - throw new UnsupportedOperationException("createContainerSetContent"); - } - - default Object createSetCursorItem(Object nmsItem) { - throw new UnsupportedOperationException("createSetCursorItem"); - } - - default Object createSetPassengers(int vehicleId, int... passengerIds) { - throw new UnsupportedOperationException("createSetPassengers"); - } -} diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/PacketWrapper.java b/nms-api/src/main/java/org/mastersmp/packet/nms/PacketWrapper.java deleted file mode 100644 index ae361e6..0000000 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/PacketWrapper.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.mastersmp.packet.nms; - -import org.bukkit.entity.Player; - -/** - * Interface for wrapping and handling NMS packets across different Minecraft versions. - */ -public interface PacketWrapper { - - /** - * Injects a packet handler into the player's channel pipeline. - * @param player The player to inject for - * @param handler The packet handler to inject - */ - void injectHandler(Player player, PacketHandler handler); - - /** - * Removes a packet handler from the player's channel pipeline. - * @param player The player to remove from - * @param handlerName The name of the handler to remove - */ - void removeHandler(Player player, String handlerName); - - /** - * Gets the player's NMS connection object. - * @param player The player - * @return The NMS connection object - */ - Object getConnection(Player player); - - /** - * Gets the player's NMS channel. - * @param player The player - * @return The Netty channel - */ - Object getChannel(Player player); - - /** - * Checks if a handler is already injected. - * @param player The player to check - * @param handlerName The handler name - * @return true if the handler exists - */ - boolean hasHandler(Player player, String handlerName); - - /** - * Interface for handling packets at the NMS level. - */ - interface PacketHandler { - /** - * Called when a packet is received from the player. - * @param packet The NMS packet - * @param playerHandle The player's NMS handle (ServerPlayer) - * @return true to cancel the packet, false to continue - */ - boolean onPacketReceive(Object packet, Object playerHandle); - - /** - * Called when a packet is sent to the player. - * @param packet The NMS packet - * @param playerHandle The player's NMS handle (ServerPlayer) - * @return true to cancel the packet, false to continue - */ - boolean onPacketSend(Object packet, Object playerHandle); - - /** - * Gets the name of this handler. - * @return The handler name - */ - String getName(); - } -} diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/PlayerBridge.java b/nms-api/src/main/java/org/mastersmp/packet/nms/PlayerBridge.java deleted file mode 100644 index de6b32f..0000000 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/PlayerBridge.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.mastersmp.packet.nms; - -import org.bukkit.entity.Player; - -public interface PlayerBridge { - - Object handle(Player player); - - void send(Player player, Object nmsPacket); - - boolean isConnected(Player player); -} diff --git a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/PacketViews.java b/nms-api/src/main/java/org/mastersmp/packet/nms/packet/PacketViews.java deleted file mode 100644 index 8c41377..0000000 --- a/nms-api/src/main/java/org/mastersmp/packet/nms/packet/PacketViews.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.mastersmp.packet.nms.packet; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.bukkit.block.BlockFace; -import org.bukkit.util.Vector; - -import net.kyori.adventure.text.Component; - -public final class PacketViews { - - private PacketViews() { - } - - public record ExplodeView( - double x, - double y, - double z, - float power, - int blockCount, - Vector knockback, - Object particle, - Object sound, - Object blockParticles - ) { - } - - public record EquipmentEntry(String slot, Object nmsItem) { - } - - public record PlayerInfoEntry( - UUID profileId, - String name, - boolean listed, - int latency, - String gameMode, - Component displayName - ) { - } - - public record SuggestionsView(int id, int start, int length, List entries) { - } - - public record ScoreView(String owner, String objective, int score, Component display) { - } - - public record ObjectiveView(String name, int method, String renderType) { - } - - public record OpenScreenView(int containerId, Object menuType, String typeKey, Component title) { - } - - public record ContainerSlotView(int containerId, int stateId, int slot, Object nmsItem) { - } - - public record ContainerContentView(int containerId, int stateId, List items, Object carried) { - } - - public record InteractView(int entityId, InteractAction action, Hand hand, Optional location) { - } - - public record PlayerActionView(PlayerActionType action, BlockPosView pos, BlockFace face) { - } - - public record UseItemOnView(Hand hand, BlockPosView pos, BlockFace face) { - } -} diff --git a/nms-api/src/test/java/net/opmasterleo/packet/nms/AdapterLoaderTest.java b/nms-api/src/test/java/net/opmasterleo/packet/nms/AdapterLoaderTest.java new file mode 100644 index 0000000..fd71b4f --- /dev/null +++ b/nms-api/src/test/java/net/opmasterleo/packet/nms/AdapterLoaderTest.java @@ -0,0 +1,33 @@ +package net.opmasterleo.packet.nms; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +class AdapterLoaderTest { + + @Test + void stripsBukkitSnapshotSuffix() { + assertEquals("26.2", AdapterLoader.normalizeMinecraftVersion("26.2-R0.1-SNAPSHOT")); + assertEquals("1.21.4", AdapterLoader.normalizeMinecraftVersion("1.21.4-R0.1-SNAPSHOT")); + } + + @Test + void stripsPaperBuildSuffix() { + assertEquals("26.2", AdapterLoader.normalizeMinecraftVersion("26.2.build.12")); + } + + @Test + void mapsKnownVersions() { + assertEquals("v1_16_R3", AdapterLoader.lookupBucket("1.16.5")); + assertEquals("v1_21_R3", AdapterLoader.lookupBucket("1.21.4")); + assertEquals("v26_2", AdapterLoader.lookupBucket("26.2")); + assertEquals("v26_1", AdapterLoader.lookupBucket("26.1.2")); + } + + @Test + void unknownLegacyIsNull() { + assertNull(AdapterLoader.lookupBucket("1.8.8")); + } +} diff --git a/nms-api/src/test/java/net/opmasterleo/packet/nms/packet/PacketWrapTest.java b/nms-api/src/test/java/net/opmasterleo/packet/nms/packet/PacketWrapTest.java new file mode 100644 index 0000000..c83b148 --- /dev/null +++ b/nms-api/src/test/java/net/opmasterleo/packet/nms/packet/PacketWrapTest.java @@ -0,0 +1,38 @@ +package net.opmasterleo.packet.nms.packet; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PacketWrapTest { + + @Test + void classifiesClientboundName() { + PacketWrap wrap = PacketWrap.of(new ClientboundSetHealthPacket()); + assertEquals("ClientboundSetHealthPacket", wrap.type()); + assertTrue(wrap.clientbound()); + assertEquals(PacketWrap.Direction.CLIENTBOUND, wrap.direction()); + } + + @Test + void classifiesServerboundName() { + PacketWrap wrap = PacketWrap.of(new ServerboundInteractPacket()); + assertEquals(PacketWrap.Direction.SERVERBOUND, wrap.direction()); + } + + @Test + void withHandleKeepsType() { + PacketWrap original = PacketWrap.of(new ClientboundSetHealthPacket()); + Object replacement = new ClientboundSetHealthPacket(); + PacketWrap next = original.withHandle(replacement); + assertEquals(replacement, next.handle()); + assertEquals(original.type(), next.type()); + } + + static final class ClientboundSetHealthPacket { + } + + static final class ServerboundInteractPacket { + } +} diff --git a/nms-shared/Reflect.java b/nms-shared/Reflect.java index 79d2333..8cd5c9b 100644 --- a/nms-shared/Reflect.java +++ b/nms-shared/Reflect.java @@ -1,7 +1,12 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; +/** + * Reflection helpers for public Mojang-mapped members and mid/legacy private NMS fields. + * Prefer {@link Class#getField(String)} / {@link Class#getMethod} when possible. + */ final class Reflect { private Reflect() { @@ -9,9 +14,18 @@ private Reflect() { static Field field(Class owner, String... names) { for (String name : names) { + try { + return owner.getField(name); + } catch (NoSuchFieldException ignored) { + } try { Field field = owner.getDeclaredField(name); - field.setAccessible(true); + // Mid/legacy CraftBukkit fields are not public; Module opens are unavailable at runtime. + try { + field.trySetAccessible(); + } catch (SecurityException ignored) { + continue; + } return field; } catch (NoSuchFieldException ignored) { } @@ -30,6 +44,16 @@ static Object get(Field field, Object instance) { } } + static void set(Field field, Object instance, Object value) { + if (field == null) { + return; + } + try { + field.set(instance, value); + } catch (IllegalAccessException ignored) { + } + } + static Object invoke(Object target, String name, Class[] types, Object... args) { if (target == null) { return null; @@ -57,4 +81,21 @@ static Object invoke(Object target, String... names) { } return null; } + + static Object construct(Class type, Class[] paramTypes, Object... args) { + if (type == null) { + return null; + } + try { + Constructor ctor = type.getDeclaredConstructor(paramTypes); + try { + ctor.trySetAccessible(); + } catch (SecurityException ignored) { + return null; + } + return ctor.newInstance(args); + } catch (ReflectiveOperationException ignored) { + return null; + } + } } diff --git a/nms-shared/adapter/legacy/AbstractNmsAdapter.java b/nms-shared/adapter/legacy/AbstractNmsAdapter.java index 83c5bd2..f7b1d26 100644 --- a/nms-shared/adapter/legacy/AbstractNmsAdapter.java +++ b/nms-shared/adapter/legacy/AbstractNmsAdapter.java @@ -1,13 +1,13 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; -import org.mastersmp.packet.nms.ComponentBridge; -import org.mastersmp.packet.nms.ConnectionBridge; -import org.mastersmp.packet.nms.ItemBridge; -import org.mastersmp.packet.nms.MenuBridge; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.PacketBridge; -import org.mastersmp.packet.nms.PlayerBridge; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.ComponentBridge; +import net.opmasterleo.packet.nms.ConnectionBridge; +import net.opmasterleo.packet.nms.ItemBridge; +import net.opmasterleo.packet.nms.MenuBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.PlayerBridge; +import net.opmasterleo.packet.nms.WorldBridge; public abstract class AbstractNmsAdapter implements NmsAdapter { diff --git a/nms-shared/adapter/legacy/SharedComponentBridge.java b/nms-shared/adapter/legacy/SharedComponentBridge.java index 775fdfa..3f2eba0 100644 --- a/nms-shared/adapter/legacy/SharedComponentBridge.java +++ b/nms-shared/adapter/legacy/SharedComponentBridge.java @@ -1,9 +1,9 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.mastersmp.packet.nms.ComponentBridge; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.opmasterleo.packet.nms.ComponentBridge; public final class SharedComponentBridge implements ComponentBridge { @@ -25,7 +25,7 @@ public boolean isWorthLine(Component component) { if (component == null) { return false; } - String plain = PlainTextComponentSerializer.plainText().serialize(component); + String plain = LegacyComponentSerializer.legacySection().serialize(component); return plain.contains("Worth") || plain.contains("worth"); } } diff --git a/nms-shared/adapter/mid/AbstractNmsAdapter.java b/nms-shared/adapter/mid/AbstractNmsAdapter.java index 83c5bd2..f7b1d26 100644 --- a/nms-shared/adapter/mid/AbstractNmsAdapter.java +++ b/nms-shared/adapter/mid/AbstractNmsAdapter.java @@ -1,13 +1,13 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; -import org.mastersmp.packet.nms.ComponentBridge; -import org.mastersmp.packet.nms.ConnectionBridge; -import org.mastersmp.packet.nms.ItemBridge; -import org.mastersmp.packet.nms.MenuBridge; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.PacketBridge; -import org.mastersmp.packet.nms.PlayerBridge; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.ComponentBridge; +import net.opmasterleo.packet.nms.ConnectionBridge; +import net.opmasterleo.packet.nms.ItemBridge; +import net.opmasterleo.packet.nms.MenuBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.PlayerBridge; +import net.opmasterleo.packet.nms.WorldBridge; public abstract class AbstractNmsAdapter implements NmsAdapter { diff --git a/nms-shared/adapter/mid/SharedComponentBridge.java b/nms-shared/adapter/mid/SharedComponentBridge.java index 601e850..3f2eba0 100644 --- a/nms-shared/adapter/mid/SharedComponentBridge.java +++ b/nms-shared/adapter/mid/SharedComponentBridge.java @@ -1,30 +1,21 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.mastersmp.packet.nms.ComponentBridge; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.opmasterleo.packet.nms.ComponentBridge; public final class SharedComponentBridge implements ComponentBridge { @Override public Object fromAdventure(Component component) { - try { - return io.papermc.paper.adventure.PaperAdventure.asVanilla(component); - } catch (Throwable ignored) { - return net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(component); - } + return GsonComponentSerializer.gson().serialize(component); } @Override public Component toAdventure(Object nmsComponent) { - if (nmsComponent instanceof net.minecraft.network.chat.Component component) { - try { - return io.papermc.paper.adventure.PaperAdventure.asAdventure(component); - } catch (Throwable ignored) { - } - } if (nmsComponent instanceof String json) { - return net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(json); + return GsonComponentSerializer.gson().deserialize(json); } return Component.empty(); } @@ -34,7 +25,7 @@ public boolean isWorthLine(Component component) { if (component == null) { return false; } - String plain = PlainTextComponentSerializer.plainText().serialize(component); + String plain = LegacyComponentSerializer.legacySection().serialize(component); return plain.contains("Worth") || plain.contains("worth"); } } diff --git a/nms-shared/adapter/modern/AbstractNmsAdapter.java b/nms-shared/adapter/modern/AbstractNmsAdapter.java index 73c5b95..0cf80d7 100644 --- a/nms-shared/adapter/modern/AbstractNmsAdapter.java +++ b/nms-shared/adapter/modern/AbstractNmsAdapter.java @@ -1,14 +1,14 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; -import org.mastersmp.packet.nms.ComponentBridge; -import org.mastersmp.packet.nms.ConnectionBridge; -import org.mastersmp.packet.nms.ItemBridge; -import org.mastersmp.packet.nms.MenuBridge; -import org.mastersmp.packet.nms.NmsAdapter; -import org.mastersmp.packet.nms.PacketBridge; -import org.mastersmp.packet.nms.PacketWrapper; -import org.mastersmp.packet.nms.PlayerBridge; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.ComponentBridge; +import net.opmasterleo.packet.nms.ConnectionBridge; +import net.opmasterleo.packet.nms.ItemBridge; +import net.opmasterleo.packet.nms.MenuBridge; +import net.opmasterleo.packet.nms.MetadataBridge; +import net.opmasterleo.packet.nms.NmsAdapter; +import net.opmasterleo.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.PlayerBridge; +import net.opmasterleo.packet.nms.WorldBridge; public abstract class AbstractNmsAdapter implements NmsAdapter { @@ -20,7 +20,7 @@ public abstract class AbstractNmsAdapter implements NmsAdapter { private final MenuBridge menus = new SharedMenuBridge(); private final WorldBridge worlds = new SharedWorldBridge(); private final ComponentBridge components = new SharedComponentBridge(); - private final PacketWrapper wrapper = new SharedPacketWrapper(); + private final MetadataBridge metadata = new SharedMetadataBridge(components); protected AbstractNmsAdapter(String bucketId) { this.bucketId = bucketId; @@ -67,7 +67,7 @@ public ComponentBridge components() { } @Override - public PacketWrapper wrapper() { - return wrapper; + public MetadataBridge metadata() { + return metadata; } } diff --git a/nms-shared/adapter/modern/SharedComponentBridge.java b/nms-shared/adapter/modern/SharedComponentBridge.java index 909becc..732bf7f 100644 --- a/nms-shared/adapter/modern/SharedComponentBridge.java +++ b/nms-shared/adapter/modern/SharedComponentBridge.java @@ -1,8 +1,8 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.mastersmp.packet.nms.ComponentBridge; +import net.opmasterleo.packet.nms.ComponentBridge; public final class SharedComponentBridge implements ComponentBridge { diff --git a/nms-shared/adapter/modern/SharedMetadataBridge.java b/nms-shared/adapter/modern/SharedMetadataBridge.java new file mode 100644 index 0000000..ab98a03 --- /dev/null +++ b/nms-shared/adapter/modern/SharedMetadataBridge.java @@ -0,0 +1,74 @@ +package net.opmasterleo.packet.nms.shared; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Display; +import net.minecraft.world.entity.Entity; +import net.opmasterleo.packet.nms.ComponentBridge; +import net.opmasterleo.packet.nms.MetadataBridge; +import net.opmasterleo.packet.nms.packet.PacketViews; + +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; + +public final class SharedMetadataBridge implements MetadataBridge { + + private static final byte SEE_THROUGH = 1 << 1; + private static final AtomicInteger FALLBACK_IDS = new AtomicInteger(1_000_000); + + private final ComponentBridge components; + + public SharedMetadataBridge(ComponentBridge components) { + this.components = components; + } + + @Override + public Object accessor(Class owner, String fieldName) { + try { + // Public Mojang-mapped DATA_* fields only — no setAccessible. + return owner.getField(fieldName).get(null); + } catch (ReflectiveOperationException error) { + throw new IllegalStateException("Missing entity data accessor " + owner.getName() + "." + fieldName, error); + } + } + + @Override + public Object dataValue(Object accessor, Object value) { + if (!(accessor instanceof EntityDataAccessor dataAccessor)) { + throw new IllegalArgumentException("accessor"); + } + @SuppressWarnings({"rawtypes", "unchecked"}) + SynchedEntityData.DataValue created = SynchedEntityData.DataValue.create((EntityDataAccessor) dataAccessor, value); + return created; + } + + @Override + public Object dataValue(int id, Object value) { + throw new UnsupportedOperationException("Use dataValue(accessor, value) on modern NMS"); + } + + @Override + public List textDisplayValues(PacketViews.TextDisplayStyle style) { + Object vanilla = components.fromAdventure(style.text()); + byte flags = style.seeThrough() ? SEE_THROUGH : 0; + List values = new ArrayList<>(5); + values.add(dataValue(accessor(Display.TextDisplay.class, "DATA_TEXT_ID"), vanilla)); + values.add(dataValue(accessor(Display.TextDisplay.class, "DATA_LINE_WIDTH_ID"), style.lineWidth())); + values.add(dataValue(accessor(Display.TextDisplay.class, "DATA_BACKGROUND_COLOR_ID"), style.backgroundColor())); + values.add(dataValue(accessor(Display.TextDisplay.class, "DATA_TEXT_OPACITY_ID"), style.textOpacity())); + values.add(dataValue(accessor(Display.TextDisplay.class, "DATA_STYLE_FLAGS_ID"), flags)); + return values; + } + + @Override + public int nextEntityId() { + Object id = invoke(Entity.class, "nextEntityId"); + if (id instanceof Integer i) { + return i; + } + return FALLBACK_IDS.getAndIncrement(); + } +} diff --git a/nms-shared/connection/legacy/SharedConnectionBridge.java b/nms-shared/connection/legacy/SharedConnectionBridge.java index b455a90..e21ccb4 100644 --- a/nms-shared/connection/legacy/SharedConnectionBridge.java +++ b/nms-shared/connection/legacy/SharedConnectionBridge.java @@ -1,59 +1,38 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.NMS.entity.CraftPlayer; import org.bukkit.entity.Player; -import io.netty.channel.Channel; import net.minecraft.server.NMS.EntityPlayer; -import net.minecraft.server.NMS.NetworkManager; -import net.minecraft.server.NMS.PlayerConnection; -import org.mastersmp.packet.nms.ConnectionBridge; - -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; +import net.opmasterleo.packet.nms.ConnectionBridge; public final class SharedConnectionBridge implements ConnectionBridge { - private static final String[] ANCHORS = { - "packet_handler", - "encoder", - "decoder", - "prepender", - "compress" - }; - - @Override - public Channel channel(Player player) { - EntityPlayer sp = handle(player); - if (sp == null || sp.playerConnection == null) { - return null; - } - NetworkManager manager = sp.playerConnection.networkManager; - Object channel = get(field(manager.getClass(), "channel"), manager); - return channel instanceof Channel c ? c : null; - } - @Override public Object connection(Player player) { - EntityPlayer sp = handle(player); + EntityPlayer sp = nms(player); return sp == null || sp.playerConnection == null ? null : sp.playerConnection.networkManager; } @Override - public Object gamePacketListener(Player player) { - EntityPlayer sp = handle(player); + public Object listener(Player player) { + EntityPlayer sp = nms(player); return sp == null ? null : sp.playerConnection; } @Override - public String[] injectBeforeNames() { - return ANCHORS.clone(); + public int latency(Player player) { + EntityPlayer sp = nms(player); + return sp == null ? 0 : sp.ping; + } + + @Override + public boolean accepting(Player player) { + EntityPlayer sp = nms(player); + return sp != null && sp.playerConnection != null && player.isOnline(); } - private static EntityPlayer handle(Player player) { - if (player instanceof CraftPlayer craft) { - return craft.getHandle(); - } - return null; + private static EntityPlayer nms(Player player) { + return player instanceof CraftPlayer craft ? craft.getHandle() : null; } } diff --git a/nms-shared/connection/mid/SharedConnectionBridge.java b/nms-shared/connection/mid/SharedConnectionBridge.java index 31ef801..a8c8854 100644 --- a/nms-shared/connection/mid/SharedConnectionBridge.java +++ b/nms-shared/connection/mid/SharedConnectionBridge.java @@ -1,91 +1,71 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.NMS.entity.CraftPlayer; import org.bukkit.entity.Player; -import io.netty.channel.Channel; import net.minecraft.network.Connection; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; -import org.mastersmp.packet.nms.ConnectionBridge; +import net.opmasterleo.packet.nms.ConnectionBridge; -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.field; +import static net.opmasterleo.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedConnectionBridge implements ConnectionBridge { - private static final String[] ANCHORS = { - "packet_handler", - "encoder", - "decoder", - "prepender", - "compress" - }; - @Override - public Channel channel(Player player) { - ServerPlayer sp = handle(player); - if (sp == null) { + public Object connection(Player player) { + ServerPlayer sp = nms(player); + if (sp == null || sp.connection == null) { return null; } - Connection connection = resolveConnection(sp); - if (connection != null && connection.channel != null) { - return connection.channel; + if (sp.connection instanceof ServerGamePacketListenerImpl listener) { + Object value = get(field(listener.getClass(), "connection"), listener); + return value instanceof Connection connection ? connection : listener; } - return channelByAddress(player); - } - - @Override - public Object connection(Player player) { - ServerPlayer sp = handle(player); - return sp == null ? null : resolveConnection(sp); + Object value = get(field(sp.connection.getClass(), "connection", "networkManager"), sp.connection); + return value instanceof Connection connection ? connection : sp.connection; } @Override - public Object gamePacketListener(Player player) { - ServerPlayer sp = handle(player); + public Object listener(Player player) { + ServerPlayer sp = nms(player); return sp == null ? null : sp.connection; } @Override - public String[] injectBeforeNames() { - return ANCHORS.clone(); - } - - private static ServerPlayer handle(Player player) { - if (player instanceof CraftPlayer craft) { - return craft.getHandle(); + public int latency(Player player) { + ServerPlayer sp = nms(player); + if (sp == null) { + return 0; } - return null; - } - - private static Connection resolveConnection(ServerPlayer sp) { - if (sp.connection instanceof ServerGamePacketListenerImpl listener) { - Object value = get(field(listener.getClass(), "connection"), listener); - return value instanceof Connection connection ? connection : null; + Object ping = invoke(sp, "latency", "getPing"); + if (ping instanceof Integer i) { + return i; } - Object value = get(field(sp.connection.getClass(), "connection", "networkManager"), sp.connection); - return value instanceof Connection connection ? connection : null; + Object listener = sp.connection; + ping = invoke(listener, "latency", "getLatency"); + if (ping instanceof Integer i) { + return i; + } + return player.getPing(); } - private static Channel channelByAddress(Player player) { - if (player == null || player.getAddress() == null) { - return null; + @Override + public boolean accepting(Player player) { + ServerPlayer sp = nms(player); + if (sp == null || sp.connection == null) { + return false; } - try { - var address = player.getAddress().getAddress(); - for (Connection connection : MinecraftServer.getServer().getConnection().getConnections()) { - if (connection == null || connection.channel == null) { - continue; - } - if (connection.getRemoteAddress() instanceof java.net.InetSocketAddress remote - && address.equals(remote.getAddress())) { - return connection.channel; - } - } - } catch (Throwable ignored) { + Object accepting = invoke(sp.connection, "isAcceptingMessages"); + if (accepting instanceof Boolean b) { + return b; } - return null; + return player.isOnline(); + } + + private static ServerPlayer nms(Player player) { + return player instanceof CraftPlayer craft ? craft.getHandle() : null; } } diff --git a/nms-shared/connection/modern/SharedConnectionBridge.java b/nms-shared/connection/modern/SharedConnectionBridge.java index 3f2e86e..a50f2dc 100644 --- a/nms-shared/connection/modern/SharedConnectionBridge.java +++ b/nms-shared/connection/modern/SharedConnectionBridge.java @@ -1,92 +1,49 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; -import io.netty.channel.Channel; import net.minecraft.network.Connection; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; -import org.mastersmp.packet.nms.ConnectionBridge; - -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; +import net.opmasterleo.packet.nms.ConnectionBridge; public final class SharedConnectionBridge implements ConnectionBridge { - private static final String[] ANCHORS = { - "packet_handler", - "inbound_config", - "outbound_config", - "encoder", - "decoder", - "prepender", - "compress" - }; - @Override - public Channel channel(Player player) { - ServerPlayer sp = handle(player); - if (sp == null) { + public Object connection(Player player) { + ServerPlayer sp = nms(player); + if (sp == null || sp.connection == null) { return null; } - Connection connection = resolveConnection(sp); - if (connection != null && connection.channel != null) { - return connection.channel; + if (sp.connection instanceof ServerGamePacketListenerImpl listener) { + return listener.connection; } - return channelByAddress(player); - } - - @Override - public Object connection(Player player) { - ServerPlayer sp = handle(player); - return sp == null ? null : resolveConnection(sp); + return sp.connection; } @Override - public Object gamePacketListener(Player player) { - ServerPlayer sp = handle(player); + public Object listener(Player player) { + ServerPlayer sp = nms(player); return sp == null ? null : sp.connection; } @Override - public String[] injectBeforeNames() { - return ANCHORS.clone(); - } - - private static ServerPlayer handle(Player player) { - if (player instanceof CraftPlayer craft) { - return craft.getHandle(); + public int latency(Player player) { + ServerPlayer sp = nms(player); + if (sp == null || sp.connection == null) { + return 0; } - return null; + return sp.connection.latency(); } - private static Connection resolveConnection(ServerPlayer sp) { - if (sp.connection instanceof ServerGamePacketListenerImpl listener) { - return listener.connection; - } - Object value = get(field(sp.connection.getClass(), "connection"), sp.connection); - return value instanceof Connection connection ? connection : null; + @Override + public boolean accepting(Player player) { + ServerPlayer sp = nms(player); + return sp != null && sp.connection != null && sp.connection.isAcceptingMessages(); } - private static Channel channelByAddress(Player player) { - if (player == null || player.getAddress() == null) { - return null; - } - try { - var address = player.getAddress().getAddress(); - for (Connection connection : MinecraftServer.getServer().getConnection().getConnections()) { - if (connection == null || connection.channel == null) { - continue; - } - if (connection.getRemoteAddress() instanceof java.net.InetSocketAddress remote - && address.equals(remote.getAddress())) { - return connection.channel; - } - } - } catch (Throwable ignored) { - } - return null; + private static ServerPlayer nms(Player player) { + return player instanceof CraftPlayer craft ? craft.getHandle() : null; } } diff --git a/nms-shared/item/legacy/SharedItemBridge.java b/nms-shared/item/legacy/SharedItemBridge.java index 96080db..91be9ae 100644 --- a/nms-shared/item/legacy/SharedItemBridge.java +++ b/nms-shared/item/legacy/SharedItemBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.ArrayList; import java.util.List; @@ -11,11 +11,11 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionType; import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.ItemBridge; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.opmasterleo.packet.nms.ItemBridge; public final class SharedItemBridge implements ItemBridge { @@ -41,17 +41,33 @@ public List getLore(Object nmsItem) { return List.of(); } ItemMeta meta = bukkit.getItemMeta(); - if (meta == null || meta.lore() == null) { + if (meta == null || !meta.hasLore()) { return List.of(); } - return List.copyOf(meta.lore()); + List lore = meta.getLore(); + if (lore == null || lore.isEmpty()) { + return List.of(); + } + List out = new ArrayList<>(lore.size()); + for (String line : lore) { + out.add(LegacyComponentSerializer.legacySection().deserialize(line)); + } + return List.copyOf(out); } @Override public void setLore(Object nmsItem, List lore) { ItemStack bukkit = CraftItemStack.asCraftMirror((net.minecraft.server.NMS.ItemStack) nmsItem); ItemMeta meta = bukkit.getItemMeta(); - meta.lore(lore); + if (lore == null) { + meta.setLore(null); + } else { + List lines = new ArrayList<>(lore.size()); + for (Component line : lore) { + lines.add(LegacyComponentSerializer.legacySection().serialize(line)); + } + meta.setLore(lines); + } bukkit.setItemMeta(meta); } diff --git a/nms-shared/item/mid/SharedItemBridge.java b/nms-shared/item/mid/SharedItemBridge.java index e408c2b..f4ceb0b 100644 --- a/nms-shared/item/mid/SharedItemBridge.java +++ b/nms-shared/item/mid/SharedItemBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.ArrayList; import java.util.List; @@ -11,11 +11,11 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionType; import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.ItemBridge; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.opmasterleo.packet.nms.ItemBridge; public final class SharedItemBridge implements ItemBridge { @@ -40,15 +40,34 @@ public List getLore(Object nmsItem) { if (bukkit == null || !bukkit.hasItemMeta()) { return List.of(); } - List lore = bukkit.getItemMeta().lore(); - return lore == null ? List.of() : List.copyOf(lore); + ItemMeta meta = bukkit.getItemMeta(); + if (meta == null || !meta.hasLore()) { + return List.of(); + } + List lore = meta.getLore(); + if (lore == null || lore.isEmpty()) { + return List.of(); + } + List out = new ArrayList<>(lore.size()); + for (String line : lore) { + out.add(LegacyComponentSerializer.legacySection().deserialize(line)); + } + return List.copyOf(out); } @Override public void setLore(Object nmsItem, List lore) { ItemStack bukkit = CraftItemStack.asCraftMirror((net.minecraft.world.item.ItemStack) nmsItem); ItemMeta meta = bukkit.getItemMeta(); - meta.lore(lore); + if (lore == null) { + meta.setLore(null); + } else { + List lines = new ArrayList<>(lore.size()); + for (Component line : lore) { + lines.add(LegacyComponentSerializer.legacySection().serialize(line)); + } + meta.setLore(lines); + } bukkit.setItemMeta(meta); } @@ -106,12 +125,7 @@ public ItemStack enchant(ItemStack item, Enchantment enchantment, int level) { @Override public ItemStack applyPotion(ItemStack item, PotionType potionType) { - ItemStack copy = item.clone(); - if (copy.getItemMeta() instanceof PotionMeta meta) { - meta.setBasePotionType(potionType); - copy.setItemMeta(meta); - } - return copy; + return item.clone(); } @Override diff --git a/nms-shared/item/modern/SharedItemBridge.java b/nms-shared/item/modern/SharedItemBridge.java index 22e0733..89e36af 100644 --- a/nms-shared/item/modern/SharedItemBridge.java +++ b/nms-shared/item/modern/SharedItemBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.ArrayList; import java.util.List; @@ -15,7 +15,7 @@ import org.bukkit.potion.PotionType; import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.ItemBridge; +import net.opmasterleo.packet.nms.ItemBridge; public final class SharedItemBridge implements ItemBridge { diff --git a/nms-shared/item/modern21_5/SharedItemBridge.java b/nms-shared/item/modern21_5/SharedItemBridge.java index e7efcf4..150f88b 100644 --- a/nms-shared/item/modern21_5/SharedItemBridge.java +++ b/nms-shared/item/modern21_5/SharedItemBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.ArrayList; import java.util.List; @@ -15,7 +15,7 @@ import org.bukkit.potion.PotionType; import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.ItemBridge; +import net.opmasterleo.packet.nms.ItemBridge; public final class SharedItemBridge implements ItemBridge { diff --git a/nms-shared/menu/legacy/SharedMenuBridge.java b/nms-shared/menu/legacy/SharedMenuBridge.java index 2b12039..368ab34 100644 --- a/nms-shared/menu/legacy/SharedMenuBridge.java +++ b/nms-shared/menu/legacy/SharedMenuBridge.java @@ -1,10 +1,10 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.MenuBridge; +import net.opmasterleo.packet.nms.MenuBridge; public final class SharedMenuBridge implements MenuBridge { diff --git a/nms-shared/menu/mid/SharedMenuBridge.java b/nms-shared/menu/mid/SharedMenuBridge.java index f5c4832..a6ce60b 100644 --- a/nms-shared/menu/mid/SharedMenuBridge.java +++ b/nms-shared/menu/mid/SharedMenuBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.NMS.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -6,11 +6,11 @@ import net.kyori.adventure.text.Component; import net.minecraft.server.level.ServerPlayer; -import org.mastersmp.packet.nms.MenuBridge; +import net.opmasterleo.packet.nms.MenuBridge; -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.field; +import static net.opmasterleo.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedMenuBridge implements MenuBridge { diff --git a/nms-shared/menu/modern/SharedMenuBridge.java b/nms-shared/menu/modern/SharedMenuBridge.java index e09ecae..80475d1 100644 --- a/nms-shared/menu/modern/SharedMenuBridge.java +++ b/nms-shared/menu/modern/SharedMenuBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -8,9 +8,9 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; -import org.mastersmp.packet.nms.MenuBridge; +import net.opmasterleo.packet.nms.MenuBridge; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedMenuBridge implements MenuBridge { diff --git a/nms-shared/packet/legacy/SharedPacketBridge.java b/nms-shared/packet/legacy/SharedPacketBridge.java index f9d5cf5..cca616e 100644 --- a/nms-shared/packet/legacy/SharedPacketBridge.java +++ b/nms-shared/packet/legacy/SharedPacketBridge.java @@ -1,18 +1,30 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; -import java.util.ArrayList; import java.util.List; -import org.bukkit.World; -import org.bukkit.craftbukkit.NMS.inventory.CraftItemStack; -import org.bukkit.inventory.ItemStack; +import net.minecraft.server.NMS.Block; +import net.minecraft.server.NMS.BlockPosition; +import net.minecraft.server.NMS.Blocks; +import net.minecraft.server.NMS.Entity; +import net.minecraft.server.NMS.IBlockData; +import net.minecraft.server.NMS.PacketPlayOutAnimation; +import net.minecraft.server.NMS.PacketPlayOutBlockAction; +import net.minecraft.server.NMS.PacketPlayOutBlockBreakAnimation; +import net.minecraft.server.NMS.PacketPlayOutBlockChange; +import net.minecraft.server.NMS.PacketPlayOutCamera; +import net.minecraft.server.NMS.PacketPlayOutCollect; +import net.minecraft.server.NMS.PacketPlayOutEntityDestroy; +import net.minecraft.server.NMS.PacketPlayOutEntityHeadRotation; +import net.minecraft.server.NMS.PacketPlayOutEntityStatus; +import net.minecraft.server.NMS.PacketPlayOutExperience; +import net.minecraft.server.NMS.PacketPlayOutMount; +import net.minecraft.server.NMS.PacketPlayOutUpdateHealth; +import net.opmasterleo.packet.nms.PacketBridge; -import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.PacketBridge; - -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.field; +import static net.opmasterleo.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.set; public final class SharedPacketBridge implements PacketBridge { @@ -47,63 +59,96 @@ public List unwrapBundle(Object packet) { } @Override - public Object rebuildBundle(List packets) { - throw new UnsupportedOperationException("Bundle packets require 1.19.4+"); + public Object removeEntities(int... entityIds) { + return new PacketPlayOutEntityDestroy(entityIds); } @Override - public Object createAddTextDisplay( - int entityId, - double x, - double y, - double z, - Component text, - int lineWidth, - int backgroundColor, - byte textOpacity, - boolean seeThrough - ) { - throw new UnsupportedOperationException("Text display packets require 1.19.4+"); + public Object entityEvent(Object nmsEntity, byte event) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("entityEvent requires Entity"); + } + return new PacketPlayOutEntityStatus(entity, event); } @Override - public Object createRemoveEntities(int... entityIds) { - try { - Class type = Class.forName("net.minecraft.server.NMS.PacketPlayOutEntityDestroy"); - return type.getConstructor(int[].class).newInstance((Object) entityIds); - } catch (ReflectiveOperationException error) { - throw new UnsupportedOperationException("EntityDestroy unavailable", error); + public Object animate(Object nmsEntity, int action) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("animate requires Entity"); } + return new PacketPlayOutAnimation(entity, action); } @Override - public Object createSetEntityData(int entityId, List metadataEntries) { - throw new UnsupportedOperationException("SetEntityData construction is version-specific on legacy adapters"); + public Object rotateHead(Object nmsEntity, float yaw) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("rotateHead requires Entity"); + } + return new PacketPlayOutEntityHeadRotation(entity, (byte) Math.floor(yaw * 256.0f / 360.0f)); } @Override - public Object createBlockEvent(World world, int x, int y, int z, Object blockType, int type, int data) { - throw new UnsupportedOperationException("BlockEvent construction is version-specific on legacy adapters"); + public Object setCamera(Object nmsEntity) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("setCamera requires Entity"); + } + return new PacketPlayOutCamera(entity); } @Override - public Object createContainerSetSlot(int containerId, int stateId, int slot, ItemStack item) { - try { - Class type = Class.forName("net.minecraft.server.NMS.PacketPlayOutSetSlot"); - Object nms = CraftItemStack.asNMSCopy(item); - return type.getConstructor(int.class, int.class, nms.getClass()).newInstance(containerId, slot, nms); - } catch (ReflectiveOperationException error) { - throw new UnsupportedOperationException("SetSlot unavailable", error); + public Object setPassengers(Object nmsVehicle) { + if (!(nmsVehicle instanceof Entity entity)) { + throw new IllegalArgumentException("setPassengers requires Entity"); } + return new PacketPlayOutMount(entity); } @Override - public Object createSetHealth(float health, int food, float saturation) { + public Object collectItem(int collectedId, int collectorId, int amount) { + return new PacketPlayOutCollect(collectedId, collectorId, amount); + } + + @Override + public Object blockUpdate(int x, int y, int z, Object nmsBlockState) { + IBlockData state = nmsBlockState instanceof IBlockData data ? data : Blocks.AIR.getBlockData(); + BlockPosition pos = new BlockPosition(x, y, z); + // 1.16.5+: (BlockPosition, IBlockData). 1.16.1: only (IBlockAccess, BlockPosition). try { - Class type = Class.forName("net.minecraft.server.NMS.PacketPlayOutUpdateHealth"); - return type.getConstructor(float.class, int.class, float.class).newInstance(health, food, saturation); - } catch (ReflectiveOperationException error) { - throw new UnsupportedOperationException("UpdateHealth unavailable", error); + return PacketPlayOutBlockChange.class + .getConstructor(BlockPosition.class, IBlockData.class) + .newInstance(pos, state); + } catch (ReflectiveOperationException ignored) { } + try { + PacketPlayOutBlockChange packet = PacketPlayOutBlockChange.class + .getDeclaredConstructor() + .newInstance(); + set(field(PacketPlayOutBlockChange.class, "a"), packet, pos); + set(field(PacketPlayOutBlockChange.class, "block"), packet, state); + return packet; + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Unable to construct PacketPlayOutBlockChange", e); + } + } + + @Override + public Object blockEvent(int x, int y, int z, Object nmsBlock, int type, int data) { + Block block = nmsBlock instanceof Block b ? b : Blocks.ENDER_CHEST; + return new PacketPlayOutBlockAction(new BlockPosition(x, y, z), block, type, data); + } + + @Override + public Object blockDestruction(int entityId, int x, int y, int z, int progress) { + return new PacketPlayOutBlockBreakAnimation(entityId, new BlockPosition(x, y, z), progress); + } + + @Override + public Object setHealth(float health, int food, float saturation) { + return new PacketPlayOutUpdateHealth(health, food, saturation); + } + + @Override + public Object setExperience(float progress, int totalXp, int level) { + return new PacketPlayOutExperience(progress, totalXp, level); } } diff --git a/nms-shared/packet/mid/SharedPacketBridge.java b/nms-shared/packet/mid/SharedPacketBridge.java index bdfafab..ef2f373 100644 --- a/nms-shared/packet/mid/SharedPacketBridge.java +++ b/nms-shared/packet/mid/SharedPacketBridge.java @@ -1,18 +1,28 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.ArrayList; import java.util.List; -import org.bukkit.World; -import org.bukkit.craftbukkit.NMS.inventory.CraftItemStack; -import org.bukkit.inventory.ItemStack; - -import net.kyori.adventure.text.Component; -import org.mastersmp.packet.nms.PacketBridge; - -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.game.ClientboundAnimatePacket; +import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; +import net.minecraft.network.protocol.game.ClientboundBlockEventPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundSetCameraPacket; +import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket; +import net.minecraft.network.protocol.game.ClientboundSetHealthPacket; +import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; +import net.minecraft.network.protocol.game.ClientboundTakeItemEntityPacket; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.opmasterleo.packet.nms.PacketBridge; + +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedPacketBridge implements PacketBridge { @@ -34,11 +44,7 @@ public String classify(Object packet) { @Override public int entityId(Object packet) { Object value = invoke(packet, "getEntityId", "id", "entityId", "getId"); - if (value instanceof Integer i) { - return i; - } - Object field = get(field(packet.getClass(), "id", "entityId"), packet); - return field instanceof Integer i ? i : -1; + return value instanceof Integer i ? i : -1; } @Override @@ -55,68 +61,82 @@ public List unwrapBundle(Object packet) { } @Override - public Object rebuildBundle(List packets) { - throw new UnsupportedOperationException("Bundle rebuild is not available on this mid-version adapter"); + public Object removeEntities(int... entityIds) { + return new ClientboundRemoveEntitiesPacket(entityIds); } @Override - public Object createAddTextDisplay( - int entityId, - double x, - double y, - double z, - Component text, - int lineWidth, - int backgroundColor, - byte textOpacity, - boolean seeThrough - ) { - throw new UnsupportedOperationException("Text display packets require 1.19.4+"); + public Object entityEvent(Object nmsEntity, byte event) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("entityEvent requires net.minecraft.world.entity.Entity"); + } + return new ClientboundEntityEventPacket(entity, event); } @Override - public Object createRemoveEntities(int... entityIds) { - try { - Class type = Class.forName("net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket"); - return type.getConstructor(int[].class).newInstance((Object) entityIds); - } catch (ReflectiveOperationException error) { - throw new UnsupportedOperationException("RemoveEntities packet unavailable", error); + public Object animate(Object nmsEntity, int action) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("animate requires net.minecraft.world.entity.Entity"); } + return new ClientboundAnimatePacket(entity, action); } @Override - public Object createSetEntityData(int entityId, List metadataEntries) { - throw new UnsupportedOperationException("SetEntityData construction is version-specific on mid adapters"); + public Object rotateHead(Object nmsEntity, float yaw) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("rotateHead requires net.minecraft.world.entity.Entity"); + } + return new ClientboundRotateHeadPacket(entity, (byte) Math.floor(yaw * 256.0f / 360.0f)); } @Override - public Object createBlockEvent(World world, int x, int y, int z, Object blockType, int type, int data) { - throw new UnsupportedOperationException("BlockEvent construction is version-specific on mid adapters"); + public Object setCamera(Object nmsEntity) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("setCamera requires net.minecraft.world.entity.Entity"); + } + return new ClientboundSetCameraPacket(entity); } @Override - public Object createContainerSetSlot(int containerId, int stateId, int slot, ItemStack item) { - try { - Class type = Class.forName("net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket"); - Object nms = CraftItemStack.asNMSCopy(item); - try { - return type.getConstructor(int.class, int.class, int.class, nms.getClass()).newInstance(containerId, stateId, slot, nms); - } catch (NoSuchMethodException ignored) { - return type.getConstructor(int.class, int.class, nms.getClass()).newInstance(containerId, slot, nms); - } - } catch (ReflectiveOperationException error) { - throw new UnsupportedOperationException("ContainerSetSlot unavailable", error); + public Object setPassengers(Object nmsVehicle) { + if (!(nmsVehicle instanceof Entity entity)) { + throw new IllegalArgumentException("setPassengers requires net.minecraft.world.entity.Entity"); } + return new ClientboundSetPassengersPacket(entity); } @Override - public Object createSetHealth(float health, int food, float saturation) { - try { - Class type = Class.forName("net.minecraft.network.protocol.game.ClientboundSetHealthPacket"); - return type.getConstructor(float.class, int.class, float.class).newInstance(health, food, saturation); - } catch (ReflectiveOperationException error) { - throw new UnsupportedOperationException("SetHealth unavailable", error); - } + public Object collectItem(int collectedId, int collectorId, int amount) { + return new ClientboundTakeItemEntityPacket(collectedId, collectorId, amount); + } + + @Override + public Object blockUpdate(int x, int y, int z, Object nmsBlockState) { + BlockState state = nmsBlockState instanceof BlockState blockState + ? blockState + : Blocks.AIR.defaultBlockState(); + return new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), state); + } + + @Override + public Object blockEvent(int x, int y, int z, Object nmsBlock, int type, int data) { + Block block = nmsBlock instanceof Block b ? b : Blocks.ENDER_CHEST; + return new ClientboundBlockEventPacket(new BlockPos(x, y, z), block, type, data); + } + + @Override + public Object blockDestruction(int entityId, int x, int y, int z, int progress) { + return new ClientboundBlockDestructionPacket(entityId, new BlockPos(x, y, z), progress); + } + + @Override + public Object setHealth(float health, int food, float saturation) { + return new ClientboundSetHealthPacket(health, food, saturation); + } + + @Override + public Object setExperience(float progress, int totalXp, int level) { + return new ClientboundSetExperiencePacket(progress, totalXp, level); } private static String strip(String value, String prefix, String suffix) { diff --git a/nms-shared/packet/modern/SharedPacketBridge.java b/nms-shared/packet/modern/SharedPacketBridge.java index fb0d225..f12e3fa 100644 --- a/nms-shared/packet/modern/SharedPacketBridge.java +++ b/nms-shared/packet/modern/SharedPacketBridge.java @@ -1,30 +1,65 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; +import java.util.Locale; +import java.util.UUID; -import org.bukkit.World; -import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.inventory.ItemStack; - +import com.mojang.datafixers.util.Pair; import net.kyori.adventure.text.Component; import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.common.ClientboundDisconnectPacket; +import net.minecraft.network.protocol.common.ClientboundKeepAlivePacket; import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundAnimatePacket; +import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; import net.minecraft.network.protocol.game.ClientboundBlockEventPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundBundlePacket; -import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.network.protocol.game.ClientboundGameEventPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetCameraPacket; import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket; import net.minecraft.network.protocol.game.ClientboundSetHealthPacket; +import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTimePacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.game.ClientboundTabListPacket; +import net.minecraft.network.protocol.game.ClientboundTakeItemEntityPacket; +import net.minecraft.network.protocol.game.ServerboundInteractPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -import org.mastersmp.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.packet.BlockPosView; +import net.opmasterleo.packet.nms.packet.Hand; +import net.opmasterleo.packet.nms.packet.InteractAction; +import net.opmasterleo.packet.nms.packet.PacketViews; +import net.opmasterleo.packet.nms.packet.PlayerActionType; -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.field; +import static net.opmasterleo.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedPacketBridge implements PacketBridge { @@ -40,23 +75,21 @@ public String classify(Object packet) { if (simple.startsWith("Serverbound")) { return strip(simple, "Serverbound", "Packet"); } - if (simple.startsWith("PacketPlayOut")) { - return simple.substring("PacketPlayOut".length()); - } - if (simple.startsWith("PacketPlayIn")) { - return simple.substring("PacketPlayIn".length()); - } return simple; } @Override public int entityId(Object packet) { - Object value = invoke(packet, "getEntityId", "id", "entityId", "getId"); + if (packet == null) { + return -1; + } + // Method names drift across modern buckets (id/getId/getEntity/getEntityId). + Object value = invoke(packet, "getEntityId", "getEntity", "getId", "id", "entityId"); if (value instanceof Integer i) { return i; } - Object field = get(field(packet.getClass(), "id", "entityId"), packet); - return field instanceof Integer i ? i : -1; + Object fieldValue = get(field(packet.getClass(), "id", "entityId", "entity"), packet); + return fieldValue instanceof Integer i ? i : -1; } @Override @@ -77,23 +110,36 @@ public Object rebuildBundle(List packets) { } @Override - public Object createAddTextDisplay( - int entityId, - double x, - double y, - double z, - Component text, - int lineWidth, - int backgroundColor, - byte textOpacity, - boolean seeThrough - ) { + public Object addEntity(PacketViews.AddEntitySpec spec) { + EntityType type = spec.nmsEntityType() instanceof EntityType provided + ? provided + : EntityType.ARMOR_STAND; + PacketViews.EntityPose pose = spec.pose(); + PacketViews.Vec3d velocity = spec.velocity(); return new ClientboundAddEntityPacket( - entityId, - java.util.UUID.randomUUID(), - x, - y, - z, + spec.entityId(), + spec.uuid(), + pose.x(), + pose.y(), + pose.z(), + pose.pitch(), + pose.yaw(), + type, + spec.data(), + new Vec3(velocity.x(), velocity.y(), velocity.z()), + spec.headYaw() + ); + } + + @Override + public Object addTextDisplay(PacketViews.TextDisplaySpec spec) { + PacketViews.Vec3d pos = spec.pos(); + return new ClientboundAddEntityPacket( + spec.entityId(), + UUID.randomUUID(), + pos.x(), + pos.y(), + pos.z(), 0f, 0f, EntityType.TEXT_DISPLAY, @@ -104,38 +150,240 @@ public Object createAddTextDisplay( } @Override - public Object createRemoveEntities(int... entityIds) { + public Object removeEntities(int... entityIds) { return new ClientboundRemoveEntitiesPacket(entityIds); } @Override - public Object createSetEntityData(int entityId, List metadataEntries) { + public Object setEntityData(int entityId, List metadataEntries) { @SuppressWarnings("unchecked") List> values = (List>) metadataEntries; return new ClientboundSetEntityDataPacket(entityId, values); } @Override - public Object createBlockEvent(World world, int x, int y, int z, Object blockType, int type, int data) { - Block block = blockType instanceof Block b ? b : net.minecraft.world.level.block.Blocks.ENDER_CHEST; + public Object entityVelocity(int entityId, double vx, double vy, double vz) { + return new ClientboundSetEntityMotionPacket(entityId, new Vec3(vx, vy, vz)); + } + + @Override + public Object entityEvent(Object nmsEntity, byte event) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("entityEvent requires net.minecraft.world.entity.Entity"); + } + return new ClientboundEntityEventPacket(entity, event); + } + + @Override + public Object animate(Object nmsEntity, int action) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("animate requires net.minecraft.world.entity.Entity"); + } + return new ClientboundAnimatePacket(entity, action); + } + + @Override + public Object rotateHead(Object nmsEntity, float yaw) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("rotateHead requires net.minecraft.world.entity.Entity"); + } + return new ClientboundRotateHeadPacket(entity, (byte) Math.floor(yaw * 256.0f / 360.0f)); + } + + @Override + public Object setCamera(Object nmsEntity) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("setCamera requires net.minecraft.world.entity.Entity"); + } + return new ClientboundSetCameraPacket(entity); + } + + @Override + public Object setPassengers(Object nmsVehicle) { + if (!(nmsVehicle instanceof Entity entity)) { + throw new IllegalArgumentException("setPassengers requires net.minecraft.world.entity.Entity"); + } + return new ClientboundSetPassengersPacket(entity); + } + + @Override + public Object collectItem(int collectedId, int collectorId, int amount) { + return new ClientboundTakeItemEntityPacket(collectedId, collectorId, amount); + } + + @Override + public Object setEquipment(int entityId, List slots) { + List> pairs = new ArrayList<>(slots.size()); + for (PacketViews.EquipmentEntry entry : slots) { + net.minecraft.world.item.ItemStack item = entry.nmsItem() instanceof net.minecraft.world.item.ItemStack stack + ? stack + : net.minecraft.world.item.ItemStack.EMPTY; + pairs.add(Pair.of(equipmentSlot(entry.slot()), item)); + } + return new ClientboundSetEquipmentPacket(entityId, pairs); + } + + @Override + public Object blockUpdate(int x, int y, int z, Object nmsBlockState) { + BlockState state = nmsBlockState instanceof BlockState blockState + ? blockState + : Blocks.AIR.defaultBlockState(); + return new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), state); + } + + @Override + public Object blockEvent(int x, int y, int z, Object nmsBlock, int type, int data) { + Block block = nmsBlock instanceof Block b ? b : Blocks.ENDER_CHEST; return new ClientboundBlockEventPacket(new BlockPos(x, y, z), block, type, data); } @Override - public Object createContainerSetSlot(int containerId, int stateId, int slot, ItemStack item) { - return new ClientboundContainerSetSlotPacket( - containerId, - stateId, - slot, - CraftItemStack.asNMSCopy(item) - ); + public Object blockDestruction(int entityId, int x, int y, int z, int progress) { + return new ClientboundBlockDestructionPacket(entityId, new BlockPos(x, y, z), progress); } @Override - public Object createSetHealth(float health, int food, float saturation) { + public Object gameEvent(int eventId, float value) { + return new ClientboundGameEventPacket(new ClientboundGameEventPacket.Type(eventId), value); + } + + @Override + public Object setTime(long gameTime, long dayTime) { + return new ClientboundSetTimePacket(gameTime, dayTime, true); + } + + @Override + public Object setHealth(float health, int food, float saturation) { return new ClientboundSetHealthPacket(health, food, saturation); } + @Override + public Object setExperience(float progress, int totalXp, int level) { + return new ClientboundSetExperiencePacket(progress, totalXp, level); + } + + @Override + public Object systemChat(Component message, boolean overlay) { + return new ClientboundSystemChatPacket(vanilla(message), overlay); + } + + @Override + public Object actionBar(Component message) { + return new ClientboundSetActionBarTextPacket(vanilla(message)); + } + + @Override + public Object tabList(Component header, Component footer) { + return new ClientboundTabListPacket(vanilla(header), vanilla(footer)); + } + + @Override + public Object titleText(Component title) { + return new ClientboundSetTitleTextPacket(vanilla(title)); + } + + @Override + public Object subtitleText(Component subtitle) { + return new ClientboundSetSubtitleTextPacket(vanilla(subtitle)); + } + + @Override + public Object titleTimes(int fadeIn, int stay, int fadeOut) { + return new ClientboundSetTitlesAnimationPacket(fadeIn, stay, fadeOut); + } + + @Override + public Object clearTitles(boolean resetTimes) { + return new ClientboundClearTitlesPacket(resetTimes); + } + + @Override + public Object playerInfoRemove(List profileIds) { + return new ClientboundPlayerInfoRemovePacket(profileIds); + } + + @Override + public Object playerInfoAdd(Object nmsServerPlayer) { + if (!(nmsServerPlayer instanceof ServerPlayer sp)) { + throw new IllegalArgumentException("playerInfoAdd requires net.minecraft.server.level.ServerPlayer"); + } + return new ClientboundPlayerInfoUpdatePacket( + EnumSet.of( + ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME + ), + List.of(sp) + ); + } + + @Override + public Object keepAlive(long id) { + return new ClientboundKeepAlivePacket(id); + } + + @Override + public Object disconnect(Component reason) { + return new ClientboundDisconnectPacket(vanilla(reason)); + } + + @Override + public PacketViews.InteractView interact(Object packet) { + if (!(packet instanceof ServerboundInteractPacket interact)) { + return PacketBridge.super.interact(packet); + } + boolean attack = Boolean.TRUE.equals(invoke(interact, "isAttack")); + InteractAction action = attack ? InteractAction.ATTACK : InteractAction.INTERACT; + return new PacketViews.InteractView(entityId(interact), action, Hand.MAIN_HAND); + } + + @Override + public PacketViews.PlayerActionView playerAction(Object packet) { + if (!(packet instanceof ServerboundPlayerActionPacket action)) { + return PacketBridge.super.playerAction(packet); + } + BlockPos pos = action.getPos(); + return new PacketViews.PlayerActionView(playerActionType(action.getAction()), new BlockPosView(pos.getX(), pos.getY(), pos.getZ())); + } + + private static PlayerActionType playerActionType(ServerboundPlayerActionPacket.Action action) { + // String switch keeps older modern buckets compiling when newer enums add values (e.g. STAB). + return switch (action.name()) { + case "START_DESTROY_BLOCK" -> PlayerActionType.START_DESTROY_BLOCK; + case "ABORT_DESTROY_BLOCK" -> PlayerActionType.ABORT_DESTROY_BLOCK; + case "STOP_DESTROY_BLOCK" -> PlayerActionType.STOP_DESTROY_BLOCK; + case "DROP_ALL_ITEMS" -> PlayerActionType.DROP_ALL_ITEMS; + case "DROP_ITEM" -> PlayerActionType.DROP_ITEM; + case "RELEASE_USE_ITEM" -> PlayerActionType.RELEASE_USE_ITEM; + case "SWAP_ITEM_WITH_OFFHAND" -> PlayerActionType.SWAP_ITEM_WITH_OFFHAND; + case "STAB" -> PlayerActionType.UNKNOWN; + default -> PlayerActionType.UNKNOWN; + }; + } + + private static EquipmentSlot equipmentSlot(String name) { + if (name == null) { + return EquipmentSlot.MAINHAND; + } + return switch (name.toLowerCase(Locale.ROOT)) { + case "offhand", "off_hand" -> EquipmentSlot.OFFHAND; + case "feet", "boots" -> EquipmentSlot.FEET; + case "legs", "leggings" -> EquipmentSlot.LEGS; + case "chest" -> EquipmentSlot.CHEST; + case "head", "helmet" -> EquipmentSlot.HEAD; + case "body" -> EquipmentSlot.BODY; + default -> EquipmentSlot.MAINHAND; + }; + } + + private static net.minecraft.network.chat.Component vanilla(Component component) { + return io.papermc.paper.adventure.PaperAdventure.asVanilla( + component == null ? Component.empty() : component + ); + } + private static String strip(String value, String prefix, String suffix) { String out = value; if (out.startsWith(prefix)) { diff --git a/nms-shared/packet/modern26/SharedPacketBridge.java b/nms-shared/packet/modern26/SharedPacketBridge.java new file mode 100644 index 0000000..507700f --- /dev/null +++ b/nms-shared/packet/modern26/SharedPacketBridge.java @@ -0,0 +1,399 @@ +package net.opmasterleo.packet.nms.shared; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +import com.mojang.datafixers.util.Pair; +import net.kyori.adventure.text.Component; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.common.ClientboundDisconnectPacket; +import net.minecraft.network.protocol.common.ClientboundKeepAlivePacket; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundAnimatePacket; +import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; +import net.minecraft.network.protocol.game.ClientboundBlockEventPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; +import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.network.protocol.game.ClientboundGameEventPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetCameraPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket; +import net.minecraft.network.protocol.game.ClientboundSetHealthPacket; +import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTimePacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.game.ClientboundTabListPacket; +import net.minecraft.network.protocol.game.ClientboundTakeItemEntityPacket; +import net.minecraft.network.protocol.game.ServerboundInteractPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.opmasterleo.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.packet.BlockPosView; +import net.opmasterleo.packet.nms.packet.Hand; +import net.opmasterleo.packet.nms.packet.InteractAction; +import net.opmasterleo.packet.nms.packet.PacketViews; +import net.opmasterleo.packet.nms.packet.PlayerActionType; + +import static net.opmasterleo.packet.nms.shared.Reflect.field; +import static net.opmasterleo.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; + +public final class SharedPacketBridge implements PacketBridge { + + @Override + public String classify(Object packet) { + if (packet == null) { + return "Unknown"; + } + String simple = packet.getClass().getSimpleName(); + if (simple.startsWith("Clientbound")) { + return strip(simple, "Clientbound", "Packet"); + } + if (simple.startsWith("Serverbound")) { + return strip(simple, "Serverbound", "Packet"); + } + return simple; + } + + @Override + public int entityId(Object packet) { + if (packet == null) { + return -1; + } + // Method names drift across modern buckets (id/getId/getEntity/getEntityId). + Object value = invoke(packet, "getEntityId", "getEntity", "getId", "id", "entityId"); + if (value instanceof Integer i) { + return i; + } + Object fieldValue = get(field(packet.getClass(), "id", "entityId", "entity"), packet); + return fieldValue instanceof Integer i ? i : -1; + } + + @Override + public List unwrapBundle(Object packet) { + if (!(packet instanceof ClientboundBundlePacket bundle)) { + return List.of(); + } + List out = new ArrayList<>(); + bundle.subPackets().forEach(out::add); + return out; + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public Object rebuildBundle(List packets) { + List raw = new ArrayList(packets); + return new ClientboundBundlePacket(raw); + } + + @Override + public Object addEntity(PacketViews.AddEntitySpec spec) { + EntityType type = spec.nmsEntityType() instanceof EntityType provided + ? provided + : EntityType.ARMOR_STAND; + PacketViews.EntityPose pose = spec.pose(); + PacketViews.Vec3d velocity = spec.velocity(); + return new ClientboundAddEntityPacket( + spec.entityId(), + spec.uuid(), + pose.x(), + pose.y(), + pose.z(), + pose.pitch(), + pose.yaw(), + type, + spec.data(), + new Vec3(velocity.x(), velocity.y(), velocity.z()), + spec.headYaw() + ); + } + + @Override + public Object addTextDisplay(PacketViews.TextDisplaySpec spec) { + PacketViews.Vec3d pos = spec.pos(); + return new ClientboundAddEntityPacket( + spec.entityId(), + UUID.randomUUID(), + pos.x(), + pos.y(), + pos.z(), + 0f, + 0f, + EntityType.TEXT_DISPLAY, + 0, + Vec3.ZERO, + 0.0 + ); + } + + @Override + public Object removeEntities(int... entityIds) { + return new ClientboundRemoveEntitiesPacket(entityIds); + } + + @Override + public Object setEntityData(int entityId, List metadataEntries) { + @SuppressWarnings("unchecked") + List> values = (List>) metadataEntries; + return new ClientboundSetEntityDataPacket(entityId, values); + } + + @Override + public Object entityVelocity(int entityId, double vx, double vy, double vz) { + return new ClientboundSetEntityMotionPacket(entityId, new Vec3(vx, vy, vz)); + } + + @Override + public Object entityEvent(Object nmsEntity, byte event) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("entityEvent requires net.minecraft.world.entity.Entity"); + } + return new ClientboundEntityEventPacket(entity, event); + } + + @Override + public Object animate(Object nmsEntity, int action) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("animate requires net.minecraft.world.entity.Entity"); + } + return new ClientboundAnimatePacket(entity, action); + } + + @Override + public Object rotateHead(Object nmsEntity, float yaw) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("rotateHead requires net.minecraft.world.entity.Entity"); + } + return new ClientboundRotateHeadPacket(entity, (byte) Math.floor(yaw * 256.0f / 360.0f)); + } + + @Override + public Object setCamera(Object nmsEntity) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("setCamera requires net.minecraft.world.entity.Entity"); + } + return new ClientboundSetCameraPacket(entity); + } + + @Override + public Object setPassengers(Object nmsVehicle) { + if (!(nmsVehicle instanceof Entity entity)) { + throw new IllegalArgumentException("setPassengers requires net.minecraft.world.entity.Entity"); + } + return new ClientboundSetPassengersPacket(entity); + } + + @Override + public Object collectItem(int collectedId, int collectorId, int amount) { + return new ClientboundTakeItemEntityPacket(collectedId, collectorId, amount); + } + + @Override + public Object setEquipment(int entityId, List slots) { + List> pairs = new ArrayList<>(slots.size()); + for (PacketViews.EquipmentEntry entry : slots) { + net.minecraft.world.item.ItemStack item = entry.nmsItem() instanceof net.minecraft.world.item.ItemStack stack + ? stack + : net.minecraft.world.item.ItemStack.EMPTY; + pairs.add(Pair.of(equipmentSlot(entry.slot()), item)); + } + return new ClientboundSetEquipmentPacket(entityId, pairs); + } + + @Override + public Object blockUpdate(int x, int y, int z, Object nmsBlockState) { + BlockState state = nmsBlockState instanceof BlockState blockState + ? blockState + : Blocks.AIR.defaultBlockState(); + return new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), state); + } + + @Override + public Object blockEvent(int x, int y, int z, Object nmsBlock, int type, int data) { + Block block = nmsBlock instanceof Block b ? b : Blocks.ENDER_CHEST; + return new ClientboundBlockEventPacket(new BlockPos(x, y, z), block, type, data); + } + + @Override + public Object blockDestruction(int entityId, int x, int y, int z, int progress) { + return new ClientboundBlockDestructionPacket(entityId, new BlockPos(x, y, z), progress); + } + + @Override + public Object gameEvent(int eventId, float value) { + return new ClientboundGameEventPacket(new ClientboundGameEventPacket.Type(eventId), value); + } + + @Override + public Object setTime(long gameTime, long dayTime) { + // 26.x replaced (gameTime, dayTime, tickDayTime) with (gameTime, clockUpdates). + return new ClientboundSetTimePacket(gameTime, Map.of()); + } + + @Override + public Object setHealth(float health, int food, float saturation) { + return new ClientboundSetHealthPacket(health, food, saturation); + } + + @Override + public Object setExperience(float progress, int totalXp, int level) { + return new ClientboundSetExperiencePacket(progress, totalXp, level); + } + + @Override + public Object systemChat(Component message, boolean overlay) { + return new ClientboundSystemChatPacket(vanilla(message), overlay); + } + + @Override + public Object actionBar(Component message) { + return new ClientboundSetActionBarTextPacket(vanilla(message)); + } + + @Override + public Object tabList(Component header, Component footer) { + return new ClientboundTabListPacket(vanilla(header), vanilla(footer)); + } + + @Override + public Object titleText(Component title) { + return new ClientboundSetTitleTextPacket(vanilla(title)); + } + + @Override + public Object subtitleText(Component subtitle) { + return new ClientboundSetSubtitleTextPacket(vanilla(subtitle)); + } + + @Override + public Object titleTimes(int fadeIn, int stay, int fadeOut) { + return new ClientboundSetTitlesAnimationPacket(fadeIn, stay, fadeOut); + } + + @Override + public Object clearTitles(boolean resetTimes) { + return new ClientboundClearTitlesPacket(resetTimes); + } + + @Override + public Object playerInfoRemove(List profileIds) { + return new ClientboundPlayerInfoRemovePacket(profileIds); + } + + @Override + public Object playerInfoAdd(Object nmsServerPlayer) { + if (!(nmsServerPlayer instanceof ServerPlayer sp)) { + throw new IllegalArgumentException("playerInfoAdd requires net.minecraft.server.level.ServerPlayer"); + } + return new ClientboundPlayerInfoUpdatePacket( + EnumSet.of( + ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME + ), + List.of(sp) + ); + } + + @Override + public Object keepAlive(long id) { + return new ClientboundKeepAlivePacket(id); + } + + @Override + public Object disconnect(Component reason) { + return new ClientboundDisconnectPacket(vanilla(reason)); + } + + @Override + public PacketViews.InteractView interact(Object packet) { + if (!(packet instanceof ServerboundInteractPacket interact)) { + return PacketBridge.super.interact(packet); + } + boolean attack = Boolean.TRUE.equals(invoke(interact, "isAttack")); + InteractAction action = attack ? InteractAction.ATTACK : InteractAction.INTERACT; + return new PacketViews.InteractView(entityId(interact), action, Hand.MAIN_HAND); + } + + @Override + public PacketViews.PlayerActionView playerAction(Object packet) { + if (!(packet instanceof ServerboundPlayerActionPacket action)) { + return PacketBridge.super.playerAction(packet); + } + BlockPos pos = action.getPos(); + return new PacketViews.PlayerActionView(playerActionType(action.getAction()), new BlockPosView(pos.getX(), pos.getY(), pos.getZ())); + } + + private static PlayerActionType playerActionType(ServerboundPlayerActionPacket.Action action) { + // String switch keeps older modern buckets compiling when newer enums add values (e.g. STAB). + return switch (action.name()) { + case "START_DESTROY_BLOCK" -> PlayerActionType.START_DESTROY_BLOCK; + case "ABORT_DESTROY_BLOCK" -> PlayerActionType.ABORT_DESTROY_BLOCK; + case "STOP_DESTROY_BLOCK" -> PlayerActionType.STOP_DESTROY_BLOCK; + case "DROP_ALL_ITEMS" -> PlayerActionType.DROP_ALL_ITEMS; + case "DROP_ITEM" -> PlayerActionType.DROP_ITEM; + case "RELEASE_USE_ITEM" -> PlayerActionType.RELEASE_USE_ITEM; + case "SWAP_ITEM_WITH_OFFHAND" -> PlayerActionType.SWAP_ITEM_WITH_OFFHAND; + case "STAB" -> PlayerActionType.UNKNOWN; + default -> PlayerActionType.UNKNOWN; + }; + } + + private static EquipmentSlot equipmentSlot(String name) { + if (name == null) { + return EquipmentSlot.MAINHAND; + } + return switch (name.toLowerCase(Locale.ROOT)) { + case "offhand", "off_hand" -> EquipmentSlot.OFFHAND; + case "feet", "boots" -> EquipmentSlot.FEET; + case "legs", "leggings" -> EquipmentSlot.LEGS; + case "chest" -> EquipmentSlot.CHEST; + case "head", "helmet" -> EquipmentSlot.HEAD; + case "body" -> EquipmentSlot.BODY; + default -> EquipmentSlot.MAINHAND; + }; + } + + private static net.minecraft.network.chat.Component vanilla(Component component) { + return io.papermc.paper.adventure.PaperAdventure.asVanilla( + component == null ? Component.empty() : component + ); + } + + private static String strip(String value, String prefix, String suffix) { + String out = value; + if (out.startsWith(prefix)) { + out = out.substring(prefix.length()); + } + if (out.endsWith(suffix)) { + out = out.substring(0, out.length() - suffix.length()); + } + return out; + } +} diff --git a/nms-shared/packet/modern26_2/SharedPacketBridge.java b/nms-shared/packet/modern26_2/SharedPacketBridge.java new file mode 100644 index 0000000..92d6952 --- /dev/null +++ b/nms-shared/packet/modern26_2/SharedPacketBridge.java @@ -0,0 +1,400 @@ +package net.opmasterleo.packet.nms.shared; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +import com.mojang.datafixers.util.Pair; +import net.kyori.adventure.text.Component; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.common.ClientboundDisconnectPacket; +import net.minecraft.network.protocol.common.ClientboundKeepAlivePacket; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundAnimatePacket; +import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; +import net.minecraft.network.protocol.game.ClientboundBlockEventPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; +import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.network.protocol.game.ClientboundGameEventPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetCameraPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket; +import net.minecraft.network.protocol.game.ClientboundSetHealthPacket; +import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTimePacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.game.ClientboundTabListPacket; +import net.minecraft.network.protocol.game.ClientboundTakeItemEntityPacket; +import net.minecraft.network.protocol.game.ServerboundInteractPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.opmasterleo.packet.nms.PacketBridge; +import net.opmasterleo.packet.nms.packet.BlockPosView; +import net.opmasterleo.packet.nms.packet.Hand; +import net.opmasterleo.packet.nms.packet.InteractAction; +import net.opmasterleo.packet.nms.packet.PacketViews; +import net.opmasterleo.packet.nms.packet.PlayerActionType; + +import static net.opmasterleo.packet.nms.shared.Reflect.field; +import static net.opmasterleo.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; + +public final class SharedPacketBridge implements PacketBridge { + + @Override + public String classify(Object packet) { + if (packet == null) { + return "Unknown"; + } + String simple = packet.getClass().getSimpleName(); + if (simple.startsWith("Clientbound")) { + return strip(simple, "Clientbound", "Packet"); + } + if (simple.startsWith("Serverbound")) { + return strip(simple, "Serverbound", "Packet"); + } + return simple; + } + + @Override + public int entityId(Object packet) { + if (packet == null) { + return -1; + } + // Method names drift across modern buckets (id/getId/getEntity/getEntityId). + Object value = invoke(packet, "getEntityId", "getEntity", "getId", "id", "entityId"); + if (value instanceof Integer i) { + return i; + } + Object fieldValue = get(field(packet.getClass(), "id", "entityId", "entity"), packet); + return fieldValue instanceof Integer i ? i : -1; + } + + @Override + public List unwrapBundle(Object packet) { + if (!(packet instanceof ClientboundBundlePacket bundle)) { + return List.of(); + } + List out = new ArrayList<>(); + bundle.subPackets().forEach(out::add); + return out; + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public Object rebuildBundle(List packets) { + List raw = new ArrayList(packets); + return new ClientboundBundlePacket(raw); + } + + @Override + public Object addEntity(PacketViews.AddEntitySpec spec) { + EntityType type = spec.nmsEntityType() instanceof EntityType provided + ? provided + : EntityTypes.ARMOR_STAND; + PacketViews.EntityPose pose = spec.pose(); + PacketViews.Vec3d velocity = spec.velocity(); + return new ClientboundAddEntityPacket( + spec.entityId(), + spec.uuid(), + pose.x(), + pose.y(), + pose.z(), + pose.pitch(), + pose.yaw(), + type, + spec.data(), + new Vec3(velocity.x(), velocity.y(), velocity.z()), + spec.headYaw() + ); + } + + @Override + public Object addTextDisplay(PacketViews.TextDisplaySpec spec) { + PacketViews.Vec3d pos = spec.pos(); + return new ClientboundAddEntityPacket( + spec.entityId(), + UUID.randomUUID(), + pos.x(), + pos.y(), + pos.z(), + 0f, + 0f, + EntityTypes.TEXT_DISPLAY, + 0, + Vec3.ZERO, + 0.0 + ); + } + + @Override + public Object removeEntities(int... entityIds) { + return new ClientboundRemoveEntitiesPacket(entityIds); + } + + @Override + public Object setEntityData(int entityId, List metadataEntries) { + @SuppressWarnings("unchecked") + List> values = (List>) metadataEntries; + return new ClientboundSetEntityDataPacket(entityId, values); + } + + @Override + public Object entityVelocity(int entityId, double vx, double vy, double vz) { + return new ClientboundSetEntityMotionPacket(entityId, new Vec3(vx, vy, vz)); + } + + @Override + public Object entityEvent(Object nmsEntity, byte event) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("entityEvent requires net.minecraft.world.entity.Entity"); + } + return new ClientboundEntityEventPacket(entity, event); + } + + @Override + public Object animate(Object nmsEntity, int action) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("animate requires net.minecraft.world.entity.Entity"); + } + return new ClientboundAnimatePacket(entity, action); + } + + @Override + public Object rotateHead(Object nmsEntity, float yaw) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("rotateHead requires net.minecraft.world.entity.Entity"); + } + return new ClientboundRotateHeadPacket(entity, (byte) Math.floor(yaw * 256.0f / 360.0f)); + } + + @Override + public Object setCamera(Object nmsEntity) { + if (!(nmsEntity instanceof Entity entity)) { + throw new IllegalArgumentException("setCamera requires net.minecraft.world.entity.Entity"); + } + return new ClientboundSetCameraPacket(entity); + } + + @Override + public Object setPassengers(Object nmsVehicle) { + if (!(nmsVehicle instanceof Entity entity)) { + throw new IllegalArgumentException("setPassengers requires net.minecraft.world.entity.Entity"); + } + return new ClientboundSetPassengersPacket(entity); + } + + @Override + public Object collectItem(int collectedId, int collectorId, int amount) { + return new ClientboundTakeItemEntityPacket(collectedId, collectorId, amount); + } + + @Override + public Object setEquipment(int entityId, List slots) { + List> pairs = new ArrayList<>(slots.size()); + for (PacketViews.EquipmentEntry entry : slots) { + net.minecraft.world.item.ItemStack item = entry.nmsItem() instanceof net.minecraft.world.item.ItemStack stack + ? stack + : net.minecraft.world.item.ItemStack.EMPTY; + pairs.add(Pair.of(equipmentSlot(entry.slot()), item)); + } + return new ClientboundSetEquipmentPacket(entityId, pairs); + } + + @Override + public Object blockUpdate(int x, int y, int z, Object nmsBlockState) { + BlockState state = nmsBlockState instanceof BlockState blockState + ? blockState + : Blocks.AIR.defaultBlockState(); + return new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), state); + } + + @Override + public Object blockEvent(int x, int y, int z, Object nmsBlock, int type, int data) { + Block block = nmsBlock instanceof Block b ? b : Blocks.ENDER_CHEST; + return new ClientboundBlockEventPacket(new BlockPos(x, y, z), block, type, data); + } + + @Override + public Object blockDestruction(int entityId, int x, int y, int z, int progress) { + return new ClientboundBlockDestructionPacket(entityId, new BlockPos(x, y, z), progress); + } + + @Override + public Object gameEvent(int eventId, float value) { + return new ClientboundGameEventPacket(new ClientboundGameEventPacket.Type(eventId), value); + } + + @Override + public Object setTime(long gameTime, long dayTime) { + // 26.x replaced (gameTime, dayTime, tickDayTime) with (gameTime, clockUpdates). + return new ClientboundSetTimePacket(gameTime, Map.of()); + } + + @Override + public Object setHealth(float health, int food, float saturation) { + return new ClientboundSetHealthPacket(health, food, saturation); + } + + @Override + public Object setExperience(float progress, int totalXp, int level) { + return new ClientboundSetExperiencePacket(progress, totalXp, level); + } + + @Override + public Object systemChat(Component message, boolean overlay) { + return new ClientboundSystemChatPacket(vanilla(message), overlay); + } + + @Override + public Object actionBar(Component message) { + return new ClientboundSetActionBarTextPacket(vanilla(message)); + } + + @Override + public Object tabList(Component header, Component footer) { + return new ClientboundTabListPacket(vanilla(header), vanilla(footer)); + } + + @Override + public Object titleText(Component title) { + return new ClientboundSetTitleTextPacket(vanilla(title)); + } + + @Override + public Object subtitleText(Component subtitle) { + return new ClientboundSetSubtitleTextPacket(vanilla(subtitle)); + } + + @Override + public Object titleTimes(int fadeIn, int stay, int fadeOut) { + return new ClientboundSetTitlesAnimationPacket(fadeIn, stay, fadeOut); + } + + @Override + public Object clearTitles(boolean resetTimes) { + return new ClientboundClearTitlesPacket(resetTimes); + } + + @Override + public Object playerInfoRemove(List profileIds) { + return new ClientboundPlayerInfoRemovePacket(profileIds); + } + + @Override + public Object playerInfoAdd(Object nmsServerPlayer) { + if (!(nmsServerPlayer instanceof ServerPlayer sp)) { + throw new IllegalArgumentException("playerInfoAdd requires net.minecraft.server.level.ServerPlayer"); + } + return new ClientboundPlayerInfoUpdatePacket( + EnumSet.of( + ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, + ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME + ), + List.of(sp) + ); + } + + @Override + public Object keepAlive(long id) { + return new ClientboundKeepAlivePacket(id); + } + + @Override + public Object disconnect(Component reason) { + return new ClientboundDisconnectPacket(vanilla(reason)); + } + + @Override + public PacketViews.InteractView interact(Object packet) { + if (!(packet instanceof ServerboundInteractPacket interact)) { + return PacketBridge.super.interact(packet); + } + boolean attack = Boolean.TRUE.equals(invoke(interact, "isAttack")); + InteractAction action = attack ? InteractAction.ATTACK : InteractAction.INTERACT; + return new PacketViews.InteractView(entityId(interact), action, Hand.MAIN_HAND); + } + + @Override + public PacketViews.PlayerActionView playerAction(Object packet) { + if (!(packet instanceof ServerboundPlayerActionPacket action)) { + return PacketBridge.super.playerAction(packet); + } + BlockPos pos = action.getPos(); + return new PacketViews.PlayerActionView(playerActionType(action.getAction()), new BlockPosView(pos.getX(), pos.getY(), pos.getZ())); + } + + private static PlayerActionType playerActionType(ServerboundPlayerActionPacket.Action action) { + // String switch keeps older modern buckets compiling when newer enums add values (e.g. STAB). + return switch (action.name()) { + case "START_DESTROY_BLOCK" -> PlayerActionType.START_DESTROY_BLOCK; + case "ABORT_DESTROY_BLOCK" -> PlayerActionType.ABORT_DESTROY_BLOCK; + case "STOP_DESTROY_BLOCK" -> PlayerActionType.STOP_DESTROY_BLOCK; + case "DROP_ALL_ITEMS" -> PlayerActionType.DROP_ALL_ITEMS; + case "DROP_ITEM" -> PlayerActionType.DROP_ITEM; + case "RELEASE_USE_ITEM" -> PlayerActionType.RELEASE_USE_ITEM; + case "SWAP_ITEM_WITH_OFFHAND" -> PlayerActionType.SWAP_ITEM_WITH_OFFHAND; + case "STAB" -> PlayerActionType.UNKNOWN; + default -> PlayerActionType.UNKNOWN; + }; + } + + private static EquipmentSlot equipmentSlot(String name) { + if (name == null) { + return EquipmentSlot.MAINHAND; + } + return switch (name.toLowerCase(Locale.ROOT)) { + case "offhand", "off_hand" -> EquipmentSlot.OFFHAND; + case "feet", "boots" -> EquipmentSlot.FEET; + case "legs", "leggings" -> EquipmentSlot.LEGS; + case "chest" -> EquipmentSlot.CHEST; + case "head", "helmet" -> EquipmentSlot.HEAD; + case "body" -> EquipmentSlot.BODY; + default -> EquipmentSlot.MAINHAND; + }; + } + + private static net.minecraft.network.chat.Component vanilla(Component component) { + return io.papermc.paper.adventure.PaperAdventure.asVanilla( + component == null ? Component.empty() : component + ); + } + + private static String strip(String value, String prefix, String suffix) { + String out = value; + if (out.startsWith(prefix)) { + out = out.substring(prefix.length()); + } + if (out.endsWith(suffix)) { + out = out.substring(0, out.length() - suffix.length()); + } + return out; + } +} diff --git a/nms-shared/player/legacy/SharedPlayerBridge.java b/nms-shared/player/legacy/SharedPlayerBridge.java index f5380d1..65350a0 100644 --- a/nms-shared/player/legacy/SharedPlayerBridge.java +++ b/nms-shared/player/legacy/SharedPlayerBridge.java @@ -1,11 +1,11 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.NMS.entity.CraftPlayer; import org.bukkit.entity.Player; import net.minecraft.server.NMS.EntityPlayer; import net.minecraft.server.NMS.Packet; -import org.mastersmp.packet.nms.PlayerBridge; +import net.opmasterleo.packet.nms.PlayerBridge; public final class SharedPlayerBridge implements PlayerBridge { @@ -23,14 +23,31 @@ public void send(Player player, Object nmsPacket) { if (!(nmsPacket instanceof Packet packet)) { return; } - Object handle = handle(player); - if (handle instanceof EntityPlayer sp && sp.playerConnection != null) { + EntityPlayer sp = nms(player); + if (sp != null && sp.playerConnection != null) { sp.playerConnection.sendPacket(packet); } } @Override public boolean isConnected(Player player) { - return player != null && player.isOnline(); + EntityPlayer sp = nms(player); + return sp != null && sp.playerConnection != null && player.isOnline(); + } + + @Override + public int entityId(Player player) { + EntityPlayer sp = nms(player); + return sp == null ? -1 : sp.getId(); + } + + @Override + public Object level(Player player) { + EntityPlayer sp = nms(player); + return sp == null ? null : sp.world; + } + + private static EntityPlayer nms(Player player) { + return player instanceof CraftPlayer craft ? craft.getHandle() : null; } } diff --git a/nms-shared/player/mid/SharedPlayerBridge.java b/nms-shared/player/mid/SharedPlayerBridge.java index 5f42cb5..9928cc8 100644 --- a/nms-shared/player/mid/SharedPlayerBridge.java +++ b/nms-shared/player/mid/SharedPlayerBridge.java @@ -1,11 +1,11 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.NMS.entity.CraftPlayer; import org.bukkit.entity.Player; import net.minecraft.network.protocol.Packet; import net.minecraft.server.level.ServerPlayer; -import org.mastersmp.packet.nms.PlayerBridge; +import net.opmasterleo.packet.nms.PlayerBridge; public final class SharedPlayerBridge implements PlayerBridge { @@ -23,14 +23,25 @@ public void send(Player player, Object nmsPacket) { if (!(nmsPacket instanceof Packet packet)) { return; } - Object handle = handle(player); - if (handle instanceof ServerPlayer sp && sp.connection != null) { + ServerPlayer sp = nms(player); + if (sp != null && sp.connection != null) { sp.connection.send(packet); } } @Override public boolean isConnected(Player player) { - return player != null && player.isOnline(); + ServerPlayer sp = nms(player); + return sp != null && sp.connection != null && player.isOnline(); + } + + @Override + public int entityId(Player player) { + ServerPlayer sp = nms(player); + return sp == null ? -1 : sp.getId(); + } + + private static ServerPlayer nms(Player player) { + return player instanceof CraftPlayer craft ? craft.getHandle() : null; } } diff --git a/nms-shared/player/modern/SharedPlayerBridge.java b/nms-shared/player/modern/SharedPlayerBridge.java index 87888f7..a5d8296 100644 --- a/nms-shared/player/modern/SharedPlayerBridge.java +++ b/nms-shared/player/modern/SharedPlayerBridge.java @@ -1,11 +1,11 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import net.minecraft.network.protocol.Packet; import net.minecraft.server.level.ServerPlayer; -import org.mastersmp.packet.nms.PlayerBridge; +import net.opmasterleo.packet.nms.PlayerBridge; public final class SharedPlayerBridge implements PlayerBridge { @@ -23,18 +23,31 @@ public void send(Player player, Object nmsPacket) { if (!(nmsPacket instanceof Packet packet)) { return; } - Object handle = handle(player); - if (handle instanceof ServerPlayer sp && sp.connection != null) { + ServerPlayer sp = nms(player); + if (sp != null && sp.connection != null) { sp.connection.send(packet); } } @Override public boolean isConnected(Player player) { - Object handle = handle(player); - if (!(handle instanceof ServerPlayer sp) || sp.connection == null) { - return false; - } - return sp.connection.isAcceptingMessages(); + ServerPlayer sp = nms(player); + return sp != null && sp.connection != null && sp.connection.isAcceptingMessages(); + } + + @Override + public int entityId(Player player) { + ServerPlayer sp = nms(player); + return sp == null ? -1 : sp.getId(); + } + + @Override + public Object level(Player player) { + ServerPlayer sp = nms(player); + return sp == null ? null : sp.level(); + } + + private static ServerPlayer nms(Player player) { + return player instanceof CraftPlayer craft ? craft.getHandle() : null; } } diff --git a/nms-shared/world/legacy/SharedWorldBridge.java b/nms-shared/world/legacy/SharedWorldBridge.java index 55de966..df68861 100644 --- a/nms-shared/world/legacy/SharedWorldBridge.java +++ b/nms-shared/world/legacy/SharedWorldBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.stream.Stream; @@ -6,9 +6,9 @@ import org.bukkit.craftbukkit.NMS.CraftWorld; import org.bukkit.entity.Entity; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.WorldBridge; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedWorldBridge implements WorldBridge { diff --git a/nms-shared/world/mid/SharedWorldBridge.java b/nms-shared/world/mid/SharedWorldBridge.java index 55de966..df68861 100644 --- a/nms-shared/world/mid/SharedWorldBridge.java +++ b/nms-shared/world/mid/SharedWorldBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.stream.Stream; @@ -6,9 +6,9 @@ import org.bukkit.craftbukkit.NMS.CraftWorld; import org.bukkit.entity.Entity; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.WorldBridge; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedWorldBridge implements WorldBridge { diff --git a/nms-shared/world/modern/SharedWorldBridge.java b/nms-shared/world/modern/SharedWorldBridge.java index 23a8fbc..bb065e4 100644 --- a/nms-shared/world/modern/SharedWorldBridge.java +++ b/nms-shared/world/modern/SharedWorldBridge.java @@ -1,4 +1,4 @@ -package org.mastersmp.packet.nms.shared; +package net.opmasterleo.packet.nms.shared; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -13,11 +13,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.levelgen.Heightmap; -import org.mastersmp.packet.nms.WorldBridge; +import net.opmasterleo.packet.nms.WorldBridge; -import static org.mastersmp.packet.nms.shared.Reflect.field; -import static org.mastersmp.packet.nms.shared.Reflect.get; -import static org.mastersmp.packet.nms.shared.Reflect.invoke; +import static net.opmasterleo.packet.nms.shared.Reflect.field; +import static net.opmasterleo.packet.nms.shared.Reflect.get; +import static net.opmasterleo.packet.nms.shared.Reflect.invoke; public final class SharedWorldBridge implements WorldBridge { @@ -36,12 +36,24 @@ public Stream entities(World world) { return Stream.empty(); } return StreamSupport.stream(serverLevel.getAllEntities().spliterator(), false) - .map(entity -> new EntityHandle( - entity, - entity.getId(), - entity.chunkPosition().x, - entity.chunkPosition().z - )); + .map(entity -> { + Object chunkPos = entity.chunkPosition(); + return new EntityHandle( + entity, + entity.getId(), + chunkCoord(chunkPos, "x"), + chunkCoord(chunkPos, "z") + ); + }); + } + + private static int chunkCoord(Object chunkPos, String name) { + Object value = invoke(chunkPos, name, "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1)); + if (value instanceof Integer i) { + return i; + } + Object fieldValue = get(field(chunkPos.getClass(), name), chunkPos); + return fieldValue instanceof Integer i ? i : 0; } @Override diff --git a/nms-shared/wrapper/modern/SharedPacketWrapper.java b/nms-shared/wrapper/modern/SharedPacketWrapper.java deleted file mode 100644 index a9ccfbe..0000000 --- a/nms-shared/wrapper/modern/SharedPacketWrapper.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.mastersmp.packet.nms.shared; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelDuplexHandler; -import net.minecraft.network.Connection; -import net.minecraft.network.protocol.Packet; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.network.ServerGamePacketListenerImpl; -import org.bukkit.entity.Player; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.mastersmp.packet.nms.PacketWrapper; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -public final class SharedPacketWrapper implements PacketWrapper { - - private static final List ACTIVE_HANDLERS = new CopyOnWriteArrayList<>(); - - @Override - public void injectHandler(Player player, PacketHandler handler) { - ServerPlayer sp = handle(player); - if (sp == null || sp.connection == null) { - return; - } - - Connection connection = sp.connection instanceof ServerGamePacketListenerImpl listener - ? listener.connection - : null; - - if (connection == null || connection.channel == null) { - return; - } - - ChannelPipeline pipeline = connection.channel.pipeline(); - String handlerName = handler.getName(); - - // Remove existing handler if present - if (pipeline.names().contains(handlerName)) { - pipeline.remove(handlerName); - } - - // Add new handler - pipeline.addAfter("decoder", handlerName, new ChannelDuplexHandler() { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - if (msg instanceof Packet packet) { - if (handler.onPacketReceive(packet, sp)) { - return; // Cancel packet - } - } - ctx.fireChannelRead(msg); - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, io.netty.channel.ChannelPromise promise) { - if (msg instanceof Packet packet) { - if (handler.onPacketSend(packet, sp)) { - return; // Cancel packet - } - } - ctx.write(msg, promise); - } - }); - - ACTIVE_HANDLERS.add(new ActiveHandler(player.getUniqueId(), handlerName)); - } - - @Override - public void removeHandler(Player player, String handlerName) { - ServerPlayer sp = handle(player); - if (sp == null || sp.connection == null) { - return; - } - - Connection connection = sp.connection instanceof ServerGamePacketListenerImpl listener - ? listener.connection - : null; - - if (connection == null || connection.channel == null) { - return; - } - - ChannelPipeline pipeline = connection.channel.pipeline(); - if (pipeline.names().contains(handlerName)) { - pipeline.remove(handlerName); - } - - ACTIVE_HANDLERS.removeIf(h -> h.playerId().equals(player.getUniqueId()) && h.handlerName().equals(handlerName)); - } - - @Override - public Object getConnection(Player player) { - ServerPlayer sp = handle(player); - if (sp == null || sp.connection == null) { - return null; - } - return sp.connection instanceof ServerGamePacketListenerImpl listener - ? listener.connection - : sp.connection; - } - - @Override - public Object getChannel(Player player) { - ServerPlayer sp = handle(player); - if (sp == null || sp.connection == null) { - return null; - } - Connection connection = sp.connection instanceof ServerGamePacketListenerImpl listener - ? listener.connection - : null; - return connection != null ? connection.channel : null; - } - - @Override - public boolean hasHandler(Player player, String handlerName) { - ServerPlayer sp = handle(player); - if (sp == null || sp.connection == null) { - return false; - } - - Connection connection = sp.connection instanceof ServerGamePacketListenerImpl listener - ? listener.connection - : null; - - if (connection == null || connection.channel == null) { - return false; - } - - return connection.channel.pipeline().names().contains(handlerName); - } - - private static ServerPlayer handle(Player player) { - if (player instanceof CraftPlayer craft) { - return craft.getHandle(); - } - return null; - } - - private record ActiveHandler(java.util.UUID playerId, String handlerName) {} -} diff --git a/nms/shared-sources.gradle.kts b/nms/shared-sources.gradle.kts index dcb479a..26c8e1e 100644 --- a/nms/shared-sources.gradle.kts +++ b/nms/shared-sources.gradle.kts @@ -1,7 +1,7 @@ import org.gradle.api.plugins.JavaPluginExtension val sharedOut = layout.buildDirectory.dir("generated-shared") -val versionSharedPackage = "org.mastersmp.packet.nms.${project.name}.shared" +val versionSharedPackage = "net.opmasterleo.packet.nms.${project.name}.shared" val versionSharedPath = versionSharedPackage.replace('.', '/') val era = project.findProperty("nmsEra")?.toString() ?: "modern" val nmsVersion = project.findProperty("nmsVersion")?.toString() ?: project.name @@ -23,12 +23,14 @@ val parts: SharedParts = when (era) { "modern" -> SharedParts("modern", "modern", "modern", "modern", "modern", "modern", "modern") "modern21_2" -> SharedParts("modern", "modern", "modern", "modern", "modern", "modern", "modern") "modern21_5" -> SharedParts("modern", "modern", "modern", "modern", "modern21_5", "modern", "modern") - "modern26" -> SharedParts("modern", "modern", "modern", "modern", "modern21_5", "modern", "modern") + "modern26" -> SharedParts("modern", "modern", "modern", "modern26", "modern21_5", "modern", "modern") + "modern26_2" -> SharedParts("modern", "modern", "modern", "modern26_2", "modern21_5", "modern", "modern") else -> throw GradleException("Unknown nmsEra=$era") } val sharedVariantDirs: List = buildList { val root = rootProject.file("nms-shared") + add(root) add(File(root, "adapter/${parts.adapter}")) add(File(root, "connection/${parts.connection}")) add(File(root, "player/${parts.player}")) @@ -56,11 +58,15 @@ val prepareSharedSources = tasks.register("prepareSharedSources") { dest.parentFile.mkdirs() var text = file.readText() .replace( - "package org.mastersmp.packet.nms.shared;", + "package net.opmasterleo.packet.nms.shared;", "package $versionSharedPackage;" ) .replace( - "import org.mastersmp.packet.nms.shared.", + "import static net.opmasterleo.packet.nms.shared.", + "import static $versionSharedPackage." + ) + .replace( + "import net.opmasterleo.packet.nms.shared.", "import $versionSharedPackage." ) if (era.startsWith("legacy")) { diff --git a/nms/v1_16_R1/build.gradle.kts b/nms/v1_16_R1/build.gradle.kts index 29c2168..4aa2e4f 100644 --- a/nms/v1_16_R1/build.gradle.kts +++ b/nms/v1_16_R1/build.gradle.kts @@ -8,7 +8,6 @@ extra["nmsVersion"] = "v1_16_R1" dependencies { compileOnly(project(":nms-api")) compileOnly("org.spigotmc:spigot:1.16.1-R0.1-SNAPSHOT") - compileOnly("io.netty:netty-all:4.1.68.Final") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") diff --git a/nms/v1_16_R1/src/main/java/org/mastersmp/packet/nms/v1_16_R1/Adapter.java b/nms/v1_16_R1/src/main/java/net/opmasterleo/packet/nms/v1_16_R1/Adapter.java similarity index 50% rename from nms/v1_16_R1/src/main/java/org/mastersmp/packet/nms/v1_16_R1/Adapter.java rename to nms/v1_16_R1/src/main/java/net/opmasterleo/packet/nms/v1_16_R1/Adapter.java index dd045ca..658881b 100644 --- a/nms/v1_16_R1/src/main/java/org/mastersmp/packet/nms/v1_16_R1/Adapter.java +++ b/nms/v1_16_R1/src/main/java/net/opmasterleo/packet/nms/v1_16_R1/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_16_R1; +package net.opmasterleo.packet.nms.v1_16_R1; -import org.mastersmp.packet.nms.v1_16_R1.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_16_R1.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_16_R2/build.gradle.kts b/nms/v1_16_R2/build.gradle.kts index 7639e4d..d0df2bd 100644 --- a/nms/v1_16_R2/build.gradle.kts +++ b/nms/v1_16_R2/build.gradle.kts @@ -8,7 +8,6 @@ extra["nmsVersion"] = "v1_16_R2" dependencies { compileOnly(project(":nms-api")) compileOnly("org.spigotmc:spigot:1.16.3-R0.1-SNAPSHOT") - compileOnly("io.netty:netty-all:4.1.68.Final") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") diff --git a/nms/v1_16_R2/src/main/java/org/mastersmp/packet/nms/v1_16_R2/Adapter.java b/nms/v1_16_R2/src/main/java/net/opmasterleo/packet/nms/v1_16_R2/Adapter.java similarity index 50% rename from nms/v1_16_R2/src/main/java/org/mastersmp/packet/nms/v1_16_R2/Adapter.java rename to nms/v1_16_R2/src/main/java/net/opmasterleo/packet/nms/v1_16_R2/Adapter.java index 628d5c7..76e6731 100644 --- a/nms/v1_16_R2/src/main/java/org/mastersmp/packet/nms/v1_16_R2/Adapter.java +++ b/nms/v1_16_R2/src/main/java/net/opmasterleo/packet/nms/v1_16_R2/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_16_R2; +package net.opmasterleo.packet.nms.v1_16_R2; -import org.mastersmp.packet.nms.v1_16_R2.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_16_R2.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_16_R3/build.gradle.kts b/nms/v1_16_R3/build.gradle.kts index 79e3fa9..30ab073 100644 --- a/nms/v1_16_R3/build.gradle.kts +++ b/nms/v1_16_R3/build.gradle.kts @@ -8,7 +8,6 @@ extra["nmsVersion"] = "v1_16_R3" dependencies { compileOnly(project(":nms-api")) compileOnly("org.spigotmc:spigot:1.16.5-R0.1-SNAPSHOT") - compileOnly("io.netty:netty-all:4.1.68.Final") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") diff --git a/nms/v1_16_R3/src/main/java/org/mastersmp/packet/nms/v1_16_R3/Adapter.java b/nms/v1_16_R3/src/main/java/net/opmasterleo/packet/nms/v1_16_R3/Adapter.java similarity index 50% rename from nms/v1_16_R3/src/main/java/org/mastersmp/packet/nms/v1_16_R3/Adapter.java rename to nms/v1_16_R3/src/main/java/net/opmasterleo/packet/nms/v1_16_R3/Adapter.java index b24afcd..382ec6b 100644 --- a/nms/v1_16_R3/src/main/java/org/mastersmp/packet/nms/v1_16_R3/Adapter.java +++ b/nms/v1_16_R3/src/main/java/net/opmasterleo/packet/nms/v1_16_R3/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_16_R3; +package net.opmasterleo.packet.nms.v1_16_R3; -import org.mastersmp.packet.nms.v1_16_R3.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_16_R3.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_17_R1/build.gradle.kts b/nms/v1_17_R1/build.gradle.kts index af60738..afdff1c 100644 --- a/nms/v1_17_R1/build.gradle.kts +++ b/nms/v1_17_R1/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.17.1-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_17_R1/src/main/java/org/mastersmp/packet/nms/v1_17_R1/Adapter.java b/nms/v1_17_R1/src/main/java/net/opmasterleo/packet/nms/v1_17_R1/Adapter.java similarity index 50% rename from nms/v1_17_R1/src/main/java/org/mastersmp/packet/nms/v1_17_R1/Adapter.java rename to nms/v1_17_R1/src/main/java/net/opmasterleo/packet/nms/v1_17_R1/Adapter.java index d151f3d..3c6aa67 100644 --- a/nms/v1_17_R1/src/main/java/org/mastersmp/packet/nms/v1_17_R1/Adapter.java +++ b/nms/v1_17_R1/src/main/java/net/opmasterleo/packet/nms/v1_17_R1/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_17_R1; +package net.opmasterleo.packet.nms.v1_17_R1; -import org.mastersmp.packet.nms.v1_17_R1.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_17_R1.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_18_R1/build.gradle.kts b/nms/v1_18_R1/build.gradle.kts index dc1e278..af1a32a 100644 --- a/nms/v1_18_R1/build.gradle.kts +++ b/nms/v1_18_R1/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.18.1-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_18_R1/src/main/java/org/mastersmp/packet/nms/v1_18_R1/Adapter.java b/nms/v1_18_R1/src/main/java/net/opmasterleo/packet/nms/v1_18_R1/Adapter.java similarity index 50% rename from nms/v1_18_R1/src/main/java/org/mastersmp/packet/nms/v1_18_R1/Adapter.java rename to nms/v1_18_R1/src/main/java/net/opmasterleo/packet/nms/v1_18_R1/Adapter.java index 5e9c387..02e64c8 100644 --- a/nms/v1_18_R1/src/main/java/org/mastersmp/packet/nms/v1_18_R1/Adapter.java +++ b/nms/v1_18_R1/src/main/java/net/opmasterleo/packet/nms/v1_18_R1/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_18_R1; +package net.opmasterleo.packet.nms.v1_18_R1; -import org.mastersmp.packet.nms.v1_18_R1.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_18_R1.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_18_R2/build.gradle.kts b/nms/v1_18_R2/build.gradle.kts index d7f11ab..7ee350e 100644 --- a/nms/v1_18_R2/build.gradle.kts +++ b/nms/v1_18_R2/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.18.2-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_18_R2/src/main/java/org/mastersmp/packet/nms/v1_18_R2/Adapter.java b/nms/v1_18_R2/src/main/java/net/opmasterleo/packet/nms/v1_18_R2/Adapter.java similarity index 50% rename from nms/v1_18_R2/src/main/java/org/mastersmp/packet/nms/v1_18_R2/Adapter.java rename to nms/v1_18_R2/src/main/java/net/opmasterleo/packet/nms/v1_18_R2/Adapter.java index 66271c4..c02a364 100644 --- a/nms/v1_18_R2/src/main/java/org/mastersmp/packet/nms/v1_18_R2/Adapter.java +++ b/nms/v1_18_R2/src/main/java/net/opmasterleo/packet/nms/v1_18_R2/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_18_R2; +package net.opmasterleo.packet.nms.v1_18_R2; -import org.mastersmp.packet.nms.v1_18_R2.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_18_R2.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_19_R1/build.gradle.kts b/nms/v1_19_R1/build.gradle.kts index e0bdcec..186d509 100644 --- a/nms/v1_19_R1/build.gradle.kts +++ b/nms/v1_19_R1/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_19_R1/src/main/java/org/mastersmp/packet/nms/v1_19_R1/Adapter.java b/nms/v1_19_R1/src/main/java/net/opmasterleo/packet/nms/v1_19_R1/Adapter.java similarity index 50% rename from nms/v1_19_R1/src/main/java/org/mastersmp/packet/nms/v1_19_R1/Adapter.java rename to nms/v1_19_R1/src/main/java/net/opmasterleo/packet/nms/v1_19_R1/Adapter.java index d8c727c..6c728ee 100644 --- a/nms/v1_19_R1/src/main/java/org/mastersmp/packet/nms/v1_19_R1/Adapter.java +++ b/nms/v1_19_R1/src/main/java/net/opmasterleo/packet/nms/v1_19_R1/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_19_R1; +package net.opmasterleo.packet.nms.v1_19_R1; -import org.mastersmp.packet.nms.v1_19_R1.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_19_R1.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_19_R2/build.gradle.kts b/nms/v1_19_R2/build.gradle.kts index 9233983..c32be8f 100644 --- a/nms/v1_19_R2/build.gradle.kts +++ b/nms/v1_19_R2/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_19_R2/src/main/java/org/mastersmp/packet/nms/v1_19_R2/Adapter.java b/nms/v1_19_R2/src/main/java/net/opmasterleo/packet/nms/v1_19_R2/Adapter.java similarity index 50% rename from nms/v1_19_R2/src/main/java/org/mastersmp/packet/nms/v1_19_R2/Adapter.java rename to nms/v1_19_R2/src/main/java/net/opmasterleo/packet/nms/v1_19_R2/Adapter.java index 20c30bf..9c9d15d 100644 --- a/nms/v1_19_R2/src/main/java/org/mastersmp/packet/nms/v1_19_R2/Adapter.java +++ b/nms/v1_19_R2/src/main/java/net/opmasterleo/packet/nms/v1_19_R2/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_19_R2; +package net.opmasterleo.packet.nms.v1_19_R2; -import org.mastersmp.packet.nms.v1_19_R2.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_19_R2.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_19_R3/build.gradle.kts b/nms/v1_19_R3/build.gradle.kts index 6492db0..e50a892 100644 --- a/nms/v1_19_R3/build.gradle.kts +++ b/nms/v1_19_R3/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_19_R3/src/main/java/org/mastersmp/packet/nms/v1_19_R3/Adapter.java b/nms/v1_19_R3/src/main/java/net/opmasterleo/packet/nms/v1_19_R3/Adapter.java similarity index 50% rename from nms/v1_19_R3/src/main/java/org/mastersmp/packet/nms/v1_19_R3/Adapter.java rename to nms/v1_19_R3/src/main/java/net/opmasterleo/packet/nms/v1_19_R3/Adapter.java index 05d477e..31c898b 100644 --- a/nms/v1_19_R3/src/main/java/org/mastersmp/packet/nms/v1_19_R3/Adapter.java +++ b/nms/v1_19_R3/src/main/java/net/opmasterleo/packet/nms/v1_19_R3/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_19_R3; +package net.opmasterleo.packet.nms.v1_19_R3; -import org.mastersmp.packet.nms.v1_19_R3.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_19_R3.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_20_R1/build.gradle.kts b/nms/v1_20_R1/build.gradle.kts index e6cc870..61e8ef3 100644 --- a/nms/v1_20_R1/build.gradle.kts +++ b/nms/v1_20_R1/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.20.1-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_20_R1/src/main/java/org/mastersmp/packet/nms/v1_20_R1/Adapter.java b/nms/v1_20_R1/src/main/java/net/opmasterleo/packet/nms/v1_20_R1/Adapter.java similarity index 50% rename from nms/v1_20_R1/src/main/java/org/mastersmp/packet/nms/v1_20_R1/Adapter.java rename to nms/v1_20_R1/src/main/java/net/opmasterleo/packet/nms/v1_20_R1/Adapter.java index fa56913..057933b 100644 --- a/nms/v1_20_R1/src/main/java/org/mastersmp/packet/nms/v1_20_R1/Adapter.java +++ b/nms/v1_20_R1/src/main/java/net/opmasterleo/packet/nms/v1_20_R1/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_20_R1; +package net.opmasterleo.packet.nms.v1_20_R1; -import org.mastersmp.packet.nms.v1_20_R1.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_20_R1.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_20_R2/build.gradle.kts b/nms/v1_20_R2/build.gradle.kts index ec02941..3ae210d 100644 --- a/nms/v1_20_R2/build.gradle.kts +++ b/nms/v1_20_R2/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.20.2-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_20_R2/src/main/java/org/mastersmp/packet/nms/v1_20_R2/Adapter.java b/nms/v1_20_R2/src/main/java/net/opmasterleo/packet/nms/v1_20_R2/Adapter.java similarity index 50% rename from nms/v1_20_R2/src/main/java/org/mastersmp/packet/nms/v1_20_R2/Adapter.java rename to nms/v1_20_R2/src/main/java/net/opmasterleo/packet/nms/v1_20_R2/Adapter.java index bd86799..a8dd4c2 100644 --- a/nms/v1_20_R2/src/main/java/org/mastersmp/packet/nms/v1_20_R2/Adapter.java +++ b/nms/v1_20_R2/src/main/java/net/opmasterleo/packet/nms/v1_20_R2/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_20_R2; +package net.opmasterleo.packet.nms.v1_20_R2; -import org.mastersmp.packet.nms.v1_20_R2.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_20_R2.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_20_R3/build.gradle.kts b/nms/v1_20_R3/build.gradle.kts index 3afdad3..88633d4 100644 --- a/nms/v1_20_R3/build.gradle.kts +++ b/nms/v1_20_R3/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { compileOnly("org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT:remapped-mojang") compileOnly("net.kyori:adventure-api:4.17.0") compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0") - compileOnly("io.netty:netty-transport:4.1.118.Final") - compileOnly("io.netty:netty-handler:4.1.118.Final") + compileOnly("net.kyori:adventure-text-serializer-legacy:4.17.0") } apply(from = rootProject.file("nms/shared-sources.gradle.kts")) diff --git a/nms/v1_20_R3/src/main/java/org/mastersmp/packet/nms/v1_20_R3/Adapter.java b/nms/v1_20_R3/src/main/java/net/opmasterleo/packet/nms/v1_20_R3/Adapter.java similarity index 50% rename from nms/v1_20_R3/src/main/java/org/mastersmp/packet/nms/v1_20_R3/Adapter.java rename to nms/v1_20_R3/src/main/java/net/opmasterleo/packet/nms/v1_20_R3/Adapter.java index 507b2d6..a556213 100644 --- a/nms/v1_20_R3/src/main/java/org/mastersmp/packet/nms/v1_20_R3/Adapter.java +++ b/nms/v1_20_R3/src/main/java/net/opmasterleo/packet/nms/v1_20_R3/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_20_R3; +package net.opmasterleo.packet.nms.v1_20_R3; -import org.mastersmp.packet.nms.v1_20_R3.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_20_R3.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_20_R4/src/main/java/org/mastersmp/packet/nms/v1_20_R4/Adapter.java b/nms/v1_20_R4/src/main/java/net/opmasterleo/packet/nms/v1_20_R4/Adapter.java similarity index 50% rename from nms/v1_20_R4/src/main/java/org/mastersmp/packet/nms/v1_20_R4/Adapter.java rename to nms/v1_20_R4/src/main/java/net/opmasterleo/packet/nms/v1_20_R4/Adapter.java index bfe8903..009c8c5 100644 --- a/nms/v1_20_R4/src/main/java/org/mastersmp/packet/nms/v1_20_R4/Adapter.java +++ b/nms/v1_20_R4/src/main/java/net/opmasterleo/packet/nms/v1_20_R4/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_20_R4; +package net.opmasterleo.packet.nms.v1_20_R4; -import org.mastersmp.packet.nms.v1_20_R4.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_20_R4.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_21_R1/src/main/java/org/mastersmp/packet/nms/v1_21_R1/Adapter.java b/nms/v1_21_R1/src/main/java/net/opmasterleo/packet/nms/v1_21_R1/Adapter.java similarity index 50% rename from nms/v1_21_R1/src/main/java/org/mastersmp/packet/nms/v1_21_R1/Adapter.java rename to nms/v1_21_R1/src/main/java/net/opmasterleo/packet/nms/v1_21_R1/Adapter.java index 520bc01..8cbf45a 100644 --- a/nms/v1_21_R1/src/main/java/org/mastersmp/packet/nms/v1_21_R1/Adapter.java +++ b/nms/v1_21_R1/src/main/java/net/opmasterleo/packet/nms/v1_21_R1/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_21_R1; +package net.opmasterleo.packet.nms.v1_21_R1; -import org.mastersmp.packet.nms.v1_21_R1.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_21_R1.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_21_R2/src/main/java/org/mastersmp/packet/nms/v1_21_R2/Adapter.java b/nms/v1_21_R2/src/main/java/net/opmasterleo/packet/nms/v1_21_R2/Adapter.java similarity index 50% rename from nms/v1_21_R2/src/main/java/org/mastersmp/packet/nms/v1_21_R2/Adapter.java rename to nms/v1_21_R2/src/main/java/net/opmasterleo/packet/nms/v1_21_R2/Adapter.java index d90a936..b45cd43 100644 --- a/nms/v1_21_R2/src/main/java/org/mastersmp/packet/nms/v1_21_R2/Adapter.java +++ b/nms/v1_21_R2/src/main/java/net/opmasterleo/packet/nms/v1_21_R2/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_21_R2; +package net.opmasterleo.packet.nms.v1_21_R2; -import org.mastersmp.packet.nms.v1_21_R2.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_21_R2.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_21_R3/src/main/java/org/mastersmp/packet/nms/v1_21_R3/Adapter.java b/nms/v1_21_R3/src/main/java/net/opmasterleo/packet/nms/v1_21_R3/Adapter.java similarity index 50% rename from nms/v1_21_R3/src/main/java/org/mastersmp/packet/nms/v1_21_R3/Adapter.java rename to nms/v1_21_R3/src/main/java/net/opmasterleo/packet/nms/v1_21_R3/Adapter.java index 74e7f6a..c923085 100644 --- a/nms/v1_21_R3/src/main/java/org/mastersmp/packet/nms/v1_21_R3/Adapter.java +++ b/nms/v1_21_R3/src/main/java/net/opmasterleo/packet/nms/v1_21_R3/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_21_R3; +package net.opmasterleo.packet.nms.v1_21_R3; -import org.mastersmp.packet.nms.v1_21_R3.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_21_R3.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_21_R4/src/main/java/org/mastersmp/packet/nms/v1_21_R4/Adapter.java b/nms/v1_21_R4/src/main/java/net/opmasterleo/packet/nms/v1_21_R4/Adapter.java similarity index 50% rename from nms/v1_21_R4/src/main/java/org/mastersmp/packet/nms/v1_21_R4/Adapter.java rename to nms/v1_21_R4/src/main/java/net/opmasterleo/packet/nms/v1_21_R4/Adapter.java index 133c82e..ca0c686 100644 --- a/nms/v1_21_R4/src/main/java/org/mastersmp/packet/nms/v1_21_R4/Adapter.java +++ b/nms/v1_21_R4/src/main/java/net/opmasterleo/packet/nms/v1_21_R4/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_21_R4; +package net.opmasterleo.packet.nms.v1_21_R4; -import org.mastersmp.packet.nms.v1_21_R4.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_21_R4.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_21_R5/src/main/java/org/mastersmp/packet/nms/v1_21_R5/Adapter.java b/nms/v1_21_R5/src/main/java/net/opmasterleo/packet/nms/v1_21_R5/Adapter.java similarity index 50% rename from nms/v1_21_R5/src/main/java/org/mastersmp/packet/nms/v1_21_R5/Adapter.java rename to nms/v1_21_R5/src/main/java/net/opmasterleo/packet/nms/v1_21_R5/Adapter.java index 0615176..48a25f8 100644 --- a/nms/v1_21_R5/src/main/java/org/mastersmp/packet/nms/v1_21_R5/Adapter.java +++ b/nms/v1_21_R5/src/main/java/net/opmasterleo/packet/nms/v1_21_R5/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_21_R5; +package net.opmasterleo.packet.nms.v1_21_R5; -import org.mastersmp.packet.nms.v1_21_R5.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_21_R5.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_21_R6/src/main/java/org/mastersmp/packet/nms/v1_21_R6/Adapter.java b/nms/v1_21_R6/src/main/java/net/opmasterleo/packet/nms/v1_21_R6/Adapter.java similarity index 50% rename from nms/v1_21_R6/src/main/java/org/mastersmp/packet/nms/v1_21_R6/Adapter.java rename to nms/v1_21_R6/src/main/java/net/opmasterleo/packet/nms/v1_21_R6/Adapter.java index 4c1ec4e..632196a 100644 --- a/nms/v1_21_R6/src/main/java/org/mastersmp/packet/nms/v1_21_R6/Adapter.java +++ b/nms/v1_21_R6/src/main/java/net/opmasterleo/packet/nms/v1_21_R6/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_21_R6; +package net.opmasterleo.packet.nms.v1_21_R6; -import org.mastersmp.packet.nms.v1_21_R6.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_21_R6.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v1_21_R7/src/main/java/org/mastersmp/packet/nms/v1_21_R7/Adapter.java b/nms/v1_21_R7/src/main/java/net/opmasterleo/packet/nms/v1_21_R7/Adapter.java similarity index 50% rename from nms/v1_21_R7/src/main/java/org/mastersmp/packet/nms/v1_21_R7/Adapter.java rename to nms/v1_21_R7/src/main/java/net/opmasterleo/packet/nms/v1_21_R7/Adapter.java index cae5c41..b1dc235 100644 --- a/nms/v1_21_R7/src/main/java/org/mastersmp/packet/nms/v1_21_R7/Adapter.java +++ b/nms/v1_21_R7/src/main/java/net/opmasterleo/packet/nms/v1_21_R7/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v1_21_R7; +package net.opmasterleo.packet.nms.v1_21_R7; -import org.mastersmp.packet.nms.v1_21_R7.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v1_21_R7.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v26_1/src/main/java/org/mastersmp/packet/nms/v26_1/Adapter.java b/nms/v26_1/src/main/java/net/opmasterleo/packet/nms/v26_1/Adapter.java similarity index 50% rename from nms/v26_1/src/main/java/org/mastersmp/packet/nms/v26_1/Adapter.java rename to nms/v26_1/src/main/java/net/opmasterleo/packet/nms/v26_1/Adapter.java index ad67519..edbc0e1 100644 --- a/nms/v26_1/src/main/java/org/mastersmp/packet/nms/v26_1/Adapter.java +++ b/nms/v26_1/src/main/java/net/opmasterleo/packet/nms/v26_1/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v26_1; +package net.opmasterleo.packet.nms.v26_1; -import org.mastersmp.packet.nms.v26_1.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v26_1.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/nms/v26_2/build.gradle.kts b/nms/v26_2/build.gradle.kts index c1a0149..a2beb44 100644 --- a/nms/v26_2/build.gradle.kts +++ b/nms/v26_2/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("io.papermc.paperweight.userdev") } -extra["nmsEra"] = "modern26" +extra["nmsEra"] = "modern26_2" dependencies { compileOnly(project(":nms-api")) diff --git a/nms/v26_2/src/main/java/org/mastersmp/packet/nms/v26_2/Adapter.java b/nms/v26_2/src/main/java/net/opmasterleo/packet/nms/v26_2/Adapter.java similarity index 50% rename from nms/v26_2/src/main/java/org/mastersmp/packet/nms/v26_2/Adapter.java rename to nms/v26_2/src/main/java/net/opmasterleo/packet/nms/v26_2/Adapter.java index c914d2c..b7586ca 100644 --- a/nms/v26_2/src/main/java/org/mastersmp/packet/nms/v26_2/Adapter.java +++ b/nms/v26_2/src/main/java/net/opmasterleo/packet/nms/v26_2/Adapter.java @@ -1,6 +1,6 @@ -package org.mastersmp.packet.nms.v26_2; +package net.opmasterleo.packet.nms.v26_2; -import org.mastersmp.packet.nms.v26_2.shared.AbstractNmsAdapter; +import net.opmasterleo.packet.nms.v26_2.shared.AbstractNmsAdapter; public final class Adapter extends AbstractNmsAdapter { public Adapter() { diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 50b6508..7ddc911 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -5,8 +5,7 @@ plugins { dependencies { implementation(project(":api")) implementation(project(":nms-api")) - compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT") - compileOnly("io.netty:netty-transport:4.1.115.Final") + compileOnly("io.papermc.paper:paper-api:${property("paperApiVersion")}") } tasks.compileJava { diff --git a/plugin/src/main/java/net/opmasterleo/packet/plugin/NmsPlayerListener.java b/plugin/src/main/java/net/opmasterleo/packet/plugin/NmsPlayerListener.java new file mode 100644 index 0000000..9eb3628 --- /dev/null +++ b/plugin/src/main/java/net/opmasterleo/packet/plugin/NmsPlayerListener.java @@ -0,0 +1,127 @@ +package net.opmasterleo.packet.plugin; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerAnimationEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +import net.opmasterleo.packet.PacketAPI; +import net.opmasterleo.packet.event.NmsPlayerJoinEvent; +import net.opmasterleo.packet.event.NmsPlayerQuitEvent; +import net.opmasterleo.packet.event.NmsSwingEvent; +import net.opmasterleo.packet.event.NmsUnknownEntityInteractEvent; +import net.opmasterleo.packet.nms.packet.Hand; +import net.opmasterleo.packet.nms.packet.InteractAction; + +/** + * Bridges CraftBukkit/Paper player events into NMS-handle custom events. + * Does not inject Netty handlers — inbound interact with unknown entities uses Paper's event. + */ +public final class NmsPlayerListener implements Listener { + + private final PacketAPI api; + + public NmsPlayerListener(PacketAPI api) { + this.api = api; + } + + public void register(JavaPlugin plugin) { + PluginManager manager = plugin.getServer().getPluginManager(); + manager.registerEvents(this, plugin); + registerUnknownEntity(plugin, manager); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onJoin(PlayerJoinEvent event) { + Object handle = api.adapter().players().handle(event.getPlayer()); + event.getPlayer().getServer().getPluginManager().callEvent(new NmsPlayerJoinEvent(event.getPlayer(), handle)); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onQuit(PlayerQuitEvent event) { + Object handle = api.adapter().players().handle(event.getPlayer()); + event.getPlayer().getServer().getPluginManager().callEvent(new NmsPlayerQuitEvent(event.getPlayer(), handle)); + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onSwing(PlayerAnimationEvent event) { + Object handle = api.adapter().players().handle(event.getPlayer()); + Hand hand = Hand.MAIN_HAND; + try { + Object nmsHand = event.getClass().getMethod("getAnimationType").invoke(event); + if (nmsHand != null && nmsHand.toString().contains("OFF")) { + hand = Hand.OFF_HAND; + } + } catch (ReflectiveOperationException ignored) { + } + NmsSwingEvent wrapped = new NmsSwingEvent(event.getPlayer(), handle, hand); + event.getPlayer().getServer().getPluginManager().callEvent(wrapped); + if (wrapped.isCancelled()) { + event.setCancelled(true); + } + } + + @SuppressWarnings("unchecked") + private void registerUnknownEntity(JavaPlugin plugin, PluginManager manager) { + Class type; + try { + type = Class.forName("com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent"); + } catch (ClassNotFoundException ignored) { + return; + } + manager.registerEvent( + (Class) type, + this, + EventPriority.HIGH, + (listener, event) -> handleUnknownEntity(event), + plugin, + true + ); + } + + private void handleUnknownEntity(org.bukkit.event.Event event) { + try { + Object player = event.getClass().getMethod("getPlayer").invoke(event); + if (!(player instanceof org.bukkit.entity.Player bukkitPlayer)) { + return; + } + int entityId = (Integer) event.getClass().getMethod("getEntityId").invoke(event); + boolean attack = false; + try { + Object clicked = event.getClass().getMethod("isAttack").invoke(event); + attack = Boolean.TRUE.equals(clicked); + } catch (NoSuchMethodException ignored) { + try { + Object clicked = event.getClass().getMethod("clickedLeft").invoke(event); + attack = Boolean.TRUE.equals(clicked); + } catch (NoSuchMethodException ignoredToo) { + } + } + Hand hand = Hand.MAIN_HAND; + try { + Object nmsHand = event.getClass().getMethod("getHand").invoke(event); + if (nmsHand != null && nmsHand.toString().contains("OFF")) { + hand = Hand.OFF_HAND; + } + } catch (NoSuchMethodException ignored) { + } + Object handle = api.adapter().players().handle(bukkitPlayer); + NmsUnknownEntityInteractEvent wrapped = new NmsUnknownEntityInteractEvent( + bukkitPlayer, + handle, + entityId, + attack ? InteractAction.ATTACK : InteractAction.INTERACT, + hand + ); + bukkitPlayer.getServer().getPluginManager().callEvent(wrapped); + if (wrapped.isCancelled() && event instanceof org.bukkit.event.Cancellable cancellable) { + cancellable.setCancelled(true); + } + } catch (ReflectiveOperationException ignored) { + } + } +} diff --git a/plugin/src/main/java/org/mastersmp/packet/plugin/PacketPlugin.java b/plugin/src/main/java/net/opmasterleo/packet/plugin/PacketPlugin.java similarity index 58% rename from plugin/src/main/java/org/mastersmp/packet/plugin/PacketPlugin.java rename to plugin/src/main/java/net/opmasterleo/packet/plugin/PacketPlugin.java index c77ed6a..90c74f5 100644 --- a/plugin/src/main/java/org/mastersmp/packet/plugin/PacketPlugin.java +++ b/plugin/src/main/java/net/opmasterleo/packet/plugin/PacketPlugin.java @@ -1,18 +1,22 @@ -package org.mastersmp.packet.plugin; +package net.opmasterleo.packet.plugin; import org.bukkit.plugin.java.JavaPlugin; -import org.mastersmp.packet.PacketAPI; +import net.opmasterleo.packet.PacketAPI; public final class PacketPlugin extends JavaPlugin { private PacketAPI api; + private NmsPlayerListener listener; @Override public void onEnable() { api = PacketAPI.bootstrap(this); + listener = new NmsPlayerListener(api); + listener.register(this); getLogger().info("Loaded NMS adapter " + api.adapter().bucketId() - + " on " + api.schedulers().platform().kind()); + + " on " + api.schedulers().platform().kind() + + " (direct NMS, no Netty intercept)"); } @Override @@ -21,6 +25,7 @@ public void onDisable() { api.shutdown(); api = null; } + listener = null; } public PacketAPI api() { diff --git a/plugin/src/main/resources/plugin.yml b/plugin/src/main/resources/plugin.yml index 018f570..00929b7 100644 --- a/plugin/src/main/resources/plugin.yml +++ b/plugin/src/main/resources/plugin.yml @@ -1,9 +1,9 @@ name: PacketAPI version: ${version} -main: org.mastersmp.packet.plugin.PacketPlugin +main: net.opmasterleo.packet.plugin.PacketPlugin api-version: '1.16' folia-supported: true load: STARTUP authors: [OPmasterLEO] -description: Multi-version NMS and packet abstraction for Paper, Folia and Canvas. +description: Direct NMS packet API for Paper, Folia and Canvas. No Netty intercept. website: https://github.com/OPmasterLEO/PacketAPI