diff --git a/pom.xml b/pom.xml
index c0c8e2e..17a47bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
tech.sbdevelopment
MapReflectionAPI
- 1.3
+ 1.4
jar
MapReflectionAPI
@@ -188,13 +188,7 @@
org.spigotmc
spigot-api
- 1.19.1-R0.1-SNAPSHOT
- provided
-
-
- com.comphenix.protocol
- ProtocolLib
- 5.0.0-SNAPSHOT
+ 1.19.2-R0.1-SNAPSHOT
provided
@@ -204,19 +198,25 @@
provided
-
-
- org.jetbrains
- annotations-java5
- 23.0.0
- provided
-
-
org.bstats
bstats-bukkit
3.0.0
compile
+
+
+
+ org.jetbrains
+ annotations-java5
+ 23.0.0
+ provided
+
+
+ io.netty
+ netty-transport
+ 4.1.77.Final
+ provided
+
\ No newline at end of file
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java
index d4a0555..df43435 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java
@@ -19,7 +19,6 @@
package tech.sbdevelopment.mapreflectionapi;
import com.bergerkiller.bukkit.common.map.MapColorPalette;
-import com.comphenix.protocol.ProtocolLibrary;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SingleLineChart;
import org.bukkit.Bukkit;
@@ -84,12 +83,6 @@ public class MapReflectionAPI extends JavaPlugin {
}
MapColorPalette.getColor(0, 0, 0); //Initializes the class
- if (!Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")) {
- getLogger().severe("MapReflectionAPI requires ProtocolLib to function!");
- Bukkit.getPluginManager().disablePlugin(this);
- return;
- }
-
getLogger().info("Loading the configuration...");
Configuration.init(this);
@@ -120,7 +113,7 @@ public class MapReflectionAPI extends JavaPlugin {
getLogger().info("Registering the listeners...");
Bukkit.getPluginManager().registerEvents(new MapListener(), this);
- ProtocolLibrary.getProtocolManager().addPacketListener(new PacketListener(this));
+ Bukkit.getPluginManager().registerEvents(new PacketListener(), this);
getLogger().info("Loading metrics...");
Metrics metrics = new Metrics(this, 16033);
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
index 24f8c12..7887358 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
@@ -18,90 +18,143 @@
package tech.sbdevelopment.mapreflectionapi.listeners;
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.events.ListenerPriority;
-import com.comphenix.protocol.events.PacketAdapter;
-import com.comphenix.protocol.events.PacketEvent;
-import com.comphenix.protocol.wrappers.EnumWrappers;
-import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.plugin.Plugin;
import org.bukkit.util.Vector;
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
import tech.sbdevelopment.mapreflectionapi.api.events.CreateInventoryMapUpdateEvent;
import tech.sbdevelopment.mapreflectionapi.api.events.MapCancelEvent;
import tech.sbdevelopment.mapreflectionapi.api.events.MapInteractEvent;
+import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil;
-public class PacketListener extends PacketAdapter {
- public PacketListener(Plugin plugin) {
- super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP, PacketType.Play.Client.USE_ENTITY, PacketType.Play.Client.SET_CREATIVE_SLOT);
+import java.util.concurrent.TimeUnit;
+
+import static tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil.*;
+
+public class PacketListener implements Listener {
+ private static final Class> packetPlayOutMapClass = getNMSClass("network.protocol.game", "PacketPlayOutMap");
+ private static final Class> packetPlayInUseEntityClass = getNMSClass("network.protocol.game", "PacketPlayInUseEntity");
+ private static final Class> packetPlayInSetCreativeSlotClass = getNMSClass("network.protocol.game", "packetPlayInSetCreativeSlot");
+ private static final Class> vec3DClass = getNMSClass("world.phys", "Vec3D");
+ private static final Class> craftStackClass = getCraftClass("CraftItemStack");
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent e) {
+ injectPlayer(e.getPlayer());
}
- @Override
- public void onPacketSending(PacketEvent event) {
- if (event.getPacketType() == PacketType.Play.Server.MAP) {
- handleOUTMapPacket(event);
- }
+ @EventHandler
+ public void onQuit(PlayerQuitEvent e) {
+ removePlayer(e.getPlayer());
}
- @Override
- public void onPacketReceiving(PacketEvent event) {
- if (event.getPacketType() == PacketType.Play.Client.USE_ENTITY) {
- handleINUseEntityPacket(event);
- } else if (event.getPacketType() == PacketType.Play.Client.SET_CREATIVE_SLOT) {
- handleINSetCreativeSlotPacket(event);
- }
+ private void injectPlayer(Player player) {
+ ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
+ @Override
+ public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
+ if (packet.getClass().isAssignableFrom(packetPlayOutMapClass)) {
+ Object packetPlayOutMap = packetPlayOutMapClass.cast(packet);
+
+ int id = (int) getDeclaredField(packetPlayOutMap, "a");
+ if (id < 0) {
+ int newId = -id;
+ setDeclaredField(packetPlayOutMap, "a", newId);
+ } else {
+ boolean async = !MapReflectionAPI.getInstance().getServer().isPrimaryThread();
+ MapCancelEvent event = new MapCancelEvent(player, id, async);
+ if (MapReflectionAPI.getMapManager().isIdUsedBy(player, id)) event.setCancelled(true);
+ if (event.getHandlers().getRegisteredListeners().length > 0)
+ Bukkit.getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) return;
+ }
+ }
+
+ super.write(ctx, packet, promise);
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception {
+ if (packet.getClass().isAssignableFrom(packetPlayInUseEntityClass)) {
+ Object packetPlayInEntity = packetPlayInUseEntityClass.cast(packet);
+
+ int entityId = (int) getDeclaredField(packetPlayInEntity, "a");
+
+ Enum> actionEnum;
+ Enum> hand;
+ Object pos;
+ if (ReflectionUtil.supports(17)) {
+ Object action = getDeclaredField(packetPlayInEntity, "b");
+ actionEnum = (Enum>) callDeclaredMethod(action, "a"); //action type
+ hand = hasField(action, "a") ? (Enum>) getDeclaredField(action, "a") : null;
+ pos = hasField(action, "b") ? getDeclaredField(action, "b") : null;
+ } else {
+ actionEnum = (Enum>) getDeclaredField(packetPlayInEntity, ReflectionUtil.supports(13) ? "b" : "a"); //1.13 = b, 1.12 = a
+ hand = (Enum>) callDeclaredMethod(packetPlayInEntity, ReflectionUtil.supports(13) ? "c" : "b"); //1.13 = c, 1.12 = b
+ pos = callDeclaredMethod(packetPlayInEntity, ReflectionUtil.supports(13) ? "d" : "c"); //1.13 = d, 1.12 = c
+ }
+
+ if (Bukkit.getScheduler().callSyncMethod(MapReflectionAPI.getInstance(), () -> {
+ boolean async = !MapReflectionAPI.getInstance().getServer().isPrimaryThread();
+ MapInteractEvent event = new MapInteractEvent(player, entityId, actionEnum.ordinal(), pos != null ? vec3DToVector(pos) : null, hand != null ? hand.ordinal() : 0, async);
+ if (event.getFrame() != null && event.getMapWrapper() != null) {
+ Bukkit.getPluginManager().callEvent(event);
+ return event.isCancelled();
+ }
+ return false;
+ }).get(1, TimeUnit.SECONDS)) return;
+ } else if (packet.getClass().isAssignableFrom(packetPlayInSetCreativeSlotClass)) {
+ Object packetPlayInSetCreativeSlot = packetPlayInSetCreativeSlotClass.cast(packet);
+
+ int slot = (int) ReflectionUtil.callDeclaredMethod(packetPlayInSetCreativeSlot, ReflectionUtil.supports(13) ? "b" : "a"); //1.13 = b, 1.12 = a
+ Object nmsStack = ReflectionUtil.callDeclaredMethod(packetPlayInSetCreativeSlot, ReflectionUtil.supports(18) ? "c" : "getItemStack"); //1.18 = c, 1.17 = getItemStack
+ ItemStack craftStack = (ItemStack) ReflectionUtil.callDeclaredMethod(craftStackClass, "asBukkitCopy", nmsStack);
+
+ boolean async = !MapReflectionAPI.getInstance().getServer().isPrimaryThread();
+ CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(player, slot, craftStack, async);
+ if (event.getMapWrapper() != null) {
+ Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled()) return;
+ }
+ }
+
+ super.channelRead(ctx, packet);
+ }
+ };
+
+ Channel channel = getChannel(player);
+ channel.pipeline().addBefore("packet_handler", player.getName(), channelDuplexHandler);
}
- private void handleOUTMapPacket(PacketEvent event) {
- int id = event.getPacket().getIntegers().read(0); //Read first int (a); that's the MAP id
-
- if (id < 0) {
- //It's one of our maps, invert ID and let through!
- int newId = -id;
- event.getPacket().getIntegers().write(0, newId); //set the MAP id to the reverse
- } else {
- boolean async = !plugin.getServer().isPrimaryThread();
- MapCancelEvent cancelEvent = new MapCancelEvent(event.getPlayer(), id, async);
- if (MapReflectionAPI.getMapManager().isIdUsedBy(event.getPlayer(), id)) cancelEvent.setCancelled(true);
- if (cancelEvent.getHandlers().getRegisteredListeners().length > 0)
- Bukkit.getPluginManager().callEvent(cancelEvent);
-
- if (cancelEvent.isCancelled()) event.setCancelled(true);
- }
+ private void removePlayer(Player player) {
+ Channel channel = getChannel(player);
+ channel.eventLoop().submit(() -> channel.pipeline().remove(player.getName()));
}
- private void handleINUseEntityPacket(PacketEvent event) {
- int entityId = event.getPacket().getIntegers().read(0); //entityId
- WrappedEnumEntityUseAction action = event.getPacket().getEnumEntityUseActions().read(0);
- EnumWrappers.EntityUseAction actionEnum = null;
- EnumWrappers.Hand hand = null;
- Vector pos = null;
- try {
- actionEnum = action.getAction();
- hand = action.getHand();
- pos = action.getPosition();
- } catch (IllegalArgumentException ignored) {
- }
-
- boolean async = !plugin.getServer().isPrimaryThread();
- MapInteractEvent interactEvent = new MapInteractEvent(event.getPlayer(), entityId, actionEnum != null ? actionEnum.ordinal() : 0, pos, hand != null ? hand.ordinal() : 0, async);
- if (interactEvent.getFrame() != null && interactEvent.getMapWrapper() != null) {
- Bukkit.getPluginManager().callEvent(interactEvent);
- if (interactEvent.isCancelled()) event.setCancelled(true);
- }
+ private Channel getChannel(Player player) {
+ Object playerHandle = getHandle(player);
+ Object connection = getDeclaredField(playerHandle, "b");
+ Object connection2 = getDeclaredField(connection, ReflectionUtil.supports(19) ? "b" : "a"); //1.19 = b, 1.18 = a
+ return (Channel) getDeclaredField(connection2, ReflectionUtil.supports(18) ? "m" : "k"); //1.18 = m, 1.17 = k
}
- private void handleINSetCreativeSlotPacket(PacketEvent event) {
- int slot = event.getPacket().getIntegers().read(0);
- ItemStack item = event.getPacket().getItemModifier().read(0);
+ private Vector vec3DToVector(Object vec3d) {
+ if (!(vec3d.getClass().isAssignableFrom(vec3DClass))) return new Vector(0, 0, 0);
- boolean async = !plugin.getServer().isPrimaryThread();
- CreateInventoryMapUpdateEvent updateEvent = new CreateInventoryMapUpdateEvent(event.getPlayer(), slot, item, async);
- if (updateEvent.getMapWrapper() != null) {
- Bukkit.getPluginManager().callEvent(updateEvent);
- if (updateEvent.isCancelled()) event.setCancelled(true);
- }
+ Object vec3dNMS = vec3DClass.cast(vec3d);
+ double x = (double) ReflectionUtil.getDeclaredField(vec3dNMS, ReflectionUtil.supports(19) ? "c" : ReflectionUtil.supports(17) ? "b" : "x"); //1.19 = c, 1.18 = b, 1.16 = x
+ double y = (double) ReflectionUtil.getDeclaredField(vec3dNMS, ReflectionUtil.supports(19) ? "d" : ReflectionUtil.supports(17) ? "c" : "y"); //1.19 = d, 1.18 = c, 1.16 = y
+ double z = (double) ReflectionUtil.getDeclaredField(vec3dNMS, ReflectionUtil.supports(19) ? "e" : ReflectionUtil.supports(17) ? "d" : "z"); //1.19 = e, 1.18 = d, 1.16 = z
+
+ return new Vector(x, y, z);
}
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java
index ab94819..19ee0d9 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java
@@ -318,6 +318,15 @@ public class ReflectionUtil {
}
}
+ public static boolean hasField(Object packet, String field) {
+ try {
+ packet.getClass().getDeclaredField(field);
+ return true;
+ } catch (NoSuchFieldException ex) {
+ return false;
+ }
+ }
+
@Nullable
public static Object getField(Object object, String field) {
try {
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 358fc74..41d8a18 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -5,7 +5,6 @@ api-version: 1.13
authors: [ inventivetalent, SBDeveloper ]
description: This API helps developer with viewing images on maps or in inventories.
website: https://sbdevelopment.tech
-softdepend: [ ProtocolLib ]
commands:
mapmanager:
description: The main command of MapManager.