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