package org.inventivetalent.packetlistener.handler; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.inventivetalent.reflection.minecraft.Minecraft; import org.inventivetalent.reflection.resolver.FieldResolver; import org.inventivetalent.reflection.resolver.MethodResolver; import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver; import org.inventivetalent.reflection.util.AccessUtil; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public abstract class PacketHandler { private static final List<PacketHandler> handlers = new ArrayList<>(); private boolean hasSendOptions; private boolean forcePlayerSend; private boolean forceServerSend; private boolean hasReceiveOptions; private boolean forcePlayerReceive; private boolean forceServerReceive; public static boolean addHandler(PacketHandler handler) { boolean b = handlers.contains(handler); if (!b) { try { PacketOptions options = handler.getClass().getMethod("onSend", SentPacket.class).getAnnotation(PacketOptions.class); if (options != null) { handler.hasSendOptions = true; if (options.forcePlayer() && options.forceServer()) { throw new IllegalArgumentException("Cannot force player and server packets at the same time!"); } if (options.forcePlayer()) { handler.forcePlayerSend = true; } else if (options.forceServer()) { handler.forceServerSend = true; } } } catch (Exception e) { throw new RuntimeException("Failed to register handler (onSend)", e); } try { PacketOptions options = handler.getClass().getMethod("onReceive", ReceivedPacket.class).getAnnotation(PacketOptions.class); if (options != null) { handler.hasReceiveOptions = true; if (options.forcePlayer() && options.forceServer()) { throw new IllegalArgumentException("Cannot force player and server packets at the same time!"); } if (options.forcePlayer()) { handler.forcePlayerReceive = true; } else if (options.forceServer()) { handler.forceServerReceive = true; } } } catch (Exception e) { throw new RuntimeException("Failed to register handler (onReceive)", e); } } handlers.add(handler); return !b; } public static boolean removeHandler(PacketHandler handler) { return handlers.remove(handler); } public static void notifyHandlers(SentPacket packet) { for (PacketHandler handler : getHandlers()) { try { if (handler.hasSendOptions) { if (handler.forcePlayerSend) { if (!packet.hasPlayer()) { continue; } } else if (handler.forceServerSend) { if (!packet.hasChannel()) { continue; } } } handler.onSend(packet); } catch (Exception e) { System.err.println("[PacketListenerAPI] An exception occured while trying to execute 'onSend'" + (handler.plugin != null ? " in plugin " + handler.plugin.getName() : "") + ": " + e.getMessage()); e.printStackTrace(System.err); } } } public static void notifyHandlers(ReceivedPacket packet) { for (PacketHandler handler : getHandlers()) { try { if (handler.hasReceiveOptions) { if (handler.forcePlayerReceive) { if (!packet.hasPlayer()) { continue; } } else if (handler.forceServerReceive) { if (!packet.hasChannel()) { continue; } } } handler.onReceive(packet); } catch (Exception e) { System.err.println("[PacketListenerAPI] An exception occured while trying to execute 'onReceive'" + (handler.plugin != null ? " in plugin " + handler.plugin.getName() : "") + ": " + e.getMessage()); e.printStackTrace(System.err); } } } @Override public boolean equals(Object object) { if (this == object) { return true; } if (object == null || getClass() != object.getClass()) { return false; } PacketHandler that = (PacketHandler) object; if (hasSendOptions != that.hasSendOptions) { return false; } if (forcePlayerSend != that.forcePlayerSend) { return false; } if (forceServerSend != that.forceServerSend) { return false; } if (hasReceiveOptions != that.hasReceiveOptions) { return false; } if (forcePlayerReceive != that.forcePlayerReceive) { return false; } if (forceServerReceive != that.forceServerReceive) { return false; } return !(plugin != null ? !plugin.equals(that.plugin) : that.plugin != null); } @Override public int hashCode() { int result = (hasSendOptions ? 1 : 0); result = 31 * result + (forcePlayerSend ? 1 : 0); result = 31 * result + (forceServerSend ? 1 : 0); result = 31 * result + (hasReceiveOptions ? 1 : 0); result = 31 * result + (forcePlayerReceive ? 1 : 0); result = 31 * result + (forceServerReceive ? 1 : 0); result = 31 * result + (plugin != null ? plugin.hashCode() : 0); return result; } @Override public String toString() { return "PacketHandler{" + "hasSendOptions=" + hasSendOptions + ", forcePlayerSend=" + forcePlayerSend + ", forceServerSend=" + forceServerSend + ", hasReceiveOptions=" + hasReceiveOptions + ", forcePlayerReceive=" + forcePlayerReceive + ", forceServerReceive=" + forceServerReceive + ", plugin=" + plugin + '}'; } public static List<PacketHandler> getHandlers() { return new ArrayList<>(handlers); } public static List<PacketHandler> getForPlugin(Plugin plugin) { List<PacketHandler> handlers = new ArrayList<>(); if (plugin == null) { return handlers; } for (PacketHandler h : getHandlers()) if (plugin.equals(h.getPlugin())) { handlers.add(h); } return handlers; } static NMSClassResolver nmsClassResolver = new NMSClassResolver(); static FieldResolver EntityPlayerFieldResolver = new FieldResolver(nmsClassResolver.resolveSilent("EntityPlayer")); static MethodResolver PlayerConnectionMethodResolver = new MethodResolver(nmsClassResolver.resolveSilent("PlayerConnection")); // Sending methods public void sendPacket(Player p, Object packet) { if (p == null || packet == null) { throw new NullPointerException(); } try { Object handle = Minecraft.getHandle(p); Object connection = EntityPlayerFieldResolver.resolve("playerConnection").get(handle); PlayerConnectionMethodResolver.resolve("sendPacket").invoke(connection, new Object[] { packet }); } catch (Exception e) { System.err.println("[PacketListenerAPI] Exception while sending " + packet + " to " + p); e.printStackTrace(); } } public Object cloneObject(Object obj) throws Exception { if (obj == null) { return obj; } Object clone = obj.getClass().newInstance(); for (Field f : obj.getClass().getDeclaredFields()) { f = AccessUtil.setAccessible(f); f.set(clone, f.get(obj)); } return clone; } // ////////////////////////////////////////////////// private Plugin plugin; @Deprecated public PacketHandler() { } public PacketHandler(Plugin plugin) { this.plugin = plugin; } public Plugin getPlugin() { return this.plugin; } public abstract void onSend(SentPacket packet); public abstract void onReceive(ReceivedPacket packet); }