From 6d1dab78aade012a1d484c9189b11c3af67c896e Mon Sep 17 00:00:00 2001 From: SBDeveloper Date: Fri, 1 Jul 2022 12:07:10 +0200 Subject: [PATCH 1/7] :art: Moved back to reflection, still WIP --- .idea/encodings.xml | 2 - .idea/misc.xml | 16 +- API/pom.xml | 75 ---- .../mapreflectionapi/api/MapWrapper.java | 38 -- .../listeners/PacketListener.java | 85 ---- .../mapreflectionapi/util/ReflectionUtil.java | 54 --- Dist/pom.xml | 101 ----- NMS-v1_12_R1/pom.xml | 54 --- .../nms/PacketListener_v1_12_R1.java | 128 ------ NMS-v1_13_R2/pom.xml | 54 --- .../nms/MapSender_v1_13_R2.java | 139 ------- .../nms/MapWrapper_v1_13_R2.java | 251 ------------ .../nms/PacketListener_v1_13_R2.java | 128 ------ NMS-v1_14_R1/pom.xml | 54 --- .../nms/MapSender_v1_14_R1.java | 140 ------- .../nms/MapWrapper_v1_14_R1.java | 251 ------------ .../nms/PacketListener_v1_14_R1.java | 128 ------ NMS-v1_15_R1/pom.xml | 54 --- .../nms/MapSender_v1_15_R1.java | 140 ------- .../nms/MapWrapper_v1_15_R1.java | 252 ------------ .../nms/PacketListener_v1_15_R1.java | 128 ------ NMS-v1_16_R3/pom.xml | 54 --- .../nms/MapSender_v1_16_R3.java | 140 ------- .../nms/MapWrapper_v1_16_R3.java | 251 ------------ .../nms/PacketListener_v1_16_R3.java | 128 ------ NMS-v1_17_R1/pom.xml | 77 ---- .../nms/MapSender_v1_17_R1.java | 111 ----- .../nms/MapWrapper_v1_17_R1.java | 254 ------------ .../nms/PacketListener_v1_17_R1.java | 126 ------ NMS-v1_18_R2/pom.xml | 77 ---- .../nms/MapSender_v1_18_R2.java | 111 ----- .../nms/MapWrapper_v1_18_R2.java | 254 ------------ .../nms/PacketListener_v1_18_R2.java | 126 ------ NMS-v1_19_R1/pom.xml | 77 ---- .../nms/MapSender_v1_19_R1.java | 111 ----- .../nms/MapWrapper_v1_19_R1.java | 254 ------------ .../nms/PacketListener_v1_19_R1.java | 126 ------ pom.xml | 116 +++--- .../mapreflectionapi/MapReflectionAPI.java | 17 +- .../mapreflectionapi/api/ArrayImage.java | 10 + .../mapreflectionapi/api/MapController.java | 0 .../mapreflectionapi/api/MapManager.java | 0 .../mapreflectionapi/api/MapSender.java | 74 ++-- .../mapreflectionapi/api/MapWrapper.java | 140 ++++--- .../events/CreateInventoryMapUpdateEvent.java | 0 .../api/events/MapCancelEvent.java | 0 .../api/events/MapInteractEvent.java | 0 .../exceptions/MapLimitExceededException.java | 0 .../listeners/MapListener.java | 0 .../listeners/PacketListener.java | 94 +++++ .../mapreflectionapi/util/ReflectionUtil.java | 165 ++++++++ .../util/ReflectionUtils.java | 381 ++++++++++++++++++ {API/src => src}/main/resources/plugin.yml | 0 53 files changed, 879 insertions(+), 4667 deletions(-) delete mode 100644 API/pom.xml delete mode 100644 API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java delete mode 100644 API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java delete mode 100644 API/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java delete mode 100644 Dist/pom.xml delete mode 100644 NMS-v1_12_R1/pom.xml delete mode 100644 NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_12_R1.java delete mode 100644 NMS-v1_13_R2/pom.xml delete mode 100644 NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_13_R2.java delete mode 100644 NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_13_R2.java delete mode 100644 NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_13_R2.java delete mode 100644 NMS-v1_14_R1/pom.xml delete mode 100644 NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_14_R1.java delete mode 100644 NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_14_R1.java delete mode 100644 NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_14_R1.java delete mode 100644 NMS-v1_15_R1/pom.xml delete mode 100644 NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_15_R1.java delete mode 100644 NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_15_R1.java delete mode 100644 NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_15_R1.java delete mode 100644 NMS-v1_16_R3/pom.xml delete mode 100644 NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_16_R3.java delete mode 100644 NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_16_R3.java delete mode 100644 NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_16_R3.java delete mode 100644 NMS-v1_17_R1/pom.xml delete mode 100644 NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_17_R1.java delete mode 100644 NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_17_R1.java delete mode 100644 NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_17_R1.java delete mode 100644 NMS-v1_18_R2/pom.xml delete mode 100644 NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_18_R2.java delete mode 100644 NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_18_R2.java delete mode 100644 NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_18_R2.java delete mode 100644 NMS-v1_19_R1/pom.xml delete mode 100644 NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_19_R1.java delete mode 100644 NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_19_R1.java delete mode 100644 NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_19_R1.java rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java (87%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java (91%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java (100%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java (100%) rename NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_12_R1.java => src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java (65%) rename NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_12_R1.java => src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java (53%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java (100%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java (100%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java (100%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java (100%) rename {API/src => src}/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java (100%) create mode 100644 src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java create mode 100644 src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java create mode 100644 src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java rename {API/src => src}/main/resources/plugin.yml (100%) diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 8d3469f..337d139 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -1,8 +1,6 @@ - - diff --git a/.idea/misc.xml b/.idea/misc.xml index 6410ee3..200af21 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -15,8 +15,22 @@ + - + \ No newline at end of file diff --git a/API/pom.xml b/API/pom.xml deleted file mode 100644 index 172cb4c..0000000 --- a/API/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-API - - - 11 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - - - src/main/resources - true - - - - - - - MG-Dev Jenkins CI Maven Repository - https://ci.mg-dev.eu/plugin/repository/everything - - - - - - com.bergerkiller.bukkit - BKCommonLib - 1.19-v1 - provided - - - \ No newline at end of file diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java deleted file mode 100644 index e797653..0000000 --- a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.api; - -public abstract class MapWrapper { - protected ArrayImage content; - - public MapWrapper(ArrayImage image) { - this.content = image; - } - - public abstract MapController getController(); - - public ArrayImage getContent() { - return content; - } -} diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java deleted file mode 100644 index 6079a40..0000000 --- a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.listeners; - -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.plugin.java.JavaPlugin; -import org.bukkit.util.Vector; - -public abstract class PacketListener implements Listener { - protected JavaPlugin plugin; - - public static PacketListener construct(JavaPlugin plugin) throws IllegalStateException { - String packageName = Bukkit.getServer().getClass().getPackage().getName(); - String version = packageName.substring(packageName.lastIndexOf('.') + 1); - - plugin.getLogger().info("Initializing the packet handler for Minecraft version " + version + "..."); - - try { - final Class clazz = Class.forName("tech.sbdevelopment.mapreflectionapi.nms.PacketListener_" + version); - if (PacketListener.class.isAssignableFrom(clazz)) { - return (PacketListener) clazz.getDeclaredConstructor().newInstance(); - } else { - throw new IllegalStateException("Plugin corrupted! Detected invalid PacketListener class."); - } - } catch (Exception ex) { - throw new IllegalStateException("This Minecraft version (" + version + ") is not supported! Contact the developer to get support."); - } - } - - public void init(JavaPlugin plugin) { - this.plugin = plugin; - Bukkit.getPluginManager().registerEvents(this, plugin); - } - - @EventHandler - public void onJoin(PlayerJoinEvent e) { - injectPlayer(e.getPlayer()); - } - - @EventHandler - public void onQuit(PlayerQuitEvent e) { - removePlayer(e.getPlayer()); - } - - protected abstract void injectPlayer(Player p); - - public abstract void removePlayer(Player p); - - protected abstract Vector vec3DToVector(Object vec3d); - - protected boolean hasField(Object packet, String field) { - try { - packet.getClass().getDeclaredField(field); - return true; - } catch (NoSuchFieldException ex) { - return false; - } - } -} diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java deleted file mode 100644 index 9c508a7..0000000 --- a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.util; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class ReflectionUtil { - public static Object getField(Object packet, String field) throws NoSuchFieldException, IllegalAccessException { - Field f = packet.getClass().getDeclaredField(field); - f.setAccessible(true); - return f.get(packet); - } - - public static Object getField(Class clazz, String field) throws NoSuchFieldException, IllegalAccessException { - Field f = clazz.getDeclaredField(field); - f.setAccessible(true); - return f.get(null); - } - - public static void setField(Object packet, String field, Object value) throws NoSuchFieldException, IllegalAccessException { - Field f = packet.getClass().getDeclaredField(field); - f.setAccessible(true); - f.set(packet, value); - } - - public static Object getValue(Object packet, String method) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - Method m = packet.getClass().getDeclaredMethod(method, null); - m.setAccessible(true); - return m.invoke(packet, null); - } -} diff --git a/Dist/pom.xml b/Dist/pom.xml deleted file mode 100644 index 29d8267..0000000 --- a/Dist/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - jar - - MapReflectionAPI-Dist - - - ../target - ${project.parent.name}-${project.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - org.apache.maven.plugins - maven-shade-plugin - 3.3.0 - - - package - - shade - - - false - - - - - tech.sbdevelopment:MapReflectionAPI* - - - - - - - - - - - - tech.sbdevelopment - MapReflectionAPI-API - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_19_R1 - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_18_R2 - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_16_R3 - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_17_R1 - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_15_R1 - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_14_R1 - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_13_R2 - ${project.parent.version} - - - tech.sbdevelopment - MapReflectionAPI-NMS-v1_12_R1 - ${project.parent.version} - - - \ No newline at end of file diff --git a/NMS-v1_12_R1/pom.xml b/NMS-v1_12_R1/pom.xml deleted file mode 100644 index 97d3164..0000000 --- a/NMS-v1_12_R1/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_12_R1 - - - 1.12.2-R0.1-SNAPSHOT - 11 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_12_R1.java b/NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_12_R1.java deleted file mode 100644 index 1063510..0000000 --- a/NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_12_R1.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.server.v1_12_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class PacketListener_v1_12_R1 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap) { - PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet; - - int id = (int) getField(packetPlayOutMap, "a"); - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity) { - PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet; - - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.a(); //action - EnumHand hand = packetPlayInUseEntity.b(); //hand - Vec3D pos = packetPlayInUseEntity.c(); //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, entityId, action.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 instanceof PacketPlayInSetCreativeSlot) { - PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet; - - int slot = packetPlayInSetCreativeSlot.a(); - ItemStack item = packetPlayInSetCreativeSlot.getItemStack(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline(); - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel; - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0); - - Vec3D vec3dObj = (Vec3D) vec3d; - return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z); - } -} diff --git a/NMS-v1_13_R2/pom.xml b/NMS-v1_13_R2/pom.xml deleted file mode 100644 index 1e53137..0000000 --- a/NMS-v1_13_R2/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_13_R2 - - - 1.13.2-R0.1-SNAPSHOT - 11 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_13_R2.java b/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_13_R2.java deleted file mode 100644 index cc34470..0000000 --- a/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_13_R2.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_13_R2.PacketPlayOutMap; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; -import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class MapSender_v1_13_R2 { - private static final List sendQueue = new ArrayList<>(); - private static int senderID = -1; - - public static void addToQueue(final int id, final ArrayImage content, final Player player) { - QueuedMap toSend = new QueuedMap(id, content, player); - if (sendQueue.contains(toSend)) return; - sendQueue.add(toSend); - - runSender(); - } - - private static void runSender() { - if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) - return; - - senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> { - if (sendQueue.isEmpty()) return; - - for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) { - QueuedMap current = sendQueue.get(0); - if (current == null) return; - - sendMap(current.id, current.image, current.player); - - if (!sendQueue.isEmpty()) sendQueue.remove(0); - } - }, 0, 2); - } - - public static void sendMap(final int id0, final ArrayImage content, final Player player) { - if (player == null || !player.isOnline()) { - List toRemove = new ArrayList<>(); - for (QueuedMap qMap : sendQueue) { - if (qMap == null) continue; - - if (qMap.player == null || !qMap.player.isOnline()) { - toRemove.add(qMap); - } - } - Bukkit.getScheduler().cancelTask(senderID); - sendQueue.removeAll(toRemove); - - return; - } - - final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //??? - new ArrayList<>(), //Icons - content.array, //Data - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY //Y size (2nd Y pos) - ); - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } catch (Exception e) { - e.printStackTrace(); - } - }); - } - - static final class QueuedMap { - private final int id; - private final ArrayImage image; - private final Player player; - - QueuedMap(int id, ArrayImage image, Player player) { - this.id = id; - this.image = image; - this.player = player; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (QueuedMap) obj; - return this.id == that.id && - Objects.equals(this.image, that.image) && - Objects.equals(this.player, that.player); - } - - @Override - public int hashCode() { - return Objects.hash(id, image, player); - } - - @Override - public String toString() { - return "QueuedMap[" + - "id=" + id + ", " + - "image=" + image + ", " + - "player=" + player + ']'; - } - } -} diff --git a/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_13_R2.java b/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_13_R2.java deleted file mode 100644 index 13b0efa..0000000 --- a/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_13_R2.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_13_R2.*; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.*; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.metadata.FixedMetadataValue; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; - -import java.util.*; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class MapWrapper_v1_13_R2 extends MapWrapper { - protected MapController controller = new MapController() { - private final Map viewers = new HashMap<>(); - - @Override - public void addViewer(Player player) throws MapLimitExceededException { - if (!isViewing(player)) { - viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player)); - } - } - - @Override - public void removeViewer(OfflinePlayer player) { - viewers.remove(player.getUniqueId()); - } - - @Override - public void clearViewers() { - for (UUID uuid : viewers.keySet()) { - viewers.remove(uuid); - } - } - - @Override - public boolean isViewing(OfflinePlayer player) { - if (player == null) return false; - return viewers.containsKey(player.getUniqueId()); - } - - @Override - public int getMapId(OfflinePlayer player) { - if (isViewing(player)) { - return viewers.get(player.getUniqueId()); - } - return -1; - } - - @Override - public void update(ArrayImage content) { - MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); - if (duplicate != null) { - MapWrapper_v1_13_R2.this.content = duplicate.getContent(); - return; - } - - MapWrapper_v1_13_R2.this.content = content; - - for (UUID id : viewers.keySet()) { - sendContent(Bukkit.getPlayer(id)); - } - } - - @Override - public ArrayImage getContent() { - return MapWrapper_v1_13_R2.this.getContent(); - } - - @Override - public void sendContent(Player player) { - sendContent(player, false); - } - - @Override - public void sendContent(Player player, boolean withoutQueue) { - if (!isViewing(player)) return; - - int id = getMapId(player); - if (withoutQueue) { - MapSender_v1_13_R2.sendMap(id, MapWrapper_v1_13_R2.this.content, player); - } else { - MapSender_v1_13_R2.addToQueue(id, MapWrapper_v1_13_R2.this.content, player); - } - } - - @Override - public void showInInventory(Player player, int slot, boolean force) { - if (!isViewing(player)) return; - - if (player.getGameMode() == GameMode.CREATIVE && !force) return; - - if (slot < 9) { - slot += 36; - } else if (slot > 35 && slot != 45) { - slot = 8 - (slot - 36); - } - - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().defaultContainer.windowId; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - net.minecraft.server.v1_13_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack); - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - - @Override - public void showInInventory(Player player, int slot) { - showInInventory(player, slot, false); - } - - @Override - public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return; - showInInventory(player, player.getInventory().getHeldItemSlot(), force); - } - - @Override - public void showInHand(Player player) { - showInHand(player, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame) { - showInFrame(player, frame, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.FILLED_MAP && !force) return; - showInFrame(player, frame.getEntityId()); - } - - @Override - public void showInFrame(Player player, int entityId) { - showInFrame(player, entityId, null); - } - - @Override - public void showInFrame(Player player, int entityId, String debugInfo) { - if (!isViewing(player)) return; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - if (debugInfo != null) { - ItemMeta itemMeta = stack.getItemMeta(); - itemMeta.setDisplayName(debugInfo); - stack.setItemMeta(itemMeta); - } - - Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> { - ItemFrame frame = getItemFrameById(player.getWorld(), entityId); - if (frame != null) { - frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_13_R2.this)); - } - - sendItemFramePacket(player, entityId, stack, getMapId(player)); - }); - } - - @Override - public void clearFrame(Player player, int entityId) { - - } - - @Override - public void clearFrame(Player player, ItemFrame frame) { - - } - - @Override - public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; - - Entity entity = craftWorld.getHandle().getEntity(entityId); - if (entity == null) return null; - - org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); - if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity; - - return null; - } - - private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.server.v1_13_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt - - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); - - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "e"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - }; - - public MapWrapper_v1_13_R2(ArrayImage image) { - super(image); - } - - @Override - public MapController getController() { - return controller; - } -} diff --git a/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_13_R2.java b/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_13_R2.java deleted file mode 100644 index e8b28ce..0000000 --- a/NMS-v1_13_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_13_R2.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.server.v1_13_R2.*; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class PacketListener_v1_13_R2 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap) { - PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet; - - int id = (int) getField(packetPlayOutMap, "a"); - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity) { - PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet; - - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action - EnumHand hand = packetPlayInUseEntity.c(); //hand - Vec3D pos = packetPlayInUseEntity.d(); //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, entityId, action.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 instanceof PacketPlayInSetCreativeSlot) { - PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet; - - int slot = packetPlayInSetCreativeSlot.b(); - ItemStack item = packetPlayInSetCreativeSlot.getItemStack(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline(); - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel; - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0); - - Vec3D vec3dObj = (Vec3D) vec3d; - return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z); - } -} diff --git a/NMS-v1_14_R1/pom.xml b/NMS-v1_14_R1/pom.xml deleted file mode 100644 index 51f3551..0000000 --- a/NMS-v1_14_R1/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_14_R1 - - - 1.14.4-R0.1-SNAPSHOT - 11 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_14_R1.java b/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_14_R1.java deleted file mode 100644 index afc893e..0000000 --- a/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_14_R1.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_14_R1.PacketPlayOutMap; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class MapSender_v1_14_R1 { - private static final List sendQueue = new ArrayList<>(); - private static int senderID = -1; - - public static void addToQueue(final int id, final ArrayImage content, final Player player) { - QueuedMap toSend = new QueuedMap(id, content, player); - if (sendQueue.contains(toSend)) return; - sendQueue.add(toSend); - - runSender(); - } - - private static void runSender() { - if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) - return; - - senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> { - if (sendQueue.isEmpty()) return; - - for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) { - QueuedMap current = sendQueue.get(0); - if (current == null) return; - - sendMap(current.id, current.image, current.player); - - if (!sendQueue.isEmpty()) sendQueue.remove(0); - } - }, 0, 2); - } - - public static void sendMap(final int id0, final ArrayImage content, final Player player) { - if (player == null || !player.isOnline()) { - List toRemove = new ArrayList<>(); - for (QueuedMap qMap : sendQueue) { - if (qMap == null) continue; - - if (qMap.player == null || !qMap.player.isOnline()) { - toRemove.add(qMap); - } - } - Bukkit.getScheduler().cancelTask(senderID); - sendQueue.removeAll(toRemove); - - return; - } - - final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //Tracking position - false, //Locked - new ArrayList<>(), //Icons - content.array, //Data - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY //Y size (2nd Y pos) - ); - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } catch (Exception e) { - e.printStackTrace(); - } - }); - } - - static final class QueuedMap { - private final int id; - private final ArrayImage image; - private final Player player; - - QueuedMap(int id, ArrayImage image, Player player) { - this.id = id; - this.image = image; - this.player = player; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (QueuedMap) obj; - return this.id == that.id && - Objects.equals(this.image, that.image) && - Objects.equals(this.player, that.player); - } - - @Override - public int hashCode() { - return Objects.hash(id, image, player); - } - - @Override - public String toString() { - return "QueuedMap[" + - "id=" + id + ", " + - "image=" + image + ", " + - "player=" + player + ']'; - } - } -} diff --git a/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_14_R1.java b/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_14_R1.java deleted file mode 100644 index 4e526c9..0000000 --- a/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_14_R1.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_14_R1.*; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.*; -import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.metadata.FixedMetadataValue; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; - -import java.util.*; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class MapWrapper_v1_14_R1 extends MapWrapper { - protected MapController controller = new MapController() { - private final Map viewers = new HashMap<>(); - - @Override - public void addViewer(Player player) throws MapLimitExceededException { - if (!isViewing(player)) { - viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player)); - } - } - - @Override - public void removeViewer(OfflinePlayer player) { - viewers.remove(player.getUniqueId()); - } - - @Override - public void clearViewers() { - for (UUID uuid : viewers.keySet()) { - viewers.remove(uuid); - } - } - - @Override - public boolean isViewing(OfflinePlayer player) { - if (player == null) return false; - return viewers.containsKey(player.getUniqueId()); - } - - @Override - public int getMapId(OfflinePlayer player) { - if (isViewing(player)) { - return viewers.get(player.getUniqueId()); - } - return -1; - } - - @Override - public void update(ArrayImage content) { - MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); - if (duplicate != null) { - MapWrapper_v1_14_R1.this.content = duplicate.getContent(); - return; - } - - MapWrapper_v1_14_R1.this.content = content; - - for (UUID id : viewers.keySet()) { - sendContent(Bukkit.getPlayer(id)); - } - } - - @Override - public ArrayImage getContent() { - return MapWrapper_v1_14_R1.this.getContent(); - } - - @Override - public void sendContent(Player player) { - sendContent(player, false); - } - - @Override - public void sendContent(Player player, boolean withoutQueue) { - if (!isViewing(player)) return; - - int id = getMapId(player); - if (withoutQueue) { - MapSender_v1_14_R1.sendMap(id, MapWrapper_v1_14_R1.this.content, player); - } else { - MapSender_v1_14_R1.addToQueue(id, MapWrapper_v1_14_R1.this.content, player); - } - } - - @Override - public void showInInventory(Player player, int slot, boolean force) { - if (!isViewing(player)) return; - - if (player.getGameMode() == GameMode.CREATIVE && !force) return; - - if (slot < 9) { - slot += 36; - } else if (slot > 35 && slot != 45) { - slot = 8 - (slot - 36); - } - - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().defaultContainer.windowId; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - net.minecraft.server.v1_14_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack); - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - - @Override - public void showInInventory(Player player, int slot) { - showInInventory(player, slot, false); - } - - @Override - public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return; - showInInventory(player, player.getInventory().getHeldItemSlot(), force); - } - - @Override - public void showInHand(Player player) { - showInHand(player, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame) { - showInFrame(player, frame, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.FILLED_MAP && !force) return; - showInFrame(player, frame.getEntityId()); - } - - @Override - public void showInFrame(Player player, int entityId) { - showInFrame(player, entityId, null); - } - - @Override - public void showInFrame(Player player, int entityId, String debugInfo) { - if (!isViewing(player)) return; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - if (debugInfo != null) { - ItemMeta itemMeta = stack.getItemMeta(); - itemMeta.setDisplayName(debugInfo); - stack.setItemMeta(itemMeta); - } - - Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> { - ItemFrame frame = getItemFrameById(player.getWorld(), entityId); - if (frame != null) { - frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_14_R1.this)); - } - - sendItemFramePacket(player, entityId, stack, getMapId(player)); - }); - } - - @Override - public void clearFrame(Player player, int entityId) { - - } - - @Override - public void clearFrame(Player player, ItemFrame frame) { - - } - - @Override - public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; - - Entity entity = craftWorld.getHandle().getEntity(entityId); - if (entity == null) return null; - - org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); - if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity; - - return null; - } - - private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.server.v1_14_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt - - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); - - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "ITEM"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - }; - - public MapWrapper_v1_14_R1(ArrayImage image) { - super(image); - } - - @Override - public MapController getController() { - return controller; - } -} diff --git a/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_14_R1.java b/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_14_R1.java deleted file mode 100644 index 1083801..0000000 --- a/NMS-v1_14_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_14_R1.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.server.v1_14_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class PacketListener_v1_14_R1 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap) { - PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet; - - int id = (int) getField(packetPlayOutMap, "a"); - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity) { - PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet; - - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action - EnumHand hand = packetPlayInUseEntity.c(); //hand - Vec3D pos = packetPlayInUseEntity.d(); //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, entityId, action.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 instanceof PacketPlayInSetCreativeSlot) { - PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet; - - int slot = packetPlayInSetCreativeSlot.b(); - ItemStack item = packetPlayInSetCreativeSlot.getItemStack(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline(); - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel; - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0); - - Vec3D vec3dObj = (Vec3D) vec3d; - return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z); - } -} diff --git a/NMS-v1_15_R1/pom.xml b/NMS-v1_15_R1/pom.xml deleted file mode 100644 index cce4f6d..0000000 --- a/NMS-v1_15_R1/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_15_R1 - - - 1.15.2-R0.1-SNAPSHOT - 11 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_15_R1.java b/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_15_R1.java deleted file mode 100644 index e16c48e..0000000 --- a/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_15_R1.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_15_R1.PacketPlayOutMap; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class MapSender_v1_15_R1 { - private static final List sendQueue = new ArrayList<>(); - private static int senderID = -1; - - public static void addToQueue(final int id, final ArrayImage content, final Player player) { - QueuedMap toSend = new QueuedMap(id, content, player); - if (sendQueue.contains(toSend)) return; - sendQueue.add(toSend); - - runSender(); - } - - private static void runSender() { - if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) - return; - - senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> { - if (sendQueue.isEmpty()) return; - - for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) { - QueuedMap current = sendQueue.get(0); - if (current == null) return; - - sendMap(current.id, current.image, current.player); - - if (!sendQueue.isEmpty()) sendQueue.remove(0); - } - }, 0, 2); - } - - public static void sendMap(final int id0, final ArrayImage content, final Player player) { - if (player == null || !player.isOnline()) { - List toRemove = new ArrayList<>(); - for (QueuedMap qMap : sendQueue) { - if (qMap == null) continue; - - if (qMap.player == null || !qMap.player.isOnline()) { - toRemove.add(qMap); - } - } - Bukkit.getScheduler().cancelTask(senderID); - sendQueue.removeAll(toRemove); - - return; - } - - final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //Tracking position - false, //Locked - new ArrayList<>(), //Icons - content.array, //Data - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY //Y size (2nd Y pos) - ); - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } catch (Exception e) { - e.printStackTrace(); - } - }); - } - - static final class QueuedMap { - private final int id; - private final ArrayImage image; - private final Player player; - - QueuedMap(int id, ArrayImage image, Player player) { - this.id = id; - this.image = image; - this.player = player; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (QueuedMap) obj; - return this.id == that.id && - Objects.equals(this.image, that.image) && - Objects.equals(this.player, that.player); - } - - @Override - public int hashCode() { - return Objects.hash(id, image, player); - } - - @Override - public String toString() { - return "QueuedMap[" + - "id=" + id + ", " + - "image=" + image + ", " + - "player=" + player + ']'; - } - } -} diff --git a/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_15_R1.java b/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_15_R1.java deleted file mode 100644 index 51db039..0000000 --- a/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_15_R1.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_15_R1.*; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.*; -import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.metadata.FixedMetadataValue; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; - -import java.util.*; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class MapWrapper_v1_15_R1 extends MapWrapper { - - protected MapController controller = new MapController() { - private final Map viewers = new HashMap<>(); - - @Override - public void addViewer(Player player) throws MapLimitExceededException { - if (!isViewing(player)) { - viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player)); - } - } - - @Override - public void removeViewer(OfflinePlayer player) { - viewers.remove(player.getUniqueId()); - } - - @Override - public void clearViewers() { - for (UUID uuid : viewers.keySet()) { - viewers.remove(uuid); - } - } - - @Override - public boolean isViewing(OfflinePlayer player) { - if (player == null) return false; - return viewers.containsKey(player.getUniqueId()); - } - - @Override - public int getMapId(OfflinePlayer player) { - if (isViewing(player)) { - return viewers.get(player.getUniqueId()); - } - return -1; - } - - @Override - public void update(ArrayImage content) { - MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); - if (duplicate != null) { - MapWrapper_v1_15_R1.this.content = duplicate.getContent(); - return; - } - - MapWrapper_v1_15_R1.this.content = content; - - for (UUID id : viewers.keySet()) { - sendContent(Bukkit.getPlayer(id)); - } - } - - @Override - public ArrayImage getContent() { - return MapWrapper_v1_15_R1.this.getContent(); - } - - @Override - public void sendContent(Player player) { - sendContent(player, false); - } - - @Override - public void sendContent(Player player, boolean withoutQueue) { - if (!isViewing(player)) return; - - int id = getMapId(player); - if (withoutQueue) { - MapSender_v1_15_R1.sendMap(id, MapWrapper_v1_15_R1.this.content, player); - } else { - MapSender_v1_15_R1.addToQueue(id, MapWrapper_v1_15_R1.this.content, player); - } - } - - @Override - public void showInInventory(Player player, int slot, boolean force) { - if (!isViewing(player)) return; - - if (player.getGameMode() == GameMode.CREATIVE && !force) return; - - if (slot < 9) { - slot += 36; - } else if (slot > 35 && slot != 45) { - slot = 8 - (slot - 36); - } - - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().defaultContainer.windowId; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - net.minecraft.server.v1_15_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack); - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - - @Override - public void showInInventory(Player player, int slot) { - showInInventory(player, slot, false); - } - - @Override - public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return; - showInInventory(player, player.getInventory().getHeldItemSlot(), force); - } - - @Override - public void showInHand(Player player) { - showInHand(player, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame) { - showInFrame(player, frame, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.FILLED_MAP && !force) return; - showInFrame(player, frame.getEntityId()); - } - - @Override - public void showInFrame(Player player, int entityId) { - showInFrame(player, entityId, null); - } - - @Override - public void showInFrame(Player player, int entityId, String debugInfo) { - if (!isViewing(player)) return; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - if (debugInfo != null) { - ItemMeta itemMeta = stack.getItemMeta(); - itemMeta.setDisplayName(debugInfo); - stack.setItemMeta(itemMeta); - } - - Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> { - ItemFrame frame = getItemFrameById(player.getWorld(), entityId); - if (frame != null) { - frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_15_R1.this)); - } - - sendItemFramePacket(player, entityId, stack, getMapId(player)); - }); - } - - @Override - public void clearFrame(Player player, int entityId) { - - } - - @Override - public void clearFrame(Player player, ItemFrame frame) { - - } - - @Override - public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; - - Entity entity = craftWorld.getHandle().getEntity(entityId); - if (entity == null) return null; - - org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); - if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity; - - return null; - } - - private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.server.v1_15_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt - - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); - - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "ITEM"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - }; - - public MapWrapper_v1_15_R1(ArrayImage image) { - super(image); - } - - @Override - public MapController getController() { - return controller; - } -} diff --git a/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_15_R1.java b/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_15_R1.java deleted file mode 100644 index ba807c1..0000000 --- a/NMS-v1_15_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_15_R1.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.server.v1_15_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class PacketListener_v1_15_R1 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap) { - PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet; - - int id = (int) getField(packetPlayOutMap, "a"); - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity) { - PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet; - - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action - EnumHand hand = packetPlayInUseEntity.c(); //hand - Vec3D pos = packetPlayInUseEntity.d(); //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, entityId, action.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 instanceof PacketPlayInSetCreativeSlot) { - PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet; - - int slot = packetPlayInSetCreativeSlot.b(); - ItemStack item = packetPlayInSetCreativeSlot.getItemStack(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline(); - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel; - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0); - - Vec3D vec3dObj = (Vec3D) vec3d; - return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z); - } -} diff --git a/NMS-v1_16_R3/pom.xml b/NMS-v1_16_R3/pom.xml deleted file mode 100644 index 17b221c..0000000 --- a/NMS-v1_16_R3/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_16_R3 - - - 1.16.4-R0.1-SNAPSHOT - 11 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_16_R3.java b/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_16_R3.java deleted file mode 100644 index 661205c..0000000 --- a/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_16_R3.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_16_R3.PacketPlayOutMap; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class MapSender_v1_16_R3 { - private static final List sendQueue = new ArrayList<>(); - private static int senderID = -1; - - public static void addToQueue(final int id, final ArrayImage content, final Player player) { - QueuedMap toSend = new QueuedMap(id, content, player); - if (sendQueue.contains(toSend)) return; - sendQueue.add(toSend); - - runSender(); - } - - private static void runSender() { - if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) - return; - - senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> { - if (sendQueue.isEmpty()) return; - - for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) { - QueuedMap current = sendQueue.get(0); - if (current == null) return; - - sendMap(current.id, current.image, current.player); - - if (!sendQueue.isEmpty()) sendQueue.remove(0); - } - }, 0, 2); - } - - public static void sendMap(final int id0, final ArrayImage content, final Player player) { - if (player == null || !player.isOnline()) { - List toRemove = new ArrayList<>(); - for (QueuedMap qMap : sendQueue) { - if (qMap == null) continue; - - if (qMap.player == null || !qMap.player.isOnline()) { - toRemove.add(qMap); - } - } - Bukkit.getScheduler().cancelTask(senderID); - sendQueue.removeAll(toRemove); - - return; - } - - final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //Tracking position - false, //Locked - new ArrayList<>(), //Icons - content.array, //Data - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY //Y size (2nd Y pos) - ); - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } catch (Exception e) { - e.printStackTrace(); - } - }); - } - - static final class QueuedMap { - private final int id; - private final ArrayImage image; - private final Player player; - - QueuedMap(int id, ArrayImage image, Player player) { - this.id = id; - this.image = image; - this.player = player; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (QueuedMap) obj; - return this.id == that.id && - Objects.equals(this.image, that.image) && - Objects.equals(this.player, that.player); - } - - @Override - public int hashCode() { - return Objects.hash(id, image, player); - } - - @Override - public String toString() { - return "QueuedMap[" + - "id=" + id + ", " + - "image=" + image + ", " + - "player=" + player + ']'; - } - } -} diff --git a/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_16_R3.java b/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_16_R3.java deleted file mode 100644 index 061f41b..0000000 --- a/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_16_R3.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.server.v1_16_R3.*; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.*; -import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.metadata.FixedMetadataValue; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; - -import java.util.*; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class MapWrapper_v1_16_R3 extends MapWrapper { - protected MapController controller = new MapController() { - private final Map viewers = new HashMap<>(); - - @Override - public void addViewer(Player player) throws MapLimitExceededException { - if (!isViewing(player)) { - viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player)); - } - } - - @Override - public void removeViewer(OfflinePlayer player) { - viewers.remove(player.getUniqueId()); - } - - @Override - public void clearViewers() { - for (UUID uuid : viewers.keySet()) { - viewers.remove(uuid); - } - } - - @Override - public boolean isViewing(OfflinePlayer player) { - if (player == null) return false; - return viewers.containsKey(player.getUniqueId()); - } - - @Override - public int getMapId(OfflinePlayer player) { - if (isViewing(player)) { - return viewers.get(player.getUniqueId()); - } - return -1; - } - - @Override - public void update(ArrayImage content) { - MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); - if (duplicate != null) { - MapWrapper_v1_16_R3.this.content = duplicate.getContent(); - return; - } - - MapWrapper_v1_16_R3.this.content = content; - - for (UUID id : viewers.keySet()) { - sendContent(Bukkit.getPlayer(id)); - } - } - - @Override - public ArrayImage getContent() { - return MapWrapper_v1_16_R3.this.getContent(); - } - - @Override - public void sendContent(Player player) { - sendContent(player, false); - } - - @Override - public void sendContent(Player player, boolean withoutQueue) { - if (!isViewing(player)) return; - - int id = getMapId(player); - if (withoutQueue) { - MapSender_v1_16_R3.sendMap(id, MapWrapper_v1_16_R3.this.content, player); - } else { - MapSender_v1_16_R3.addToQueue(id, MapWrapper_v1_16_R3.this.content, player); - } - } - - @Override - public void showInInventory(Player player, int slot, boolean force) { - if (!isViewing(player)) return; - - if (player.getGameMode() == GameMode.CREATIVE && !force) return; - - if (slot < 9) { - slot += 36; - } else if (slot > 35 && slot != 45) { - slot = 8 - (slot - 36); - } - - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().defaultContainer.windowId; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - net.minecraft.server.v1_16_R3.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack); - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - - @Override - public void showInInventory(Player player, int slot) { - showInInventory(player, slot, false); - } - - @Override - public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return; - showInInventory(player, player.getInventory().getHeldItemSlot(), force); - } - - @Override - public void showInHand(Player player) { - showInHand(player, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame) { - showInFrame(player, frame, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.FILLED_MAP && !force) return; - showInFrame(player, frame.getEntityId()); - } - - @Override - public void showInFrame(Player player, int entityId) { - showInFrame(player, entityId, null); - } - - @Override - public void showInFrame(Player player, int entityId, String debugInfo) { - if (!isViewing(player)) return; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - if (debugInfo != null) { - ItemMeta itemMeta = stack.getItemMeta(); - itemMeta.setDisplayName(debugInfo); - stack.setItemMeta(itemMeta); - } - - Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> { - ItemFrame frame = getItemFrameById(player.getWorld(), entityId); - if (frame != null) { - frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_16_R3.this)); - } - - sendItemFramePacket(player, entityId, stack, getMapId(player)); - }); - } - - @Override - public void clearFrame(Player player, int entityId) { - - } - - @Override - public void clearFrame(Player player, ItemFrame frame) { - - } - - @Override - public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; - - Entity entity = craftWorld.getHandle().getEntity(entityId); - if (entity == null) return null; - - org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); - if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity; - - return null; - } - - private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.server.v1_16_R3.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt - - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); - - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "ITEM"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - }; - - public MapWrapper_v1_16_R3(ArrayImage image) { - super(image); - } - - @Override - public MapController getController() { - return controller; - } -} diff --git a/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_16_R3.java b/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_16_R3.java deleted file mode 100644 index 3e846ba..0000000 --- a/NMS-v1_16_R3/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_16_R3.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.server.v1_16_R3.*; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class PacketListener_v1_16_R3 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap) { - PacketPlayOutMap packetPlayOutMap = (PacketPlayOutMap) packet; - - int id = (int) getField(packetPlayOutMap, "a"); - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity) { - PacketPlayInUseEntity packetPlayInUseEntity = (PacketPlayInUseEntity) packet; - - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - PacketPlayInUseEntity.EnumEntityUseAction action = packetPlayInUseEntity.b(); //action - EnumHand hand = packetPlayInUseEntity.c(); //hand - Vec3D pos = packetPlayInUseEntity.d(); //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, entityId, action.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 instanceof PacketPlayInSetCreativeSlot) { - PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) packet; - - int slot = packetPlayInSetCreativeSlot.b(); - ItemStack item = packetPlayInSetCreativeSlot.getItemStack(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel.pipeline(); - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().playerConnection.networkManager.channel; - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D)) return new Vector(0, 0, 0); - - Vec3D vec3dObj = (Vec3D) vec3d; - return new Vector(vec3dObj.x, vec3dObj.y, vec3dObj.z); - } -} diff --git a/NMS-v1_17_R1/pom.xml b/NMS-v1_17_R1/pom.xml deleted file mode 100644 index b36444c..0000000 --- a/NMS-v1_17_R1/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_17_R1 - - - 1.17.1-R0.1-SNAPSHOT - 16 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_17_R1.java b/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_17_R1.java deleted file mode 100644 index c639def..0000000 --- a/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_17_R1.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.network.protocol.game.PacketPlayOutMap; -import net.minecraft.world.level.saveddata.maps.WorldMap; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; - -import java.util.ArrayList; -import java.util.List; - -public class MapSender_v1_17_R1 { - private static final List sendQueue = new ArrayList<>(); - private static int senderID = -1; - - public static void addToQueue(final int id, final ArrayImage content, final Player player) { - QueuedMap toSend = new QueuedMap(id, content, player); - if (sendQueue.contains(toSend)) return; - sendQueue.add(toSend); - - runSender(); - } - - private static void runSender() { - if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) - return; - - senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> { - if (sendQueue.isEmpty()) return; - - for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) { - QueuedMap current = sendQueue.get(0); - if (current == null) return; - - sendMap(current.id, current.image, current.player); - - if (!sendQueue.isEmpty()) sendQueue.remove(0); - } - }, 0, 2); - } - - public static void sendMap(final int id0, final ArrayImage content, final Player player) { - if (player == null || !player.isOnline()) { - List toRemove = new ArrayList<>(); - for (QueuedMap qMap : sendQueue) { - if (qMap == null) continue; - - if (qMap.player == null || !qMap.player.isOnline()) { - toRemove.add(qMap); - } - } - Bukkit.getScheduler().cancelTask(senderID); - sendQueue.removeAll(toRemove); - - return; - } - - final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - WorldMap.b updateData = new WorldMap.b( - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY, //Y size (2nd Y pos) - content.array //Data - ); - - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //Show icons - new ArrayList<>(), //Icons - updateData - ); - - ((CraftPlayer) player).getHandle().b.sendPacket(packet); //connection send() - } catch (Exception e) { - e.printStackTrace(); - } - }); - } - - record QueuedMap(int id, ArrayImage image, Player player) { - } -} \ No newline at end of file diff --git a/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_17_R1.java b/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_17_R1.java deleted file mode 100644 index e31eb45..0000000 --- a/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_17_R1.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; -import net.minecraft.network.protocol.game.PacketPlayOutSetSlot; -import net.minecraft.network.syncher.DataWatcher; -import net.minecraft.network.syncher.DataWatcherObject; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.decoration.EntityItemFrame; -import org.bukkit.*; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.metadata.FixedMetadataValue; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; - -import java.util.*; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class MapWrapper_v1_17_R1 extends MapWrapper { - protected MapController controller = new MapController() { - private final Map viewers = new HashMap<>(); - - @Override - public void addViewer(Player player) throws MapLimitExceededException { - if (!isViewing(player)) { - viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player)); - } - } - - @Override - public void removeViewer(OfflinePlayer player) { - viewers.remove(player.getUniqueId()); - } - - @Override - public void clearViewers() { - for (UUID uuid : viewers.keySet()) { - viewers.remove(uuid); - } - } - - @Override - public boolean isViewing(OfflinePlayer player) { - if (player == null) return false; - return viewers.containsKey(player.getUniqueId()); - } - - @Override - public int getMapId(OfflinePlayer player) { - if (isViewing(player)) { - return viewers.get(player.getUniqueId()); - } - return -1; - } - - @Override - public void update(ArrayImage content) { - MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); - if (duplicate != null) { - MapWrapper_v1_17_R1.this.content = duplicate.getContent(); - return; - } - - MapWrapper_v1_17_R1.this.content = content; - - for (UUID id : viewers.keySet()) { - sendContent(Bukkit.getPlayer(id)); - } - } - - @Override - public ArrayImage getContent() { - return MapWrapper_v1_17_R1.this.getContent(); - } - - @Override - public void sendContent(Player player) { - sendContent(player, false); - } - - @Override - public void sendContent(Player player, boolean withoutQueue) { - if (!isViewing(player)) return; - - int id = getMapId(player); - if (withoutQueue) { - MapSender_v1_17_R1.sendMap(id, MapWrapper_v1_17_R1.this.content, player); - } else { - MapSender_v1_17_R1.addToQueue(id, MapWrapper_v1_17_R1.this.content, player); - } - } - - @Override - public void showInInventory(Player player, int slot, boolean force) { - if (!isViewing(player)) return; - - if (player.getGameMode() == GameMode.CREATIVE && !force) return; - - if (slot < 9) { - slot += 36; - } else if (slot > 35 && slot != 45) { - slot = 8 - (slot - 36); - } - - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().bU.j; //inventoryMenu containerId - int stateId = craftPlayer.getHandle().bU.getStateId(); //inventoryMenu getStateId() - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, stateId, slot, nmsStack); - ((CraftPlayer) player).getHandle().b.sendPacket(packet); - } - - @Override - public void showInInventory(Player player, int slot) { - showInInventory(player, slot, false); - } - - @Override - public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return; - showInInventory(player, player.getInventory().getHeldItemSlot(), force); - } - - @Override - public void showInHand(Player player) { - showInHand(player, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame) { - showInFrame(player, frame, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.FILLED_MAP && !force) return; - showInFrame(player, frame.getEntityId()); - } - - @Override - public void showInFrame(Player player, int entityId) { - showInFrame(player, entityId, null); - } - - @Override - public void showInFrame(Player player, int entityId, String debugInfo) { - if (!isViewing(player)) return; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - if (debugInfo != null) { - ItemMeta itemMeta = stack.getItemMeta(); - itemMeta.setDisplayName(debugInfo); - stack.setItemMeta(itemMeta); - } - - Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> { - ItemFrame frame = getItemFrameById(player.getWorld(), entityId); - if (frame != null) { - frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_17_R1.this)); - } - - sendItemFramePacket(player, entityId, stack, getMapId(player)); - }); - } - - @Override - public void clearFrame(Player player, int entityId) { - - } - - @Override - public void clearFrame(Player player, ItemFrame frame) { - - } - - @Override - public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; - - Entity entity = craftWorld.getHandle().getEntity(entityId); - if (entity == null) return null; - - if (entity instanceof ItemFrame) return (ItemFrame) entity; - - return null; - } - - private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - nmsStack.getOrCreateTag().setInt("map", mapId); //getOrCreateTag putInt - - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); - - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "ao"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - ((CraftPlayer) player).getHandle().b.sendPacket(packet); - } - }; - - public MapWrapper_v1_17_R1(ArrayImage image) { - super(image); - } - - @Override - public MapController getController() { - return controller; - } -} \ No newline at end of file diff --git a/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_17_R1.java b/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_17_R1.java deleted file mode 100644 index 1b26136..0000000 --- a/NMS-v1_17_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_17_R1.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot; -import net.minecraft.network.protocol.game.PacketPlayInUseEntity; -import net.minecraft.network.protocol.game.PacketPlayOutMap; -import net.minecraft.world.EnumHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3D; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.*; - -public class PacketListener_v1_17_R1 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap packetPlayOutMap) { - int id = (int) getField(packetPlayOutMap, "a"); - - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity packetPlayInUseEntity) { - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - Object action = getField(packetPlayInUseEntity, "b"); //action - Enum actionEnum = (Enum) getValue(action, "a"); //action type - EnumHand hand = hasField(action, "a") ? (EnumHand) getField(action, "a") : null; //hand - Vec3D pos = hasField(action, "b") ? (Vec3D) getField(action, "b") : null; //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, 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 instanceof PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot) { - int slot = packetPlayInSetCreativeSlot.b(); - ItemStack item = packetPlayInSetCreativeSlot.getItemStack(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().b.a.k.pipeline(); //connection connection channel - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().b.a.k; //connection connection channel - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D vec3dObj)) return new Vector(0, 0, 0); - return new Vector(vec3dObj.b, vec3dObj.c, vec3dObj.d); //x, y, z - } -} \ No newline at end of file diff --git a/NMS-v1_18_R2/pom.xml b/NMS-v1_18_R2/pom.xml deleted file mode 100644 index d3f7388..0000000 --- a/NMS-v1_18_R2/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_18_R2 - - - 1.18.2-R0.1-SNAPSHOT - 17 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_18_R2.java b/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_18_R2.java deleted file mode 100644 index dae512a..0000000 --- a/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_18_R2.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.network.protocol.game.PacketPlayOutMap; -import net.minecraft.world.level.saveddata.maps.WorldMap; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; - -import java.util.ArrayList; -import java.util.List; - -public class MapSender_v1_18_R2 { - private static final List sendQueue = new ArrayList<>(); - private static int senderID = -1; - - public static void addToQueue(final int id, final ArrayImage content, final Player player) { - QueuedMap toSend = new QueuedMap(id, content, player); - if (sendQueue.contains(toSend)) return; - sendQueue.add(toSend); - - runSender(); - } - - private static void runSender() { - if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) - return; - - senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> { - if (sendQueue.isEmpty()) return; - - for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) { - QueuedMap current = sendQueue.get(0); - if (current == null) return; - - sendMap(current.id, current.image, current.player); - - if (!sendQueue.isEmpty()) sendQueue.remove(0); - } - }, 0, 2); - } - - public static void sendMap(final int id0, final ArrayImage content, final Player player) { - if (player == null || !player.isOnline()) { - List toRemove = new ArrayList<>(); - for (QueuedMap qMap : sendQueue) { - if (qMap == null) continue; - - if (qMap.player == null || !qMap.player.isOnline()) { - toRemove.add(qMap); - } - } - Bukkit.getScheduler().cancelTask(senderID); - sendQueue.removeAll(toRemove); - - return; - } - - final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - WorldMap.b updateData = new WorldMap.b( - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY, //Y size (2nd Y pos) - content.array //Data - ); - - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //Show icons - new ArrayList<>(), //Icons - updateData - ); - - ((CraftPlayer) player).getHandle().b.a(packet); //connection send() - } catch (Exception e) { - e.printStackTrace(); - } - }); - } - - record QueuedMap(int id, ArrayImage image, Player player) { - } -} \ No newline at end of file diff --git a/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_18_R2.java b/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_18_R2.java deleted file mode 100644 index 671c86e..0000000 --- a/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_18_R2.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; -import net.minecraft.network.protocol.game.PacketPlayOutSetSlot; -import net.minecraft.network.syncher.DataWatcher; -import net.minecraft.network.syncher.DataWatcherObject; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.decoration.EntityItemFrame; -import org.bukkit.*; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.metadata.FixedMetadataValue; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; - -import java.util.*; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class MapWrapper_v1_18_R2 extends MapWrapper { - protected MapController controller = new MapController() { - private final Map viewers = new HashMap<>(); - - @Override - public void addViewer(Player player) throws MapLimitExceededException { - if (!isViewing(player)) { - viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player)); - } - } - - @Override - public void removeViewer(OfflinePlayer player) { - viewers.remove(player.getUniqueId()); - } - - @Override - public void clearViewers() { - for (UUID uuid : viewers.keySet()) { - viewers.remove(uuid); - } - } - - @Override - public boolean isViewing(OfflinePlayer player) { - if (player == null) return false; - return viewers.containsKey(player.getUniqueId()); - } - - @Override - public int getMapId(OfflinePlayer player) { - if (isViewing(player)) { - return viewers.get(player.getUniqueId()); - } - return -1; - } - - @Override - public void update(ArrayImage content) { - MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); - if (duplicate != null) { - MapWrapper_v1_18_R2.this.content = duplicate.getContent(); - return; - } - - MapWrapper_v1_18_R2.this.content = content; - - for (UUID id : viewers.keySet()) { - sendContent(Bukkit.getPlayer(id)); - } - } - - @Override - public ArrayImage getContent() { - return MapWrapper_v1_18_R2.this.getContent(); - } - - @Override - public void sendContent(Player player) { - sendContent(player, false); - } - - @Override - public void sendContent(Player player, boolean withoutQueue) { - if (!isViewing(player)) return; - - int id = getMapId(player); - if (withoutQueue) { - MapSender_v1_18_R2.sendMap(id, MapWrapper_v1_18_R2.this.content, player); - } else { - MapSender_v1_18_R2.addToQueue(id, MapWrapper_v1_18_R2.this.content, player); - } - } - - @Override - public void showInInventory(Player player, int slot, boolean force) { - if (!isViewing(player)) return; - - if (player.getGameMode() == GameMode.CREATIVE && !force) return; - - if (slot < 9) { - slot += 36; - } else if (slot > 35 && slot != 45) { - slot = 8 - (slot - 36); - } - - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().bU.j; //inventoryMenu containerId - int stateId = craftPlayer.getHandle().bU.j(); //inventoryMenu getStateId() - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, stateId, slot, nmsStack); - ((CraftPlayer) player).getHandle().b.a(packet); - } - - @Override - public void showInInventory(Player player, int slot) { - showInInventory(player, slot, false); - } - - @Override - public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return; - showInInventory(player, player.getInventory().getHeldItemSlot(), force); - } - - @Override - public void showInHand(Player player) { - showInHand(player, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame) { - showInFrame(player, frame, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.FILLED_MAP && !force) return; - showInFrame(player, frame.getEntityId()); - } - - @Override - public void showInFrame(Player player, int entityId) { - showInFrame(player, entityId, null); - } - - @Override - public void showInFrame(Player player, int entityId, String debugInfo) { - if (!isViewing(player)) return; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - if (debugInfo != null) { - ItemMeta itemMeta = stack.getItemMeta(); - itemMeta.setDisplayName(debugInfo); - stack.setItemMeta(itemMeta); - } - - Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> { - ItemFrame frame = getItemFrameById(player.getWorld(), entityId); - if (frame != null) { - frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_18_R2.this)); - } - - sendItemFramePacket(player, entityId, stack, getMapId(player)); - }); - } - - @Override - public void clearFrame(Player player, int entityId) { - - } - - @Override - public void clearFrame(Player player, ItemFrame frame) { - - } - - @Override - public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; - - Entity entity = craftWorld.getHandle().a(entityId); - if (entity == null) return null; - - if (entity instanceof ItemFrame) return (ItemFrame) entity; - - return null; - } - - private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - nmsStack.u().a("map", mapId); //getOrCreateTag putInt - - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); - - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "ao"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - ((CraftPlayer) player).getHandle().b.a(packet); - } - }; - - public MapWrapper_v1_18_R2(ArrayImage image) { - super(image); - } - - @Override - public MapController getController() { - return controller; - } -} diff --git a/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_18_R2.java b/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_18_R2.java deleted file mode 100644 index ed14a73..0000000 --- a/NMS-v1_18_R2/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_18_R2.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot; -import net.minecraft.network.protocol.game.PacketPlayInUseEntity; -import net.minecraft.network.protocol.game.PacketPlayOutMap; -import net.minecraft.world.EnumHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3D; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.*; - -public class PacketListener_v1_18_R2 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap packetPlayOutMap) { - int id = (int) getField(packetPlayOutMap, "a"); - - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity packetPlayInUseEntity) { - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - Object action = getField(packetPlayInUseEntity, "b"); //action - Enum actionEnum = (Enum) getValue(action, "a"); //action type - EnumHand hand = hasField(action, "a") ? (EnumHand) getField(action, "a") : null; //hand - Vec3D pos = hasField(action, "b") ? (Vec3D) getField(action, "b") : null; //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, 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 instanceof PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot) { - int slot = packetPlayInSetCreativeSlot.b(); - ItemStack item = packetPlayInSetCreativeSlot.c(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().b.a.m.pipeline(); //connection connection channel - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().b.a.m; //connection connection channel - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D vec3dObj)) return new Vector(0, 0, 0); - return new Vector(vec3dObj.b, vec3dObj.c, vec3dObj.d); //x, y, z - } -} diff --git a/NMS-v1_19_R1/pom.xml b/NMS-v1_19_R1/pom.xml deleted file mode 100644 index 6fe4d53..0000000 --- a/NMS-v1_19_R1/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - MapReflectionAPI - tech.sbdevelopment - ${revision} - - 4.0.0 - - MapReflectionAPI-NMS-v1_19_R1 - - - 1.19-R0.1-SNAPSHOT - 17 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.9.0-SNAPSHOT - - ${jdk.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - - - - - - - - org.bukkit - craftbukkit - ${NMSVersion} - provided - - - tech.sbdevelopment - MapReflectionAPI-API - 1.0-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_19_R1.java b/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_19_R1.java deleted file mode 100644 index 3d420c0..0000000 --- a/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_19_R1.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.network.protocol.game.PacketPlayOutMap; -import net.minecraft.world.level.saveddata.maps.WorldMap; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; - -import java.util.ArrayList; -import java.util.List; - -public class MapSender_v1_19_R1 { - private static final List sendQueue = new ArrayList<>(); - private static int senderID = -1; - - public static void addToQueue(final int id, final ArrayImage content, final Player player) { - QueuedMap toSend = new QueuedMap(id, content, player); - if (sendQueue.contains(toSend)) return; - sendQueue.add(toSend); - - runSender(); - } - - private static void runSender() { - if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) - return; - - senderID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MapReflectionAPI.getInstance(), () -> { - if (sendQueue.isEmpty()) return; - - for (int i = 0; i < Math.min(sendQueue.size(), 10 + 1); i++) { - QueuedMap current = sendQueue.get(0); - if (current == null) return; - - sendMap(current.id, current.image, current.player); - - if (!sendQueue.isEmpty()) sendQueue.remove(0); - } - }, 0, 2); - } - - public static void sendMap(final int id0, final ArrayImage content, final Player player) { - if (player == null || !player.isOnline()) { - List toRemove = new ArrayList<>(); - for (QueuedMap qMap : sendQueue) { - if (qMap == null) continue; - - if (qMap.player == null || !qMap.player.isOnline()) { - toRemove.add(qMap); - } - } - Bukkit.getScheduler().cancelTask(senderID); - sendQueue.removeAll(toRemove); - - return; - } - - final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - WorldMap.b updateData = new WorldMap.b( - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY, //Y size (2nd Y pos) - content.array //Data - ); - - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //Show icons - new ArrayList<>(), //Icons - updateData - ); - - ((CraftPlayer) player).getHandle().b.a(packet); //connection send() - } catch (Exception e) { - e.printStackTrace(); - } - }); - } - - record QueuedMap(int id, ArrayImage image, Player player) { - } -} diff --git a/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_19_R1.java b/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_19_R1.java deleted file mode 100644 index 9267d6f..0000000 --- a/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_19_R1.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; -import net.minecraft.network.protocol.game.PacketPlayOutSetSlot; -import net.minecraft.network.syncher.DataWatcher; -import net.minecraft.network.syncher.DataWatcherObject; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.decoration.EntityItemFrame; -import org.bukkit.*; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.metadata.FixedMetadataValue; -import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; - -import java.util.*; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; - -public class MapWrapper_v1_19_R1 extends MapWrapper { - protected MapController controller = new MapController() { - private final Map viewers = new HashMap<>(); - - @Override - public void addViewer(Player player) throws MapLimitExceededException { - if (!isViewing(player)) { - viewers.put(player.getUniqueId(), MapReflectionAPI.getMapManager().getNextFreeIdFor(player)); - } - } - - @Override - public void removeViewer(OfflinePlayer player) { - viewers.remove(player.getUniqueId()); - } - - @Override - public void clearViewers() { - for (UUID uuid : viewers.keySet()) { - viewers.remove(uuid); - } - } - - @Override - public boolean isViewing(OfflinePlayer player) { - if (player == null) return false; - return viewers.containsKey(player.getUniqueId()); - } - - @Override - public int getMapId(OfflinePlayer player) { - if (isViewing(player)) { - return viewers.get(player.getUniqueId()); - } - return -1; - } - - @Override - public void update(ArrayImage content) { - MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); - if (duplicate != null) { - MapWrapper_v1_19_R1.this.content = duplicate.getContent(); - return; - } - - MapWrapper_v1_19_R1.this.content = content; - - for (UUID id : viewers.keySet()) { - sendContent(Bukkit.getPlayer(id)); - } - } - - @Override - public ArrayImage getContent() { - return MapWrapper_v1_19_R1.this.getContent(); - } - - @Override - public void sendContent(Player player) { - sendContent(player, false); - } - - @Override - public void sendContent(Player player, boolean withoutQueue) { - if (!isViewing(player)) return; - - int id = getMapId(player); - if (withoutQueue) { - MapSender_v1_19_R1.sendMap(id, MapWrapper_v1_19_R1.this.content, player); - } else { - MapSender_v1_19_R1.addToQueue(id, MapWrapper_v1_19_R1.this.content, player); - } - } - - @Override - public void showInInventory(Player player, int slot, boolean force) { - if (!isViewing(player)) return; - - if (player.getGameMode() == GameMode.CREATIVE && !force) return; - - if (slot < 9) { - slot += 36; - } else if (slot > 35 && slot != 45) { - slot = 8 - (slot - 36); - } - - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().bT.j; //inventoryMenu containerId - int stateId = craftPlayer.getHandle().bT.j(); //inventoryMenu getStateId() - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, stateId, slot, nmsStack); - ((CraftPlayer) player).getHandle().b.a(packet); - } - - @Override - public void showInInventory(Player player, int slot) { - showInInventory(player, slot, false); - } - - @Override - public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.FILLED_MAP && !force) return; - showInInventory(player, player.getInventory().getHeldItemSlot(), force); - } - - @Override - public void showInHand(Player player) { - showInHand(player, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame) { - showInFrame(player, frame, false); - } - - @Override - public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.FILLED_MAP && !force) return; - showInFrame(player, frame.getEntityId()); - } - - @Override - public void showInFrame(Player player, int entityId) { - showInFrame(player, entityId, null); - } - - @Override - public void showInFrame(Player player, int entityId, String debugInfo) { - if (!isViewing(player)) return; - - ItemStack stack = new ItemStack(Material.FILLED_MAP, 1); - if (debugInfo != null) { - ItemMeta itemMeta = stack.getItemMeta(); - itemMeta.setDisplayName(debugInfo); - stack.setItemMeta(itemMeta); - } - - Bukkit.getScheduler().runTask(MapReflectionAPI.getInstance(), () -> { - ItemFrame frame = getItemFrameById(player.getWorld(), entityId); - if (frame != null) { - frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_19_R1.this)); - } - - sendItemFramePacket(player, entityId, stack, getMapId(player)); - }); - } - - @Override - public void clearFrame(Player player, int entityId) { - - } - - @Override - public void clearFrame(Player player, ItemFrame frame) { - - } - - @Override - public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; - - Entity entity = craftWorld.getHandle().a(entityId); - if (entity == null) return null; - - if (entity instanceof ItemFrame) return (ItemFrame) entity; - - return null; - } - - private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - nmsStack.v().a("map", mapId); //getOrCreateTag putInt - - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); - - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "ao"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; - } - - ((CraftPlayer) player).getHandle().b.a(packet); - } - }; - - public MapWrapper_v1_19_R1(ArrayImage image) { - super(image); - } - - @Override - public MapController getController() { - return controller; - } -} diff --git a/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_19_R1.java b/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_19_R1.java deleted file mode 100644 index 3786d4d..0000000 --- a/NMS-v1_19_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/PacketListener_v1_19_R1.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package tech.sbdevelopment.mapreflectionapi.nms; - -import io.netty.channel.*; -import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot; -import net.minecraft.network.protocol.game.PacketPlayInUseEntity; -import net.minecraft.network.protocol.game.PacketPlayOutMap; -import net.minecraft.world.EnumHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3D; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; -import org.bukkit.entity.Player; -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.listeners.PacketListener; - -import java.util.concurrent.TimeUnit; - -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.*; - -public class PacketListener_v1_19_R1 extends PacketListener { - @Override - protected void injectPlayer(Player p) { - ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { - @Override - //On send packet - public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { - if (packet instanceof PacketPlayOutMap packetPlayOutMap) { - int id = (int) getField(packetPlayOutMap, "a"); - - if (id < 0) { - //It's one of our maps, invert ID and let through! - int newId = -id; - setField(packetPlayOutMap, "a", newId); //mapId - } else { - boolean async = !plugin.getServer().isPrimaryThread(); - MapCancelEvent event = new MapCancelEvent(p, id, async); - if (MapReflectionAPI.getMapManager().isIdUsedBy(p, id)) event.setCancelled(true); - if (event.getHandlers().getRegisteredListeners().length > 0) - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; - } - } - - super.write(ctx, packet, promise); - } - - @Override - //On receive packet - public void channelRead(ChannelHandlerContext ctx, Object packet) throws Exception { - if (packet instanceof PacketPlayInUseEntity packetPlayInUseEntity) { - int entityId = (int) getField(packetPlayInUseEntity, "a"); //entityId - Object action = getField(packetPlayInUseEntity, "b"); //action - Enum actionEnum = (Enum) getValue(action, "a"); //action type - EnumHand hand = hasField(action, "a") ? (EnumHand) getField(action, "a") : null; //hand - Vec3D pos = hasField(action, "b") ? (Vec3D) getField(action, "b") : null; //pos - - if (Bukkit.getScheduler().callSyncMethod(plugin, () -> { - boolean async = !plugin.getServer().isPrimaryThread(); - MapInteractEvent event = new MapInteractEvent(p, 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 instanceof PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot) { - int slot = packetPlayInSetCreativeSlot.b(); - ItemStack item = packetPlayInSetCreativeSlot.c(); - - boolean async = !plugin.getServer().isPrimaryThread(); - CreateInventoryMapUpdateEvent event = new CreateInventoryMapUpdateEvent(p, slot, CraftItemStack.asBukkitCopy(item), async); - if (event.getMapWrapper() != null) { - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) return; - } - } - - super.channelRead(ctx, packet); - } - }; - - ChannelPipeline pipeline = ((CraftPlayer) p).getHandle().b.b.m.pipeline(); //connection connection channel - pipeline.addBefore("packet_handler", p.getName(), channelDuplexHandler); - } - - @Override - public void removePlayer(Player p) { - Channel channel = ((CraftPlayer) p).getHandle().b.b.m; //connection connection channel - channel.eventLoop().submit(() -> channel.pipeline().remove(p.getName())); - } - - @Override - protected Vector vec3DToVector(Object vec3d) { - if (!(vec3d instanceof Vec3D vec3dObj)) return new Vector(0, 0, 0); - return new Vector(vec3dObj.c, vec3dObj.d, vec3dObj.e); //x, y, z - } -} diff --git a/pom.xml b/pom.xml index a575d69..5bff386 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,27 @@ + + @@ -6,69 +29,50 @@ tech.sbdevelopment MapReflectionAPI - pom - ${revision} + 1.1 + jar + + MapReflectionAPI + This API helps developer with viewing images on maps. + https://sbdplugins.nl - 1.0-SNAPSHOT UTF-8 - 11 - - API - Dist - NMS-v1_19_R1 - NMS-v1_18_R2 - NMS-v1_17_R1 - NMS-v1_16_R3 - NMS-v1_15_R1 - NMS-v1_14_R1 - NMS-v1_13_R2 - NMS-v1_12_R1 - - - clean package org.apache.maven.plugins - maven-toolchains-plugin - 3.1.0 + maven-compiler-plugin + 3.9.0-SNAPSHOT + + 11 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.3.1-SNAPSHOT + package - toolchain + shade + + false + - - - - ${jdk.version} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.10.1 - - ${jdk.version} - - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M2 - - true - + + + src/main/resources + true + + @@ -76,6 +80,14 @@ spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + MG-Dev Jenkins CI Maven Repository + https://ci.mg-dev.eu/plugin/repository/everything + + + dmulloy2-repo + https://repo.dmulloy2.net/repository/public/ + @@ -84,5 +96,17 @@ spigot-api 1.19-R0.1-SNAPSHOT + + com.bergerkiller.bukkit + BKCommonLib + 1.19-v1 + provided + + + com.comphenix.protocol + ProtocolLib + 4.8.0 + provided + \ No newline at end of file diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java similarity index 87% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java index e12d932..7c20b33 100644 --- a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java @@ -23,6 +23,8 @@ package tech.sbdevelopment.mapreflectionapi; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; import org.bukkit.Bukkit; import org.bukkit.map.MapView; import org.bukkit.plugin.java.JavaPlugin; @@ -35,7 +37,7 @@ import java.util.logging.Level; public class MapReflectionAPI extends JavaPlugin { private static MapReflectionAPI instance; private static MapManager mapManager; - private static PacketListener packetListener; + private ProtocolManager protocolManager; public static MapReflectionAPI getInstance() { if (instance == null) throw new IllegalStateException("The plugin is not enabled yet!"); @@ -61,14 +63,8 @@ public class MapReflectionAPI extends JavaPlugin { return; } - try { - packetListener = PacketListener.construct(this); - } catch (IllegalStateException e) { - getLogger().log(Level.SEVERE, e.getMessage(), e); - Bukkit.getPluginManager().disablePlugin(this); - return; - } - packetListener.init(this); + protocolManager = ProtocolLibrary.getProtocolManager(); + protocolManager.addPacketListener(new PacketListener(this)); try { mapManager = new MapManager(this); @@ -99,9 +95,6 @@ public class MapReflectionAPI extends JavaPlugin { @Override public void onDisable() { - getLogger().info("Disabling the packet handler..."); - if (packetListener != null) Bukkit.getOnlinePlayers().forEach(p -> packetListener.removePlayer(p)); - getLogger().info("MapReflectionAPI is disabled!"); instance = null; diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java similarity index 91% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java index 47d0244..b285d54 100644 --- a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java @@ -71,6 +71,16 @@ public class ArrayImage { this.array = result; } + public BufferedImage toBuffered() { + BufferedImage img = new BufferedImage(width, height, this.imageType); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + img.setRGB(x, y, MapColorPalette.getRealColor(array[y * width + x]).getRGB()); + } + } + return img; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java similarity index 100% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java similarity index 100% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java diff --git a/NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_12_R1.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java similarity index 65% rename from NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_12_R1.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java index 88f0e6f..89fef87 100644 --- a/NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapSender_v1_12_R1.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java @@ -21,20 +21,19 @@ * SOFTWARE. */ -package tech.sbdevelopment.mapreflectionapi.nms; +package tech.sbdevelopment.mapreflectionapi.api; -import net.minecraft.server.v1_12_R1.PacketPlayOutMap; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; +import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil; +import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils; import java.util.ArrayList; import java.util.List; import java.util.Objects; -public class MapSender_v1_12_R1 { +public class MapSender { private static final List sendQueue = new ArrayList<>(); private static int senderID = -1; @@ -80,28 +79,55 @@ public class MapSender_v1_12_R1 { return; } + Class packetClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutMap"); final int id = -id0; - Bukkit.getScheduler().runTaskAsynchronously(MapReflectionAPI.getInstance(), () -> { - try { - PacketPlayOutMap packet = new PacketPlayOutMap( - id, //ID - (byte) 0, //Scale - false, //??? - new ArrayList<>(), //Icons - content.array, //Data - content.minX, //X pos - content.minY, //Y pos - content.maxX, //X size (2nd X pos) - content.maxY //Y size (2nd Y pos) - ); + Object packet; + if (ReflectionUtils.supports(17)) { //1.17+ + Class worldMapClass = ReflectionUtils.getNMSClass("world.level.saveddata.maps", "WorldMap"); + Object updateData = ReflectionUtil.callConstructor(worldMapClass, + content.minX, //X pos + content.minY, //Y pos + content.maxX, //X size (2nd X pos) + content.maxY, //Y size (2nd Y pos) + content.array //Data + ); - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } catch (Exception e) { - e.printStackTrace(); - } - }); + packet = ReflectionUtil.callConstructor(packetClass, + id, //ID + (byte) 0, //Scale + false, //Show icons + new ArrayList<>(), //Icons + updateData + ); + } else if (ReflectionUtils.supports(14)) { //1.16-1.14 + packet = ReflectionUtil.callConstructor(packetClass, + id, //ID + (byte) 0, //Scale + false, //Tracking position + false, //Locked + new ArrayList<>(), //Icons + content.array, //Data + content.minX, //X pos + content.minY, //Y pos + content.maxX, //X size (2nd X pos) + content.maxY //Y size (2nd Y pos) + ); + } else { //1.13- + packet = ReflectionUtil.callConstructor(packetClass, + id, //ID + (byte) 0, //Scale + false, //??? + new ArrayList<>(), //Icons + content.array, //Data + content.minX, //X pos + content.minY, //Y pos + content.maxX, //X size (2nd X pos) + content.maxY //Y size (2nd Y pos) + ); + } + + ReflectionUtils.sendPacket(player, packet); } - static final class QueuedMap { private final int id; private final ArrayImage image; diff --git a/NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_12_R1.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java similarity index 53% rename from NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_12_R1.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java index 6a38063..41f460d 100644 --- a/NMS-v1_12_R1/src/main/java/tech/sbdevelopment/mapreflectionapi/nms/MapWrapper_v1_12_R1.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java @@ -21,32 +21,28 @@ * SOFTWARE. */ -package tech.sbdevelopment.mapreflectionapi.nms; +package tech.sbdevelopment.mapreflectionapi.api; -import net.minecraft.server.v1_12_R1.*; -import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.*; -import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.metadata.FixedMetadataValue; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.api.ArrayImage; -import tech.sbdevelopment.mapreflectionapi.api.MapController; -import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; +import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil; +import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils; import java.util.*; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.getField; -import static tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil.setField; +public class MapWrapper { + protected ArrayImage content; + + public MapWrapper(ArrayImage image) { + this.content = image; + } -public class MapWrapper_v1_12_R1 extends MapWrapper { protected MapController controller = new MapController() { private final Map viewers = new HashMap<>(); @@ -87,11 +83,11 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { public void update(ArrayImage content) { MapWrapper duplicate = MapReflectionAPI.getMapManager().getDuplicate(content); if (duplicate != null) { - MapWrapper_v1_12_R1.this.content = duplicate.getContent(); + MapWrapper.this.content = duplicate.getContent(); return; } - MapWrapper_v1_12_R1.this.content = content; + MapWrapper.this.content = content; for (UUID id : viewers.keySet()) { sendContent(Bukkit.getPlayer(id)); @@ -100,7 +96,7 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { @Override public ArrayImage getContent() { - return MapWrapper_v1_12_R1.this.getContent(); + return MapWrapper.this.getContent(); } @Override @@ -114,9 +110,9 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { int id = getMapId(player); if (withoutQueue) { - MapSender_v1_12_R1.sendMap(id, MapWrapper_v1_12_R1.this.content, player); + MapSender.sendMap(id, MapWrapper.this.content, player); } else { - MapSender_v1_12_R1.addToQueue(id, MapWrapper_v1_12_R1.this.content, player); + MapSender.addToQueue(id, MapWrapper.this.content, player); } } @@ -132,14 +128,35 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { slot = 8 - (slot - 36); } - CraftPlayer craftPlayer = (CraftPlayer) player; - int windowId = craftPlayer.getHandle().defaultContainer.windowId; + Object playerHandle = ReflectionUtils.getHandle(player); + Object inventoryMenu = ReflectionUtil.getField(playerHandle, ReflectionUtils.supports(19) ? "bT" : ReflectionUtils.supports(17) ? "bU" : "defaultContainer"); + int windowId = (int) ReflectionUtil.getField(inventoryMenu, ReflectionUtils.supports(17) ? "j" : "windowId"); - ItemStack stack = new ItemStack(Material.MAP, 1); - net.minecraft.server.v1_12_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); + ItemStack stack = new ItemStack(ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP, 1); - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(windowId, slot, nmsStack); - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); + Class craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack"); + Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack); + + Class setSlotPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutSetSlot"); + Object packet; + if (ReflectionUtils.supports(17)) { //1.17+ + int stateId = (int) ReflectionUtil.callMethod(inventoryMenu, ReflectionUtils.supports(18) ? "j" : "getStateId"); + + packet = ReflectionUtil.callConstructor(setSlotPacketClass, + windowId, + stateId, + slot, + nmsStack + ); + } else { //1.16- + packet = ReflectionUtil.callConstructor(setSlotPacketClass, + windowId, + slot, + nmsStack + ); + } + + ReflectionUtils.sendPacket(player, packet); } @Override @@ -149,7 +166,8 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { @Override public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != Material.MAP && !force) return; + if (player.getInventory().getItemInMainHand().getType() != (ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force) + return; showInInventory(player, player.getInventory().getHeldItemSlot(), force); } @@ -165,7 +183,8 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { @Override public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != Material.MAP && !force) return; + if (frame.getItem().getType() != (ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force) + return; showInFrame(player, frame.getEntityId()); } @@ -178,7 +197,7 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { public void showInFrame(Player player, int entityId, String debugInfo) { if (!isViewing(player)) return; - ItemStack stack = new ItemStack(Material.MAP, 1); + ItemStack stack = new ItemStack(ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP, 1); if (debugInfo != null) { ItemMeta itemMeta = stack.getItemMeta(); itemMeta.setDisplayName(debugInfo); @@ -189,7 +208,7 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { ItemFrame frame = getItemFrameById(player.getWorld(), entityId); if (frame != null) { frame.removeMetadata("MAP_WRAPPER_REF", MapReflectionAPI.getInstance()); - frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper_v1_12_R1.this)); + frame.setMetadata("MAP_WRAPPER_REF", new FixedMetadataValue(MapReflectionAPI.getInstance(), MapWrapper.this)); } sendItemFramePacket(player, entityId, stack, getMapId(player)); @@ -208,45 +227,64 @@ public class MapWrapper_v1_12_R1 extends MapWrapper { @Override public ItemFrame getItemFrameById(World world, int entityId) { - CraftWorld craftWorld = (CraftWorld) world; + Object worldHandle = ReflectionUtils.getHandle(world); + Object nmsEntity = ReflectionUtil.callMethod(worldHandle, ReflectionUtils.supports(18) ? "a" : "getEntity"); + if (nmsEntity == null) return null; - Entity entity = craftWorld.getHandle().getEntity(entityId); - if (entity == null) return null; - - org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); - if (bukkitEntity instanceof ItemFrame) return (ItemFrame) bukkitEntity; + if (!ReflectionUtils.supports(17)) { + nmsEntity = ReflectionUtil.callMethod(nmsEntity, "getBukkitEntity"); + } + if (nmsEntity instanceof ItemFrame) return (ItemFrame) nmsEntity; return null; } private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - net.minecraft.server.v1_12_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(stack); - if (nmsStack.getTag() == null) nmsStack.setTag(new NBTTagCompound()); //No orCreate on 1.12.2! - nmsStack.getTag().setInt("map", mapId); //getTag putInt + Class craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack"); + Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack); - PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(entityId, new DataWatcher(null), true); + Object nbtObject = ReflectionUtil.callMethod(nmsStack, ReflectionUtils.supports(19) ? "v" : ReflectionUtils.supports(18) ? "u" : ReflectionUtils.supports(13) ? "getOrCreateTag" : "getTag"); - try { - List> list = new ArrayList<>(); - DataWatcherObject dataWatcherObject = (DataWatcherObject) getField(EntityItemFrame.class, "c"); - DataWatcher.Item dataWatcherItem = new DataWatcher.Item<>(dataWatcherObject, nmsStack); - list.add(dataWatcherItem); - setField(packet, "b", list); - } catch (Exception e) { - e.printStackTrace(); - return; + if (!ReflectionUtils.supports(13) && nbtObject == null) { //1.12 has no getOrCreate, call create if null! + Class tagCompoundClass = ReflectionUtils.getCraftClass("NBTTagCompound"); + Object tagCompound = ReflectionUtil.callConstructor(tagCompoundClass); + + ReflectionUtil.callMethod(nbtObject, "setTag", tagCompound); } - ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); + ReflectionUtil.callMethod(nbtObject, ReflectionUtils.supports(18) ? "a" : "setInt", "map", mapId); + + Class entityClass = ReflectionUtils.getNMSClass("world.entity", "Entity"); + + Class dataWatcherClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher"); + Object dataWatcher = ReflectionUtil.callConstructor(dataWatcherClass, entityClass.cast(null)); + + Class entityMetadataPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata"); + Object packet = ReflectionUtil.callConstructor(entityMetadataPacketClass, + entityId, + dataWatcher, //dummy watcher! + true + ); + + List list = new ArrayList<>(); + Class entityItemFrameClass = ReflectionUtils.getNMSClass("world.entity.decoration", "EntityItemFrame"); + Object dataWatcherObject = ReflectionUtil.getDeclaredField(entityItemFrameClass, ReflectionUtils.supports(17) ? "ao" : ReflectionUtils.supports(14) ? "ITEM" : ReflectionUtils.supports(13) ? "e" : "c"); + Class dataWatcherItemClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher$Item"); + Object dataWatcherItem = ReflectionUtil.callConstructor(dataWatcherItemClass, dataWatcherObject, nmsStack); + list.add(dataWatcherItem); + ReflectionUtil.setDeclaredField(packet, "b", list); + + ReflectionUtils.sendPacket(player, packet); } }; - public MapWrapper_v1_12_R1(ArrayImage image) { - super(image); + public ArrayImage getContent() { + return content; } - @Override public MapController getController() { return controller; } + + } diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java similarity index 100% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java similarity index 100% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java similarity index 100% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java similarity index 100% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java similarity index 100% rename from API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java new file mode 100644 index 0000000..7e48703 --- /dev/null +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java @@ -0,0 +1,94 @@ +/* + * This file is part of MapReflectionAPI. + * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +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 org.bukkit.Bukkit; +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; + +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); + } + + @Override + public void onPacketSending(PacketEvent event) { + if (event.getPacketType() != PacketType.Play.Server.MAP) return; //Make sure it's the right packet! + + 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); + } + } + + @Override + public void onPacketReceiving(PacketEvent event) { + if (event.getPacketType() == PacketType.Play.Client.USE_ENTITY) { + int entityId = event.getPacket().getIntegers().read(0); //entityId + WrappedEnumEntityUseAction action = event.getPacket().getEnumEntityUseActions().read(0); + EnumWrappers.EntityUseAction actionEnum = action.getAction(); + EnumWrappers.Hand hand = action.getHand(); + Vector pos = action.getPosition(); + + boolean async = !plugin.getServer().isPrimaryThread(); + MapInteractEvent interactEvent = new MapInteractEvent(event.getPlayer(), entityId, actionEnum.ordinal(), pos, hand.ordinal(), async); + if (interactEvent.getFrame() != null && interactEvent.getMapWrapper() != null) { + Bukkit.getPluginManager().callEvent(interactEvent); + if (interactEvent.isCancelled()) event.setCancelled(true); + } + } else if (event.getPacketType() == PacketType.Play.Client.SET_CREATIVE_SLOT) { + int slot = event.getPacket().getIntegers().read(0); + ItemStack item = event.getPacket().getItemModifier().read(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); + } + } + } +} diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java new file mode 100644 index 0000000..b6cbfe0 --- /dev/null +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java @@ -0,0 +1,165 @@ +/* + * This file is part of MapReflectionAPI. + * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package tech.sbdevelopment.mapreflectionapi.util; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; + +/** + * ReflectionUtil - Reflection handler for NMS and CraftBukkit.
+ * Caches the packet related methods and is asynchronous. + *

+ * This class does not handle null checks as most of the requests are from the + * other utility classes that already handle null checks. + *

+ * Clientbound Packets are considered fake + * updates to the client without changing the actual data. Since all the data is handled + * by the server. + * + * @author Crypto Morin, Stijn Bannink + * @version 2.1 + */ +public class ReflectionUtil { + private ReflectionUtil() { + } + + private static Class wrapperToPrimitive(Class clazz) { + if (clazz == Boolean.class) return boolean.class; + if (clazz == Integer.class) return int.class; + if (clazz == Double.class) return double.class; + if (clazz == Float.class) return float.class; + if (clazz == Long.class) return long.class; + if (clazz == Short.class) return short.class; + if (clazz == Byte.class) return byte.class; + if (clazz == Void.class) return void.class; + if (clazz == Character.class) return char.class; + return clazz; + } + + private static Class[] toParamTypes(Object... params) { + return Arrays.stream(params) + .map(obj -> wrapperToPrimitive(obj.getClass())) + .toArray(Class[]::new); + } + + @Nullable + public static Class getClass(@NotNull String name) { + try { + return Class.forName(name); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } + + @Nullable + public static Object callConstructor(Class clazz, Object... params) { + try { + Constructor con = clazz.getConstructor(toParamTypes(params)); + con.setAccessible(true); + return con.newInstance(params); + } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | + InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } + } + + @Nullable + public static Object callDeclaredConstructor(Class clazz, Object... params) { + try { + Constructor con = clazz.getDeclaredConstructor(toParamTypes(params)); + con.setAccessible(true); + return con.newInstance(params); + } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | + InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } + } + + @Nullable + public static Object callMethod(Object obj, String method, Object... params) { + try { + Method m = obj.getClass().getMethod(method, toParamTypes(params)); + m.setAccessible(true); + return m.invoke(obj, params); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } + } + + @Nullable + public static Object callDeclaredMethod(Object obj, String method, Object... params) { + try { + Method m = obj.getClass().getDeclaredMethod(method, toParamTypes(params)); + m.setAccessible(true); + return m.invoke(obj, params); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } + } + + @Nullable + public static Object getField(Object object, String field) { + try { + Field f = object.getClass().getField(field); + f.setAccessible(true); + return f.get(object); + } catch (NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + return null; + } + } + + @Nullable + public static Object getDeclaredField(Object object, String field) { + try { + Field f = object.getClass().getDeclaredField(field); + f.setAccessible(true); + return f.get(object); + } catch (NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + return null; + } + } + + public static void setDeclaredField(Object object, String field, Object value) { + try { + Field f = object.getClass().getDeclaredField(field); + f.setAccessible(true); + f.set(object, toParamTypes(value)); + } catch (NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java new file mode 100644 index 0000000..0f1c566 --- /dev/null +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java @@ -0,0 +1,381 @@ +/* + * This file is part of MapReflectionAPI. + * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package tech.sbdevelopment.mapreflectionapi.util; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; + +/** + * ReflectionUtils - Reflection handler for NMS and CraftBukkit.
+ * Caches the packet related methods and is asynchronous. + *

+ * This class does not handle null checks as most of the requests are from the + * other utility classes that already handle null checks. + *

+ * Clientbound Packets are considered fake + * updates to the client without changing the actual data. Since all the data is handled + * by the server. + *

+ * A useful resource used to compare mappings is Mini's Mapping Viewer + * + * @author Crypto Morin + * @version 6.0.1 + */ +public final class ReflectionUtils { + /** + * We use reflection mainly to avoid writing a new class for version barrier. + * The version barrier is for NMS that uses the Minecraft version as the main package name. + *

+ * E.g. EntityPlayer in 1.15 is in the class {@code net.minecraft.server.v1_15_R1} + * but in 1.14 it's in {@code net.minecraft.server.v1_14_R1} + * In order to maintain cross-version compatibility we cannot import these classes. + *

+ * Performance is not a concern for these specific statically initialized values. + */ + public static final String VERSION; + /** + * The raw minor version number. + * E.g. {@code v1_17_R1} to {@code 17} + * + * @since 4.0.0 + */ + public static final int VER = Integer.parseInt(VERSION.substring(1).split("_")[1]); + /** + * Mojang remapped their NMS in 1.17 https://www.spigotmc.org/threads/spigot-bungeecord-1-17.510208/#post-4184317 + */ + public static final String + CRAFTBUKKIT = "org.bukkit.craftbukkit." + VERSION + '.', + NMS = v(17, "net.minecraft.").orElse("net.minecraft.server." + VERSION + '.'); + /** + * A nullable public accessible field only available in {@code EntityPlayer}. + * This can be null if the player is offline. + */ + private static final MethodHandle PLAYER_CONNECTION; + /** + * Responsible for getting the NMS handler {@code EntityPlayer} object for the player. + * {@code CraftPlayer} is simply a wrapper for {@code EntityPlayer}. + * Used mainly for handling packet related operations. + *

+ * This is also where the famous player {@code ping} field comes from! + */ + private static final MethodHandle GET_HANDLE; + private static final MethodHandle GET_HANDLE_WORLD; + /** + * Sends a packet to the player's client through a {@code NetworkManager} which + * is where {@code ProtocolLib} controls packets by injecting channels! + */ + private static final MethodHandle SEND_PACKET; + + static { // This needs to be right below VERSION because of initialization order. + // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() + // which allows easier testing as well. + String found = null; + for (Package pack : Package.getPackages()) { + String name = pack.getName(); + + // .v because there are other packages. + if (name.startsWith("org.bukkit.craftbukkit.v")) { + found = pack.getName().split("\\.")[3]; + + // Just a final guard to make sure it finds this important class. + // As a protection for forge+bukkit implementation that tend to mix versions. + // The real CraftPlayer should exist in the package. + // Note: Doesn't seem to function properly. Will need to separate the version + // handler for NMS and CraftBukkit for softwares like catmc. + try { + Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); + break; + } catch (ClassNotFoundException e) { + found = null; + } + } + } + if (found == null) + throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); + VERSION = found; + } + + static { + Class entityPlayer = getNMSClass("server.level", "EntityPlayer"); + Class worldServer = getNMSClass("server.level", "WorldServer"); + Class craftPlayer = getCraftClass("entity.CraftPlayer"); + Class craftWorld = getCraftClass("CraftWorld"); + Class playerConnection = getNMSClass("server.network", "PlayerConnection"); + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle sendPacket = null, getHandle = null, getHandleWorld = null, connection = null; + + try { + connection = lookup.findGetter(entityPlayer, + v(17, "b").orElse("playerConnection"), playerConnection); + getHandle = lookup.findVirtual(craftPlayer, "getHandle", MethodType.methodType(entityPlayer)); + getHandleWorld = lookup.findVirtual(craftWorld, "getHandle", MethodType.methodType(worldServer)); + sendPacket = lookup.findVirtual(playerConnection, + v(18, "a").orElse("sendPacket"), + MethodType.methodType(void.class, getNMSClass("network.protocol", "Packet"))); + } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + } + + PLAYER_CONNECTION = connection; + SEND_PACKET = sendPacket; + GET_HANDLE = getHandle; + GET_HANDLE_WORLD = getHandleWorld; + } + + private ReflectionUtils() { + } + + /** + * This method is purely for readability. + * No performance is gained. + * + * @since 5.0.0 + */ + public static VersionHandler v(int version, T handle) { + return new VersionHandler<>(version, handle); + } + + public static CallableVersionHandler v(int version, Callable handle) { + return new CallableVersionHandler<>(version, handle); + } + + /** + * Checks whether the server version is equal or greater than the given version. + * + * @param version the version to compare the server version with. + * @return true if the version is equal or newer, otherwise false. + * @since 4.0.0 + */ + public static boolean supports(int version) { + return VER >= version; + } + + /** + * Get a NMS (net.minecraft.server) class which accepts a package for 1.17 compatibility. + * + * @param newPackage the 1.17 package name. + * @param name the name of the class. + * @return the NMS class or null if not found. + * @since 4.0.0 + */ + @Nullable + public static Class getNMSClass(@Nonnull String newPackage, @Nonnull String name) { + if (supports(17)) name = newPackage + '.' + name; + return getNMSClass(name); + } + + /** + * Get a NMS (net.minecraft.server) class. + * + * @param name the name of the class. + * @return the NMS class or null if not found. + * @since 1.0.0 + */ + @Nullable + public static Class getNMSClass(@Nonnull String name) { + try { + return Class.forName(NMS + name); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } + + /** + * Sends a packet to the player asynchronously if they're online. + * Packets are thread-safe. + * + * @param player the player to send the packet to. + * @param packets the packets to send. + * @return the async thread handling the packet. + * @see #sendPacketSync(Player, Object...) + * @since 1.0.0 + */ + @Nonnull + public static CompletableFuture sendPacket(@Nonnull Player player, @Nonnull Object... packets) { + return CompletableFuture.runAsync(() -> sendPacketSync(player, packets)) + .exceptionally(ex -> { + ex.printStackTrace(); + return null; + }); + } + + /** + * Sends a packet to the player synchronously if they're online. + * + * @param player the player to send the packet to. + * @param packets the packets to send. + * @see #sendPacket(Player, Object...) + * @since 2.0.0 + */ + public static void sendPacketSync(@Nonnull Player player, @Nonnull Object... packets) { + try { + Object handle = GET_HANDLE.invoke(player); + Object connection = PLAYER_CONNECTION.invoke(handle); + + // Checking if the connection is not null is enough. There is no need to check if the player is online. + if (connection != null) { + for (Object packet : packets) SEND_PACKET.invoke(connection, packet); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + @Nullable + public static Object getHandle(@Nonnull Player player) { + Objects.requireNonNull(player, "Cannot get handle of null player"); + try { + return GET_HANDLE.invoke(player); + } catch (Throwable throwable) { + throwable.printStackTrace(); + return null; + } + } + + @Nullable + public static Object getHandle(@Nonnull World world) { + Objects.requireNonNull(world, "Cannot get handle of null world"); + try { + return GET_HANDLE_WORLD.invoke(world); + } catch (Throwable throwable) { + throwable.printStackTrace(); + return null; + } + } + + @Nullable + public static Object getConnection(@Nonnull Player player) { + Objects.requireNonNull(player, "Cannot get connection of null player"); + try { + Object handle = GET_HANDLE.invoke(player); + return PLAYER_CONNECTION.invoke(handle); + } catch (Throwable throwable) { + throwable.printStackTrace(); + return null; + } + } + + /** + * Get a CraftBukkit (org.bukkit.craftbukkit) class. + * + * @param name the name of the class to load. + * @return the CraftBukkit class or null if not found. + * @since 1.0.0 + */ + @Nullable + public static Class getCraftClass(@Nonnull String name) { + try { + return Class.forName(CRAFTBUKKIT + name); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } + + public static Class getArrayClass(String clazz, boolean nms) { + clazz = "[L" + (nms ? NMS : CRAFTBUKKIT) + clazz + ';'; + try { + return Class.forName(clazz); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } + + public static Class toArrayClass(Class clazz) { + try { + return Class.forName("[L" + clazz.getName() + ';'); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } + + public static final class VersionHandler { + private int version; + private T handle; + + private VersionHandler(int version, T handle) { + if (supports(version)) { + this.version = version; + this.handle = handle; + } + } + + public VersionHandler v(int version, T handle) { + if (version == this.version) + throw new IllegalArgumentException("Cannot have duplicate version handles for version: " + version); + if (version > this.version && supports(version)) { + this.version = version; + this.handle = handle; + } + return this; + } + + public T orElse(T handle) { + return this.version == 0 ? handle : this.handle; + } + } + + public static final class CallableVersionHandler { + private int version; + private Callable handle; + + private CallableVersionHandler(int version, Callable handle) { + if (supports(version)) { + this.version = version; + this.handle = handle; + } + } + + public CallableVersionHandler v(int version, Callable handle) { + if (version == this.version) + throw new IllegalArgumentException("Cannot have duplicate version handles for version: " + version); + if (version > this.version && supports(version)) { + this.version = version; + this.handle = handle; + } + return this; + } + + public T orElse(Callable handle) { + try { + return (this.version == 0 ? handle : this.handle).call(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } +} \ No newline at end of file diff --git a/API/src/main/resources/plugin.yml b/src/main/resources/plugin.yml similarity index 100% rename from API/src/main/resources/plugin.yml rename to src/main/resources/plugin.yml -- 2.45.3 From 3ca16d49b8b4d1b759e9cee502a3a410775ed148 Mon Sep 17 00:00:00 2001 From: SBDeveloper Date: Fri, 1 Jul 2022 12:13:25 +0200 Subject: [PATCH 2/7] Fixed ReflectionUtils code order --- .../mapreflectionapi/MapReflectionAPI.java | 18 ++++-- .../util/ReflectionUtils.java | 59 ++++++++++--------- src/main/resources/plugin.yml | 2 +- 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java index 7c20b33..4a62c76 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java @@ -24,20 +24,19 @@ package tech.sbdevelopment.mapreflectionapi; import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; import org.bukkit.Bukkit; import org.bukkit.map.MapView; import org.bukkit.plugin.java.JavaPlugin; import tech.sbdevelopment.mapreflectionapi.api.MapManager; import tech.sbdevelopment.mapreflectionapi.listeners.MapListener; import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener; +import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils; import java.util.logging.Level; public class MapReflectionAPI extends JavaPlugin { private static MapReflectionAPI instance; private static MapManager mapManager; - private ProtocolManager protocolManager; public static MapReflectionAPI getInstance() { if (instance == null) throw new IllegalStateException("The plugin is not enabled yet!"); @@ -57,14 +56,25 @@ public class MapReflectionAPI extends JavaPlugin { getLogger().info("MapReflectionAPI v" + getDescription().getVersion() + ""); getLogger().info("Made by © Copyright SBDevelopment 2022"); + if (!ReflectionUtils.supports(12)) { + getLogger().severe("MapReflectionAPI only supports Minecraft 1.12 - 1.19!"); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + if (!Bukkit.getPluginManager().isPluginEnabled("BKCommonLib")) { getLogger().severe("MapReflectionAPI requires BKCommonLib to function!"); Bukkit.getPluginManager().disablePlugin(this); return; } - protocolManager = ProtocolLibrary.getProtocolManager(); - protocolManager.addPacketListener(new PacketListener(this)); + if (!Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")) { + getLogger().severe("MapReflectionAPI requires ProtocolLib to function!"); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + ProtocolLibrary.getProtocolManager().addPacketListener(new PacketListener(this)); try { mapManager = new MapManager(this); diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java index 0f1c566..7c4e830 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java @@ -62,6 +62,36 @@ public final class ReflectionUtils { * Performance is not a concern for these specific statically initialized values. */ public static final String VERSION; + + static { // This needs to be right below VERSION because of initialization order. + // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() + // which allows easier testing as well. + String found = null; + for (Package pack : Package.getPackages()) { + String name = pack.getName(); + + // .v because there are other packages. + if (name.startsWith("org.bukkit.craftbukkit.v")) { + found = pack.getName().split("\\.")[3]; + + // Just a final guard to make sure it finds this important class. + // As a protection for forge+bukkit implementation that tend to mix versions. + // The real CraftPlayer should exist in the package. + // Note: Doesn't seem to function properly. Will need to separate the version + // handler for NMS and CraftBukkit for softwares like catmc. + try { + Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); + break; + } catch (ClassNotFoundException e) { + found = null; + } + } + } + if (found == null) + throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); + VERSION = found; + } + /** * The raw minor version number. * E.g. {@code v1_17_R1} to {@code 17} @@ -95,35 +125,6 @@ public final class ReflectionUtils { */ private static final MethodHandle SEND_PACKET; - static { // This needs to be right below VERSION because of initialization order. - // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() - // which allows easier testing as well. - String found = null; - for (Package pack : Package.getPackages()) { - String name = pack.getName(); - - // .v because there are other packages. - if (name.startsWith("org.bukkit.craftbukkit.v")) { - found = pack.getName().split("\\.")[3]; - - // Just a final guard to make sure it finds this important class. - // As a protection for forge+bukkit implementation that tend to mix versions. - // The real CraftPlayer should exist in the package. - // Note: Doesn't seem to function properly. Will need to separate the version - // handler for NMS and CraftBukkit for softwares like catmc. - try { - Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); - break; - } catch (ClassNotFoundException e) { - found = null; - } - } - } - if (found == null) - throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); - VERSION = found; - } - static { Class entityPlayer = getNMSClass("server.level", "EntityPlayer"); Class worldServer = getNMSClass("server.level", "WorldServer"); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 030ee7f..025688e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,4 +5,4 @@ api-version: 1.13 authors: [ inventivetalent, SBDeveloper ] description: This API helps developer with viewing images on maps. website: https://sbdevelopment.tech -softdepend: [ BKCommonLib ] \ No newline at end of file +softdepend: [ BKCommonLib, ProtocolLib ] \ No newline at end of file -- 2.45.3 From c6cf6c2c3bbf47929fd858a1430c248f5aa8f827 Mon Sep 17 00:00:00 2001 From: SBDeveloper Date: Fri, 1 Jul 2022 12:29:59 +0200 Subject: [PATCH 3/7] :zap: Moved class definitions out of methods --- .../mapreflectionapi/api/MapManager.java | 25 +++---------------- .../mapreflectionapi/api/MapSender.java | 13 +++++----- .../mapreflectionapi/api/MapWrapper.java | 22 +++++++--------- 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java index f661e5c..920737c 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java @@ -31,7 +31,6 @@ import org.jetbrains.annotations.Nullable; import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; import java.awt.image.BufferedImage; -import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -40,24 +39,12 @@ import java.util.concurrent.CopyOnWriteArrayList; public class MapManager { protected final Set OCCUPIED_IDS = new HashSet<>(); private final List MANAGED_MAPS = new CopyOnWriteArrayList<>(); - private final Class wrapperClass; public MapManager(JavaPlugin plugin) throws IllegalStateException { String packageName = Bukkit.getServer().getClass().getPackage().getName(); String version = packageName.substring(packageName.lastIndexOf('.') + 1); plugin.getLogger().info("Initializing the map manager for Minecraft version " + version + "..."); - - try { - final Class clazz = Class.forName("tech.sbdevelopment.mapreflectionapi.nms.MapWrapper_" + version); - if (MapWrapper.class.isAssignableFrom(clazz)) { - wrapperClass = clazz; - } else { - throw new IllegalStateException("Plugin corrupted! Detected invalid MapWrapper class."); - } - } catch (Exception ex) { - throw new IllegalStateException("This Spigot version (" + version + ") is not supported! Contact the developer to get support."); - } } @Nullable @@ -74,15 +61,9 @@ public class MapManager { } private MapWrapper wrapNewImage(ArrayImage image) { - try { - MapWrapper wrapper = (MapWrapper) wrapperClass.getDeclaredConstructor(ArrayImage.class).newInstance(image); - MANAGED_MAPS.add(wrapper); - return wrapper; - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | - InvocationTargetException e) { - e.printStackTrace(); - return null; - } + MapWrapper wrapper = new MapWrapper(image); + MANAGED_MAPS.add(wrapper); + return wrapper; } public void unwrapImage(MapWrapper wrapper) { diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java index 89fef87..ce2b72e 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java @@ -63,6 +63,9 @@ public class MapSender { }, 0, 2); } + private static final Class packetPlayOutMapClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutMap"); + private static final Class worldMapData = ReflectionUtils.supports(17) ? ReflectionUtils.getNMSClass("world.level.saveddata.maps", "WorldMap") : null; + public static void sendMap(final int id0, final ArrayImage content, final Player player) { if (player == null || !player.isOnline()) { List toRemove = new ArrayList<>(); @@ -79,12 +82,10 @@ public class MapSender { return; } - Class packetClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutMap"); final int id = -id0; Object packet; if (ReflectionUtils.supports(17)) { //1.17+ - Class worldMapClass = ReflectionUtils.getNMSClass("world.level.saveddata.maps", "WorldMap"); - Object updateData = ReflectionUtil.callConstructor(worldMapClass, + Object updateData = ReflectionUtil.callConstructor(worldMapData, content.minX, //X pos content.minY, //Y pos content.maxX, //X size (2nd X pos) @@ -92,7 +93,7 @@ public class MapSender { content.array //Data ); - packet = ReflectionUtil.callConstructor(packetClass, + packet = ReflectionUtil.callConstructor(packetPlayOutMapClass, id, //ID (byte) 0, //Scale false, //Show icons @@ -100,7 +101,7 @@ public class MapSender { updateData ); } else if (ReflectionUtils.supports(14)) { //1.16-1.14 - packet = ReflectionUtil.callConstructor(packetClass, + packet = ReflectionUtil.callConstructor(packetPlayOutMapClass, id, //ID (byte) 0, //Scale false, //Tracking position @@ -113,7 +114,7 @@ public class MapSender { content.maxY //Y size (2nd Y pos) ); } else { //1.13- - packet = ReflectionUtil.callConstructor(packetClass, + packet = ReflectionUtil.callConstructor(packetPlayOutMapClass, id, //ID (byte) 0, //Scale false, //??? diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java index 41f460d..c626fae 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java @@ -43,6 +43,15 @@ public class MapWrapper { this.content = image; } + private static final Class craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack"); + private static final Class setSlotPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutSetSlot"); + private static final Class tagCompoundClass = ReflectionUtils.getCraftClass("NBTTagCompound"); + private static final Class entityClass = ReflectionUtils.getNMSClass("world.entity", "Entity"); + private static final Class dataWatcherClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher"); + private static final Class entityMetadataPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata"); + private static final Class entityItemFrameClass = ReflectionUtils.getNMSClass("world.entity.decoration", "EntityItemFrame"); + private static final Class dataWatcherItemClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher$Item"); + protected MapController controller = new MapController() { private final Map viewers = new HashMap<>(); @@ -134,10 +143,8 @@ public class MapWrapper { ItemStack stack = new ItemStack(ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP, 1); - Class craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack"); Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack); - Class setSlotPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutSetSlot"); Object packet; if (ReflectionUtils.supports(17)) { //1.17+ int stateId = (int) ReflectionUtil.callMethod(inventoryMenu, ReflectionUtils.supports(18) ? "j" : "getStateId"); @@ -240,26 +247,17 @@ public class MapWrapper { } private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { - Class craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack"); Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack); - Object nbtObject = ReflectionUtil.callMethod(nmsStack, ReflectionUtils.supports(19) ? "v" : ReflectionUtils.supports(18) ? "u" : ReflectionUtils.supports(13) ? "getOrCreateTag" : "getTag"); if (!ReflectionUtils.supports(13) && nbtObject == null) { //1.12 has no getOrCreate, call create if null! - Class tagCompoundClass = ReflectionUtils.getCraftClass("NBTTagCompound"); Object tagCompound = ReflectionUtil.callConstructor(tagCompoundClass); - ReflectionUtil.callMethod(nbtObject, "setTag", tagCompound); } ReflectionUtil.callMethod(nbtObject, ReflectionUtils.supports(18) ? "a" : "setInt", "map", mapId); - - Class entityClass = ReflectionUtils.getNMSClass("world.entity", "Entity"); - - Class dataWatcherClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher"); Object dataWatcher = ReflectionUtil.callConstructor(dataWatcherClass, entityClass.cast(null)); - Class entityMetadataPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata"); Object packet = ReflectionUtil.callConstructor(entityMetadataPacketClass, entityId, dataWatcher, //dummy watcher! @@ -267,9 +265,7 @@ public class MapWrapper { ); List list = new ArrayList<>(); - Class entityItemFrameClass = ReflectionUtils.getNMSClass("world.entity.decoration", "EntityItemFrame"); Object dataWatcherObject = ReflectionUtil.getDeclaredField(entityItemFrameClass, ReflectionUtils.supports(17) ? "ao" : ReflectionUtils.supports(14) ? "ITEM" : ReflectionUtils.supports(13) ? "e" : "c"); - Class dataWatcherItemClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher$Item"); Object dataWatcherItem = ReflectionUtil.callConstructor(dataWatcherItemClass, dataWatcherObject, nmsStack); list.add(dataWatcherItem); ReflectionUtil.setDeclaredField(packet, "b", list); -- 2.45.3 From e110f0afccd785791540b1d09722c8b6444b4d35 Mon Sep 17 00:00:00 2001 From: SBDeveloper Date: Fri, 1 Jul 2022 12:54:19 +0200 Subject: [PATCH 4/7] :memo: Added API documentation --- pom.xml | 13 +++ .../mapreflectionapi/MapReflectionAPI.java | 30 +++--- .../mapreflectionapi/api/ArrayImage.java | 51 +++------- .../mapreflectionapi/api/MapController.java | 7 +- .../mapreflectionapi/api/MapManager.java | 94 ++++++++++++++++--- .../mapreflectionapi/api/MapSender.java | 21 ++++- .../mapreflectionapi/api/MapWrapper.java | 23 ++++- .../events/CreateInventoryMapUpdateEvent.java | 73 +++++++------- .../api/events/MapCancelEvent.java | 46 ++++----- .../api/events/MapInteractEvent.java | 81 +++++++--------- .../exceptions/MapLimitExceededException.java | 10 +- .../{util => utils}/ReflectionUtil.java | 2 +- .../{util => utils}/ReflectionUtils.java | 2 +- 13 files changed, 268 insertions(+), 185 deletions(-) rename src/main/java/tech/sbdevelopment/mapreflectionapi/{ => api}/exceptions/MapLimitExceededException.java (83%) rename src/main/java/tech/sbdevelopment/mapreflectionapi/{util => utils}/ReflectionUtil.java (99%) rename src/main/java/tech/sbdevelopment/mapreflectionapi/{util => utils}/ReflectionUtils.java (99%) diff --git a/pom.xml b/pom.xml index 5bff386..88dc353 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,13 @@ 3.9.0-SNAPSHOT 11 + + + org.projectlombok + lombok + 1.18.24 + + @@ -108,5 +115,11 @@ 4.8.0 provided + + org.projectlombok + lombok + 1.18.24 + 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 4a62c76..aa32b80 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java @@ -30,7 +30,7 @@ import org.bukkit.plugin.java.JavaPlugin; import tech.sbdevelopment.mapreflectionapi.api.MapManager; import tech.sbdevelopment.mapreflectionapi.listeners.MapListener; import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener; -import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils; +import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtils; import java.util.logging.Level; @@ -38,11 +38,21 @@ public class MapReflectionAPI extends JavaPlugin { private static MapReflectionAPI instance; private static MapManager mapManager; + /** + * Get the plugin instance + * + * @return The {@link MapReflectionAPI} instance + */ public static MapReflectionAPI getInstance() { if (instance == null) throw new IllegalStateException("The plugin is not enabled yet!"); return instance; } + /** + * Get the {@link MapManager} + * + * @return The manager + */ public static MapManager getMapManager() { if (mapManager == null) throw new IllegalStateException("The plugin is not enabled yet!"); return mapManager; @@ -74,18 +84,8 @@ public class MapReflectionAPI extends JavaPlugin { return; } - ProtocolLibrary.getProtocolManager().addPacketListener(new PacketListener(this)); - - try { - mapManager = new MapManager(this); - } catch (IllegalStateException e) { - getLogger().log(Level.SEVERE, e.getMessage(), e); - Bukkit.getPluginManager().disablePlugin(this); - return; - } - - getLogger().info("Registering the events..."); - Bukkit.getPluginManager().registerEvents(new MapListener(), this); + getLogger().info("Loading the map manager..."); + mapManager = new MapManager(); getLogger().info("Discovering occupied Map IDs..."); for (int s = 0; s < Short.MAX_VALUE; s++) { @@ -99,6 +99,10 @@ public class MapReflectionAPI extends JavaPlugin { } } + getLogger().info("Registering the listeners..."); + Bukkit.getPluginManager().registerEvents(new MapListener(), this); + ProtocolLibrary.getProtocolManager().addPacketListener(new PacketListener(this)); + getLogger().info("MapReflectionAPI is enabled!"); getLogger().info("----------------"); } diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java index b285d54..6ae3b61 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/ArrayImage.java @@ -24,14 +24,21 @@ package tech.sbdevelopment.mapreflectionapi.api; import com.bergerkiller.bukkit.common.map.MapColorPalette; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import lombok.ToString; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Arrays; -import java.util.Objects; +/** + * This class contains an image converted to a Minecraft byte array + */ +@RequiredArgsConstructor +@EqualsAndHashCode +@ToString public class ArrayImage { - public byte[] array; + public final byte[] array; public int minX = 0; public int minY = 0; public int maxX = 128; @@ -40,10 +47,6 @@ public class ArrayImage { private int height; private int imageType = BufferedImage.TYPE_4BYTE_ABGR; - public ArrayImage(byte[] data) { - this.array = data; - } - /** * Convert a {@link BufferedImage} to an ArrayImage * @@ -71,6 +74,11 @@ public class ArrayImage { this.array = result; } + /** + * Get the {@link BufferedImage} of this ArrayImage + * + * @return The converted image + */ public BufferedImage toBuffered() { BufferedImage img = new BufferedImage(width, height, this.imageType); for (int x = 0; x < width; x++) { @@ -80,33 +88,4 @@ public class ArrayImage { } return img; } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ArrayImage)) return false; - ArrayImage that = (ArrayImage) o; - return width == that.width && height == that.height && imageType == that.imageType && Arrays.equals(array, that.array); - } - - @Override - public int hashCode() { - int result = Objects.hash(width, height, imageType); - result = 31 * result + Arrays.hashCode(array); - return result; - } - - @Override - public String toString() { - return "ArrayImage{" + - "array=" + Arrays.toString(array) + - ", minX=" + minX + - ", minY=" + minY + - ", maxX=" + maxX + - ", maxY=" + maxY + - ", width=" + width + - ", height=" + height + - ", imageType=" + imageType + - '}'; - } } diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java index 0ea623d..90274d8 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapController.java @@ -27,7 +27,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; +import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException; public interface MapController { /** @@ -72,6 +72,11 @@ public interface MapController { */ void update(ArrayImage content); + /** + * Get the content of the controller + * + * @return The {@link ArrayImage} + */ ArrayImage getContent(); /** diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java index 920737c..fc1fede 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java @@ -23,12 +23,10 @@ package tech.sbdevelopment.mapreflectionapi.api; -import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.Nullable; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; +import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException; import java.awt.image.BufferedImage; import java.util.HashSet; @@ -40,19 +38,22 @@ public class MapManager { protected final Set OCCUPIED_IDS = new HashSet<>(); private final List MANAGED_MAPS = new CopyOnWriteArrayList<>(); - public MapManager(JavaPlugin plugin) throws IllegalStateException { - String packageName = Bukkit.getServer().getClass().getPackage().getName(); - String version = packageName.substring(packageName.lastIndexOf('.') + 1); - - plugin.getLogger().info("Initializing the map manager for Minecraft version " + version + "..."); - } - - @Nullable + /** + * Wrap a {@link BufferedImage} in a {@link MapWrapper} + * + * @param image The image to wrap + * @return The wrapper + */ public MapWrapper wrapImage(BufferedImage image) { return wrapImage(new ArrayImage(image)); } - @Nullable + /** + * Wrap a {@link ArrayImage} in a {@link MapWrapper} + * + * @param image The image to wrap + * @return The wrapper + */ public MapWrapper wrapImage(ArrayImage image) { for (MapWrapper wrapper : MANAGED_MAPS) { if (wrapper.getContent().equals(image)) return wrapper; @@ -60,12 +61,23 @@ public class MapManager { return wrapNewImage(image); } + /** + * Wrap a new image + * + * @param image The image to wrap + * @return The wrapper + */ private MapWrapper wrapNewImage(ArrayImage image) { MapWrapper wrapper = new MapWrapper(image); MANAGED_MAPS.add(wrapper); return wrapper; } + /** + * Unwrap an image (will remove the wrapper) + * + * @param wrapper The {@link MapWrapper} to unwrap + */ public void unwrapImage(MapWrapper wrapper) { //TODO Cancel IDs @@ -73,6 +85,12 @@ public class MapManager { MANAGED_MAPS.remove(wrapper); } + /** + * Get the maps a player can see + * + * @param player The {@link Player} to check for + * @return A {@link Set} with the {@link MapWrapper}s + */ public Set getMapsVisibleTo(OfflinePlayer player) { Set visible = new HashSet<>(); for (MapWrapper wrapper : MANAGED_MAPS) { @@ -83,6 +101,14 @@ public class MapManager { return visible; } + /** + * Get the wrapper by a player and map id + * + * @param player The {@link OfflinePlayer} to check for + * @param id The ID of the map + * @return The {@link MapWrapper} for that map or null + */ + @Nullable public MapWrapper getWrapperForId(OfflinePlayer player, int id) { for (MapWrapper wrapper : getMapsVisibleTo(player)) { if (wrapper.getController().getMapId(player) == id) { @@ -92,14 +118,30 @@ public class MapManager { return null; } + /** + * Register an occupied map ID + * + * @param id The map ID to register + */ public void registerOccupiedID(int id) { OCCUPIED_IDS.add(id); } + /** + * Unregister an occupied map ID + * + * @param id The map ID to unregister + */ public void unregisterOccupiedID(int id) { OCCUPIED_IDS.remove(id); } + /** + * Get the occupied IDs for a player + * + * @param player The {@link OfflinePlayer} to check for + * @return A {@link Set} with the found map IDs + */ public Set getOccupiedIdsFor(OfflinePlayer player) { Set ids = new HashSet<>(); for (MapWrapper wrapper : MANAGED_MAPS) { @@ -111,10 +153,24 @@ public class MapManager { return ids; } + /** + * Check if a player uses a map ID + * + * @param player The {@link OfflinePlayer} to check for + * @param id The map ID to check for + * @return true/false + */ public boolean isIdUsedBy(OfflinePlayer player, int id) { return id > 0 && getOccupiedIdsFor(player).contains(id); } + /** + * Get the next ID that can be used for this player + * + * @param player The {@link Player} to check for + * @return The next ID + * @throws MapLimitExceededException If no IDs are available + */ public int getNextFreeIdFor(Player player) throws MapLimitExceededException { Set occupied = getOccupiedIdsFor(player); //Add the 'default' occupied IDs @@ -143,12 +199,26 @@ public class MapManager { throw new MapLimitExceededException("'" + player + "' reached the maximum amount of available Map-IDs"); } + /** + * Clear all the maps of a player + * This makes them no longer viewable for this player + * + * @param player The {@link OfflinePlayer} to clear for + */ public void clearAllMapsFor(OfflinePlayer player) { for (MapWrapper wrapper : getMapsVisibleTo(player)) { wrapper.getController().removeViewer(player); } } + /** + * Check if a MapWrapper exists for this image + * If so, the same MapWrapper can be used + * + * @param image The {@link ArrayImage} to check for + * @return A {@link MapWrapper} if duplicate, or null if not + */ + @Nullable public MapWrapper getDuplicate(ArrayImage image) { for (MapWrapper wrapper : MANAGED_MAPS) { if (image.equals(wrapper.getContent())) { diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java index ce2b72e..ffd694c 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java @@ -26,8 +26,8 @@ package tech.sbdevelopment.mapreflectionapi.api; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil; -import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils; +import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil; +import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtils; import java.util.ArrayList; import java.util.List; @@ -37,6 +37,13 @@ public class MapSender { private static final List sendQueue = new ArrayList<>(); private static int senderID = -1; + /** + * Add a map to the send queue + * + * @param id The ID of the map + * @param content The {@link ArrayImage} to view on the map + * @param player The {@link Player} to view for + */ public static void addToQueue(final int id, final ArrayImage content, final Player player) { QueuedMap toSend = new QueuedMap(id, content, player); if (sendQueue.contains(toSend)) return; @@ -45,6 +52,9 @@ public class MapSender { runSender(); } + /** + * Run the sender task + */ private static void runSender() { if (Bukkit.getScheduler().isQueued(senderID) || Bukkit.getScheduler().isCurrentlyRunning(senderID) || sendQueue.isEmpty()) return; @@ -66,6 +76,13 @@ public class MapSender { private static final Class packetPlayOutMapClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutMap"); private static final Class worldMapData = ReflectionUtils.supports(17) ? ReflectionUtils.getNMSClass("world.level.saveddata.maps", "WorldMap") : null; + /** + * Send a map to a player + * + * @param id0 The ID of the map + * @param content The {@link ArrayImage} to view on the map + * @param player The {@link Player} to view for + */ public static void sendMap(final int id0, final ArrayImage content, final Player player) { if (player == null || !player.isOnline()) { List toRemove = new ArrayList<>(); diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java index c626fae..e10ff64 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java @@ -30,15 +30,20 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.metadata.FixedMetadataValue; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; -import tech.sbdevelopment.mapreflectionapi.exceptions.MapLimitExceededException; -import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtil; -import tech.sbdevelopment.mapreflectionapi.util.ReflectionUtils; +import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException; +import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil; +import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtils; import java.util.*; public class MapWrapper { protected ArrayImage content; + /** + * Construct a new {@link MapWrapper} + * + * @param image The {@link ArrayImage} to wrap + */ public MapWrapper(ArrayImage image) { this.content = image; } @@ -274,13 +279,21 @@ public class MapWrapper { } }; + /** + * Get the content that is wrapped + * + * @return The {@link ArrayImage} + */ public ArrayImage getContent() { return content; } + /** + * Get the controller of this wrapper + * + * @return The {@link MapController} + */ public MapController getController() { return controller; } - - } diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java index 8c9fe99..05c956a 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java @@ -23,29 +23,42 @@ package tech.sbdevelopment.mapreflectionapi.api.events; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; +/** + * This event gets fired when a map in the creative inventory gets updated + */ +@RequiredArgsConstructor +@Getter public class CreateInventoryMapUpdateEvent extends Event implements Cancellable { private static final HandlerList handlerList = new HandlerList(); + @Setter + private boolean cancelled; + private final Player player; private final int slot; private final ItemStack item; private MapWrapper mapWrapper; - private boolean cancelled; - - public CreateInventoryMapUpdateEvent(Player player, int slot, ItemStack item) { - this.player = player; - this.slot = slot; - this.item = item; - } + /** + * Construct a new {@link CreateInventoryMapUpdateEvent} + * + * @param player The player whose inventory is updated + * @param slot The new slot + * @param item The item in the new slot + * @param isAsync Is this event called async? + */ public CreateInventoryMapUpdateEvent(Player player, int slot, ItemStack item, boolean isAsync) { super(isAsync); this.player = player; @@ -53,44 +66,24 @@ public class CreateInventoryMapUpdateEvent extends Event implements Cancellable this.item = item; } - public static HandlerList getHandlerList() { - return handlerList; - } - - public Player getPlayer() { - return player; - } - - public int getSlot() { - return slot; - } - - public ItemStack getItem() { - return item; - } - - public MapWrapper getMapWrapper() { - if (mapWrapper == null) { - if (item == null) return null; - if (item.getType() != Material.MAP) return null; - MapReflectionAPI.getMapManager().getWrapperForId(player, item.getDurability()); - } - - return mapWrapper; - } - @Override public HandlerList getHandlers() { return handlerList; } - @Override - public boolean isCancelled() { - return cancelled; - } + /** + * Get the {@link MapWrapper} of the map of this event + * + * @return The {@link MapWrapper} + */ + @Nullable + public MapWrapper getMapWrapper() { + if (mapWrapper == null) { + if (item == null) return null; + if (item.getType() != Material.MAP) return null; + mapWrapper = MapReflectionAPI.getMapManager().getWrapperForId(player, item.getDurability()); + } - @Override - public void setCancelled(boolean b) { - this.cancelled = b; + return mapWrapper; } } diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java index 72d40d0..4ab8825 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java @@ -23,52 +23,42 @@ package tech.sbdevelopment.mapreflectionapi.api.events; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +/** + * This event gets fired when a map creation is cancelled + */ +@RequiredArgsConstructor +@Getter public class MapCancelEvent extends Event implements Cancellable { private static final HandlerList handlerList = new HandlerList(); - private final Player player; - private final int id; + @Setter private boolean cancelled; - public MapCancelEvent(Player player, int id) { - this.player = player; - this.id = id; - } + private final Player player; + private final int id; + /** + * Construct a new {@link MapCancelEvent} + * + * @param player The player who tried to create the map + * @param id The ID of the map + * @param isAsync Is this event called async? + */ public MapCancelEvent(Player player, int id, boolean isAsync) { super(isAsync); this.player = player; this.id = id; } - public static HandlerList getHandlerList() { - return handlerList; - } - - public Player getPlayer() { - return player; - } - - public int getId() { - return id; - } - @Override public HandlerList getHandlers() { return handlerList; } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public void setCancelled(boolean b) { - this.cancelled = b; - } } diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java index 327c762..aad264b 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java @@ -23,17 +23,29 @@ package tech.sbdevelopment.mapreflectionapi.api.events; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.util.Vector; +import org.jetbrains.annotations.Nullable; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; import tech.sbdevelopment.mapreflectionapi.api.MapWrapper; +/** + * This event gets fired when a player interact with a map + */ +@RequiredArgsConstructor +@Getter public class MapInteractEvent extends Event implements Cancellable { private static final HandlerList handlerList = new HandlerList(); + @Setter + private boolean cancelled; + private final Player player; private final int entityID; private final int action; @@ -41,16 +53,17 @@ public class MapInteractEvent extends Event implements Cancellable { private final int hand; private ItemFrame frame; private MapWrapper mapWrapper; - private boolean cancelled; - - public MapInteractEvent(Player player, int entityID, int action, Vector vector, int hand) { - this.player = player; - this.entityID = entityID; - this.action = action; - this.vector = vector; - this.hand = hand; - } + /** + * Construct a new {@link MapInteractEvent} + * + * @param player The player who interacted + * @param entityID The ID of the entity the map is in + * @param action The interact action + * @param vector The location of the entity + * @param hand The hand the player clicked with + * @param isAsync Is this event called async? + */ public MapInteractEvent(Player player, int entityID, int action, Vector vector, int hand, boolean isAsync) { super(isAsync); this.player = player; @@ -60,30 +73,17 @@ public class MapInteractEvent extends Event implements Cancellable { this.hand = hand; } - public static HandlerList getHandlerList() { + @Override + public HandlerList getHandlers() { return handlerList; } - public Player getPlayer() { - return player; - } - - public int getEntityID() { - return entityID; - } - - public int getAction() { - return action; - } - - public Vector getVector() { - return vector; - } - - public int getHand() { - return hand; - } - + /** + * Get the {@link ItemFrame} the map is in + * + * @return The frame the map is in, or null if it's not a map + */ + @Nullable public ItemFrame getFrame() { if (getMapWrapper() == null) return null; @@ -93,6 +93,12 @@ public class MapInteractEvent extends Event implements Cancellable { return frame; } + /** + * Get the {@link MapWrapper} of the map + * + * @return The wrapper + */ + @Nullable public MapWrapper getMapWrapper() { if (mapWrapper == null) { mapWrapper = MapReflectionAPI.getMapManager().getWrapperForId(player, entityID); @@ -100,19 +106,4 @@ public class MapInteractEvent extends Event implements Cancellable { return mapWrapper; } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public void setCancelled(boolean b) { - this.cancelled = b; - } - - @Override - public HandlerList getHandlers() { - return handlerList; - } } diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java similarity index 83% rename from src/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java index 8fd4caa..47e3510 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/exceptions/MapLimitExceededException.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java @@ -21,9 +21,17 @@ * SOFTWARE. */ -package tech.sbdevelopment.mapreflectionapi.exceptions; +package tech.sbdevelopment.mapreflectionapi.api.exceptions; +/** + * This exception gets thrown if no map IDs are available + */ public class MapLimitExceededException extends Exception { + /** + * Construct a new {@link MapLimitExceededException} + * + * @param message The message in this exception + */ public MapLimitExceededException(String message) { super(message); } diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java similarity index 99% rename from src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java index b6cbfe0..ef97a64 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtil.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package tech.sbdevelopment.mapreflectionapi.util; +package tech.sbdevelopment.mapreflectionapi.utils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtils.java similarity index 99% rename from src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java rename to src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtils.java index 7c4e830..795a3d9 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/util/ReflectionUtils.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtils.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package tech.sbdevelopment.mapreflectionapi.util; +package tech.sbdevelopment.mapreflectionapi.utils; import org.bukkit.World; import org.bukkit.entity.Player; -- 2.45.3 From 13573d4add31cf379a25d1c17afc58db3fd6a86a Mon Sep 17 00:00:00 2001 From: SBDeveloper Date: Fri, 1 Jul 2022 13:27:07 +0200 Subject: [PATCH 5/7] :recycle: Merged reflection utility classes --- .../mapreflectionapi/MapReflectionAPI.java | 4 +- .../mapreflectionapi/api/MapSender.java | 11 +- .../mapreflectionapi/api/MapWrapper.java | 53 ++- .../utils/ReflectionUtil.java | 267 ++++++++++++ .../utils/ReflectionUtils.java | 382 ------------------ 5 files changed, 300 insertions(+), 417 deletions(-) delete mode 100644 src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtils.java diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java index aa32b80..85fd0bf 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java @@ -30,7 +30,7 @@ import org.bukkit.plugin.java.JavaPlugin; import tech.sbdevelopment.mapreflectionapi.api.MapManager; import tech.sbdevelopment.mapreflectionapi.listeners.MapListener; import tech.sbdevelopment.mapreflectionapi.listeners.PacketListener; -import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtils; +import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil; import java.util.logging.Level; @@ -66,7 +66,7 @@ public class MapReflectionAPI extends JavaPlugin { getLogger().info("MapReflectionAPI v" + getDescription().getVersion() + ""); getLogger().info("Made by © Copyright SBDevelopment 2022"); - if (!ReflectionUtils.supports(12)) { + if (!ReflectionUtil.supports(12)) { getLogger().severe("MapReflectionAPI only supports Minecraft 1.12 - 1.19!"); Bukkit.getPluginManager().disablePlugin(this); return; diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java index ffd694c..388b3d8 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java @@ -27,7 +27,6 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil; -import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtils; import java.util.ArrayList; import java.util.List; @@ -73,8 +72,8 @@ public class MapSender { }, 0, 2); } - private static final Class packetPlayOutMapClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutMap"); - private static final Class worldMapData = ReflectionUtils.supports(17) ? ReflectionUtils.getNMSClass("world.level.saveddata.maps", "WorldMap") : null; + private static final Class packetPlayOutMapClass = ReflectionUtil.getNMSClass("network.protocol.game", "PacketPlayOutMap"); + private static final Class worldMapData = ReflectionUtil.supports(17) ? ReflectionUtil.getNMSClass("world.level.saveddata.maps", "WorldMap") : null; /** * Send a map to a player @@ -101,7 +100,7 @@ public class MapSender { final int id = -id0; Object packet; - if (ReflectionUtils.supports(17)) { //1.17+ + if (ReflectionUtil.supports(17)) { //1.17+ Object updateData = ReflectionUtil.callConstructor(worldMapData, content.minX, //X pos content.minY, //Y pos @@ -117,7 +116,7 @@ public class MapSender { new ArrayList<>(), //Icons updateData ); - } else if (ReflectionUtils.supports(14)) { //1.16-1.14 + } else if (ReflectionUtil.supports(14)) { //1.16-1.14 packet = ReflectionUtil.callConstructor(packetPlayOutMapClass, id, //ID (byte) 0, //Scale @@ -144,7 +143,7 @@ public class MapSender { ); } - ReflectionUtils.sendPacket(player, packet); + ReflectionUtil.sendPacket(player, packet); } static final class QueuedMap { private final int id; diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java index e10ff64..2e30754 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java @@ -32,7 +32,6 @@ import org.bukkit.metadata.FixedMetadataValue; import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI; import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException; import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil; -import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtils; import java.util.*; @@ -48,14 +47,14 @@ public class MapWrapper { this.content = image; } - private static final Class craftStackClass = ReflectionUtils.getCraftClass("CraftItemStack"); - private static final Class setSlotPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutSetSlot"); - private static final Class tagCompoundClass = ReflectionUtils.getCraftClass("NBTTagCompound"); - private static final Class entityClass = ReflectionUtils.getNMSClass("world.entity", "Entity"); - private static final Class dataWatcherClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher"); - private static final Class entityMetadataPacketClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata"); - private static final Class entityItemFrameClass = ReflectionUtils.getNMSClass("world.entity.decoration", "EntityItemFrame"); - private static final Class dataWatcherItemClass = ReflectionUtils.getNMSClass("network.syncher", "DataWatcher$Item"); + private static final Class craftStackClass = ReflectionUtil.getCraftClass("CraftItemStack"); + private static final Class setSlotPacketClass = ReflectionUtil.getNMSClass("network.protocol.game", "PacketPlayOutSetSlot"); + private static final Class tagCompoundClass = ReflectionUtil.getCraftClass("NBTTagCompound"); + private static final Class entityClass = ReflectionUtil.getNMSClass("world.entity", "Entity"); + private static final Class dataWatcherClass = ReflectionUtil.getNMSClass("network.syncher", "DataWatcher"); + private static final Class entityMetadataPacketClass = ReflectionUtil.getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata"); + private static final Class entityItemFrameClass = ReflectionUtil.getNMSClass("world.entity.decoration", "EntityItemFrame"); + private static final Class dataWatcherItemClass = ReflectionUtil.getNMSClass("network.syncher", "DataWatcher$Item"); protected MapController controller = new MapController() { private final Map viewers = new HashMap<>(); @@ -142,17 +141,17 @@ public class MapWrapper { slot = 8 - (slot - 36); } - Object playerHandle = ReflectionUtils.getHandle(player); - Object inventoryMenu = ReflectionUtil.getField(playerHandle, ReflectionUtils.supports(19) ? "bT" : ReflectionUtils.supports(17) ? "bU" : "defaultContainer"); - int windowId = (int) ReflectionUtil.getField(inventoryMenu, ReflectionUtils.supports(17) ? "j" : "windowId"); + Object playerHandle = ReflectionUtil.getHandle(player); + Object inventoryMenu = ReflectionUtil.getField(playerHandle, ReflectionUtil.supports(19) ? "bT" : ReflectionUtil.supports(17) ? "bU" : "defaultContainer"); + int windowId = (int) ReflectionUtil.getField(inventoryMenu, ReflectionUtil.supports(17) ? "j" : "windowId"); - ItemStack stack = new ItemStack(ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP, 1); + ItemStack stack = new ItemStack(ReflectionUtil.supports(13) ? Material.FILLED_MAP : Material.MAP, 1); Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack); Object packet; - if (ReflectionUtils.supports(17)) { //1.17+ - int stateId = (int) ReflectionUtil.callMethod(inventoryMenu, ReflectionUtils.supports(18) ? "j" : "getStateId"); + if (ReflectionUtil.supports(17)) { //1.17+ + int stateId = (int) ReflectionUtil.callMethod(inventoryMenu, ReflectionUtil.supports(18) ? "j" : "getStateId"); packet = ReflectionUtil.callConstructor(setSlotPacketClass, windowId, @@ -168,7 +167,7 @@ public class MapWrapper { ); } - ReflectionUtils.sendPacket(player, packet); + ReflectionUtil.sendPacket(player, packet); } @Override @@ -178,7 +177,7 @@ public class MapWrapper { @Override public void showInHand(Player player, boolean force) { - if (player.getInventory().getItemInMainHand().getType() != (ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force) + if (player.getInventory().getItemInMainHand().getType() != (ReflectionUtil.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force) return; showInInventory(player, player.getInventory().getHeldItemSlot(), force); } @@ -195,7 +194,7 @@ public class MapWrapper { @Override public void showInFrame(Player player, ItemFrame frame, boolean force) { - if (frame.getItem().getType() != (ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force) + if (frame.getItem().getType() != (ReflectionUtil.supports(13) ? Material.FILLED_MAP : Material.MAP) && !force) return; showInFrame(player, frame.getEntityId()); } @@ -209,7 +208,7 @@ public class MapWrapper { public void showInFrame(Player player, int entityId, String debugInfo) { if (!isViewing(player)) return; - ItemStack stack = new ItemStack(ReflectionUtils.supports(13) ? Material.FILLED_MAP : Material.MAP, 1); + ItemStack stack = new ItemStack(ReflectionUtil.supports(13) ? Material.FILLED_MAP : Material.MAP, 1); if (debugInfo != null) { ItemMeta itemMeta = stack.getItemMeta(); itemMeta.setDisplayName(debugInfo); @@ -239,11 +238,11 @@ public class MapWrapper { @Override public ItemFrame getItemFrameById(World world, int entityId) { - Object worldHandle = ReflectionUtils.getHandle(world); - Object nmsEntity = ReflectionUtil.callMethod(worldHandle, ReflectionUtils.supports(18) ? "a" : "getEntity"); + Object worldHandle = ReflectionUtil.getHandle(world); + Object nmsEntity = ReflectionUtil.callMethod(worldHandle, ReflectionUtil.supports(18) ? "a" : "getEntity"); if (nmsEntity == null) return null; - if (!ReflectionUtils.supports(17)) { + if (!ReflectionUtil.supports(17)) { nmsEntity = ReflectionUtil.callMethod(nmsEntity, "getBukkitEntity"); } @@ -253,14 +252,14 @@ public class MapWrapper { private void sendItemFramePacket(Player player, int entityId, ItemStack stack, int mapId) { Object nmsStack = ReflectionUtil.callMethod(craftStackClass, "asNMSCopy", stack); - Object nbtObject = ReflectionUtil.callMethod(nmsStack, ReflectionUtils.supports(19) ? "v" : ReflectionUtils.supports(18) ? "u" : ReflectionUtils.supports(13) ? "getOrCreateTag" : "getTag"); + Object nbtObject = ReflectionUtil.callMethod(nmsStack, ReflectionUtil.supports(19) ? "v" : ReflectionUtil.supports(18) ? "u" : ReflectionUtil.supports(13) ? "getOrCreateTag" : "getTag"); - if (!ReflectionUtils.supports(13) && nbtObject == null) { //1.12 has no getOrCreate, call create if null! + if (!ReflectionUtil.supports(13) && nbtObject == null) { //1.12 has no getOrCreate, call create if null! Object tagCompound = ReflectionUtil.callConstructor(tagCompoundClass); ReflectionUtil.callMethod(nbtObject, "setTag", tagCompound); } - ReflectionUtil.callMethod(nbtObject, ReflectionUtils.supports(18) ? "a" : "setInt", "map", mapId); + ReflectionUtil.callMethod(nbtObject, ReflectionUtil.supports(18) ? "a" : "setInt", "map", mapId); Object dataWatcher = ReflectionUtil.callConstructor(dataWatcherClass, entityClass.cast(null)); Object packet = ReflectionUtil.callConstructor(entityMetadataPacketClass, @@ -270,12 +269,12 @@ public class MapWrapper { ); List list = new ArrayList<>(); - Object dataWatcherObject = ReflectionUtil.getDeclaredField(entityItemFrameClass, ReflectionUtils.supports(17) ? "ao" : ReflectionUtils.supports(14) ? "ITEM" : ReflectionUtils.supports(13) ? "e" : "c"); + Object dataWatcherObject = ReflectionUtil.getDeclaredField(entityItemFrameClass, ReflectionUtil.supports(17) ? "ao" : ReflectionUtil.supports(14) ? "ITEM" : ReflectionUtil.supports(13) ? "e" : "c"); Object dataWatcherItem = ReflectionUtil.callConstructor(dataWatcherItemClass, dataWatcherObject, nmsStack); list.add(dataWatcherItem); ReflectionUtil.setDeclaredField(packet, "b", list); - ReflectionUtils.sendPacket(player, packet); + ReflectionUtil.sendPacket(player, packet); } }; diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java index ef97a64..87f9b91 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java @@ -23,14 +23,22 @@ package tech.sbdevelopment.mapreflectionapi.utils; +import org.bukkit.World; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.annotation.Nonnull; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; /** * ReflectionUtil - Reflection handler for NMS and CraftBukkit.
@@ -47,9 +55,131 @@ import java.util.Arrays; * @version 2.1 */ public class ReflectionUtil { + /** + * We use reflection mainly to avoid writing a new class for version barrier. + * The version barrier is for NMS that uses the Minecraft version as the main package name. + *

+ * E.g. EntityPlayer in 1.15 is in the class {@code net.minecraft.server.v1_15_R1} + * but in 1.14 it's in {@code net.minecraft.server.v1_14_R1} + * In order to maintain cross-version compatibility we cannot import these classes. + *

+ * Performance is not a concern for these specific statically initialized values. + */ + public static final String VERSION; + /** + * The raw minor version number. + * E.g. {@code v1_17_R1} to {@code 17} + * + * @since 4.0.0 + */ + public static final int VER = Integer.parseInt(VERSION.substring(1).split("_")[1]); + /** + * Mojang remapped their NMS in 1.17 https://www.spigotmc.org/threads/spigot-bungeecord-1-17.510208/#post-4184317 + */ + public static final String + CRAFTBUKKIT = "org.bukkit.craftbukkit." + VERSION + '.', + NMS = v(17, "net.minecraft.").orElse("net.minecraft.server." + VERSION + '.'); + /** + * A nullable public accessible field only available in {@code EntityPlayer}. + * This can be null if the player is offline. + */ + private static final MethodHandle PLAYER_CONNECTION; + /** + * Responsible for getting the NMS handler {@code EntityPlayer} object for the player. + * {@code CraftPlayer} is simply a wrapper for {@code EntityPlayer}. + * Used mainly for handling packet related operations. + *

+ * This is also where the famous player {@code ping} field comes from! + */ + private static final MethodHandle GET_HANDLE; + private static final MethodHandle GET_HANDLE_WORLD; + /** + * Sends a packet to the player's client through a {@code NetworkManager} which + * is where {@code ProtocolLib} controls packets by injecting channels! + */ + private static final MethodHandle SEND_PACKET; + + static { // This needs to be right below VERSION because of initialization order. + // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() + // which allows easier testing as well. + String found = null; + for (Package pack : Package.getPackages()) { + String name = pack.getName(); + + // .v because there are other packages. + if (name.startsWith("org.bukkit.craftbukkit.v")) { + found = pack.getName().split("\\.")[3]; + + // Just a final guard to make sure it finds this important class. + // As a protection for forge+bukkit implementation that tend to mix versions. + // The real CraftPlayer should exist in the package. + // Note: Doesn't seem to function properly. Will need to separate the version + // handler for NMS and CraftBukkit for softwares like catmc. + try { + Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); + break; + } catch (ClassNotFoundException e) { + found = null; + } + } + } + if (found == null) + throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); + VERSION = found; + } + + static { + Class entityPlayer = getNMSClass("server.level", "EntityPlayer"); + Class worldServer = getNMSClass("server.level", "WorldServer"); + Class craftPlayer = getCraftClass("entity.CraftPlayer"); + Class craftWorld = getCraftClass("CraftWorld"); + Class playerConnection = getNMSClass("server.network", "PlayerConnection"); + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle sendPacket = null, getHandle = null, getHandleWorld = null, connection = null; + + try { + connection = lookup.findGetter(entityPlayer, + v(17, "b").orElse("playerConnection"), playerConnection); + getHandle = lookup.findVirtual(craftPlayer, "getHandle", MethodType.methodType(entityPlayer)); + getHandleWorld = lookup.findVirtual(craftWorld, "getHandle", MethodType.methodType(worldServer)); + sendPacket = lookup.findVirtual(playerConnection, + v(18, "a").orElse("sendPacket"), + MethodType.methodType(void.class, getNMSClass("network.protocol", "Packet"))); + } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + } + + PLAYER_CONNECTION = connection; + SEND_PACKET = sendPacket; + GET_HANDLE = getHandle; + GET_HANDLE_WORLD = getHandleWorld; + } + private ReflectionUtil() { } + /** + * This method is purely for readability. + * No performance is gained. + * + * @since 5.0.0 + */ + public static VersionHandler v(int version, T handle) { + return new VersionHandler<>(version, handle); + } + + /** + * Checks whether the server version is equal or greater than the given version. + * + * @param version the version to compare the server version with. + * @return true if the version is equal or newer, otherwise false. + * @since 4.0.0 + */ + public static boolean supports(int version) { + return VER >= version; + } + private static Class wrapperToPrimitive(Class clazz) { if (clazz == Boolean.class) return boolean.class; if (clazz == Integer.class) return int.class; @@ -162,4 +292,141 @@ public class ReflectionUtil { ex.printStackTrace(); } } + + /** + * Get a NMS (net.minecraft.server) class which accepts a package for 1.17 compatibility. + * + * @param newPackage the 1.17 package name. + * @param name the name of the class. + * @return the NMS class or null if not found. + * @since 4.0.0 + */ + @javax.annotation.Nullable + public static Class getNMSClass(@Nonnull String newPackage, @Nonnull String name) { + if (supports(17)) name = newPackage + '.' + name; + return getNMSClass(name); + } + + /** + * Get a NMS (net.minecraft.server) class. + * + * @param name the name of the class. + * @return the NMS class or null if not found. + * @since 1.0.0 + */ + @javax.annotation.Nullable + public static Class getNMSClass(@Nonnull String name) { + try { + return Class.forName(NMS + name); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } + + /** + * Sends a packet to the player asynchronously if they're online. + * Packets are thread-safe. + * + * @param player the player to send the packet to. + * @param packets the packets to send. + * @return the async thread handling the packet. + * @see #sendPacketSync(Player, Object...) + * @since 1.0.0 + */ + @Nonnull + public static CompletableFuture sendPacket(@Nonnull Player player, @Nonnull Object... packets) { + return CompletableFuture.runAsync(() -> sendPacketSync(player, packets)) + .exceptionally(ex -> { + ex.printStackTrace(); + return null; + }); + } + + /** + * Sends a packet to the player synchronously if they're online. + * + * @param player the player to send the packet to. + * @param packets the packets to send. + * @see #sendPacket(Player, Object...) + * @since 2.0.0 + */ + public static void sendPacketSync(@Nonnull Player player, @Nonnull Object... packets) { + try { + Object handle = GET_HANDLE.invoke(player); + Object connection = PLAYER_CONNECTION.invoke(handle); + + // Checking if the connection is not null is enough. There is no need to check if the player is online. + if (connection != null) { + for (Object packet : packets) SEND_PACKET.invoke(connection, packet); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + @javax.annotation.Nullable + public static Object getHandle(@Nonnull Player player) { + Objects.requireNonNull(player, "Cannot get handle of null player"); + try { + return GET_HANDLE.invoke(player); + } catch (Throwable throwable) { + throwable.printStackTrace(); + return null; + } + } + + @javax.annotation.Nullable + public static Object getHandle(@Nonnull World world) { + Objects.requireNonNull(world, "Cannot get handle of null world"); + try { + return GET_HANDLE_WORLD.invoke(world); + } catch (Throwable throwable) { + throwable.printStackTrace(); + return null; + } + } + + /** + * Get a CraftBukkit (org.bukkit.craftbukkit) class. + * + * @param name the name of the class to load. + * @return the CraftBukkit class or null if not found. + * @since 1.0.0 + */ + @javax.annotation.Nullable + public static Class getCraftClass(@Nonnull String name) { + try { + return Class.forName(CRAFTBUKKIT + name); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } + + public static final class VersionHandler { + private int version; + private T handle; + + private VersionHandler(int version, T handle) { + if (supports(version)) { + this.version = version; + this.handle = handle; + } + } + + public VersionHandler v(int version, T handle) { + if (version == this.version) + throw new IllegalArgumentException("Cannot have duplicate version handles for version: " + version); + if (version > this.version && supports(version)) { + this.version = version; + this.handle = handle; + } + return this; + } + + public T orElse(T handle) { + return this.version == 0 ? handle : this.handle; + } + } } \ No newline at end of file diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtils.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtils.java deleted file mode 100644 index 795a3d9..0000000 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtils.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * This file is part of MapReflectionAPI. - * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package tech.sbdevelopment.mapreflectionapi.utils; - -import org.bukkit.World; -import org.bukkit.entity.Player; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.Objects; -import java.util.concurrent.Callable; -import java.util.concurrent.CompletableFuture; - -/** - * ReflectionUtils - Reflection handler for NMS and CraftBukkit.
- * Caches the packet related methods and is asynchronous. - *

- * This class does not handle null checks as most of the requests are from the - * other utility classes that already handle null checks. - *

- * Clientbound Packets are considered fake - * updates to the client without changing the actual data. Since all the data is handled - * by the server. - *

- * A useful resource used to compare mappings is Mini's Mapping Viewer - * - * @author Crypto Morin - * @version 6.0.1 - */ -public final class ReflectionUtils { - /** - * We use reflection mainly to avoid writing a new class for version barrier. - * The version barrier is for NMS that uses the Minecraft version as the main package name. - *

- * E.g. EntityPlayer in 1.15 is in the class {@code net.minecraft.server.v1_15_R1} - * but in 1.14 it's in {@code net.minecraft.server.v1_14_R1} - * In order to maintain cross-version compatibility we cannot import these classes. - *

- * Performance is not a concern for these specific statically initialized values. - */ - public static final String VERSION; - - static { // This needs to be right below VERSION because of initialization order. - // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() - // which allows easier testing as well. - String found = null; - for (Package pack : Package.getPackages()) { - String name = pack.getName(); - - // .v because there are other packages. - if (name.startsWith("org.bukkit.craftbukkit.v")) { - found = pack.getName().split("\\.")[3]; - - // Just a final guard to make sure it finds this important class. - // As a protection for forge+bukkit implementation that tend to mix versions. - // The real CraftPlayer should exist in the package. - // Note: Doesn't seem to function properly. Will need to separate the version - // handler for NMS and CraftBukkit for softwares like catmc. - try { - Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); - break; - } catch (ClassNotFoundException e) { - found = null; - } - } - } - if (found == null) - throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); - VERSION = found; - } - - /** - * The raw minor version number. - * E.g. {@code v1_17_R1} to {@code 17} - * - * @since 4.0.0 - */ - public static final int VER = Integer.parseInt(VERSION.substring(1).split("_")[1]); - /** - * Mojang remapped their NMS in 1.17 https://www.spigotmc.org/threads/spigot-bungeecord-1-17.510208/#post-4184317 - */ - public static final String - CRAFTBUKKIT = "org.bukkit.craftbukkit." + VERSION + '.', - NMS = v(17, "net.minecraft.").orElse("net.minecraft.server." + VERSION + '.'); - /** - * A nullable public accessible field only available in {@code EntityPlayer}. - * This can be null if the player is offline. - */ - private static final MethodHandle PLAYER_CONNECTION; - /** - * Responsible for getting the NMS handler {@code EntityPlayer} object for the player. - * {@code CraftPlayer} is simply a wrapper for {@code EntityPlayer}. - * Used mainly for handling packet related operations. - *

- * This is also where the famous player {@code ping} field comes from! - */ - private static final MethodHandle GET_HANDLE; - private static final MethodHandle GET_HANDLE_WORLD; - /** - * Sends a packet to the player's client through a {@code NetworkManager} which - * is where {@code ProtocolLib} controls packets by injecting channels! - */ - private static final MethodHandle SEND_PACKET; - - static { - Class entityPlayer = getNMSClass("server.level", "EntityPlayer"); - Class worldServer = getNMSClass("server.level", "WorldServer"); - Class craftPlayer = getCraftClass("entity.CraftPlayer"); - Class craftWorld = getCraftClass("CraftWorld"); - Class playerConnection = getNMSClass("server.network", "PlayerConnection"); - - MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodHandle sendPacket = null, getHandle = null, getHandleWorld = null, connection = null; - - try { - connection = lookup.findGetter(entityPlayer, - v(17, "b").orElse("playerConnection"), playerConnection); - getHandle = lookup.findVirtual(craftPlayer, "getHandle", MethodType.methodType(entityPlayer)); - getHandleWorld = lookup.findVirtual(craftWorld, "getHandle", MethodType.methodType(worldServer)); - sendPacket = lookup.findVirtual(playerConnection, - v(18, "a").orElse("sendPacket"), - MethodType.methodType(void.class, getNMSClass("network.protocol", "Packet"))); - } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException ex) { - ex.printStackTrace(); - } - - PLAYER_CONNECTION = connection; - SEND_PACKET = sendPacket; - GET_HANDLE = getHandle; - GET_HANDLE_WORLD = getHandleWorld; - } - - private ReflectionUtils() { - } - - /** - * This method is purely for readability. - * No performance is gained. - * - * @since 5.0.0 - */ - public static VersionHandler v(int version, T handle) { - return new VersionHandler<>(version, handle); - } - - public static CallableVersionHandler v(int version, Callable handle) { - return new CallableVersionHandler<>(version, handle); - } - - /** - * Checks whether the server version is equal or greater than the given version. - * - * @param version the version to compare the server version with. - * @return true if the version is equal or newer, otherwise false. - * @since 4.0.0 - */ - public static boolean supports(int version) { - return VER >= version; - } - - /** - * Get a NMS (net.minecraft.server) class which accepts a package for 1.17 compatibility. - * - * @param newPackage the 1.17 package name. - * @param name the name of the class. - * @return the NMS class or null if not found. - * @since 4.0.0 - */ - @Nullable - public static Class getNMSClass(@Nonnull String newPackage, @Nonnull String name) { - if (supports(17)) name = newPackage + '.' + name; - return getNMSClass(name); - } - - /** - * Get a NMS (net.minecraft.server) class. - * - * @param name the name of the class. - * @return the NMS class or null if not found. - * @since 1.0.0 - */ - @Nullable - public static Class getNMSClass(@Nonnull String name) { - try { - return Class.forName(NMS + name); - } catch (ClassNotFoundException ex) { - ex.printStackTrace(); - return null; - } - } - - /** - * Sends a packet to the player asynchronously if they're online. - * Packets are thread-safe. - * - * @param player the player to send the packet to. - * @param packets the packets to send. - * @return the async thread handling the packet. - * @see #sendPacketSync(Player, Object...) - * @since 1.0.0 - */ - @Nonnull - public static CompletableFuture sendPacket(@Nonnull Player player, @Nonnull Object... packets) { - return CompletableFuture.runAsync(() -> sendPacketSync(player, packets)) - .exceptionally(ex -> { - ex.printStackTrace(); - return null; - }); - } - - /** - * Sends a packet to the player synchronously if they're online. - * - * @param player the player to send the packet to. - * @param packets the packets to send. - * @see #sendPacket(Player, Object...) - * @since 2.0.0 - */ - public static void sendPacketSync(@Nonnull Player player, @Nonnull Object... packets) { - try { - Object handle = GET_HANDLE.invoke(player); - Object connection = PLAYER_CONNECTION.invoke(handle); - - // Checking if the connection is not null is enough. There is no need to check if the player is online. - if (connection != null) { - for (Object packet : packets) SEND_PACKET.invoke(connection, packet); - } - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - @Nullable - public static Object getHandle(@Nonnull Player player) { - Objects.requireNonNull(player, "Cannot get handle of null player"); - try { - return GET_HANDLE.invoke(player); - } catch (Throwable throwable) { - throwable.printStackTrace(); - return null; - } - } - - @Nullable - public static Object getHandle(@Nonnull World world) { - Objects.requireNonNull(world, "Cannot get handle of null world"); - try { - return GET_HANDLE_WORLD.invoke(world); - } catch (Throwable throwable) { - throwable.printStackTrace(); - return null; - } - } - - @Nullable - public static Object getConnection(@Nonnull Player player) { - Objects.requireNonNull(player, "Cannot get connection of null player"); - try { - Object handle = GET_HANDLE.invoke(player); - return PLAYER_CONNECTION.invoke(handle); - } catch (Throwable throwable) { - throwable.printStackTrace(); - return null; - } - } - - /** - * Get a CraftBukkit (org.bukkit.craftbukkit) class. - * - * @param name the name of the class to load. - * @return the CraftBukkit class or null if not found. - * @since 1.0.0 - */ - @Nullable - public static Class getCraftClass(@Nonnull String name) { - try { - return Class.forName(CRAFTBUKKIT + name); - } catch (ClassNotFoundException ex) { - ex.printStackTrace(); - return null; - } - } - - public static Class getArrayClass(String clazz, boolean nms) { - clazz = "[L" + (nms ? NMS : CRAFTBUKKIT) + clazz + ';'; - try { - return Class.forName(clazz); - } catch (ClassNotFoundException ex) { - ex.printStackTrace(); - return null; - } - } - - public static Class toArrayClass(Class clazz) { - try { - return Class.forName("[L" + clazz.getName() + ';'); - } catch (ClassNotFoundException ex) { - ex.printStackTrace(); - return null; - } - } - - public static final class VersionHandler { - private int version; - private T handle; - - private VersionHandler(int version, T handle) { - if (supports(version)) { - this.version = version; - this.handle = handle; - } - } - - public VersionHandler v(int version, T handle) { - if (version == this.version) - throw new IllegalArgumentException("Cannot have duplicate version handles for version: " + version); - if (version > this.version && supports(version)) { - this.version = version; - this.handle = handle; - } - return this; - } - - public T orElse(T handle) { - return this.version == 0 ? handle : this.handle; - } - } - - public static final class CallableVersionHandler { - private int version; - private Callable handle; - - private CallableVersionHandler(int version, Callable handle) { - if (supports(version)) { - this.version = version; - this.handle = handle; - } - } - - public CallableVersionHandler v(int version, Callable handle) { - if (version == this.version) - throw new IllegalArgumentException("Cannot have duplicate version handles for version: " + version); - if (version > this.version && supports(version)) { - this.version = version; - this.handle = handle; - } - return this; - } - - public T orElse(Callable handle) { - try { - return (this.version == 0 ? handle : this.handle).call(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - } -} \ No newline at end of file -- 2.45.3 From ed127b7e717b202347ea6fa161d6228372debd87 Mon Sep 17 00:00:00 2001 From: SBDeveloper Date: Fri, 1 Jul 2022 13:28:52 +0200 Subject: [PATCH 6/7] :art: Fixed code order problem --- .../utils/ReflectionUtil.java | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java index 87f9b91..ef05ada 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java @@ -66,6 +66,36 @@ public class ReflectionUtil { * Performance is not a concern for these specific statically initialized values. */ public static final String VERSION; + + static { // This needs to be right below VERSION because of initialization order. + // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() + // which allows easier testing as well. + String found = null; + for (Package pack : Package.getPackages()) { + String name = pack.getName(); + + // .v because there are other packages. + if (name.startsWith("org.bukkit.craftbukkit.v")) { + found = pack.getName().split("\\.")[3]; + + // Just a final guard to make sure it finds this important class. + // As a protection for forge+bukkit implementation that tend to mix versions. + // The real CraftPlayer should exist in the package. + // Note: Doesn't seem to function properly. Will need to separate the version + // handler for NMS and CraftBukkit for softwares like catmc. + try { + Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); + break; + } catch (ClassNotFoundException e) { + found = null; + } + } + } + if (found == null) + throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); + VERSION = found; + } + /** * The raw minor version number. * E.g. {@code v1_17_R1} to {@code 17} @@ -99,35 +129,6 @@ public class ReflectionUtil { */ private static final MethodHandle SEND_PACKET; - static { // This needs to be right below VERSION because of initialization order. - // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() - // which allows easier testing as well. - String found = null; - for (Package pack : Package.getPackages()) { - String name = pack.getName(); - - // .v because there are other packages. - if (name.startsWith("org.bukkit.craftbukkit.v")) { - found = pack.getName().split("\\.")[3]; - - // Just a final guard to make sure it finds this important class. - // As a protection for forge+bukkit implementation that tend to mix versions. - // The real CraftPlayer should exist in the package. - // Note: Doesn't seem to function properly. Will need to separate the version - // handler for NMS and CraftBukkit for softwares like catmc. - try { - Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); - break; - } catch (ClassNotFoundException e) { - found = null; - } - } - } - if (found == null) - throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); - VERSION = found; - } - static { Class entityPlayer = getNMSClass("server.level", "EntityPlayer"); Class worldServer = getNMSClass("server.level", "WorldServer"); -- 2.45.3 From ba1b3e515f038c42e0a5f3a307799be22cac1925 Mon Sep 17 00:00:00 2001 From: SBDeveloper Date: Fri, 1 Jul 2022 14:13:46 +0200 Subject: [PATCH 7/7] :bug: Fixed bugs in the code --- pom.xml | 37 +++++++++++- .../mapreflectionapi/api/MapSender.java | 2 +- .../mapreflectionapi/api/MapWrapper.java | 10 ++-- .../listeners/PacketListener.java | 14 +++-- .../utils/ReflectionUtil.java | 57 ++++++++++++++++++- 5 files changed, 107 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 88dc353..0ad424c 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,13 @@ UTF-8 + + + nexus-releases + https://repo.sbdevelopment.tech/repository/maven-releases/ + + + @@ -73,6 +80,33 @@ + + org.apache.maven.plugins + maven-deploy-plugin + 3.0.0-M2 + + true + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.13 + + + default-deploy + deploy + + deploy + + + + + nexus-releases + https://repo.sbdevelopment.tech/ + true + + @@ -102,6 +136,7 @@ org.spigotmc spigot-api 1.19-R0.1-SNAPSHOT + provided com.bergerkiller.bukkit @@ -112,7 +147,7 @@ com.comphenix.protocol ProtocolLib - 4.8.0 + 5.0.0-SNAPSHOT provided diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java index 388b3d8..30a1252 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapSender.java @@ -73,7 +73,7 @@ public class MapSender { } private static final Class packetPlayOutMapClass = ReflectionUtil.getNMSClass("network.protocol.game", "PacketPlayOutMap"); - private static final Class worldMapData = ReflectionUtil.supports(17) ? ReflectionUtil.getNMSClass("world.level.saveddata.maps", "WorldMap") : null; + private static final Class worldMapData = ReflectionUtil.supports(17) ? ReflectionUtil.getNMSClass("world.level.saveddata.maps", "WorldMap$b") : null; /** * Send a map to a player diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java index 2e30754..7e48ea9 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java @@ -47,9 +47,9 @@ public class MapWrapper { this.content = image; } - private static final Class craftStackClass = ReflectionUtil.getCraftClass("CraftItemStack"); + private static final Class craftStackClass = ReflectionUtil.getCraftClass("inventory.CraftItemStack"); private static final Class setSlotPacketClass = ReflectionUtil.getNMSClass("network.protocol.game", "PacketPlayOutSetSlot"); - private static final Class tagCompoundClass = ReflectionUtil.getCraftClass("NBTTagCompound"); + private static final Class tagCompoundClass = ReflectionUtil.getNMSClass("nbt", "NBTTagCompound"); private static final Class entityClass = ReflectionUtil.getNMSClass("world.entity", "Entity"); private static final Class dataWatcherClass = ReflectionUtil.getNMSClass("network.syncher", "DataWatcher"); private static final Class entityMetadataPacketClass = ReflectionUtil.getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata"); @@ -260,7 +260,7 @@ public class MapWrapper { } ReflectionUtil.callMethod(nbtObject, ReflectionUtil.supports(18) ? "a" : "setInt", "map", mapId); - Object dataWatcher = ReflectionUtil.callConstructor(dataWatcherClass, entityClass.cast(null)); + Object dataWatcher = ReflectionUtil.callConstructorNull(dataWatcherClass, entityClass); Object packet = ReflectionUtil.callConstructor(entityMetadataPacketClass, entityId, @@ -268,9 +268,9 @@ public class MapWrapper { true ); - List list = new ArrayList<>(); + List list = new ArrayList<>(); Object dataWatcherObject = ReflectionUtil.getDeclaredField(entityItemFrameClass, ReflectionUtil.supports(17) ? "ao" : ReflectionUtil.supports(14) ? "ITEM" : ReflectionUtil.supports(13) ? "e" : "c"); - Object dataWatcherItem = ReflectionUtil.callConstructor(dataWatcherItemClass, dataWatcherObject, nmsStack); + Object dataWatcherItem = ReflectionUtil.callFirstConstructor(dataWatcherItemClass, dataWatcherObject, nmsStack); list.add(dataWatcherItem); ReflectionUtil.setDeclaredField(packet, "b", list); diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java index 7e48703..38621f8 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java @@ -69,12 +69,18 @@ public class PacketListener extends PacketAdapter { if (event.getPacketType() == PacketType.Play.Client.USE_ENTITY) { int entityId = event.getPacket().getIntegers().read(0); //entityId WrappedEnumEntityUseAction action = event.getPacket().getEnumEntityUseActions().read(0); - EnumWrappers.EntityUseAction actionEnum = action.getAction(); - EnumWrappers.Hand hand = action.getHand(); - Vector pos = action.getPosition(); + 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.ordinal(), pos, hand.ordinal(), async); + 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); diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java index ef05ada..ac91b23 100644 --- a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java +++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java @@ -36,7 +36,9 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Objects; import java.util.concurrent.CompletableFuture; @@ -191,12 +193,13 @@ public class ReflectionUtil { if (clazz == Byte.class) return byte.class; if (clazz == Void.class) return void.class; if (clazz == Character.class) return char.class; + if (clazz == ArrayList.class) return Collection.class; return clazz; } private static Class[] toParamTypes(Object... params) { return Arrays.stream(params) - .map(obj -> wrapperToPrimitive(obj.getClass())) + .map(obj -> obj != null ? wrapperToPrimitive(obj.getClass()) : null) .toArray(Class[]::new); } @@ -210,6 +213,32 @@ public class ReflectionUtil { } } + @Nullable + public static Object callConstructorNull(Class clazz, Class paramClass) { + try { + Constructor con = clazz.getConstructor(paramClass); + con.setAccessible(true); + return con.newInstance(clazz.cast(null)); + } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | + InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } + } + + @Nullable + public static Object callFirstConstructor(Class clazz, Object... params) { + try { + Constructor con = clazz.getConstructors()[0]; + con.setAccessible(true); + return con.newInstance(params); + } catch (IllegalAccessException | InstantiationException | + InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } + } + @Nullable public static Object callConstructor(Class clazz, Object... params) { try { @@ -236,6 +265,18 @@ public class ReflectionUtil { } } + @Nullable + public static Object callMethod(Class clazz, String method, Object... params) { + try { + Method m = clazz.getMethod(method, toParamTypes(params)); + m.setAccessible(true); + return m.invoke(null, params); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } + } + @Nullable public static Object callMethod(Object obj, String method, Object... params) { try { @@ -272,6 +313,18 @@ public class ReflectionUtil { } } + @Nullable + public static Object getDeclaredField(Class clazz, String field) { + try { + Field f = clazz.getDeclaredField(field); + f.setAccessible(true); + return f.get(null); + } catch (NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + return null; + } + } + @Nullable public static Object getDeclaredField(Object object, String field) { try { @@ -288,7 +341,7 @@ public class ReflectionUtil { try { Field f = object.getClass().getDeclaredField(field); f.setAccessible(true); - f.set(object, toParamTypes(value)); + f.set(object, value); } catch (NoSuchFieldException | IllegalAccessException ex) { ex.printStackTrace(); } -- 2.45.3