diff --git a/pom.xml b/pom.xml index 5c8c024f..671ad797 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ ${project.version} - 2.0.4 + 2.0.7 1.15.2-R0.1-SNAPSHOT @@ -302,13 +302,13 @@ junit junit - 4.12 + 4.13 test org.mockito mockito-core - 3.2.0 + 3.3.3 test diff --git a/src/main/java/com/comphenix/protocol/AsynchronousManager.java b/src/main/java/com/comphenix/protocol/AsynchronousManager.java index 3d3cc260..88657548 100644 --- a/src/main/java/com/comphenix/protocol/AsynchronousManager.java +++ b/src/main/java/com/comphenix/protocol/AsynchronousManager.java @@ -42,83 +42,63 @@ public interface AsynchronousManager { * @param listener - the packet listener that will receive these asynchronous events. * @return An asynchronous handler. */ - public abstract AsyncListenerHandler registerAsyncHandler(PacketListener listener); + AsyncListenerHandler registerAsyncHandler(PacketListener listener); /** * Unregisters and closes the given asynchronous handler. * @param handler - asynchronous handler. */ - public abstract void unregisterAsyncHandler(AsyncListenerHandler handler); + void unregisterAsyncHandler(AsyncListenerHandler handler); /** * Unregisters and closes the first asynchronous handler associated with the given listener. * @param listener - asynchronous listener */ - public abstract void unregisterAsyncHandler(PacketListener listener); + void unregisterAsyncHandler(PacketListener listener); /** * Unregisters every asynchronous handler associated with this plugin. * @param plugin - the original plugin. */ - public void unregisterAsyncHandlers(Plugin plugin); - - /** - * Retrieves a immutable set containing the ID of the sent server packets that will be - * observed by the asynchronous listeners. - *

- * Deprecated: Use {@link #getSendingTypes()} instead. - * @return Every filtered server packet. - */ - @Deprecated - public abstract Set getSendingFilters(); + void unregisterAsyncHandlers(Plugin plugin); /** * Retrieves a immutable set containing the types of the sent server packets that will be * observed by the asynchronous listeners. * @return Every filtered server packet. */ - public abstract Set getSendingTypes(); - - /** - * Retrieves a immutable set containing the ID of the recieved client packets that will be - *

- * Deprecated: Use {@link #getReceivingTypes()} instead. - * observed by the asynchronous listeners. - * @return Every filtered client packet. - */ - @Deprecated - public abstract Set getReceivingFilters(); - + Set getSendingTypes(); + /** * Retrieves a immutable set containing the types of the received client packets that will be * observed by the asynchronous listeners. * @return Every filtered client packet. */ - public abstract Set getReceivingTypes(); + Set getReceivingTypes(); /** * Determine if a given synchronous packet has asynchronous listeners. * @param packet - packet to test. * @return TRUE if it does, FALSE otherwise. */ - public abstract boolean hasAsynchronousListeners(PacketEvent packet); + boolean hasAsynchronousListeners(PacketEvent packet); /** * Retrieve the default packet stream. * @return Default packet stream. */ - public abstract PacketStream getPacketStream(); + PacketStream getPacketStream(); /** * Retrieve the default error reporter. * @return Default reporter. */ - public abstract ErrorReporter getErrorReporter(); + ErrorReporter getErrorReporter(); /** * Remove listeners, close threads and transmit every delayed packet. */ - public abstract void cleanupAll(); + void cleanupAll(); /** * Signal that a packet is ready to be transmitted. @@ -127,29 +107,29 @@ public interface AsynchronousManager { * has been called previously. * @param packet - packet to signal. */ - public abstract void signalPacketTransmission(PacketEvent packet); + void signalPacketTransmission(PacketEvent packet); /** * Register a synchronous listener that handles packets when they time out. * @param listener - synchronous listener that will handle timed out packets. */ - public abstract void registerTimeoutHandler(PacketListener listener); + void registerTimeoutHandler(PacketListener listener); /** * Unregisters a given timeout listener. * @param listener - the timeout listener to unregister. */ - public abstract void unregisterTimeoutHandler(PacketListener listener); + void unregisterTimeoutHandler(PacketListener listener); /** * Get a immutable set of every registered timeout handler. * @return Set of every registered timeout handler. */ - public abstract Set getTimeoutHandlers(); + Set getTimeoutHandlers(); /** * Get an immutable set of every registered asynchronous packet listener. * @return Set of every asynchronous packet listener. */ - public abstract Set getAsyncHandlers(); + Set getAsyncHandlers(); } diff --git a/src/main/java/com/comphenix/protocol/CleanupStaticMembers.java b/src/main/java/com/comphenix/protocol/CleanupStaticMembers.java deleted file mode 100644 index b8f46183..00000000 --- a/src/main/java/com/comphenix/protocol/CleanupStaticMembers.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; - -import com.comphenix.protocol.async.AsyncListenerHandler; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.ListeningWhitelist; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.injector.BukkitUnwrapper; -import com.comphenix.protocol.injector.server.AbstractInputStreamLookup; -import com.comphenix.protocol.injector.server.TemporaryPlayerFactory; -import com.comphenix.protocol.injector.spigot.SpigotPacketInjector; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.MethodUtils; -import com.comphenix.protocol.reflect.ObjectWriter; -import com.comphenix.protocol.reflect.compiler.BackgroundCompiler; -import com.comphenix.protocol.reflect.compiler.StructureCompiler; -import com.comphenix.protocol.reflect.instances.CollectionGenerator; -import com.comphenix.protocol.reflect.instances.DefaultInstances; -import com.comphenix.protocol.reflect.instances.PrimitiveGenerator; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.wrappers.ChunkPosition; -import com.comphenix.protocol.wrappers.WrappedDataWatcher; -import com.comphenix.protocol.wrappers.WrappedWatchableObject; -import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer; - -/** - * Used to fix ClassLoader leaks that may lead to filling up the permanent generation. - * - * @author Kristian - */ -class CleanupStaticMembers { - // Reports - public final static ReportType REPORT_CANNOT_RESET_FIELD = new ReportType("Unable to reset field %s: %s"); - public final static ReportType REPORT_CANNOT_UNLOAD_CLASS = new ReportType("Unable to unload class %s."); - - private ClassLoader loader; - private ErrorReporter reporter; - - public CleanupStaticMembers(ClassLoader loader, ErrorReporter reporter) { - this.loader = loader; - this.reporter = reporter; - } - - /** - * Ensure that the previous ClassLoader is not leaking. - */ - public void resetAll() { - // This list must always be updated - @SuppressWarnings("deprecation") - Class[] publicClasses = { - AsyncListenerHandler.class, ListeningWhitelist.class, PacketContainer.class, - BukkitUnwrapper.class, DefaultInstances.class, CollectionGenerator.class, - PrimitiveGenerator.class, FuzzyReflection.class, MethodUtils.class, - BackgroundCompiler.class, StructureCompiler.class, - ObjectWriter.class, Packets.Server.class, Packets.Client.class, - ChunkPosition.class, WrappedDataWatcher.class, WrappedWatchableObject.class, - AbstractInputStreamLookup.class, TemporaryPlayerFactory.class, SpigotPacketInjector.class, - MinecraftReflection.class, NbtBinarySerializer.class - }; - - String[] internalClasses = { - "com.comphenix.protocol.events.SerializedOfflinePlayer", - "com.comphenix.protocol.injector.player.InjectedServerConnection", - "com.comphenix.protocol.injector.player.NetworkFieldInjector", - "com.comphenix.protocol.injector.player.NetworkObjectInjector", - "com.comphenix.protocol.injector.player.NetworkServerInjector", - "com.comphenix.protocol.injector.player.PlayerInjector", - "com.comphenix.protocol.injector.EntityUtilities", - "com.comphenix.protocol.injector.packet.PacketRegistry", - "com.comphenix.protocol.injector.packet.PacketInjector", - "com.comphenix.protocol.injector.packet.ReadPacketModifier", - "com.comphenix.protocol.injector.StructureCache", - "com.comphenix.protocol.reflect.compiler.BoxingHelper", - "com.comphenix.protocol.reflect.compiler.MethodDescriptor", - "com.comphenix.protocol.wrappers.nbt.WrappedElement", - }; - - resetClasses(publicClasses); - resetClasses(getClasses(loader, internalClasses)); - } - - private void resetClasses(Class[] classes) { - // Reset each class one by one - for (Class clazz : classes) { - resetClass(clazz); - } - } - - private void resetClass(Class clazz) { - for (Field field : clazz.getFields()) { - Class type = field.getType(); - - // Only check static non-primitive fields. We also skip strings. - if (Modifier.isStatic(field.getModifiers()) && - !type.isPrimitive() && !type.equals(String.class) && - !type.equals(ReportType.class)) { - - try { - setFinalStatic(field, null); - } catch (IllegalAccessException e) { - // Just inform the player - reporter.reportWarning(this, - Report.newBuilder(REPORT_CANNOT_RESET_FIELD).error(e).messageParam(field.getName(), e.getMessage()) - ); - e.printStackTrace(); - } - } - } - } - - // HACK! HAACK! - private static void setFinalStatic(Field field, Object newValue) throws IllegalAccessException { - int modifier = field.getModifiers(); - boolean isFinal = Modifier.isFinal(modifier); - - Field modifiersField = isFinal ? FieldUtils.getField(Field.class, "modifiers", true) : null; - - // We have to remove the final field first - if (isFinal) { - FieldUtils.writeField(modifiersField, field, modifier & ~Modifier.FINAL, true); - } - - // Now we can safely modify the field - FieldUtils.writeStaticField(field, newValue, true); - - // Revert modifier - if (isFinal) { - FieldUtils.writeField(modifiersField, field, modifier, true); - } - } - - private Class[] getClasses(ClassLoader loader, String[] names) { - List> output = new ArrayList>(); - - for (String name : names) { - try { - output.add(loader.loadClass(name)); - } catch (ClassNotFoundException e) { - // Warn the user - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_UNLOAD_CLASS).error(e).messageParam(name)); - } - } - - return output.toArray(new Class[0]); - } -} diff --git a/src/main/java/com/comphenix/protocol/PacketType.java b/src/main/java/com/comphenix/protocol/PacketType.java index 4d9c9175..d59e3656 100644 --- a/src/main/java/com/comphenix/protocol/PacketType.java +++ b/src/main/java/com/comphenix/protocol/PacketType.java @@ -6,8 +6,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; import java.util.function.Consumer; import com.comphenix.protocol.PacketTypeLookup.ClassLookup; @@ -15,15 +13,14 @@ import com.comphenix.protocol.events.ConnectionSide; import com.comphenix.protocol.injector.packet.PacketRegistry; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftVersion; -import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Futures; import org.apache.commons.lang.WordUtils; import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitRunnable; /** * Represents the type of a packet in a specific protocol. @@ -953,34 +950,29 @@ public class PacketType implements Serializable, Cloneable, Comparable scheduleRegister(final PacketType type, final String name) { - Callable callable = new Callable() { + public static void scheduleRegister(final PacketType type, final String name) { + BukkitRunnable runnable = new BukkitRunnable() { @Override - public Boolean call() throws Exception { + public void run() { PacketTypeEnum objEnum; // A bit ugly, but performance is critical objEnum = getObjectEnum(type); if (objEnum.registerMember(type, name)) { - getLookup().addPacketTypes(Arrays.asList(type)); - return true; + getLookup().addPacketTypes(Collections.singletonList(type)); } - return false; } }; - // Execute in the main thread if possible if (Bukkit.getServer() == null || Bukkit.isPrimaryThread()) { try { - return Futures.immediateFuture(callable.call()); - } catch (Exception e) { - return Futures.immediateFailedFuture(e); - } + runnable.run(); + } catch (Exception ignored) { } + } else { + runnable.runTaskLater(ProtocolLibrary.getPlugin(), 0); } - return ProtocolLibrary.getExecutorSync().submit(callable); } /** diff --git a/src/main/java/com/comphenix/protocol/Packets.java b/src/main/java/com/comphenix/protocol/Packets.java deleted file mode 100644 index 8610979d..00000000 --- a/src/main/java/com/comphenix/protocol/Packets.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol; - -import com.comphenix.protocol.reflect.IntEnum; - -/** - * List of known packet IDs since 1.3.2. - *

- * Deprecated: Use {@link PacketType} instead. - * @author Kristian - */ -@Deprecated -public final class Packets { - - /** - * The highest possible packet ID. It's unlikely that this value will ever change. - */ - public static final int MAXIMUM_PACKET_ID = 255; - - /** - * The maximum number of unique packet IDs. It's unlikely this will ever change. - */ - public static final int PACKET_COUNT = 256; - - /** - * List of packets sent only by the server. - *

- * Deprecated: Use {@link PacketType} instead. - * @author Kristian - */ - @Deprecated - public static final class Server extends IntEnum { - /** - * The singleton instance. Can also be retrieved from the parent class. - */ - private static Server INSTANCE = new Server(); - - public static final int KEEP_ALIVE = 0; - public static final int LOGIN = 1; - public static final int CHAT = 3; - public static final int UPDATE_TIME = 4; - public static final int ENTITY_EQUIPMENT = 5; - public static final int SPAWN_POSITION = 6; - public static final int UPDATE_HEALTH = 8; - public static final int RESPAWN = 9; - public static final int FLYING = 10; - public static final int PLAYER_POSITION = 11; - public static final int PLAYER_LOOK = 12; - public static final int PLAYER_LOOK_MOVE = 13; - /** - * Made bi-directional in 1.4.6. - */ - public static final int BLOCK_ITEM_SWITCH = 16; - public static final int ENTITY_LOCATION_ACTION = 17; - public static final int ARM_ANIMATION = 18; - public static final int NAMED_ENTITY_SPAWN = 20; - /** - * Removed in 1.4.6 and replaced with VEHICLE_SPAWN. - * @see Protocol History - MinecraftCoalition - */ - @Deprecated() - public static final int PICKUP_SPAWN = 21; - public static final int COLLECT = 22; - public static final int VEHICLE_SPAWN = 23; - public static final int MOB_SPAWN = 24; - public static final int ENTITY_PAINTING = 25; - public static final int ADD_EXP_ORB = 26; - public static final int ENTITY_VELOCITY = 28; - public static final int DESTROY_ENTITY = 29; - public static final int ENTITY = 30; - public static final int REL_ENTITY_MOVE = 31; - public static final int ENTITY_LOOK = 32; - public static final int REL_ENTITY_MOVE_LOOK = 33; - public static final int ENTITY_TELEPORT = 34; - public static final int ENTITY_HEAD_ROTATION = 35; - public static final int ENTITY_STATUS = 38; - public static final int ATTACH_ENTITY = 39; - - /** - * Sent when an entities DataWatcher is updated. - *

- * Remember to clone the packet if you are modifying it. - */ - public static final int ENTITY_METADATA = 40; - public static final int MOB_EFFECT = 41; - public static final int REMOVE_MOB_EFFECT = 42; - public static final int SET_EXPERIENCE = 43; - public static final int UPDATE_ATTRIBUTES = 44; - public static final int MAP_CHUNK = 51; - public static final int MULTI_BLOCK_CHANGE = 52; - public static final int BLOCK_CHANGE = 53; - public static final int PLAY_NOTE_BLOCK = 54; - public static final int BLOCK_BREAK_ANIMATION = 55; - public static final int MAP_CHUNK_BULK = 56; - public static final int EXPLOSION = 60; - public static final int WORLD_EVENT = 61; - public static final int NAMED_SOUND_EFFECT = 62; - public static final int WORLD_PARTICLES = 63; - public static final int BED = 70; - public static final int WEATHER = 71; - public static final int OPEN_WINDOW = 100; - public static final int CLOSE_WINDOW = 101; - public static final int SET_SLOT = 103; - public static final int WINDOW_ITEMS = 104; - public static final int CRAFT_PROGRESS_BAR = 105; - public static final int TRANSACTION = 106; - public static final int SET_CREATIVE_SLOT = 107; - public static final int UPDATE_SIGN = 130; - public static final int ITEM_DATA = 131; - - /** - * Sent the first time a tile entity (chest inventory, etc.) is withing range of the player, or has been updated. - *

- * Remember to clone the packet if you are modifying it. - */ - public static final int TILE_ENTITY_DATA = 132; - public static final int OPEN_TILE_ENTITY = 133; - public static final int STATISTIC = 200; - public static final int PLAYER_INFO = 201; - public static final int ABILITIES = 202; - public static final int TAB_COMPLETE = 203; - public static final int SCOREBOARD_OBJECTIVE = 206; - public static final int UPDATE_SCORE = 207; - public static final int DISPLAY_SCOREBOARD = 208; - public static final int TEAMS = 209; - public static final int CUSTOM_PAYLOAD = 250; - public static final int KEY_RESPONSE = 252; - public static final int KEY_REQUEST = 253; - public static final int KICK_DISCONNECT = 255; - - /** - * This packet was introduced in 1.7.2. - */ - public static final int PING_TIME = 230; - - /** - * This packet was introduced in 1.7.2. - */ - public static final int LOGIN_SUCCESS = 232; - - /** - * A registry that parses between names and packet IDs. - * @return The current server registry. - */ - public static Server getRegistry() { - return INSTANCE; - } - - // We only allow a single instance of this class - private Server() { - super(); - } - } - - /** - * List of packets sent by the client. - *

- * Deprecated: Use {@link PacketType} instead. - * @author Kristian - */ - @Deprecated - public static class Client extends IntEnum { - /** - * The singleton instance. Can also be retrieved from the parent class. - */ - private static Client INSTANCE = new Client(); - - public static final int KEEP_ALIVE = 0; - public static final int LOGIN = 1; - public static final int HANDSHAKE = 2; - public static final int CHAT = 3; - public static final int USE_ENTITY = 7; - - /** - * Since 1.3.1, the client no longer sends a respawn packet. Moved to CLIENT_COMMAND. - */ - @Deprecated - public static final int RESPAWN = 9; - - public static final int FLYING = 10; - public static final int PLAYER_POSITION = 11; - public static final int PLAYER_LOOK = 12; - public static final int PLAYER_LOOK_MOVE = 13; - public static final int BLOCK_DIG = 14; - public static final int PLACE = 15; - public static final int BLOCK_ITEM_SWITCH = 16; - public static final int ARM_ANIMATION = 18; - public static final int ENTITY_ACTION = 19; - public static final int PLAYER_INPUT = 27; - public static final int CLOSE_WINDOW = 101; - public static final int WINDOW_CLICK = 102; - public static final int TRANSACTION = 106; - public static final int SET_CREATIVE_SLOT = 107; - public static final int BUTTON_CLICK = 108; - public static final int UPDATE_SIGN = 130; - public static final int ABILITIES = 202; - public static final int TAB_COMPLETE = 203; - public static final int LOCALE_AND_VIEW_DISTANCE = 204; - public static final int CLIENT_COMMAND = 205; - public static final int CUSTOM_PAYLOAD = 250; - public static final int KEY_RESPONSE = 252; - public static final int GET_INFO = 254; - public static final int KICK_DISCONNECT = 255; - - /** - * This packet was introduced in 1.7.2. - */ - public static final int PING_TIME = 230; - - /** - * This packet was introduced in 1.7.2. - */ - public static final int LOGIN_START = 231; - - /** - * A registry that parses between names and packet IDs. - * @return The current client registry. - */ - public static Client getRegistry() { - return INSTANCE; - } - - // Like above - private Client() { - super(); - } - } - - /** - * A registry that parses between names and packet IDs. - *

- * Deprecated: Use {@link PacketType} instead. - * @return The current client registry. - */ - @Deprecated - public static Server getServerRegistry() { - return Server.getRegistry(); - } - - /** - * A registry that parses between names and packet IDs. - *

- * Deprecated: Use {@link PacketType} instead. - * @return The current server registry. - */ - @Deprecated - public static Client getClientRegistry() { - return Client.INSTANCE; - } - - /** - * Find a packet by name. Must be capitalized and use underscores. - *

- * Deprecated: Use {@link PacketType} instead. - * @param name - name of packet to find. - * @return The packet ID found. - */ - @Deprecated - public static int valueOf(String name) { - Integer serverAttempt = Server.INSTANCE.valueOf(name); - - if (serverAttempt != null) - return serverAttempt; - else - return Client.INSTANCE.valueOf(name); - } - - /** - * Retrieves the name of a packet. - *

- * Deprecated: Use {@link PacketType} instead. - * @param packetID - packet to retrieve name. - * @return The name, or NULL if unable to find such a packet. - */ - @Deprecated - public static String getDeclaredName(int packetID) { - String serverAttempt = Server.INSTANCE.getDeclaredName(packetID); - - if (serverAttempt != null) - return serverAttempt; - else - return Client.INSTANCE.getDeclaredName(packetID); - } -} diff --git a/src/main/java/com/comphenix/protocol/ProtocolLib.java b/src/main/java/com/comphenix/protocol/ProtocolLib.java index e6b6781b..42ce511b 100644 --- a/src/main/java/com/comphenix/protocol/ProtocolLib.java +++ b/src/main/java/com/comphenix/protocol/ProtocolLib.java @@ -26,21 +26,8 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.bukkit.Server; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.PluginCommand; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; - -import com.comphenix.protocol.executors.BukkitExecutors; import com.comphenix.protocol.async.AsyncFilterManager; -import com.comphenix.protocol.error.BasicErrorReporter; -import com.comphenix.protocol.error.DelegatedErrorReporter; -import com.comphenix.protocol.error.DetailedErrorReporter; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; +import com.comphenix.protocol.error.*; import com.comphenix.protocol.injector.DelayedSingleTask; import com.comphenix.protocol.injector.InternalManager; import com.comphenix.protocol.injector.PacketFilterManager; @@ -55,7 +42,13 @@ import com.comphenix.protocol.utility.MinecraftVersion; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; -import com.google.common.util.concurrent.ListeningScheduledExecutorService; + +import org.bukkit.Server; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; /** * The main entry point for ProtocolLib. @@ -112,10 +105,6 @@ public class ProtocolLib extends JavaPlugin { // Metrics and statistics private Statistics statistics; - // Executors - private static ListeningScheduledExecutorService executorAsync; - private static ListeningScheduledExecutorService executorSync; - // Structure compiler private BackgroundCompiler backgroundCompiler; @@ -157,10 +146,6 @@ public class ProtocolLib extends JavaPlugin { // Initialize enhancer factory EnhancerFactory.getInstance().setClassLoader(getClassLoader()); - // Initialize executors - executorAsync = BukkitExecutors.newAsynchronous(this); - executorSync = BukkitExecutors.newSynchronous(this); - // Add global parameters DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this); reporter = getFilteredReporter(detailedReporter); @@ -213,7 +198,7 @@ public class ProtocolLib extends JavaPlugin { .build(); // Initialize the API - ProtocolLibrary.init(this, config, protocolManager, reporter, executorAsync, executorSync); + ProtocolLibrary.init(this, config, protocolManager, reporter); // Setup error reporter detailedReporter.addGlobalParameter("manager", protocolManager); diff --git a/src/main/java/com/comphenix/protocol/ProtocolLibrary.java b/src/main/java/com/comphenix/protocol/ProtocolLibrary.java index 5a456545..3c0d3430 100644 --- a/src/main/java/com/comphenix/protocol/ProtocolLibrary.java +++ b/src/main/java/com/comphenix/protocol/ProtocolLibrary.java @@ -19,12 +19,11 @@ package com.comphenix.protocol; import java.util.Arrays; import java.util.List; -import org.apache.commons.lang.Validate; -import org.bukkit.plugin.Plugin; - import com.comphenix.protocol.error.BasicErrorReporter; import com.comphenix.protocol.error.ErrorReporter; -import com.google.common.util.concurrent.ListeningScheduledExecutorService; + +import org.apache.commons.lang.Validate; +import org.bukkit.plugin.Plugin; /** * The main entry point for ProtocolLib. @@ -56,21 +55,15 @@ public class ProtocolLibrary { private static ProtocolManager manager; private static ErrorReporter reporter = new BasicErrorReporter(); - private static ListeningScheduledExecutorService executorAsync; - private static ListeningScheduledExecutorService executorSync; - private static boolean updatesDisabled; private static boolean initialized; - protected static void init(Plugin plugin, ProtocolConfig config, ProtocolManager manager, ErrorReporter reporter, - ListeningScheduledExecutorService executorAsync, ListeningScheduledExecutorService executorSync) { + protected static void init(Plugin plugin, ProtocolConfig config, ProtocolManager manager, ErrorReporter reporter) { Validate.isTrue(!initialized, "ProtocolLib has already been initialized."); ProtocolLibrary.plugin = plugin; ProtocolLibrary.config = config; ProtocolLibrary.manager = manager; ProtocolLibrary.reporter = reporter; - ProtocolLibrary.executorAsync = executorAsync; - ProtocolLibrary.executorSync = executorSync; initialized = true; } @@ -106,26 +99,6 @@ public class ProtocolLibrary { return reporter; } - /** - * Retrieve an executor service for performing asynchronous tasks on the behalf of ProtocolLib. - *

- * Note that this service is NULL if ProtocolLib has not been initialized yet. - * @return The executor service, or NULL. - */ - public static ListeningScheduledExecutorService getExecutorAsync() { - return executorAsync; - } - - /** - * Retrieve an executor service for performing synchronous tasks (main thread) on the behalf of ProtocolLib. - *

- * Note that this service is NULL if ProtocolLib has not been initialized yet. - * @return The executor service, or NULL. - */ - public static ListeningScheduledExecutorService getExecutorSync() { - return executorSync; - } - /** * Disables the ProtocolLib update checker. */ diff --git a/src/main/java/com/comphenix/protocol/ProtocolManager.java b/src/main/java/com/comphenix/protocol/ProtocolManager.java index 1ff9c6bd..b73942dc 100644 --- a/src/main/java/com/comphenix/protocol/ProtocolManager.java +++ b/src/main/java/com/comphenix/protocol/ProtocolManager.java @@ -49,7 +49,7 @@ public interface ProtocolManager extends PacketStream { * @param player - the player. * @return The associated protocol version, or {@link Integer#MIN_VALUE} if unknown. */ - public int getProtocolVersion(Player player); + int getProtocolVersion(Player player); /** * Send a packet to the given player. @@ -63,7 +63,7 @@ public interface ProtocolManager extends PacketStream { * @throws InvocationTargetException - if an error occurred when sending the packet. */ @Override - public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters) + void sendServerPacket(Player receiver, PacketContainer packet, boolean filters) throws InvocationTargetException; /** @@ -79,7 +79,7 @@ public interface ProtocolManager extends PacketStream { * @throws IllegalAccessException If the underlying method caused an error. */ @Override - public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) + void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) throws IllegalAccessException, InvocationTargetException; /** @@ -87,7 +87,7 @@ public interface ProtocolManager extends PacketStream { * @param packet - the packet to broadcast. * @throws FieldAccessException If we were unable to send the packet due to reflection problems. */ - public void broadcastServerPacket(PacketContainer packet); + void broadcastServerPacket(PacketContainer packet); /** * Broadcast a packet to every player that is receiving information about a given entity. @@ -99,7 +99,7 @@ public interface ProtocolManager extends PacketStream { * @param includeTracker - whether or not to also transmit the packet to the entity, if it is a tracker. * @throws FieldAccessException If we were unable to send the packet due to reflection problems. */ - public void broadcastServerPacket(PacketContainer packet, Entity entity, boolean includeTracker); + void broadcastServerPacket(PacketContainer packet, Entity entity, boolean includeTracker); /** * Broadcast a packet to every player within the given maximum observer distance. @@ -107,13 +107,13 @@ public interface ProtocolManager extends PacketStream { * @param origin - the origin to consider when calculating the distance to each observer. * @param maxObserverDistance - the maximum distance to the origin. */ - public void broadcastServerPacket(PacketContainer packet, Location origin, int maxObserverDistance); + void broadcastServerPacket(PacketContainer packet, Location origin, int maxObserverDistance); /** * Retrieves a list of every registered packet listener. * @return Every registered packet listener. */ - public ImmutableSet getPacketListeners(); + ImmutableSet getPacketListeners(); /** * Adds a packet listener. @@ -123,7 +123,7 @@ public interface ProtocolManager extends PacketStream { * can register it again. * @param listener - new packet listener. */ - public void addPacketListener(PacketListener listener); + void addPacketListener(PacketListener listener); /** * Removes a given packet listener. @@ -131,47 +131,20 @@ public interface ProtocolManager extends PacketStream { * Attempting to remove a listener that doesn't exist has no effect. * @param listener - the packet listener to remove. */ - public void removePacketListener(PacketListener listener); + void removePacketListener(PacketListener listener); /** * Removes every listener associated with the given plugin. * @param plugin - the plugin to unload. */ - public void removePacketListeners(Plugin plugin); + void removePacketListeners(Plugin plugin); - /** - * Constructs a new encapsulated Minecraft packet with the given ID. - *

- * Deprecated: Use {@link #createPacket(PacketType)} instead. - * @param id - packet ID. - * @return New encapsulated Minecraft packet. - */ - @Deprecated - public PacketContainer createPacket(int id); - /** * Constructs a new encapsulated Minecraft packet with the given ID. * @param type - packet type. * @return New encapsulated Minecraft packet. */ - public PacketContainer createPacket(PacketType type); - - /** - * Constructs a new encapsulated Minecraft packet with the given ID. - *

- * If set to true, the forceDefaults option will force the system to automatically - * give non-primitive fields in the packet sensible default values. For instance, certain - * packets - like Packet60Explosion - require a List or Set to be non-null. If the - * forceDefaults option is true, the List or Set will be automatically created. - *

- * Deprecated: Use {@link #createPacket(PacketType, boolean)} instead. - * - * @param id - packet ID. - * @param forceDefaults - TRUE to use sensible defaults in most fields, FALSE otherwise. - * @return New encapsulated Minecraft packet. - */ - @Deprecated - public PacketContainer createPacket(int id, boolean forceDefaults); + PacketContainer createPacket(PacketType type); /** * Constructs a new encapsulated Minecraft packet with the given ID. @@ -185,18 +158,7 @@ public interface ProtocolManager extends PacketStream { * @param forceDefaults - TRUE to use sensible defaults in most fields, FALSE otherwise. * @return New encapsulated Minecraft packet. */ - public PacketContainer createPacket(PacketType type, boolean forceDefaults); - - /** - * Construct a packet using the special builtin Minecraft constructors. - *

- * Deprecated: Use {@link #createPacketConstructor(PacketType, Object...)} instead. - * @param id - the packet ID. - * @param arguments - arguments that will be passed to the constructor. - * @return The packet constructor. - */ - @Deprecated - public PacketConstructor createPacketConstructor(int id, Object... arguments); + PacketContainer createPacket(PacketType type, boolean forceDefaults); /** * Construct a packet using the special builtin Minecraft constructors. @@ -204,7 +166,7 @@ public interface ProtocolManager extends PacketStream { * @param arguments - arguments that will be passed to the constructor. * @return The packet constructor. */ - public PacketConstructor createPacketConstructor(PacketType type, Object... arguments); + PacketConstructor createPacketConstructor(PacketType type, Object... arguments); /** * Completely resend an entity to a list of clients. @@ -214,7 +176,7 @@ public interface ProtocolManager extends PacketStream { * @param entity - entity to refresh. * @param observers - the clients to update. */ - public void updateEntity(Entity entity, List observers) throws FieldAccessException; + void updateEntity(Entity entity, List observers) throws FieldAccessException; /** * Retrieve the associated entity. @@ -223,7 +185,7 @@ public interface ProtocolManager extends PacketStream { * @return The associated entity. * @throws FieldAccessException Reflection failed. */ - public Entity getEntityFromID(World container, int id) throws FieldAccessException; + Entity getEntityFromID(World container, int id) throws FieldAccessException; /** * Retrieve every client that is receiving information about a given entity. @@ -231,55 +193,37 @@ public interface ProtocolManager extends PacketStream { * @return Every client/player that is tracking the given entity. * @throws FieldAccessException If reflection failed. */ - public List getEntityTrackers(Entity entity) throws FieldAccessException; - - /** - * Retrieves a immutable set containing the ID of the sent server packets that will be observed by listeners. - *

- * Deprecated: Use {@link #getSendingFilterTypes()} instead. - * @return Every filtered server packet. - */ - @Deprecated - public Set getSendingFilters(); - + List getEntityTrackers(Entity entity) throws FieldAccessException; + /** * Retrieves a immutable set containing the type of the sent server packets that will be observed by listeners. * @return Every filtered server packet. */ - public Set getSendingFilterTypes(); - - /** - * Retrieves a immutable set containing the ID of the received client packets that will be observed by listeners. - *

- * Deprecated: Use {@link #getReceivingFilterTypes()} instead. - * @return Every filtered client packet. - */ - @Deprecated - public Set getReceivingFilters(); - + Set getSendingFilterTypes(); + /** * Retrieves a immutable set containing the type of the received client packets that will be observed by listeners. * @return Every filtered client packet. */ - public Set getReceivingFilterTypes(); + Set getReceivingFilterTypes(); /** * Retrieve the current Minecraft version. * @return The current version. */ - public MinecraftVersion getMinecraftVersion(); + MinecraftVersion getMinecraftVersion(); /** * Determines whether or not this protocol manager has been disabled. * @return TRUE if it has, FALSE otherwise. */ - public boolean isClosed(); + boolean isClosed(); /** * Retrieve the current asynchronous packet manager. * @return Asynchronous packet manager. */ - public AsynchronousManager getAsynchronousManager(); + AsynchronousManager getAsynchronousManager(); - public void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist); + void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist); } diff --git a/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java b/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java index abc21532..74cc1149 100644 --- a/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java +++ b/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java @@ -23,10 +23,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitScheduler; - import com.comphenix.protocol.AsynchronousManager; import com.comphenix.protocol.PacketStream; import com.comphenix.protocol.PacketType; @@ -37,12 +33,15 @@ import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.injector.PrioritizedListener; import com.comphenix.protocol.injector.SortedPacketListenerList; -import com.comphenix.protocol.injector.packet.PacketRegistry; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; + /** * Represents a filter manager for asynchronous packets. *

@@ -88,7 +87,7 @@ public class AsyncFilterManager implements AsynchronousManager { // Initialize timeout listeners this.serverTimeoutListeners = new SortedPacketListenerList(); this.clientTimeoutListeners = new SortedPacketListenerList(); - this.timeoutListeners = Sets.newSetFromMap(new ConcurrentHashMap()); + this.timeoutListeners = Sets.newSetFromMap(new ConcurrentHashMap<>()); this.playerSendingHandler = new PlayerSendingHandler(reporter, serverTimeoutListeners, clientTimeoutListeners); this.serverProcessingQueue = new PacketProcessingQueue(playerSendingHandler); @@ -327,22 +326,12 @@ public class AsyncFilterManager implements AsynchronousManager { getProcessingQueue(syncPacket).enqueue(newEvent, true); } } - - @Override - public Set getSendingFilters() { - return PacketRegistry.toLegacy(serverProcessingQueue.keySet()); - } - + @Override public Set getReceivingTypes() { return serverProcessingQueue.keySet(); } - - @Override - public Set getReceivingFilters() { - return PacketRegistry.toLegacy(clientProcessingQueue.keySet()); - } - + @Override public Set getSendingTypes() { return clientProcessingQueue.keySet(); diff --git a/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java b/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java index e2d30292..01a5c974 100644 --- a/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java +++ b/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java @@ -17,11 +17,7 @@ package com.comphenix.protocol.events; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Set; +import java.util.*; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.injector.GamePhase; @@ -44,93 +40,21 @@ public class ListeningWhitelist { private final GamePhase gamePhase; private final Set options; private final Set types; - - // Cache whitelist - private transient Set intWhitelist; - + private ListeningWhitelist(Builder builder) { this.priority = builder.priority; this.types = builder.types; this.gamePhase = builder.gamePhase; this.options = builder.options; } - - /** - * Creates a packet whitelist for a given priority with a set of packet IDs. - *

- * Deprecated: Use {@link #newBuilder()} instead. - * @param priority - the listener priority. - * @param whitelist - set of IDs to observe/enable. - */ - @Deprecated - public ListeningWhitelist(ListenerPriority priority, Set whitelist) { - this(priority, whitelist, GamePhase.PLAYING); - } - /** - * Creates a packet whitelist for a given priority with a set of packet IDs. - *

- * Deprecated: Use {@link #newBuilder()} instead. - * @param priority - the listener priority. - * @param whitelist - set of IDs to observe/enable. - * @param gamePhase - which game phase to receieve notifications on. - */ - @Deprecated - public ListeningWhitelist(ListenerPriority priority, Set whitelist, GamePhase gamePhase) { + private ListeningWhitelist(ListenerPriority priority) { this.priority = priority; - this.types = PacketRegistry.toPacketTypes(safeSet(whitelist)); - this.gamePhase = gamePhase; - this.options = EnumSet.noneOf(ListenerOptions.class); - } - - /** - * Creates a packet whitelist of a given priority for a list of packets. - *

- * Deprecated: Use {@link #newBuilder()} instead. - * @param priority - the listener priority. - * @param whitelist - list of packet IDs to observe/enable. - */ - @Deprecated - public ListeningWhitelist(ListenerPriority priority, Integer... whitelist) { - this.priority = priority; - this.types = PacketRegistry.toPacketTypes(Sets.newHashSet(whitelist)); + this.types = new HashSet<>(); this.gamePhase = GamePhase.PLAYING; this.options = EnumSet.noneOf(ListenerOptions.class); } - /** - * Creates a packet whitelist for a given priority with a set of packet IDs. - *

- * Deprecated: Use {@link #newBuilder()} instead. - * @param priority - the listener priority. - * @param whitelist - list of packet IDs to observe/enable. - * @param gamePhase - which game phase to receieve notifications on. - */ - @Deprecated - public ListeningWhitelist(ListenerPriority priority, Integer[] whitelist, GamePhase gamePhase) { - this.priority = priority; - this.types = PacketRegistry.toPacketTypes(Sets.newHashSet(whitelist)); - this.gamePhase = gamePhase; - this.options = EnumSet.noneOf(ListenerOptions.class); - } - - /** - * Creates a packet whitelist for a given priority with a set of packet IDs and options. - *

- * Deprecated: Use {@link #newBuilder()} instead. - * @param priority - the listener priority. - * @param whitelist - list of packet IDs to observe/enable. - * @param gamePhase - which game phase to receieve notifications on. - * @param options - every special option associated with this whitelist. - */ - @Deprecated - public ListeningWhitelist(ListenerPriority priority, Integer[] whitelist, GamePhase gamePhase, ListenerOptions... options) { - this.priority = priority; - this.types = PacketRegistry.toPacketTypes(Sets.newHashSet(whitelist)); - this.gamePhase = gamePhase; - this.options = safeEnumSet(Arrays.asList(options), ListenerOptions.class); - } - /** * Whether or not this whitelist has any enabled packets. * @return TRUE if there are any packets, FALSE otherwise. @@ -147,19 +71,6 @@ public class ListeningWhitelist { return priority; } - /** - * Retrieves the list of packets that will be observed by the listeners. - *

- * Deprecated: Use {@link #getTypes()} instead. - * @return Packet whitelist. - */ - @Deprecated - public Set getWhitelist() { - if (intWhitelist == null) - intWhitelist = PacketRegistry.toLegacy(types); - return intWhitelist; - } - /** * Retrieves a set of the packets that will be observed by the listeners. * @return Packet whitelist. @@ -189,23 +100,6 @@ public class ListeningWhitelist { return Objects.hashCode(priority, types, gamePhase, options); } - /** - * Determine if any of the given IDs can be found in the whitelist. - * @param whitelist - whitelist to test. - * @param idList - list of packet IDs to find. - * @return TRUE if any of the packets in the list can be found in the whitelist, FALSE otherwise. - */ - public static boolean containsAny(ListeningWhitelist whitelist, int... idList) { - if (whitelist != null) { - for (int i = 0; i < idList.length; i++) { - if (whitelist.getWhitelist().contains(idList[i])) - return true; - } - } - - return false; - } - /** * Determine if the given whitelist is empty or not. * @param whitelist - the whitelist to test. @@ -273,7 +167,7 @@ public class ListeningWhitelist { /** * Construct a copy of a given set. - * @param list - the set to copy. + * @param set - the set to copy. * @return The copied set. */ private static Set safeSet(Collection set) { @@ -364,20 +258,7 @@ public class ListeningWhitelist { public Builder high() { return priority(ListenerPriority.HIGH); } - - /** - * Set the whitelist of packet IDs to copy when constructing new whitelists. - *

- * Deprecated: Use {@link #types(Collection)} instead. - * @param whitelist - the whitelist of packets. - * @return This builder, for chaining. - */ - @Deprecated - public Builder whitelist(Collection whitelist) { - this.types = PacketRegistry.toPacketTypes(safeSet(whitelist)); - return this; - } - + /** * Set the whitelist of packet types to copy when constructing new whitelists. * @param types - the whitelist of packets. diff --git a/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java b/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java index dd58dd8e..83fb07ae 100644 --- a/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java +++ b/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java @@ -17,15 +17,11 @@ package com.comphenix.protocol.events; -import java.util.logging.Level; import java.util.logging.Logger; -import org.bukkit.plugin.Plugin; - -import com.comphenix.protocol.Packets; -import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.packet.PacketRegistry; -import com.comphenix.protocol.reflect.FieldAccessException; + +import org.bukkit.plugin.Plugin; /** * Represents a listener that is notified of every sent and received packet. @@ -45,26 +41,17 @@ public abstract class MonitorAdapter implements PacketListener { public MonitorAdapter(Plugin plugin, ConnectionSide side, Logger logger) { initialize(plugin, side, logger); } - - @SuppressWarnings("deprecation") + private void initialize(Plugin plugin, ConnectionSide side, Logger logger) { this.plugin = plugin; // Recover in case something goes wrong - try { - if (side.isForServer()) - this.sending = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getServerPacketTypes()).gamePhaseBoth().build(); - if (side.isForClient()) - this.receiving = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getClientPacketTypes()).gamePhaseBoth().build(); - } catch (FieldAccessException e) { - if (side.isForServer()) - this.sending = new ListeningWhitelist(ListenerPriority.MONITOR, Packets.Server.getRegistry().values(), GamePhase.BOTH); - if (side.isForClient()) - this.receiving = new ListeningWhitelist(ListenerPriority.MONITOR, Packets.Client.getRegistry().values(), GamePhase.BOTH); - logger.log(Level.WARNING, "Defaulting to 1.3 packets.", e); - } + if (side.isForServer()) + this.sending = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getServerPacketTypes()).gamePhaseBoth().build(); + if (side.isForClient()) + this.receiving = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getClientPacketTypes()).gamePhaseBoth().build(); } - + /** * Retrieve a logger, even if we're running in a CraftBukkit version that doesn't support it. * @param plugin - the plugin to retrieve. diff --git a/src/main/java/com/comphenix/protocol/events/PacketAdapter.java b/src/main/java/com/comphenix/protocol/events/PacketAdapter.java index a5204268..29cd316e 100644 --- a/src/main/java/com/comphenix/protocol/events/PacketAdapter.java +++ b/src/main/java/com/comphenix/protocol/events/PacketAdapter.java @@ -19,19 +19,17 @@ package com.comphenix.protocol.events; import java.util.List; import java.util.Set; - import javax.annotation.Nonnull; -import org.bukkit.plugin.Plugin; - import com.comphenix.protocol.PacketType; import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.packet.PacketRegistry; import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import org.bukkit.plugin.Plugin; + /** * Represents a packet listener with useful constructors. *

@@ -103,151 +101,7 @@ public abstract class PacketAdapter implements PacketListener { public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, PacketType... types) { this(params(plugin, types).listenerPriority(listenerPriority)); } - - /** - * Initialize a packet listener with default priority. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, Integer... packets) { - this(plugin, connectionSide, ListenerPriority.NORMAL, packets); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param listenerPriority - the event priority. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, Set packets) { - this(plugin, connectionSide, listenerPriority, GamePhase.PLAYING, packets.toArray(new Integer[0])); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param gamePhase - which game phase this listener is active under. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, GamePhase gamePhase, Set packets) { - this(plugin, connectionSide, ListenerPriority.NORMAL, gamePhase, packets.toArray(new Integer[0])); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param listenerPriority - the event priority. - * @param gamePhase - which game phase this listener is active under. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, GamePhase gamePhase, Set packets) { - this(plugin, connectionSide, listenerPriority, gamePhase, packets.toArray(new Integer[0])); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param listenerPriority - the event priority. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, Integer... packets) { - this(plugin, connectionSide, listenerPriority, GamePhase.PLAYING, packets); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param options - which listener options to use. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerOptions[] options, Integer... packets) { - this(plugin, connectionSide, ListenerPriority.NORMAL, GamePhase.PLAYING, options, packets); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param gamePhase - which game phase this listener is active under. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, GamePhase gamePhase, Integer... packets) { - this(plugin, connectionSide, ListenerPriority.NORMAL, gamePhase, packets); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param listenerPriority - the event priority. - * @param gamePhase - which game phase this listener is active under. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, GamePhase gamePhase, Integer... packets) { - this(plugin, connectionSide, listenerPriority, gamePhase, new ListenerOptions[0], packets); - } - - /** - * Initialize a packet listener for a single connection side. - *

- * The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary. - *

- * Listener options must be specified in order for {@link NetworkMarker#getInputBuffer()} to function correctly. - *

- * Deprecated: Use {@link #params()} instead. - * @param plugin - the plugin that spawned this listener. - * @param connectionSide - the packet type the listener is looking for. - * @param listenerPriority - the event priority. - * @param gamePhase - which game phase this listener is active under. - * @param options - which listener options to use. - * @param packets - the packet IDs the listener is looking for. - */ - @Deprecated - public PacketAdapter( - Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, - GamePhase gamePhase, ListenerOptions[] options, Integer... packets) { - - this(plugin, connectionSide, listenerPriority, gamePhase, options, - PacketRegistry.toPacketTypes(Sets.newHashSet(packets), connectionSide.getSender()).toArray(new PacketType[0]) - ); - } - + // For internal use only private PacketAdapter( Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, @@ -374,20 +228,6 @@ public abstract class PacketAdapter implements PacketListener { public static AdapterParameteters params() { return new AdapterParameteters(); } - - /** - * Construct a helper object for passing parameters to the packet adapter. - *

- * This is often simpler and better than passing them directly to each constructor. - * Deprecated: Use {@link #params(Plugin, PacketType...)} instead. - * @param plugin - the plugin that spawned this listener. - * @param packets - the packet IDs the listener is looking for. - * @return Helper object. - */ - @Deprecated - public static AdapterParameteters params(Plugin plugin, Integer... packets) { - return new AdapterParameteters().plugin(plugin).packets(packets); - } /** * Construct a helper object for passing parameters to the packet adapter. @@ -532,17 +372,7 @@ public abstract class PacketAdapter implements PacketListener { public AdapterParameteters optionIntercept() { return addOption(ListenerOptions.INTERCEPT_INPUT_BUFFER); } - - /** - * Set the listener option to {@link ListenerOptions#DISABLE_GAMEPHASE_DETECTION}, causing ProtocolLib to ignore automatic game phase detection. - *

- * This is no longer relevant in 1.7.2. - * @return This builder, for chaining. - */ - public AdapterParameteters optionManualGamePhase() { - return addOption(ListenerOptions.DISABLE_GAMEPHASE_DETECTION); - } - + /** * Set the listener option to {@link ListenerOptions#ASYNC}, indicating that our listener is thread safe. *

@@ -552,40 +382,7 @@ public abstract class PacketAdapter implements PacketListener { public AdapterParameteters optionAsync() { return addOption(ListenerOptions.ASYNC); } - - /** - * Set the packet IDs of the packets the listener is looking for. - *

- * This parameter is required. - *

- * Deprecated: Use {@link #types(PacketType...)} instead. - * @param packets - the packet IDs to look for. - * @return This builder, for chaining. - */ - @Deprecated - public AdapterParameteters packets(@Nonnull Integer... packets) { - Preconditions.checkNotNull(packets, "packets cannot be NULL"); - PacketType[] types = new PacketType[packets.length]; - - for (int i = 0; i < types.length; i++) { - types[i] = PacketType.findLegacy(packets[i]); - } - this.packets = types; - return this; - } - - /** - * Set the packet IDs of the packets the listener is looking for. - *

- * This parameter is required. - * @param packets - a set of the packet IDs to look for. - * @return This builder, for chaining. - */ - @Deprecated - public AdapterParameteters packets(@Nonnull Set packets) { - return packets(packets.toArray(new Integer[0])); - } - + /** * Set the packet types the listener is looking for. *

diff --git a/src/main/java/com/comphenix/protocol/events/PacketContainer.java b/src/main/java/com/comphenix/protocol/events/PacketContainer.java index ed16eec7..f900516c 100644 --- a/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -68,6 +68,7 @@ import org.bukkit.util.Vector; * * @author Kristian */ +@SuppressWarnings("unused") public class PacketContainer implements Serializable { private static final long serialVersionUID = 3; @@ -111,40 +112,6 @@ public class PacketContainer implements Serializable { private static final Set CLONING_UNSUPPORTED = Sets.newHashSet( PacketType.Play.Server.UPDATE_ATTRIBUTES, PacketType.Status.Server.SERVER_INFO); - /** - * Creates a packet container for a new packet. - *

- * Deprecated: Use {@link #PacketContainer(PacketType)} instead. - * @param id - ID of the packet to create. - */ - @Deprecated - public PacketContainer(int id) { - this(PacketType.findLegacy(id), StructureCache.newPacket(PacketType.findLegacy(id))); - } - - /** - * Creates a packet container for an existing packet. - * @param id - ID of the given packet. - * @param handle - contained packet. - * @deprecated Use {@link #PacketContainer(PacketType, Object)} instead - */ - @Deprecated - public PacketContainer(int id, Object handle) { - this(PacketType.findLegacy(id), handle); - } - - /** - * Creates a packet container for an existing packet. - * @param id - ID of the given packet. - * @param handle - contained packet. - * @param structure - structure modifier. - * @deprecated Use {@link #PacketContainer(PacketType, Object, StructureModifier)} instead - */ - @Deprecated - public PacketContainer(int id, Object handle, StructureModifier structure) { - this(PacketType.findLegacy(id), handle, structure); - } - /** * Creates a packet container for a new packet. * @param type - the type of the packet to create. @@ -1035,16 +1002,13 @@ public class PacketContainer implements Serializable { } /** - * Retrieves the ID of this packet. - *

- * Deprecated: Use {@link #getType()} instead. - * @return Packet ID. + * @deprecated Packet IDs are unreliable */ @Deprecated - public int getID() { - return type.getLegacyId(); + public int getId() { + return type.getCurrentId(); } - + /** * Retrieve the packet type of this packet. * @return The packet type. @@ -1230,61 +1194,6 @@ public class PacketContainer implements Serializable { PacketMetadata.remove(handle, key); } - // ---- Old Metadata API - // Scheduled for removal in 4.5 - - /** - * Gets the metadata value for a given key. - * - * @param key Metadata key - * @return Metadata value, or null if nonexistent. - * @deprecated Replaced with {@link #getMeta(String)} - */ - @Deprecated - public Object getMetadata(String key) { - return getMeta(key).orElse(null); - } - - /** - * Adds metadata to this packet. - *

- * Note: Since metadata is lazily initialized, this may result in the creation of the metadata map. - * - * @param key Metadata key - * @param value Metadata value - * @deprecated Replaced by {@link #setMeta(String, Object)} - */ - @Deprecated - public void addMetadata(String key, Object value) { - setMeta(key, value); - } - - /** - * Removes metadata from this packet. - *

- * Note: If this operation leaves the metadata map empty, the map will be set to null. - * - * @param key Metadata key - * @return The previous value, or null if nonexistant. - * @deprecated Replaced by {@link #removeMeta(String)}. This one was pretty much just for naming consistency. - */ - @Deprecated - public Object removeMetadata(String key) { - return PacketMetadata.remove(handle, key).orElseGet(null); - } - - /** - * Whether or not this packet has metadata for a given key. - * - * @param key Metadata key - * @return True if this packet has metadata for the key, false if not. - * @deprecated Replaced with {@code getMeta(key).isPresent()} - */ - @Deprecated - public boolean hasMetadata(String key) { - return getMeta(key).isPresent(); - } - /** * Retrieve the cached method concurrently. * @param lookup - a lazy lookup cache. diff --git a/src/main/java/com/comphenix/protocol/events/PacketEvent.java b/src/main/java/com/comphenix/protocol/events/PacketEvent.java index 177ab7b1..815f9bf1 100644 --- a/src/main/java/com/comphenix/protocol/events/PacketEvent.java +++ b/src/main/java/com/comphenix/protocol/events/PacketEvent.java @@ -247,7 +247,7 @@ public class PacketEvent extends EventObject implements Cancellable { */ @Deprecated public int getPacketID() { - return packet.getID(); + return packet.getId(); } /** diff --git a/src/main/java/com/comphenix/protocol/executors/AbstractBukkitService.java b/src/main/java/com/comphenix/protocol/executors/AbstractBukkitService.java deleted file mode 100644 index 216d7b1b..00000000 --- a/src/main/java/com/comphenix/protocol/executors/AbstractBukkitService.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.comphenix.protocol.executors; - -import java.util.Collections; -import java.util.List; -import java.util.concurrent.*; - -import com.google.common.base.Throwables; -import com.google.common.util.concurrent.ListenableScheduledFuture; - -import org.bukkit.scheduler.BukkitTask; - -abstract class AbstractBukkitService - extends AbstractListeningService implements BukkitScheduledExecutorService { - - private static final long MILLISECONDS_PER_TICK = 50; - private static final long NANOSECONDS_PER_TICK = 1000000 * MILLISECONDS_PER_TICK; - - private volatile boolean shutdown; - private final PendingTasks tasks; - - public AbstractBukkitService(PendingTasks tasks) { - this.tasks = tasks; - } - - @Override - protected RunnableAbstractFuture newTaskFor(Runnable runnable, T value) { - return newTaskFor(Executors.callable(runnable, value)); - } - - @Override - protected RunnableAbstractFuture newTaskFor(final Callable callable) { - validateState(); - return new CallableTask(callable); - } - - @Override - public void execute(Runnable command) { - validateState(); - - if (command instanceof RunnableFuture) { - tasks.add(getTask(command), (Future) command); - } else { - // Submit it first - submit(command); - } - } - - // Bridge to Bukkit - protected abstract BukkitTask getTask(Runnable command); - protected abstract BukkitTask getLaterTask(Runnable task, long ticks); - protected abstract BukkitTask getTimerTask(long ticksInitial, long ticksDelay, Runnable task); - - @Override - public List shutdownNow() { - shutdown(); - tasks.cancel(); - - // We don't support this - return Collections.emptyList(); - } - - @Override - public void shutdown() { - shutdown = true; - } - - private void validateState() { - if (shutdown) { - throw new RejectedExecutionException("Executor service has shut down. Cannot start new tasks."); - } - } - - private long toTicks(long delay, TimeUnit unit) { - return Math.round(unit.toMillis(delay) / (double)MILLISECONDS_PER_TICK); - } - - @Override - public ListenableScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { - return schedule(Executors.callable(command), delay, unit); - } - - @Override - public ListenableScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { - long ticks = toTicks(delay, unit); - - // Construct future task and Bukkit task - CallableTask task = new CallableTask(callable); - BukkitTask bukkitTask = getLaterTask(task, ticks); - - tasks.add(bukkitTask, task); - return task.getScheduledFuture(System.nanoTime() + delay * NANOSECONDS_PER_TICK, 0); - } - - @Override - public ListenableScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, - long period, TimeUnit unit) { - - long ticksInitial = toTicks(initialDelay, unit); - long ticksDelay = toTicks(period, unit); - - // Construct future task and Bukkit task - CallableTask task = new CallableTask(Executors.callable(command)) { - protected void compute() { - // Do nothing more. This future can only be finished by cancellation - try { - compute.call(); - } catch (Exception e) { - // Let Bukkit handle this - throw Throwables.propagate(e); - } - } - }; - BukkitTask bukkitTask = getTimerTask(ticksInitial, ticksDelay, task); - - tasks.add(bukkitTask, task); - return task.getScheduledFuture( - System.nanoTime() + ticksInitial * NANOSECONDS_PER_TICK, - ticksDelay * NANOSECONDS_PER_TICK); - } - - // Not supported! - @Deprecated - @Override - public ListenableScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { - return scheduleAtFixedRate(command, initialDelay, delay, unit); - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - return tasks.awaitTermination(timeout, unit); - } - - @Override - public boolean isShutdown() { - return shutdown; - } - - @Override - public boolean isTerminated() { - return tasks.isTerminated(); - } -} \ No newline at end of file diff --git a/src/main/java/com/comphenix/protocol/executors/AbstractListeningService.java b/src/main/java/com/comphenix/protocol/executors/AbstractListeningService.java deleted file mode 100644 index 4fd2d19d..00000000 --- a/src/main/java/com/comphenix/protocol/executors/AbstractListeningService.java +++ /dev/null @@ -1,288 +0,0 @@ -package com.comphenix.protocol.executors; - -/* - * This file is a modified version of - * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/AbstractExecutorService.java?revision=1.35 - * which contained the following notice: - * - * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to the - * public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/ - * - * Rationale for copying: - * Guava targets JDK5, whose AbstractExecutorService class lacks the newTaskFor protected - * customization methods needed by MoreExecutors.listeningDecorator. This class is a copy of - * AbstractExecutorService from the JSR166 CVS repository. It contains the desired methods. - */ - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.Future; -import java.util.concurrent.RunnableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import com.google.common.util.concurrent.AbstractFuture; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; -import com.google.common.util.concurrent.ListeningExecutorService; - -/** - * Provides default implementations of {@link ListeningExecutorService} - * execution methods. This class implements the submit, - * invokeAny and invokeAll methods using a - * {@link ListenableFutureTask} returned by newTaskFor. For example, - * the implementation of submit(Runnable) creates an associated - * ListenableFutureTask that is executed and returned. - * - * @author Doug Lea - */ -abstract class AbstractListeningService implements ListeningExecutorService { - /** - * Represents a runnable abstract listenable future task. - * - * @author Kristian - * @param - */ - public static abstract class RunnableAbstractFuture - extends AbstractFuture implements RunnableFuture { - - } - - /** - * Returns a ListenableFutureTask for the given runnable and - * default value. - * - * @param runnable - the runnable task being wrapped - * @param value - the default value for the returned future - * @return a ListenableFutureTask which when run will run the - * underlying runnable and which, as a Future, will yield - * the given value as its result and provide for cancellation of the - * underlying task. - */ - protected abstract RunnableAbstractFuture newTaskFor(Runnable runnable, T value); - - /** - * Returns a ListenableFutureTask for the given callable task. - * - * @param callable - the callable task being wrapped - * @return a ListenableFutureTask which when run will call the - * underlying callable and which, as a Future, will yield - * the callable's result as its result and provide for cancellation - * of the underlying task. - */ - protected abstract RunnableAbstractFuture newTaskFor(Callable callable); - - @Override - public ListenableFuture submit(Runnable task) { - if (task == null) { - throw new NullPointerException(); - } - RunnableAbstractFuture ftask = newTaskFor(task, null); - execute(ftask); - return ftask; - } - - @Override - public ListenableFuture submit(Runnable task, T result) { - if (task == null) { - throw new NullPointerException(); - } - RunnableAbstractFuture ftask = newTaskFor(task, result); - execute(ftask); - return ftask; - } - - @Override - public ListenableFuture submit(Callable task) { - if (task == null) { - throw new NullPointerException(); - } - RunnableAbstractFuture ftask = newTaskFor(task); - execute(ftask); - return ftask; - } - - /** - * The main mechanics of invokeAny. - */ - private T doInvokeAny(Collection> tasks, boolean timed, long nanos) - throws InterruptedException, ExecutionException, TimeoutException { - if (tasks == null) { - throw new NullPointerException(); - } - int ntasks = tasks.size(); - if (ntasks == 0) { - throw new IllegalArgumentException(); - } - List> futures = new ArrayList>(ntasks); - ExecutorCompletionService ecs = new ExecutorCompletionService(this); - - // For efficiency, especially in executors with limited - // parallelism, check to see if previously submitted tasks are - // done before submitting more of them. This interleaving - // plus the exception mechanics account for messiness of main - // loop. - - try { - // Record exceptions so that if we fail to obtain any - // result, we can throw the last exception we got. - ExecutionException ee = null; - long lastTime = timed ? System.nanoTime() : 0; - Iterator> it = tasks.iterator(); - - // Start one task for sure; the rest incrementally - futures.add(ecs.submit(it.next())); - --ntasks; - int active = 1; - - for (;;) { - Future f = ecs.poll(); - if (f == null) { - if (ntasks > 0) { - --ntasks; - futures.add(ecs.submit(it.next())); - ++active; - } else if (active == 0) { - break; - } else if (timed) { - f = ecs.poll(nanos, TimeUnit.NANOSECONDS); - if (f == null) { - throw new TimeoutException(); - } - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - } else { - f = ecs.take(); - } - } - if (f != null) { - --active; - try { - return f.get(); - } catch (ExecutionException eex) { - ee = eex; - } catch (RuntimeException rex) { - ee = new ExecutionException(rex); - } - } - } - - if (ee == null) { - ee = new ExecutionException(null); - } - throw ee; - - } finally { - for (Future f : futures) - f.cancel(true); - } - } - - @Override - public T invokeAny(Collection> tasks) throws InterruptedException, - ExecutionException { - try { - return doInvokeAny(tasks, false, 0); - } catch (TimeoutException cannotHappen) { - // assert false; - return null; - } - } - - @Override - public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - return doInvokeAny(tasks, true, unit.toNanos(timeout)); - } - - @Override - public List> invokeAll(Collection> tasks) - throws InterruptedException { - if (tasks == null) { - throw new NullPointerException(); - } - List> futures = new ArrayList>(tasks.size()); - boolean done = false; - try { - for (Callable t : tasks) { - RunnableAbstractFuture f = newTaskFor(t); - futures.add(f); - execute(f); - } - for (Future f : futures) { - if (!f.isDone()) { - try { - f.get(); - } catch (CancellationException | ExecutionException ignore) { } - } - } - done = true; - return futures; - } finally { - if (!done) { - for (Future f : futures) - f.cancel(true); - } - } - } - - @Override - public List> invokeAll(Collection> tasks, long timeout, - TimeUnit unit) throws InterruptedException { - if (tasks == null || unit == null) { - throw new NullPointerException(); - } - long nanos = unit.toNanos(timeout); - List> futures = new ArrayList>(tasks.size()); - boolean done = false; - try { - for (Callable t : tasks) - futures.add(newTaskFor(t)); - - long lastTime = System.nanoTime(); - - // Interleave time checks and calls to execute in case - // executor doesn't have any/much parallelism. - for (Future future : futures) { - execute((Runnable) future); - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) { - return futures; - } - } - - for (Future f : futures) { - if (!f.isDone()) { - if (nanos <= 0) { - return futures; - } - try { - f.get(nanos, TimeUnit.NANOSECONDS); - } catch (CancellationException | ExecutionException ignore) { - } catch (TimeoutException toe) { - return futures; - } - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - } - } - done = true; - return futures; - } finally { - if (!done) { - for (Future f : futures) - f.cancel(true); - } - } - } -} diff --git a/src/main/java/com/comphenix/protocol/executors/BukkitExecutors.java b/src/main/java/com/comphenix/protocol/executors/BukkitExecutors.java deleted file mode 100644 index 1729349f..00000000 --- a/src/main/java/com/comphenix/protocol/executors/BukkitExecutors.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.comphenix.protocol.executors; - -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - -import com.comphenix.protocol.executors.AbstractBukkitService; -import com.comphenix.protocol.executors.BukkitScheduledExecutorService; -import com.comphenix.protocol.executors.PendingTasks; -import com.comphenix.protocol.executors.PluginDisabledListener; -import com.google.common.base.Preconditions; - -public class BukkitExecutors { - private BukkitExecutors() { - // Don't make it constructable - } - - /** - * Retrieves a scheduled executor service for running tasks on the main thread. - * @param plugin - plugin that is executing the given tasks. - * @return Executor service. - */ - public static BukkitScheduledExecutorService newSynchronous(final Plugin plugin) { - // Bridge destination - final BukkitScheduler scheduler = getScheduler(plugin); - Preconditions.checkNotNull(plugin, "plugin cannot be NULL"); - - BukkitScheduledExecutorService service = new com.comphenix.protocol.executors.AbstractBukkitService(new PendingTasks(plugin, scheduler)) { - @Override - protected BukkitTask getTask(Runnable command) { - return scheduler.runTask(plugin, command); - } - - @Override - protected BukkitTask getLaterTask(Runnable task, long ticks) { - return scheduler.runTaskLater(plugin, task, ticks); - } - - @Override - protected BukkitTask getTimerTask(long ticksInitial, long ticksDelay, Runnable task) { - return scheduler.runTaskTimer(plugin, task, ticksInitial, ticksDelay); - } - }; - - PluginDisabledListener.getListener(plugin).addService(service); - return service; - } - - /** - * Retrieves a scheduled executor service for running asynchronous tasks. - * @param plugin - plugin that is executing the given tasks. - * @return Asynchronous executor service. - */ - public static BukkitScheduledExecutorService newAsynchronous(final Plugin plugin) { - // Bridge destination - final BukkitScheduler scheduler = getScheduler(plugin); - Preconditions.checkNotNull(plugin, "plugin cannot be NULL"); - - BukkitScheduledExecutorService service = new com.comphenix.protocol.executors.AbstractBukkitService(new PendingTasks(plugin, scheduler)) { - @Override - protected BukkitTask getTask(Runnable command) { - return scheduler.runTaskAsynchronously(plugin, command); - } - - @Override - protected BukkitTask getLaterTask(Runnable task, long ticks) { - return scheduler.runTaskLaterAsynchronously(plugin, task, ticks); - } - - @Override - protected BukkitTask getTimerTask(long ticksInitial, long ticksDelay, Runnable task) { - return scheduler.runTaskTimerAsynchronously(plugin, task, ticksInitial, ticksDelay); - } - }; - - PluginDisabledListener.getListener(plugin).addService(service); - return service; - } - - /** - * Retrieve the current Bukkit scheduler. - * @return Current scheduler. - */ - private static BukkitScheduler getScheduler(Plugin plugin) { - BukkitScheduler scheduler = plugin.getServer().getScheduler(); - - if (scheduler != null) { - return scheduler; - } else { - throw new IllegalStateException("Unable to retrieve scheduler."); - } - } -} diff --git a/src/main/java/com/comphenix/protocol/executors/BukkitFutures.java b/src/main/java/com/comphenix/protocol/executors/BukkitFutures.java deleted file mode 100644 index de741e3b..00000000 --- a/src/main/java/com/comphenix/protocol/executors/BukkitFutures.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.comphenix.protocol.executors; - -import java.lang.reflect.Method; -import java.util.concurrent.atomic.AtomicBoolean; - -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; - -import org.bukkit.event.*; -import org.bukkit.plugin.EventExecutor; -import org.bukkit.plugin.IllegalPluginAccessException; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredListener; - -public class BukkitFutures { - // Represents empty classes - private static Listener EMPTY_LISTENER = new Listener() {}; - - /** - * Retrieve a future representing the next invocation of the given event. - * @param plugin - owner plugin. - * @return Future event invocation. - */ - public static ListenableFuture nextEvent(Plugin plugin, Class eventClass) { - return BukkitFutures.nextEvent(plugin, eventClass, EventPriority.NORMAL, false); - } - - /** - * Retrieve a future representing the next invocation of the given event. - * @param plugin - owner plugin. - * @return Future event invocation. - */ - public static ListenableFuture nextEvent( - Plugin plugin, Class eventClass, EventPriority priority, boolean ignoreCancelled) { - - // Event and future - final HandlerList list = getHandlerList(eventClass); - final SettableFuture future = SettableFuture.create(); - - EventExecutor executor = new EventExecutor() { - private final AtomicBoolean once = new AtomicBoolean(); - - @SuppressWarnings("unchecked") - @Override - public void execute(Listener listener, Event event) throws EventException { - // Fire the future - if (!future.isCancelled() && !once.getAndSet(true)) { - future.set((TEvent) event); - } - } - }; - RegisteredListener listener = new RegisteredListener(EMPTY_LISTENER, executor, priority, plugin, ignoreCancelled) { - @Override - public void callEvent(Event event) throws EventException { - super.callEvent(event); - list.unregister(this); - } - }; - - // Ensure that the future is cleaned up when the plugin is disabled - PluginDisabledListener.getListener(plugin).addFuture(future); - - // Add the listener - list.register(listener); - return future; - } - - /** - * Register a given event executor. - * @param plugin - the owner plugin. - * @param eventClass - the event to register. - * @param priority - the event priority. - * @param executor - the event executor. - */ - public static void registerEventExecutor(Plugin plugin, Class eventClass, EventPriority priority, EventExecutor executor) { - getHandlerList(eventClass).register( - new RegisteredListener(EMPTY_LISTENER, executor, priority, plugin, false) - ); - } - - /** - * Retrieve the handler list associated with the given class. - * @param clazz - given event class. - * @return Associated handler list. - */ - private static HandlerList getHandlerList(Class clazz) { - // Class must have Event as its superclass - while (clazz.getSuperclass() != null && Event.class.isAssignableFrom(clazz.getSuperclass())) { - try { - Method method = clazz.getDeclaredMethod("getHandlerList"); - method.setAccessible(true); - return (HandlerList) method.invoke(null); - } catch (NoSuchMethodException e) { - // Keep on searching - clazz = clazz.getSuperclass().asSubclass(Event.class); - } catch (Exception e) { - throw new IllegalPluginAccessException(e.getMessage()); - } - } - throw new IllegalPluginAccessException("Unable to find handler list for event " - + clazz.getName()); - } -} diff --git a/src/main/java/com/comphenix/protocol/executors/BukkitScheduledExecutorService.java b/src/main/java/com/comphenix/protocol/executors/BukkitScheduledExecutorService.java deleted file mode 100644 index 43cdd32f..00000000 --- a/src/main/java/com/comphenix/protocol/executors/BukkitScheduledExecutorService.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.comphenix.protocol.executors; - -import java.util.concurrent.Callable; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import com.google.common.util.concurrent.ListenableScheduledFuture; -import com.google.common.util.concurrent.ListeningScheduledExecutorService; - -/** - * Represents a listening scheduler service that returns {@link ListenableScheduledFuture} instead of {@link ScheduledFuture}. - * @author Kristian - */ -public interface BukkitScheduledExecutorService extends ListeningScheduledExecutorService { - @Override - public ListenableScheduledFuture schedule( - Runnable command, long delay, TimeUnit unit); - - @Override - public ListenableScheduledFuture schedule( - Callable callable, long delay, TimeUnit unit); - - @Override - public ListenableScheduledFuture scheduleAtFixedRate( - Runnable command, long initialDelay, long period, TimeUnit unit); - - /** - * This is not supported by the underlying Bukkit scheduler. - */ - @Override - @Deprecated - public ListenableScheduledFuture scheduleWithFixedDelay( - Runnable command, long initialDelay, long delay, TimeUnit unit); -} \ No newline at end of file diff --git a/src/main/java/com/comphenix/protocol/executors/CallableTask.java b/src/main/java/com/comphenix/protocol/executors/CallableTask.java deleted file mode 100644 index 8f6bf2d9..00000000 --- a/src/main/java/com/comphenix/protocol/executors/CallableTask.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.comphenix.protocol.executors; - -import java.util.concurrent.Callable; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import com.comphenix.protocol.executors.AbstractListeningService.RunnableAbstractFuture; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.ListenableScheduledFuture; - -class CallableTask extends RunnableAbstractFuture { - protected final Callable compute; - - public CallableTask(Callable compute) { - Preconditions.checkNotNull(compute, "compute cannot be NULL"); - - this.compute = compute; - } - - public ListenableScheduledFuture getScheduledFuture(final long startTime, final long nextDelay) { - return new ListenableScheduledFuture() { - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return CallableTask.this.cancel(mayInterruptIfRunning); - } - - @Override - public T get() throws InterruptedException, ExecutionException { - return CallableTask.this.get(); - } - - @Override - public T get(long timeout, TimeUnit unit) throws InterruptedException, - ExecutionException, TimeoutException { - return CallableTask.this.get(timeout, unit); - } - - @Override - public boolean isCancelled() { - return CallableTask.this.isCancelled(); - } - - @Override - public boolean isDone() { - return CallableTask.this.isDone(); - } - - @Override - public void addListener(Runnable listener, Executor executor) { - CallableTask.this.addListener(listener, executor); - } - - @Override - public int compareTo(Delayed o) { - return Long.valueOf(getDelay(TimeUnit.NANOSECONDS)) - .compareTo(o.getDelay(TimeUnit.NANOSECONDS)); - } - - @Override - public long getDelay(TimeUnit unit) { - long current = System.nanoTime(); - - // Calculate the correct delay - if (current < startTime || !isPeriodic()) - return unit.convert(startTime - current, TimeUnit.NANOSECONDS); - else - return unit.convert(((current - startTime) % nextDelay), TimeUnit.NANOSECONDS); - } - - // @Override - public boolean isPeriodic() { - return nextDelay > 0; - } - }; - } - - /** - * Invoked by the thread responsible for computing this future. - */ - protected void compute() { - try { - // Save result - if (!isCancelled()) { - set(compute.call()); - } - } catch (Throwable e) { - setException(e); - } - } - - @Override - public void run() { - compute(); - } -} \ No newline at end of file diff --git a/src/main/java/com/comphenix/protocol/executors/PendingTasks.java b/src/main/java/com/comphenix/protocol/executors/PendingTasks.java deleted file mode 100644 index 6890d728..00000000 --- a/src/main/java/com/comphenix/protocol/executors/PendingTasks.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.comphenix.protocol.executors; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - -class PendingTasks { - /** - * Represents a wrapper for a cancelable task. - * - * @author Kristian - */ - private interface CancelableFuture { - void cancel(); - boolean isTaskCancelled(); - } - - // Every pending task - private final Set pending = new HashSet<>(); - private final Object pendingLock = new Object(); - - // Handle arbitrary cancelation - private final Plugin plugin; - private final BukkitScheduler scheduler; - private BukkitTask cancellationTask; - - public PendingTasks(Plugin plugin, BukkitScheduler scheduler) { - this.plugin = plugin; - this.scheduler = scheduler; - } - - public void add(final BukkitTask task, final Future future) { - add(new CancelableFuture() { - @Override - public boolean isTaskCancelled() { - // If completed, check its cancellation state - if (future.isDone()) - return future.isCancelled(); - - return !(scheduler.isCurrentlyRunning(task.getTaskId()) || - scheduler.isQueued(task.getTaskId())); - } - - @Override - public void cancel() { - // Make sure - task.cancel(); - future.cancel(true); - } - }); - } - - private CancelableFuture add(CancelableFuture task) { - synchronized (pendingLock) { - pending.add(task); - pendingLock.notifyAll(); - beginCancellationTask(); - return task; - } - } - - private void beginCancellationTask() { - if (cancellationTask == null) { - cancellationTask = scheduler.runTaskTimer(plugin, () -> { - // Check for cancellations - synchronized (pendingLock) { - boolean changed = false; - - for (Iterator it = pending.iterator(); it.hasNext(); ) { - CancelableFuture future = it.next(); - - // Remove cancelled tasks - if (future.isTaskCancelled()) { - future.cancel(); - it.remove(); - changed = true; - } - } - - // Notify waiting threads - if (changed) { - pendingLock.notifyAll(); - } - } - - // Stop if we are out of tasks - if (isTerminated()) { - cancellationTask.cancel(); - cancellationTask = null; - } - }, 1, 1); - } - } - - /** - * Cancel all pending tasks. - */ - public void cancel() { - for (CancelableFuture task : pending) { - task.cancel(); - } - } - - /** - * Wait until all pending tasks have completed. - * @param timeout - the current timeout. - * @param unit - unit of the timeout. - * @return TRUE if every pending task has terminated, FALSE if we reached the timeout. - * @throws InterruptedException - */ - public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - long expire = System.nanoTime() + unit.toNanos(timeout); - - synchronized (pendingLock) { - // Wait until the tasks have all terminated - while (!isTerminated()) { - // Check timeout - if (expire < System.nanoTime()) - return false; - unit.timedWait(pendingLock, timeout); - } - } - // Timeout! - return false; - } - - /** - * Determine if all tasks have completed executing. - * @return TRUE if they have, FALSE otherwise. - */ - public boolean isTerminated() { - return pending.isEmpty(); - } -} diff --git a/src/main/java/com/comphenix/protocol/executors/PluginDisabledListener.java b/src/main/java/com/comphenix/protocol/executors/PluginDisabledListener.java deleted file mode 100644 index 0a165a35..00000000 --- a/src/main/java/com/comphenix/protocol/executors/PluginDisabledListener.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.comphenix.protocol.executors; - -import java.util.Collections; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; - -import com.google.common.collect.MapMaker; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; - -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.plugin.Plugin; - -class PluginDisabledListener implements Listener { - private static final ConcurrentMap LISTENERS = new MapMaker().weakKeys().makeMap(); - - // Objects that must be disabled - private final Set> futures = Collections.newSetFromMap(new WeakHashMap<>()); - private final Set services = Collections.newSetFromMap(new WeakHashMap<>()); - private final Object setLock = new Object(); - - // The plugin we're looking for - private final Plugin plugin; - private boolean disabled; - - private PluginDisabledListener(Plugin plugin) { - this.plugin = plugin; - } - - /** - * Retrieve the associated disabled listener. - * @param plugin - the plugin. - * @return Associated listener. - */ - public static PluginDisabledListener getListener(final Plugin plugin) { - PluginDisabledListener result = LISTENERS.get(plugin); - - if (result == null) { - final PluginDisabledListener created = new PluginDisabledListener(plugin); - result = LISTENERS.putIfAbsent(plugin, created); - - if (result == null) { - // Register listener - we can't use the normal method as the plugin might not be enabled yet - BukkitFutures.registerEventExecutor(plugin, PluginDisableEvent.class, EventPriority.NORMAL, - (listener, event) -> { - if (event instanceof PluginDisableEvent) { - created.onPluginDisabled((PluginDisableEvent) event); - } - }); - - result = created; - } - } - return result; - } - - /** - * Ensure that the given future will be cancelled when the plugin is disabled. - * @param future - the future to cancel. - */ - public void addFuture(final ListenableFuture future) { - synchronized (setLock) { - if (disabled) { - processFuture(future); - } else { - futures.add(future); - } - } - - // Remove the future when it has computed - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(Object value) { - synchronized (setLock) { - futures.remove(future); - } - } - - @Override - public void onFailure(Throwable ex) { - synchronized (setLock) { - futures.remove(future); - } - } - }); - } - - /** - * Ensure that a given service is shutdown when the plugin is disabled. - * @param service - the service. - */ - public void addService(ExecutorService service) { - synchronized (setLock) { - if (disabled) { - processService(service); - } else { - services.add(service); - } - } - } - - // Will be registered manually - public void onPluginDisabled(PluginDisableEvent e) { - if (e.getPlugin().equals(plugin)) { - synchronized (setLock) { - disabled = true; - - // Cancel all unfinished futures - for (Future future : futures) { - processFuture(future); - } - for (ExecutorService service : services) { - processService(service); - } - } - } - } - - private void processFuture(Future future) { - if (!future.isDone()) { - future.cancel(true); - } - } - - private void processService(ExecutorService service) { - service.shutdownNow(); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java b/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java deleted file mode 100644 index 4e7d63d4..00000000 --- a/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java +++ /dev/null @@ -1,518 +0,0 @@ -package com.comphenix.protocol.injector; - -import java.lang.reflect.InvocationTargetException; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import javax.annotation.Nonnull; - -import com.comphenix.protocol.AsynchronousManager; -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.*; -import com.comphenix.protocol.injector.netty.WirePacket; -import com.comphenix.protocol.injector.packet.PacketRegistry; -import com.comphenix.protocol.reflect.FieldAccessException; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; - -/** - * A protocol manager that delays all packet listener registrations and unregistrations until - * an underlying protocol manager can be constructed. - * - * @author Kristian - */ -public class DelayedPacketManager implements InternalManager { - // Registering packet IDs that are not supported - public static final ReportType REPORT_CANNOT_SEND_QUEUED_PACKET = new ReportType("Cannot send queued packet %s."); - public static final ReportType REPORT_CANNOT_SEND_QUEUED_WIRE_PACKET = new ReportType("Cannot send queued wire packet %s."); - public static final ReportType REPORT_CANNOT_REGISTER_QUEUED_LISTENER = new ReportType("Cannot register queued listener %s."); - - private volatile InternalManager delegate; - - // Queued actions - private final List queuedActions = Collections.synchronizedList(Lists.newArrayList()); - private final List queuedListeners = Collections.synchronizedList(Lists.newArrayList()); - - private AsynchronousManager asyncManager; - private ErrorReporter reporter; - - // The current hook - private PlayerInjectHooks hook = PlayerInjectHooks.NETWORK_SERVER_OBJECT; - - // If we have been closed - private boolean closed; - private boolean debug; - - // Queued registration - private PluginManager queuedManager; - private Plugin queuedPlugin; - - private MinecraftVersion version; - - public DelayedPacketManager(@Nonnull ErrorReporter reporter, @Nonnull MinecraftVersion version) { - Preconditions.checkNotNull(reporter, "reporter cannot be NULL."); - Preconditions.checkNotNull(version, "version cannot be NULL."); - - this.reporter = reporter; - this.version = version; - } - - /** - * Retrieve the underlying protocol manager. - * @return The underlying manager. - */ - public InternalManager getDelegate() { - return delegate; - } - - @Override - public int getProtocolVersion(Player player) { - if (delegate != null) - return delegate.getProtocolVersion(player); - else - return Integer.MIN_VALUE; - } - - @Override - public MinecraftVersion getMinecraftVersion() { - if (delegate != null) - return delegate.getMinecraftVersion(); - else - return version; - } - - /** - * Update the delegate to the underlying manager. - *

- * This will prompt this packet manager to immediately transmit and - * register all queued packets an listeners. - * @param delegate - delegate to the new manager. - */ - protected void setDelegate(InternalManager delegate) { - this.delegate = delegate; - - if (delegate != null) { - // Update the hook if needed - if (!Objects.equal(delegate.getPlayerHook(), hook)) { - delegate.setPlayerHook(hook); - } - // Register events as well - if (queuedManager != null && queuedPlugin != null) { - delegate.registerEvents(queuedManager, queuedPlugin); - } - // And update the debug mode - delegate.setDebug(debug); - - // Add any pending listeners - synchronized (queuedListeners) { - for (PacketListener listener : queuedListeners) { - try { - delegate.addPacketListener(listener); - } catch (IllegalArgumentException e) { - // Inform about this plugin error - reporter.reportWarning(this, - Report.newBuilder(REPORT_CANNOT_REGISTER_QUEUED_LISTENER). - callerParam(delegate).messageParam(listener).error(e)); - } - } - } - - // Execute any delayed actions - synchronized (queuedActions) { - for (Runnable action : queuedActions) { - action.run(); - } - } - - // Don't keep this around anymore - queuedListeners.clear(); - queuedActions.clear(); - } - } - - private Runnable queuedAddPacket(final ConnectionSide side, final Player player, final PacketContainer packet, - final NetworkMarker marker, final boolean filtered) { - - return new Runnable() { - @Override - public void run() { - try { - // Attempt to send it now - switch (side) { - case CLIENT_SIDE: - delegate.recieveClientPacket(player, packet, marker, filtered); - break; - case SERVER_SIDE: - delegate.sendServerPacket(player, packet, marker, filtered); - break; - default: - throw new IllegalArgumentException("side cannot be " + side); - } - } catch (Exception e) { - // Inform about this plugin error - reporter.reportWarning(this, - Report.newBuilder(REPORT_CANNOT_SEND_QUEUED_PACKET). - callerParam(delegate).messageParam(packet).error(e)); - } - } - }; - } - - @Override - public void setPlayerHook(PlayerInjectHooks playerHook) { - this.hook = playerHook; - } - - @Override - public PlayerInjectHooks getPlayerHook() { - return hook; - } - - @Override - public void sendServerPacket(Player receiver, PacketContainer packet) throws InvocationTargetException { - sendServerPacket(receiver, packet, null, true); - } - - @Override - public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters) throws InvocationTargetException { - sendServerPacket(receiver, packet, null, filters); - } - - @Override - public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException { - if (delegate != null) { - delegate.sendServerPacket(receiver, packet, marker, filters); - } else { - queuedActions.add(queuedAddPacket(ConnectionSide.SERVER_SIDE, receiver, packet, marker, filters)); - } - } - - @Override - public void sendWirePacket(Player receiver, int id, byte[] bytes) throws InvocationTargetException { - WirePacket packet = new WirePacket(id, bytes); - sendWirePacket(receiver, packet); - } - - @Override - public void sendWirePacket(final Player receiver, final WirePacket packet) throws InvocationTargetException { - if (delegate != null) { - delegate.sendWirePacket(receiver, packet); - } else { - queuedActions.add(new Runnable() { - - @Override - public void run() { - try { - delegate.sendWirePacket(receiver, packet); - } catch (Throwable ex) { - // Inform about this plugin error - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_SEND_QUEUED_WIRE_PACKET) - .callerParam(delegate) - .messageParam(packet) - .error(ex)); - } - } - - }); - } - } - - @Override - public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException { - recieveClientPacket(sender, packet, null, true); - } - - @Override - public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) throws IllegalAccessException, InvocationTargetException { - recieveClientPacket(sender, packet, null, filters); - } - - @Override - public void recieveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters) throws IllegalAccessException, InvocationTargetException { - if (delegate != null) { - delegate.recieveClientPacket(sender, packet, marker, filters); - } else { - queuedActions.add(queuedAddPacket(ConnectionSide.CLIENT_SIDE, sender, packet, marker, filters)); - } - } - - @Override - public void broadcastServerPacket(final PacketContainer packet, final Entity entity, final boolean includeTracker) { - if (delegate != null) { - delegate.broadcastServerPacket(packet, entity, includeTracker); - } else { - queuedActions.add(new Runnable() { - @Override - public void run() { - delegate.broadcastServerPacket(packet, entity, includeTracker); - } - }); - } - } - - @Override - public void broadcastServerPacket(final PacketContainer packet, final Location origin, final int maxObserverDistance) { - if (delegate != null) { - delegate.broadcastServerPacket(packet, origin, maxObserverDistance); - } else { - queuedActions.add(new Runnable() { - @Override - public void run() { - delegate.broadcastServerPacket(packet, origin, maxObserverDistance); - } - }); - } - } - - @Override - public void broadcastServerPacket(final PacketContainer packet) { - if (delegate != null) { - delegate.broadcastServerPacket(packet); - } else { - queuedActions.add(new Runnable() { - @Override - public void run() { - delegate.broadcastServerPacket(packet); - } - }); - } - } - - @Override - public ImmutableSet getPacketListeners() { - if (delegate != null) - return delegate.getPacketListeners(); - else - return ImmutableSet.copyOf(queuedListeners); - } - - @Override - public void addPacketListener(PacketListener listener) { - if (delegate != null) - delegate.addPacketListener(listener); - else - queuedListeners.add(listener); - } - - @Override - public void removePacketListener(PacketListener listener) { - if (delegate != null) - delegate.removePacketListener(listener); - else - queuedListeners.remove(listener); - } - - @Override - public void removePacketListeners(Plugin plugin) { - if (delegate != null) { - delegate.removePacketListeners(plugin); - } else { - for (Iterator it = queuedListeners.iterator(); it.hasNext(); ) { - // Remove listeners of the same plugin - if (Objects.equal(it.next().getPlugin(), plugin)) { - it.remove(); - } - } - } - } - - @Override - @Deprecated - public PacketContainer createPacket(int id) { - if (delegate != null) - return delegate.createPacket(id); - return createPacket(id, true); - } - - @Override - @Deprecated - public PacketContainer createPacket(int id, boolean forceDefaults) { - if (delegate != null) { - return delegate.createPacket(id); - } else { - // Fallback implementation - PacketContainer packet = new PacketContainer(id); - - // Use any default values if possible - if (forceDefaults) { - try { - packet.getModifier().writeDefaults(); - } catch (FieldAccessException e) { - throw new RuntimeException("Security exception.", e); - } - } - return packet; - } - } - - @SuppressWarnings("deprecation") - @Override - public PacketConstructor createPacketConstructor(int id, Object... arguments) { - if (delegate != null) - return delegate.createPacketConstructor(id, arguments); - else - return PacketConstructor.DEFAULT.withPacket(id, arguments); - } - - @Override - public PacketConstructor createPacketConstructor(PacketType type, Object... arguments) { - if (delegate != null) - return delegate.createPacketConstructor(type, arguments); - else - return PacketConstructor.DEFAULT.withPacket(type, arguments); - } - - @Override - @Deprecated - public Set getSendingFilters() { - if (delegate != null) { - return delegate.getSendingFilters(); - } else { - // Linear scan is fast enough here - Set sending = Sets.newHashSet(); - - for (PacketListener listener : queuedListeners) { - sending.addAll(listener.getSendingWhitelist().getWhitelist()); - } - return sending; - } - } - - @Override - @Deprecated - public Set getReceivingFilters() { - if (delegate != null) { - return delegate.getReceivingFilters(); - } else { - Set recieving = Sets.newHashSet(); - - for (PacketListener listener : queuedListeners) { - recieving.addAll(listener.getReceivingWhitelist().getWhitelist()); - } - return recieving; - } - } - - @Override - public PacketContainer createPacket(PacketType type) { - return createPacket(type.getLegacyId()); - } - - @Override - public PacketContainer createPacket(PacketType type, boolean forceDefaults) { - return createPacket(type.getLegacyId(), forceDefaults); - } - - @Override - public Set getSendingFilterTypes() { - return PacketRegistry.toPacketTypes(getSendingFilters(), Sender.SERVER); - } - - @Override - public Set getReceivingFilterTypes() { - return PacketRegistry.toPacketTypes(getReceivingFilters(), Sender.CLIENT); - } - - @Override - public void updateEntity(Entity entity, List observers) throws FieldAccessException { - if (delegate != null) - delegate.updateEntity(entity, observers); - else - EntityUtilities.getInstance().updateEntity(entity, observers); - } - - @Override - public Entity getEntityFromID(World container, int id) throws FieldAccessException { - if (delegate != null) - return delegate.getEntityFromID(container, id); - else - return EntityUtilities.getInstance().getEntityFromID(container, id); - } - - @Override - public List getEntityTrackers(Entity entity) throws FieldAccessException { - if (delegate != null) - return delegate.getEntityTrackers(entity); - else - return EntityUtilities.getInstance().getEntityTrackers(entity); - } - - @Override - public boolean isClosed() { - return closed || (delegate != null && delegate.isClosed()); - } - - @Override - public AsynchronousManager getAsynchronousManager() { - if (delegate != null) - return delegate.getAsynchronousManager(); - else - return asyncManager; - } - - @Override - public boolean isDebug() { - return debug; - } - - @Override - public void setDebug(boolean debug) { - this.debug = debug; - - if (delegate != null) { - delegate.setDebug(debug); - } - } - - /** - * Update the asynchronous manager. This must be set. - * @param asyncManager - the asynchronous manager. - */ - public void setAsynchronousManager(AsynchronousManager asyncManager) { - this.asyncManager = asyncManager; - } - - @Override - public void registerEvents(PluginManager manager, Plugin plugin) { - if (delegate != null) { - delegate.registerEvents(manager, plugin); - } else { - queuedManager = manager; - queuedPlugin = plugin; - } - } - - @Override - public void close() { - if (delegate != null) - delegate.close(); - closed = true; - } - - @Override - public void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist) { - for (PacketType type : whitelist.getTypes()) { - if (type == null) { - throw new IllegalArgumentException(String.format("Packet type in in listener %s was NULL.", - PacketAdapter.getPluginName(listener)) - ); - } - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java b/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java index ae773556..a3e4ae41 100644 --- a/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java +++ b/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java @@ -19,7 +19,6 @@ package com.comphenix.protocol.injector; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.injector.packet.InterceptWritePacket; /** * Represents an object that initiate the packet listeners. @@ -32,13 +31,13 @@ public interface ListenerInvoker { * Invokes the given packet event for every registered listener. * @param event - the packet event to invoke. */ - public abstract void invokePacketRecieving(PacketEvent event); + void invokePacketRecieving(PacketEvent event); /** * Invokes the given packet event for every registered listener. * @param event - the packet event to invoke. */ - public abstract void invokePacketSending(PacketEvent event); + void invokePacketSending(PacketEvent event); /** * Retrieve the associated ID of a packet. @@ -46,49 +45,12 @@ public interface ListenerInvoker { * @return The packet ID. */ @Deprecated - public abstract int getPacketID(Object packet); + int getPacketID(Object packet); /** * Retrieve the associated type of a packet. * @param packet - the packet. * @return The packet type. */ - public abstract PacketType getPacketType(Object packet); - - /** - * Retrieve the object responsible for intercepting write packets. - * @return Object that intercepts write packets. - */ - public InterceptWritePacket getInterceptWritePacket(); - - /** - * Determine if a given packet requires input buffering. - * @param packetId - the packet to check. - * @return TRUE if it does, FALSE otherwise. - */ - @Deprecated - public boolean requireInputBuffer(int packetId); - - /** - * Associate a given class with the given packet ID. Internal method. - * @param clazz - class to associate. - */ - public abstract void unregisterPacketClass(Class clazz); - - /** - * Register a given class in the packet registry. Internal method. - * @param clazz - class to register. - * @param packetID - the the new associated packet ID. - */ - @Deprecated - public abstract void registerPacketClass(Class clazz, int packetID); - - /** - * Retrieves the correct packet class from a given packet ID. - * @param packetID - the packet ID. - * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. - * @return The associated class. - */ - @Deprecated - public abstract Class getPacketClassFromID(int packetID, boolean forceVanilla); + PacketType getPacketType(Object packet); } diff --git a/src/main/java/com/comphenix/protocol/injector/LoginPackets.java b/src/main/java/com/comphenix/protocol/injector/LoginPackets.java deleted file mode 100644 index 438db2da..00000000 --- a/src/main/java/com/comphenix/protocol/injector/LoginPackets.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.comphenix.protocol.injector; - -import org.bukkit.Bukkit; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.Packets; -import com.comphenix.protocol.concurrency.IntegerSet; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.utility.MinecraftVersion; - -/** - * Packets that are known to be transmitted during login. - *

- * This may be dynamically extended later. - * @author Kristian - */ -class LoginPackets { - private IntegerSet clientSide = new IntegerSet(Packets.PACKET_COUNT); - private IntegerSet serverSide = new IntegerSet(Packets.PACKET_COUNT); - - @SuppressWarnings("deprecation") - public LoginPackets(MinecraftVersion version) { - // Ordinary login - clientSide.add(Packets.Client.HANDSHAKE); - serverSide.add(Packets.Server.KEY_REQUEST); - clientSide.add(Packets.Client.KEY_RESPONSE); - serverSide.add(Packets.Server.KEY_RESPONSE); - clientSide.add(Packets.Client.CLIENT_COMMAND); - serverSide.add(Packets.Server.LOGIN); - - // List ping - clientSide.add(Packets.Client.GET_INFO); - - // In 1.6.2, Minecraft started sending CUSTOM_PAYLOAD in the server list protocol - // MCPC+/Cauldron contains Forge, which uses CUSTOM_PAYLOAD during login - if (version.isAtLeast(MinecraftVersion.HORSE_UPDATE) || isCauldronOrMCPC()) { - clientSide.add(Packets.Client.CUSTOM_PAYLOAD); - } - - if (isCauldronOrMCPC()) { - serverSide.add(Packets.Server.CUSTOM_PAYLOAD); - } - - serverSide.add(Packets.Server.KICK_DISCONNECT); - } - - /** - * Determine if we are running MCPC or Cauldron. - * @return TRUE if we are, FALSE otherwise. - */ - private static boolean isCauldronOrMCPC() { - String version = Bukkit.getServer().getVersion(); - return version.contains("MCPC") || version.contains("Cauldron"); - } - - /** - * Determine if a packet may be sent during login from a given direction. - * @param packetId - the ID of the packet. - * @param side - the direction. - * @return TRUE if it may, FALSE otherwise. - */ - @Deprecated - public boolean isLoginPacket(int packetId, ConnectionSide side) { - switch (side) { - case CLIENT_SIDE: - return clientSide.contains(packetId); - case SERVER_SIDE: - return serverSide.contains(packetId); - case BOTH: - return clientSide.contains(packetId) || - serverSide.contains(packetId); - default: - throw new IllegalArgumentException("Unknown connection side: " + side); - } - } - - /** - * Determine if a given packet may be sent during login. - * @param type - the packet type. - * @return TRUE if it may, FALSE otherwise. - */ - public boolean isLoginPacket(PacketType type) { - if (!MinecraftReflection.isUsingNetty()) - return isLoginPacket(type.getLegacyId(), type.getSender().toSide()); - - return PacketType.Login.Client.getInstance().hasMember(type) || - PacketType.Login.Server.getInstance().hasMember(type) || - PacketType.Status.Client.getInstance().hasMember(type) || - PacketType.Status.Server.getInstance().hasMember(type); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java b/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java index cc0b5bd4..b6d49275 100644 --- a/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java +++ b/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java @@ -81,7 +81,7 @@ public class PacketConstructor { */ @Deprecated public int getPacketID() { - return type.getLegacyId(); + return type.getCurrentId(); } /** @@ -101,22 +101,6 @@ public class PacketConstructor { return new PacketConstructor(type, constructorMethod, unwrappers, paramUnwrapper); } - /** - * Create a packet constructor that creates packets using the given ID. - *

- * Note that if you pass a Class as a value, it will use its type directly. - *

- * Deprecated: Use {@link #withPacket(PacketType, Object[])} instead. - * @param id - legacy (1.6.4) packet ID. - * @param values - the values that will match each parameter in the desired constructor. - * @return A packet constructor with these types. - * @throws IllegalArgumentException If no packet constructor could be created with these types. - */ - @Deprecated - public PacketConstructor withPacket(int id, Object[] values) { - return withPacket(PacketType.findLegacy(id), values); - } - /** * Create a packet constructor that creates packets using the given types. *

diff --git a/src/main/java/com/comphenix/protocol/injector/PacketFilterBuilder.java b/src/main/java/com/comphenix/protocol/injector/PacketFilterBuilder.java index d21d9bcc..fe8c4c3d 100644 --- a/src/main/java/com/comphenix/protocol/injector/PacketFilterBuilder.java +++ b/src/main/java/com/comphenix/protocol/injector/PacketFilterBuilder.java @@ -2,26 +2,14 @@ package com.comphenix.protocol.injector; import javax.annotation.Nonnull; -import org.bukkit.Server; -import org.bukkit.event.world.WorldInitEvent; -import org.bukkit.plugin.Plugin; - -import com.comphenix.protocol.executors.BukkitFutures; import com.comphenix.protocol.async.AsyncFilterManager; import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.injector.player.InjectedServerConnection; -import com.comphenix.protocol.injector.spigot.SpigotPacketInjector; -import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftVersion; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; + +import org.bukkit.Server; +import org.bukkit.plugin.Plugin; public class PacketFilterBuilder { - public static final ReportType REPORT_TEMPORARY_EVENT_ERROR = new ReportType("Unable to register or handle temporary event."); - public static final ReportType REPORT_SPIGOT_IS_DELAYING_INJECTOR = new ReportType("Delaying due to Spigot."); - private ClassLoader classLoader; private Server server; private Plugin library; @@ -185,63 +173,10 @@ public class PacketFilterBuilder { asyncManager = new AsyncFilterManager(reporter, server.getScheduler()); nettyEnabled = false; - - // Spigot - if (SpigotPacketInjector.canUseSpigotListener()) { - // If the server hasn't loaded yet - wait - if (InjectedServerConnection.getServerConnection(reporter, server) == null) { - // We need to delay this until we know if Netty is enabled - final DelayedPacketManager delayed = new DelayedPacketManager(reporter, mcVersion); - // They must reference each other - delayed.setAsynchronousManager(asyncManager); - asyncManager.setManager(delayed); - - Futures.addCallback(BukkitFutures.nextEvent(library, WorldInitEvent.class), - new FutureCallback() { - @Override - public void onSuccess(WorldInitEvent event) { - // Nevermind - if (delayed.isClosed()) - return; - - try { - registerSpigot(delayed); - } catch (Exception e) { - onFailure(e); - } - } - - @Override - public void onFailure(Throwable error) { - reporter.reportWarning(PacketFilterBuilder.this, Report - .newBuilder(REPORT_TEMPORARY_EVENT_ERROR).error(error)); - } - }); - - reporter.reportWarning(this, Report.newBuilder(REPORT_SPIGOT_IS_DELAYING_INJECTOR)); - - // Let plugins use this version instead - return delayed; - } else { - nettyEnabled = !MinecraftReflection.isMinecraftObject( - InjectedServerConnection.getServerConnection(reporter, server)); - } - } - - // Otherwise - construct the packet filter manager right away return buildInternal(); } - - private void registerSpigot(DelayedPacketManager delayed) { - // Use netty if we have a non-standard ServerConnection class - nettyEnabled = !MinecraftReflection.isMinecraftObject( - InjectedServerConnection.getServerConnection(reporter, server)); - // Switch to the standard manager - delayed.setDelegate(buildInternal()); - } - /** * Construct a new packet filter manager without checking for Netty. * @return A new packet filter manager. diff --git a/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index 3aba0951..b74c5211 100644 --- a/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -24,7 +24,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import javax.annotation.Nullable; +import java.util.function.Predicate; import com.comphenix.protocol.AsynchronousManager; import com.comphenix.protocol.PacketType; @@ -37,25 +37,21 @@ import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.events.*; import com.comphenix.protocol.injector.netty.ProtocolInjector; import com.comphenix.protocol.injector.netty.WirePacket; -import com.comphenix.protocol.injector.packet.InterceptWritePacket; import com.comphenix.protocol.injector.packet.PacketInjector; -import com.comphenix.protocol.injector.packet.PacketInjectorBuilder; import com.comphenix.protocol.injector.packet.PacketRegistry; import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.injector.player.PlayerInjectionHandler.ConflictStrategy; -import com.comphenix.protocol.injector.player.PlayerInjector.ServerHandlerNull; -import com.comphenix.protocol.injector.player.PlayerInjectorBuilder; -import com.comphenix.protocol.injector.spigot.SpigotPacketInjector; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.utility.Util; import com.google.common.base.Objects; import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; +import io.netty.channel.Channel; + import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Server; @@ -72,8 +68,6 @@ import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; -import io.netty.channel.Channel; - public final class PacketFilterManager implements ListenerInvoker, InternalManager { public static final ReportType REPORT_CANNOT_LOAD_PACKET_LIST = new ReportType("Cannot load server and client packet list."); @@ -106,8 +100,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag private DelayedSingleTask unhookTask; // Create a concurrent set - private Set packetListeners = - Collections.newSetFromMap(new ConcurrentHashMap()); + private Set packetListeners = Collections.newSetFromMap(new ConcurrentHashMap<>()); // Packet injection private PacketInjector packetInjector; @@ -115,9 +108,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag // Different injection types per game phase private PlayerInjectionHandler playerInjection; - // Intercepting write packet methods - private InterceptWritePacket interceptWritePacket; - // Whether or not a packet must be input buffered private volatile Set inputBufferedPackets = Sets.newHashSet(); @@ -154,9 +144,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag // Whether or not plugins are using the send/receive methods private AtomicBoolean packetCreation = new AtomicBoolean(); - // Spigot listener, if in use - private SpigotPacketInjector spigotInjector; - // Netty injector (for 1.7.2) private ProtocolInjector nettyInjector; @@ -169,9 +156,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag // The current Minecraft version private MinecraftVersion minecraftVersion; - // Login packets - private LoginPackets loginPackets; - // Debug mode private boolean debug; @@ -181,18 +165,15 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag */ public PacketFilterManager(PacketFilterBuilder builder) { // Used to determine if injection is needed - Predicate isInjectionNecessary = new Predicate() { - @Override - public boolean apply(@Nullable GamePhase phase) { - boolean result = true; + Predicate isInjectionNecessary = phase -> { + boolean result = true; - if (phase.hasLogin()) - result &= getPhaseLoginCount() > 0; - // Note that we will still hook players if the unhooking has been delayed - if (phase.hasPlaying()) - result &= getPhasePlayingCount() > 0 || unhookTask.isRunning(); - return result; - } + if (phase.hasLogin()) + result &= getPhaseLoginCount() > 0; + // Note that we will still hook players if the unhooking has been delayed + if (phase.hasPlaying()) + result &= getPhasePlayingCount() > 0 || unhookTask.isRunning(); + return result; }; // Listener containers @@ -217,47 +198,11 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag // Prepare version this.minecraftVersion = builder.getMinecraftVersion(); - this.loginPackets = new LoginPackets(minecraftVersion); - // The write packet interceptor - this.interceptWritePacket = new InterceptWritePacket(reporter); + this.nettyInjector = new ProtocolInjector(builder.getLibrary(), this, reporter); + this.playerInjection = nettyInjector.getPlayerInjector(); + this.packetInjector = nettyInjector.getPacketInjector(); - // Use the correct injection type - if (MinecraftReflection.isUsingNetty()) { - this.nettyInjector = new ProtocolInjector(builder.getLibrary(), this, reporter); - this.playerInjection = nettyInjector.getPlayerInjector(); - this.packetInjector = nettyInjector.getPacketInjector(); - - } else if (builder.isNettyEnabled()) { - this.spigotInjector = new SpigotPacketInjector(reporter, this, server); - this.playerInjection = spigotInjector.getPlayerHandler(); - this.packetInjector = spigotInjector.getPacketInjector(); - - // Set real injector, in case we need it - spigotInjector.setProxyPacketInjector(PacketInjectorBuilder.newBuilder(). - invoker(this). - reporter(reporter). - playerInjection(playerInjection). - buildInjector() - ); - - } else { - // Initialize standard injection mangers - this.playerInjection = PlayerInjectorBuilder.newBuilder(). - invoker(this). - server(server). - reporter(reporter). - packetListeners(packetListeners). - injectionFilter(isInjectionNecessary). - version(builder.getMinecraftVersion()). - buildHandler(); - - this.packetInjector = PacketInjectorBuilder.newBuilder(). - invoker(this). - reporter(reporter). - playerInjection(playerInjection). - buildInjector(); - } this.asyncFilterManager = builder.getAsyncManager(); this.library = builder.getLibrary(); @@ -331,11 +276,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag return ImmutableSet.copyOf(packetListeners); } - @Override - public InterceptWritePacket getInterceptWritePacket() { - return interceptWritePacket; - } - /** * Warn of common programming mistakes. * @param plugin - plugin to check. @@ -410,13 +350,25 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag } } + /** + * Determine if a given packet may be sent during login. + * @param type - the packet type. + * @return TRUE if it may, FALSE otherwise. + */ + public boolean isLoginPacket(PacketType type) { + return PacketType.Login.Client.getInstance().hasMember(type) || + PacketType.Login.Server.getInstance().hasMember(type) || + PacketType.Status.Client.getInstance().hasMember(type) || + PacketType.Status.Server.getInstance().hasMember(type); + } + private GamePhase processPhase(ListeningWhitelist whitelist) { // Determine if this is a login packet, ensuring that gamephase detection is enabled if (!whitelist.getGamePhase().hasLogin() && !whitelist.getOptions().contains(ListenerOptions.DISABLE_GAMEPHASE_DETECTION)) { for (PacketType type : whitelist.getTypes()) { - if (loginPackets.isLoginPacket(type)) { + if (isLoginPacket(type)) { return GamePhase.BOTH; } } @@ -565,11 +517,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag } } - @Override - public boolean requireInputBuffer(int packetId) { - return inputBufferedPackets.contains(PacketType.findLegacy(packetId, Sender.CLIENT)); - } - /** * Handle a packet sending or receiving event. *

@@ -858,23 +805,11 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag } } - @Override - @Deprecated - public PacketContainer createPacket(int id) { - return createPacket(PacketType.findLegacy(id), true); - } - @Override public PacketContainer createPacket(PacketType type) { return createPacket(type, true); } - @Override - @Deprecated - public PacketContainer createPacket(int id, boolean forceDefaults) { - return createPacket(PacketType.findLegacy(id), forceDefaults); - } - @Override public PacketContainer createPacket(PacketType type, boolean forceDefaults) { PacketContainer packet = new PacketContainer(type); @@ -891,27 +826,11 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag return packet; } - @Override - @Deprecated - public PacketConstructor createPacketConstructor(int id, Object... arguments) { - return PacketConstructor.DEFAULT.withPacket(id, arguments); - } - @Override public PacketConstructor createPacketConstructor(PacketType type, Object... arguments) { return PacketConstructor.DEFAULT.withPacket(type, arguments); } - @Override - @Deprecated - public Set getSendingFilters() { - return PacketRegistry.toLegacy(playerInjection.getSendingFilters()); - } - - @Override - public Set getReceivingFilters() { - return PacketRegistry.toLegacy(packetInjector.getPacketHandlers()); - } @Override public Set getSendingFilterTypes() { return Collections.unmodifiableSet(playerInjection.getSendingFilters()); @@ -964,8 +883,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag */ @Override public void registerEvents(PluginManager manager, final Plugin plugin) { - if (spigotInjector != null && !spigotInjector.register(plugin)) - throw new IllegalArgumentException("Spigot has already been registered."); if (nettyInjector != null) nettyInjector.inject(); @@ -1012,8 +929,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag // Let's clean up the other injection first. playerInjection.uninjectPlayer(event.getPlayer().getAddress()); playerInjection.injectPlayer(event.getPlayer(), ConflictStrategy.OVERRIDE); - } catch (ServerHandlerNull e) { - // Caused by logged out players, or fake login events in MCPC+/Cauldron. Ignore it. } catch (Exception e) { reporter.reportDetailed(PacketFilterManager.this, Report.newBuilder(REPORT_CANNOT_INJECT_PLAYER).callerParam(event).error(e) @@ -1087,44 +1002,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag } } - @Override - @Deprecated - public void registerPacketClass(Class clazz, int packetID) { - PacketRegistry.getPacketToID().put(clazz, packetID); - } - - @Override - @Deprecated - public void unregisterPacketClass(Class clazz) { - PacketRegistry.getPacketToID().remove(clazz); - } - - @Override - @Deprecated - public Class getPacketClassFromID(int packetID, boolean forceVanilla) { - return PacketRegistry.getPacketClassFromID(packetID, forceVanilla); - } - - /** - * Retrieve every known and supported server packet. - * @return An immutable set of every known server packet. - * @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft. - */ - @Deprecated - public static Set getServerPackets() throws FieldAccessException { - return PacketRegistry.getServerPackets(); - } - - /** - * Retrieve every known and supported client packet. - * @return An immutable set of every known client packet. - * @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft. - */ - @Deprecated - public static Set getClientPackets() throws FieldAccessException { - return PacketRegistry.getClientPackets(); - } - /** * Retrieves the current plugin class loader. * @return Class loader. @@ -1147,8 +1024,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag // Remove packet handlers if (packetInjector != null) packetInjector.cleanupAll(); - if (spigotInjector != null) - spigotInjector.cleanupAll(); if (nettyInjector != null) nettyInjector.close(); @@ -1161,9 +1036,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag recievedListeners = null; sendingListeners = null; - // Also cleanup the interceptor for the write packet method - interceptWritePacket.cleanup(); - // Clean up async handlers. We have to do this last. asyncFilterManager.cleanupAll(); } diff --git a/src/main/java/com/comphenix/protocol/injector/StructureCache.java b/src/main/java/com/comphenix/protocol/injector/StructureCache.java index e1254174..85648e43 100644 --- a/src/main/java/com/comphenix/protocol/injector/StructureCache.java +++ b/src/main/java/com/comphenix/protocol/injector/StructureCache.java @@ -37,22 +37,9 @@ import com.comphenix.protocol.utility.MinecraftReflection; */ public class StructureCache { // Structure modifiers - private static ConcurrentMap> structureModifiers = - new ConcurrentHashMap>(); + private static ConcurrentMap> structureModifiers = new ConcurrentHashMap<>(); - private static Set compiling = new HashSet(); - - /** - * Creates an empty Minecraft packet of the given id. - *

- * Decreated: Use {@link #newPacket(PacketType)} instead. - * @param legacyId - legacy (1.6.4) packet id. - * @return Created packet. - */ - @Deprecated - public static Object newPacket(int legacyId) { - return newPacket(PacketType.findLegacy(legacyId)); - } + private static Set compiling = new HashSet<>(); /** * Creates an empty Minecraft packet of the given type. @@ -76,18 +63,6 @@ public class StructureCache { throw new IllegalArgumentException("Cannot find associated packet class: " + type); } - /** - * Retrieve a cached structure modifier for the given packet id. - *

- * Deprecated: Use {@link #getStructure(PacketType)} instead. - * @param legacyId - the legacy (1.6.4) packet ID. - * @return A structure modifier. - */ - @Deprecated - public static StructureModifier getStructure(int legacyId) { - return getStructure(PacketType.findLegacy(legacyId)); - } - /** * Retrieve a cached structure modifier for the given packet type. * @param type - packet type. @@ -119,19 +94,6 @@ public class StructureCache { return getStructure(PacketRegistry.getPacketType(packetType), compile); } - /** - * Retrieve a cached structure modifier for the given packet ID. - *

- * Deprecated: Use {@link #getStructure(PacketType, boolean)} instead. - * @param legacyId - the legacy (1.6.4) packet ID. - * @param compile - whether or not to asynchronously compile the structure modifier. - * @return A structure modifier. - */ - @Deprecated - public static StructureModifier getStructure(final int legacyId, boolean compile) { - return getStructure(PacketType.findLegacy(legacyId), compile); - } - /** * Retrieve a cached structure modifier for the given packet type. * @param type - packet type. diff --git a/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPacketInjector.java b/src/main/java/com/comphenix/protocol/injector/netty/AbstractPacketInjector.java similarity index 96% rename from src/main/java/com/comphenix/protocol/injector/spigot/AbstractPacketInjector.java rename to src/main/java/com/comphenix/protocol/injector/netty/AbstractPacketInjector.java index df279dfe..338cab4c 100644 --- a/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPacketInjector.java +++ b/src/main/java/com/comphenix/protocol/injector/netty/AbstractPacketInjector.java @@ -1,4 +1,4 @@ -package com.comphenix.protocol.injector.spigot; +package com.comphenix.protocol.injector.netty; import java.util.Set; diff --git a/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPlayerHandler.java b/src/main/java/com/comphenix/protocol/injector/netty/AbstractPlayerHandler.java similarity index 97% rename from src/main/java/com/comphenix/protocol/injector/spigot/AbstractPlayerHandler.java rename to src/main/java/com/comphenix/protocol/injector/netty/AbstractPlayerHandler.java index 81f8616d..44880e50 100644 --- a/src/main/java/com/comphenix/protocol/injector/spigot/AbstractPlayerHandler.java +++ b/src/main/java/com/comphenix/protocol/injector/netty/AbstractPlayerHandler.java @@ -1,4 +1,4 @@ -package com.comphenix.protocol.injector.spigot; +package com.comphenix.protocol.injector.netty; import java.io.DataInputStream; import java.util.Set; diff --git a/src/main/java/com/comphenix/protocol/injector/netty/ProtocolInjector.java b/src/main/java/com/comphenix/protocol/injector/netty/ProtocolInjector.java index 146879e9..ae2fd65d 100644 --- a/src/main/java/com/comphenix/protocol/injector/netty/ProtocolInjector.java +++ b/src/main/java/com/comphenix/protocol/injector/netty/ProtocolInjector.java @@ -44,8 +44,6 @@ import com.comphenix.protocol.injector.packet.PacketInjector; import com.comphenix.protocol.injector.packet.PacketRegistry; import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.injector.server.TemporaryPlayerFactory; -import com.comphenix.protocol.injector.spigot.AbstractPacketInjector; -import com.comphenix.protocol.injector.spigot.AbstractPlayerHandler; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.utility.MinecraftReflection; diff --git a/src/main/java/com/comphenix/protocol/injector/packet/CaptureInputStream.java b/src/main/java/com/comphenix/protocol/injector/packet/CaptureInputStream.java deleted file mode 100644 index 372b79ae..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/CaptureInputStream.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.comphenix.protocol.injector.packet; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Represents an input stream that stores every read block of bytes in another output stream. - * - * @author Kristian - */ -class CaptureInputStream extends FilterInputStream { - protected OutputStream out; - - public CaptureInputStream(InputStream in, OutputStream out) { - super(in); - this.out = out; - } - - @Override - public int read() throws IOException { - int value = super.read(); - - // Write the byte - if (value >= 0) - out.write(value); - return value; - } - - @Override - public void close() throws IOException { - super.close(); - out.close(); - } - - @Override - public int read(byte[] b) throws IOException { - int count = super.read(b); - - if (count > 0 ) { - out.write(b, 0, count); - } - return count; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - int count = super.read(b, off, len); - - if (count > 0 ) { - out.write(b, off, count); - } - return count; - } - - /** - * Retrieve the output stream that receives all the read information. - * @return The output stream everything is copied to. - */ - public OutputStream getOutputStream() { - return out; - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/InterceptWritePacket.java b/src/main/java/com/comphenix/protocol/injector/packet/InterceptWritePacket.java deleted file mode 100644 index d3ecb2cd..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/InterceptWritePacket.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.comphenix.protocol.injector.packet; - -import java.io.DataOutput; -import java.lang.reflect.Method; -import java.util.concurrent.ConcurrentMap; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; - -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.reflect.MethodInfo; -import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; -import com.comphenix.protocol.utility.EnhancerFactory; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.google.common.collect.Maps; - -/** - * Retrieve a packet instance that has its write method intercepted. - * @author Kristian - */ -public class InterceptWritePacket { - public static final ReportType REPORT_CANNOT_FIND_WRITE_PACKET_METHOD = new ReportType("Cannot find write packet method in %s."); - public static final ReportType REPORT_CANNOT_CONSTRUCT_WRITE_PROXY = new ReportType("Cannot construct write proxy packet %s."); - - /** - * Matches the readPacketData(DataInputStream) method in Packet. - */ - private static FuzzyMethodContract WRITE_PACKET = FuzzyMethodContract.newBuilder(). - returnTypeVoid(). - parameterDerivedOf(DataOutput.class). - parameterCount(1). - build(); - - private CallbackFilter filter; - private boolean writePacketIntercepted; - - private ConcurrentMap> proxyClasses = Maps.newConcurrentMap(); - private ErrorReporter reporter; - - private WritePacketModifier modifierWrite; - private WritePacketModifier modifierRest; - - public InterceptWritePacket(ErrorReporter reporter) { - this.reporter = reporter; - - // Initialize modifiers - this.modifierWrite = new WritePacketModifier(reporter, true); - this.modifierRest = new WritePacketModifier(reporter, false); - } - - // TODO: PacketId should probably do something... - private Class createProxyClass() { - // Construct the proxy object - Enhancer ex = EnhancerFactory.getInstance().createEnhancer(); - - // Attempt to share callback filter - if (filter == null) { - filter = new CallbackFilter() { - @Override - public int accept(Method method) { - // Skip methods defined in Object - if (WRITE_PACKET.isMatch(MethodInfo.fromMethod(method), null)) { - writePacketIntercepted = true; - return 0; - } else { - return 1; - } - } - }; - } - - // Subclass the generic packet class - ex.setSuperclass(MinecraftReflection.getPacketClass()); - ex.setCallbackFilter(filter); - ex.setUseCache(false); - - ex.setCallbackTypes( new Class[] { WritePacketModifier.class, WritePacketModifier.class }); - Class proxyClass = ex.createClass(); - - // Register write modifiers too - Enhancer.registerStaticCallbacks(proxyClass, new Callback[] { modifierWrite, modifierRest }); - - if (proxyClass != null) { - // Check that we found the read method - if (!writePacketIntercepted) { - reporter.reportWarning(this, - Report.newBuilder(REPORT_CANNOT_FIND_WRITE_PACKET_METHOD). - messageParam(MinecraftReflection.getPacketClass())); - } - } - return proxyClass; - } - - @SuppressWarnings("deprecation") - private Class getProxyClass(int packetId) { - Class stored = proxyClasses.get(packetId); - - // Concurrent pattern - if (stored == null) { - final Class created = createProxyClass(); - stored = proxyClasses.putIfAbsent(packetId, created); - - // We won! - if (stored == null) { - stored = created; - PacketRegistry.getPacketToID().put(stored, packetId); - } - } - return stored; - } - - /** - * Construct a new instance of the proxy object. - * @param proxyObject - Object to construct proxy of - * @param event - Packet event - * @param marker - Network marker - * @return New instance of the proxy, or null if we failed. - */ - @SuppressWarnings("deprecation") - public Object constructProxy(Object proxyObject, PacketEvent event, NetworkMarker marker) { - Class proxyClass = null; - - try { - proxyClass = getProxyClass(event.getPacketID()); - Object generated = proxyClass.newInstance(); - - modifierWrite.register(generated, proxyObject, event, marker); - modifierRest.register(generated, proxyObject, event, marker); - return generated; - - } catch (Exception e) { - reporter.reportWarning(this, - Report.newBuilder(REPORT_CANNOT_CONSTRUCT_WRITE_PROXY). - messageParam(proxyClass)); - return null; - } - } - - /** - * Invoked when the write packet proxy class should be removed. - */ - @SuppressWarnings("deprecation") - public void cleanup() { - // Remove all proxy classes from the registry - for (Class stored : proxyClasses.values()) { - PacketRegistry.getPacketToID().remove(stored); - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/InverseMaps.java b/src/main/java/com/comphenix/protocol/injector/packet/InverseMaps.java deleted file mode 100644 index d5dd2aec..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/InverseMaps.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.comphenix.protocol.injector.packet; - -import java.util.Map; - -import com.google.common.base.Predicate; -import com.google.common.collect.ForwardingMap; -import com.google.common.collect.ForwardingMultimap; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; - -public class InverseMaps { - private InverseMaps() { - // Not constructable - } - - public static Multimap inverseMultimap(final Map map, final Predicate> filter) { - final MapContainer container = new MapContainer(map); - - return new ForwardingMultimap() { - // The cached multimap - private Multimap inverseMultimap; - - @Override - protected Multimap delegate() { - if (container.hasChanged()) { - inverseMultimap = HashMultimap.create(); - - // Construct the inverse map - for (Map.Entry entry : map.entrySet()) { - if (filter.apply(entry)) { - inverseMultimap.put(entry.getValue(), entry.getKey()); - } - } - container.setChanged(false); - } - return inverseMultimap; - } - }; - } - - public static Map inverseMap(final Map map, final Predicate> filter) { - final MapContainer container = new MapContainer(map); - - return new ForwardingMap() { - // The cached map - private Map inverseMap; - - @Override - protected Map delegate() { - if (container.hasChanged()) { - inverseMap = Maps.newHashMap(); - - // Construct the inverse map - for (Map.Entry entry : map.entrySet()) { - if (filter.apply(entry)) { - inverseMap.put(entry.getValue(), entry.getKey()); - } - } - container.setChanged(false); - } - return inverseMap; - } - }; - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/LegacyNetworkMarker.java b/src/main/java/com/comphenix/protocol/injector/packet/LegacyNetworkMarker.java deleted file mode 100644 index a9c41387..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/LegacyNetworkMarker.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.comphenix.protocol.injector.packet; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; - -import javax.annotation.Nonnull; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.events.NetworkMarker; -import com.google.common.io.ByteSource; -import com.google.common.primitives.Bytes; - -/** - * Represents a network marker for 1.6.4 and earlier. - * @author Kristian - */ -public class LegacyNetworkMarker extends NetworkMarker { - public LegacyNetworkMarker(@Nonnull ConnectionSide side, byte[] inputBuffer, PacketType type) { - super(side, inputBuffer, type); - } - - public LegacyNetworkMarker(@Nonnull ConnectionSide side, ByteBuffer inputBuffer, PacketType type) { - super(side, inputBuffer, type); - } - - @Override - protected DataInputStream skipHeader(DataInputStream input) throws IOException { - // This has already been done - return input; - } - - @Override - protected ByteBuffer addHeader(ByteBuffer buffer, PacketType type) { - return ByteBuffer.wrap(Bytes.concat(new byte[] { (byte) type.getLegacyId() }, buffer.array())); - } - - @Override - protected DataInputStream addHeader(final DataInputStream input, final PacketType type) { - ByteSource header = new ByteSource() { - @Override - public InputStream openStream() throws IOException { - byte[] data = new byte[] { (byte) type.getLegacyId() }; - return new ByteArrayInputStream(data); - } - }; - - ByteSource data = new ByteSource() { - @Override - public InputStream openStream() throws IOException { - return input; - } - }; - - // Combine them into a single stream - try { - return new DataInputStream(ByteSource.concat(header, data).openStream()); - } catch (IOException e) { - throw new RuntimeException("Cannot add header.", e); - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/LegacyPacketRegistry.java b/src/main/java/com/comphenix/protocol/injector/packet/LegacyPacketRegistry.java deleted file mode 100644 index 1c1fe590..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/LegacyPacketRegistry.java +++ /dev/null @@ -1,334 +0,0 @@ -package com.comphenix.protocol.injector.packet; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Nullable; - -import net.sf.cglib.proxy.Factory; - -import com.comphenix.protocol.reflect.FieldAccessException; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract; -import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; -import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.wrappers.TroveWrapper; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; - -@SuppressWarnings("rawtypes") -class LegacyPacketRegistry { - private static final int MIN_SERVER_PACKETS = 5; - private static final int MIN_CLIENT_PACKETS = 5; - - // Fuzzy reflection - private FuzzyReflection packetRegistry; - - // The packet class to packet ID translator - private Map packetToID; - - // Packet IDs to classes, grouped by whether or not they're vanilla or custom defined - private Multimap customIdToPacket; - private Map vanillaIdToPacket; - - // Whether or not certain packets are sent by the client or the server - private ImmutableSet serverPackets; - private ImmutableSet clientPackets; - - // The underlying sets - private Set serverPacketsRef; - private Set clientPacketsRef; - - // New proxy values - private Map overwrittenPackets = new HashMap(); - - // Vanilla packets - private Map previousValues = new HashMap(); - - /** - * Initialize the registry. - */ - @SuppressWarnings({ "unchecked" }) - public void initialize() { - if (packetToID == null) { - try { - Field packetsField = getPacketRegistry().getFieldByType("packetsField", Map.class); - packetToID = (Map) FieldUtils.readStaticField(packetsField, true); - } catch (IllegalArgumentException e) { - // Spigot 1.2.5 MCPC workaround - try { - packetToID = getSpigotWrapper(); - } catch (Exception e2) { - // Very bad indeed - throw new IllegalArgumentException(e.getMessage() + "; Spigot workaround failed.", e2); - } - - } catch (IllegalAccessException e) { - throw new RuntimeException("Unable to retrieve the packetClassToIdMap", e); - } - - // Create the inverse maps - customIdToPacket = InverseMaps.inverseMultimap(packetToID, new Predicate>() { - @Override - public boolean apply(@Nullable Entry entry) { - return !MinecraftReflection.isMinecraftClass(entry.getKey()); - } - }); - - // And the vanilla pack - here we assume a unique ID to class mapping - vanillaIdToPacket = InverseMaps.inverseMap(packetToID, new Predicate>() { - @Override - public boolean apply(@Nullable Entry entry) { - return MinecraftReflection.isMinecraftClass(entry.getKey()); - } - }); - } - initializeSets(); - } - - @SuppressWarnings("unchecked") - private void initializeSets() throws FieldAccessException { - if (serverPacketsRef == null || clientPacketsRef == null) { - List sets = getPacketRegistry().getFieldListByType(Set.class); - - try { - if (sets.size() > 1) { - serverPacketsRef = (Set) FieldUtils.readStaticField(sets.get(0), true); - clientPacketsRef = (Set) FieldUtils.readStaticField(sets.get(1), true); - - // Impossible - if (serverPacketsRef == null || clientPacketsRef == null) - throw new FieldAccessException("Packet sets are in an illegal state."); - - // NEVER allow callers to modify the underlying sets - serverPackets = ImmutableSet.copyOf(serverPacketsRef); - clientPackets = ImmutableSet.copyOf(clientPacketsRef); - - // Check sizes - if (serverPackets.size() < MIN_SERVER_PACKETS) - throw new InsufficientPacketsException("Insufficient server packets.", false, serverPackets.size()); - if (clientPackets.size() < MIN_CLIENT_PACKETS) - throw new InsufficientPacketsException("Insufficient client packets.", true, clientPackets.size()); - - } else { - throw new FieldAccessException("Cannot retrieve packet client/server sets."); - } - - } catch (IllegalAccessException e) { - throw new FieldAccessException("Cannot access field.", e); - } - - } else { - // Copy over again if it has changed - if (serverPacketsRef != null && serverPacketsRef.size() != serverPackets.size()) - serverPackets = ImmutableSet.copyOf(serverPacketsRef); - if (clientPacketsRef != null && clientPacketsRef.size() != clientPackets.size()) - clientPackets = ImmutableSet.copyOf(clientPacketsRef); - } - } - - /** - * Retrieve the packet mapping. - * @return The packet map. - */ - public Map getPacketToID() { - // Initialize it, if we haven't already - if (packetToID == null) { - initialize(); - } - return packetToID; - } - - private Map getSpigotWrapper() throws IllegalAccessException { - // If it talks like a duck, etc. - // Perhaps it would be nice to have a proper duck typing library as well - FuzzyClassContract mapLike = FuzzyClassContract.newBuilder(). - method(FuzzyMethodContract.newBuilder(). - nameExact("size").returnTypeExact(int.class)). - method(FuzzyMethodContract.newBuilder(). - nameExact("put").parameterCount(2)). - method(FuzzyMethodContract.newBuilder(). - nameExact("get").parameterCount(1)). - build(); - - Field packetsField = getPacketRegistry().getField( - FuzzyFieldContract.newBuilder().typeMatches(mapLike).build()); - Object troveMap = FieldUtils.readStaticField(packetsField, true); - - // Fix incorrect no entry values - TroveWrapper.transformNoEntryValue(troveMap, new Function() { - public Integer apply(Integer value) { - if (value >= 0 && value < 256) { - // Someone forgot to set the no entry value. Let's help them. - return -1; - } - return value; - } - }); - - // We'll assume this a Trove map - return TroveWrapper.getDecoratedMap(troveMap); - } - - /** - * Retrieve the cached fuzzy reflection instance allowing access to the packet registry. - * @return Reflected packet registry. - */ - private FuzzyReflection getPacketRegistry() { - if (packetRegistry == null) - packetRegistry = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true); - return packetRegistry; - } - - /** - * Retrieve the injected proxy classes handlig each packet ID. - * @return Injected classes. - */ - public Map getOverwrittenPackets() { - return overwrittenPackets; - } - - /** - * Retrieve the vanilla classes handling each packet ID. - * @return Vanilla classes. - */ - public Map getPreviousPackets() { - return previousValues; - } - - /** - * Retrieve every known and supported server packet. - * @return An immutable set of every known server packet. - * @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft. - */ - public Set getServerPackets() throws FieldAccessException { - initializeSets(); - - // Sanity check. This is impossible! - if (serverPackets != null && serverPackets.size() < MIN_SERVER_PACKETS) - throw new FieldAccessException("Server packet list is empty. Seems to be unsupported"); - return serverPackets; - } - - /** - * Retrieve every known and supported client packet. - * @return An immutable set of every known client packet. - * @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft. - */ - public Set getClientPackets() throws FieldAccessException { - initializeSets(); - - // As above - if (clientPackets != null && clientPackets.size() < MIN_CLIENT_PACKETS) - throw new FieldAccessException("Client packet list is empty. Seems to be unsupported"); - return clientPackets; - } - - /** - * Retrieves the correct packet class from a given packet ID. - * @param packetID - the packet ID. - * @return The associated class. - */ - public Class getPacketClassFromID(int packetID) { - return getPacketClassFromID(packetID, false); - } - - /** - * Retrieves the correct packet class from a given packet ID. - * @param packetID - the packet ID. - * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. - * @return The associated class. - */ - public Class getPacketClassFromID(int packetID, boolean forceVanilla) { - Map lookup = forceVanilla ? previousValues : overwrittenPackets; - Class result = null; - - // Optimized lookup - if (lookup.containsKey(packetID)) { - return removeEnhancer(lookup.get(packetID), forceVanilla); - } - - // Refresh lookup tables - getPacketToID(); - - // See if we can look for non-vanilla classes - if (!forceVanilla) { - result = Iterables.getFirst(customIdToPacket.get(packetID), null); - } - if (result == null) { - result = vanillaIdToPacket.get(packetID); - } - - // See if we got it - if (result != null) - return result; - else - throw new IllegalArgumentException("The packet ID " + packetID + " is not registered."); - } - - /** - * Retrieve the packet ID of a given packet. - * @param packet - the type of packet to check. - * @return The ID of the given packet. - * @throws IllegalArgumentException If this is not a valid packet. - */ - public int getPacketID(Class packet) { - if (packet == null) - throw new IllegalArgumentException("Packet type class cannot be NULL."); - if (!MinecraftReflection.getPacketClass().isAssignableFrom(packet)) - throw new IllegalArgumentException("Type must be a packet."); - - // The registry contains both the overridden and original packets - return getPacketToID().get(packet); - } - - /** - * Find the first superclass that is not a CBLib proxy object. - * @param clazz - the class whose hierachy we're going to search through. - * @param remove - whether or not to skip enhanced (proxy) classes. - * @return If remove is TRUE, the first superclass that is not a proxy. - */ - private static Class removeEnhancer(Class clazz, boolean remove) { - if (remove) { - // Get the underlying vanilla class - while (Factory.class.isAssignableFrom(clazz) && !clazz.equals(Object.class)) { - clazz = clazz.getSuperclass(); - } - } - return clazz; - } - - /** - * Occurs when we were unable to retrieve all the packets in the registry. - * @author Kristian - */ - public static class InsufficientPacketsException extends RuntimeException { - private static final long serialVersionUID = 1L; - - private final boolean client; - private final int packetCount; - - private InsufficientPacketsException(String message, boolean client, int packetCount) { - super(message); - this.client = client; - this.packetCount = packetCount; - } - - public boolean isClient() { - return client; - } - - public int getPacketCount() { - return packetCount; - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/PacketInjectorBuilder.java b/src/main/java/com/comphenix/protocol/injector/packet/PacketInjectorBuilder.java deleted file mode 100644 index e8977289..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/PacketInjectorBuilder.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.comphenix.protocol.injector.packet; - -import javax.annotation.Nonnull; - -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PacketFilterManager; -import com.comphenix.protocol.injector.player.PlayerInjectionHandler; -import com.comphenix.protocol.reflect.FieldAccessException; -import com.google.common.base.Preconditions; - -/** - * A builder responsible for creating incoming packet injectors. - * - * @author Kristian - */ -public class PacketInjectorBuilder { - protected PacketInjectorBuilder() { - // No need to construct this - } - - /** - * Retrieve a new packet injector builder. - * @return Injector builder. - */ - public static PacketInjectorBuilder newBuilder() { - return new PacketInjectorBuilder(); - } - - protected ListenerInvoker invoker; - protected ErrorReporter reporter; - protected PlayerInjectionHandler playerInjection; - - /** - * The error reporter used by the created injector. - * @param reporter - new error reporter. - * @return This builder, for chaining. - */ - public PacketInjectorBuilder reporter(@Nonnull ErrorReporter reporter) { - Preconditions.checkNotNull(reporter, "reporter cannot be NULL"); - this.reporter = reporter; - return this; - } - - /** - * The packet stream invoker. - * @param invoker - the invoker. - * @return This builder, for chaining. - */ - public PacketInjectorBuilder invoker(@Nonnull ListenerInvoker invoker) { - Preconditions.checkNotNull(invoker, "invoker cannot be NULL"); - this.invoker = invoker; - return this; - } - - /** - * Set the player injection. - * @param playerInjection - the injection. - * @return This builder, for chaining. - */ - @Nonnull - public PacketInjectorBuilder playerInjection(@Nonnull PlayerInjectionHandler playerInjection) { - Preconditions.checkNotNull(playerInjection, "playerInjection cannot be NULL"); - this.playerInjection = playerInjection; - return this; - } - - /** - * Called before an object is created with this builder. - */ - private void initializeDefaults() { - ProtocolManager manager = ProtocolLibrary.getProtocolManager(); - - // Initialize with default values if we can - if (reporter == null) - reporter = ProtocolLibrary.getErrorReporter(); - if (invoker == null) - invoker = (PacketFilterManager) manager; - if (playerInjection == null) - throw new IllegalStateException("Player injection parameter must be initialized."); - } - - /** - * Create a packet injector using the provided fields or the default values. - *

- * Note that any non-null builder parameters must be set. - * @return The created injector. - * @throws FieldAccessException If anything goes wrong in terms of reflection. - */ - public PacketInjector buildInjector() throws FieldAccessException { - initializeDefaults(); - return new ProxyPacketInjector(invoker, playerInjection, reporter); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java b/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java index c93643ae..78f5dc51 100644 --- a/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java +++ b/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java @@ -17,22 +17,16 @@ package com.comphenix.protocol.injector.packet; -import java.util.Collections; -import java.util.HashSet; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.injector.netty.NettyProtocolRegistry; import com.comphenix.protocol.injector.netty.ProtocolRegistry; -import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Function; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; /** * Static packet registry in Minecraft. @@ -40,19 +34,9 @@ import com.google.common.collect.Sets; */ @SuppressWarnings("rawtypes") public class PacketRegistry { - public static final ReportType REPORT_CANNOT_CORRECT_TROVE_MAP = new ReportType("Unable to correct no entry value."); - - public static final ReportType REPORT_INSUFFICIENT_SERVER_PACKETS = new ReportType("Too few server packets detected: %s"); - public static final ReportType REPORT_INSUFFICIENT_CLIENT_PACKETS = new ReportType("Too few client packets detected: %s"); - // The Netty packet registry private static volatile ProtocolRegistry NETTY; - // Cached for Netty - private static volatile Set LEGACY_SERVER_PACKETS; - private static volatile Set LEGACY_CLIENT_PACKETS; - private static volatile Map LEGACY_PREVIOUS_PACKETS; - // Whether or not the registry has been initialized private static volatile boolean INITIALIZED = false; @@ -93,13 +77,7 @@ public class PacketRegistry { @SuppressWarnings("unchecked") Map result = (Map) Maps.transformValues( - NETTY.getPacketClassLookup(), - new Function() { - @Override - public Integer apply(PacketType type) { - return type.getLegacyId(); - }; - }); + NETTY.getPacketClassLookup(), type -> type.getLegacyId()); return result; } @@ -114,55 +92,7 @@ public class PacketRegistry { Map result = (Map) NETTY.getPacketClassLookup(); return result; } - - /** - * Retrieve the injected proxy classes handlig each packet ID. - *

- * This is not supported in 1.7.2 and later. - * @return Injected classes. - */ - @Deprecated - public static Map getOverwrittenPackets() { - initialize(); - throw new IllegalStateException("Not supported on Netty."); - } - /** - * Retrieve the vanilla classes handling each packet ID. - * @return Vanilla classes. - */ - @Deprecated - public static Map getPreviousPackets() { - initialize(); - - // Construct it first - if (LEGACY_PREVIOUS_PACKETS == null) { - Map map = Maps.newHashMap(); - - for (Entry> entry : NETTY.getPacketTypeLookup().entrySet()) { - map.put(entry.getKey().getLegacyId(), entry.getValue()); - } - LEGACY_PREVIOUS_PACKETS = Collections.unmodifiableMap(map); - } - return LEGACY_PREVIOUS_PACKETS; - } - - /** - * Retrieve every known and supported server packet. - *

- * Deprecated: Use {@link #getServerPacketTypes()} instead. - * @return An immutable set of every known server packet. - * @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft. - */ - @Deprecated - public static Set getServerPackets() throws FieldAccessException { - if (LEGACY_SERVER_PACKETS == null) { - LEGACY_SERVER_PACKETS = toLegacy(getServerPacketTypes()); - } - - return LEGACY_SERVER_PACKETS; - } - /** * Retrieve every known and supported server packet type. * @return Every server packet type. @@ -174,22 +104,6 @@ public class PacketRegistry { return NETTY.getServerPackets(); } - /** - * Retrieve every known and supported client packet. - *

- * Deprecated: Use {@link #getClientPacketTypes()} instead. - * @return An immutable set of every known client packet. - * @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft. - */ - @Deprecated - public static Set getClientPackets() throws FieldAccessException { - if (LEGACY_CLIENT_PACKETS == null) { - LEGACY_CLIENT_PACKETS = toLegacy(getClientPacketTypes()); - } - - return LEGACY_CLIENT_PACKETS; - } - /** * Retrieve every known and supported server packet type. * @return Every server packet type. @@ -200,43 +114,7 @@ public class PacketRegistry { return NETTY.getClientPackets(); } - - /** - * Convert a set of packet types to a set of integers based on the legacy packet ID. - * @param types - packet type. - * @return Set of integers. - */ - public static Set toLegacy(Set types) { - Set result = Sets.newHashSet(); - - for (PacketType type : types) - result.add(type.getLegacyId()); - return Collections.unmodifiableSet(result); - } - - /** - * Convert a set of legacy packet IDs to packet types. - * @param ids - legacy packet IDs. - * @return Set of packet types. - */ - public static Set toPacketTypes(Set ids) { - return toPacketTypes(ids, null); - } - - /** - * Convert a set of legacy packet IDs to packet types. - * @param ids - legacy packet IDs. - * @param preference - the sender preference, if any. - * @return Set of packet types. - */ - public static Set toPacketTypes(Set ids, Sender preference) { - Set result = Sets.newHashSet(); - - for (int id : ids) - result.add(PacketType.fromLegacy(id, preference)); - return Collections.unmodifiableSet(result); - } - + /** * Retrieves the correct packet class from a given packet ID. *

diff --git a/src/main/java/com/comphenix/protocol/injector/packet/ProxyPacketInjector.java b/src/main/java/com/comphenix/protocol/injector/packet/ProxyPacketInjector.java deleted file mode 100644 index b047ac9c..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/ProxyPacketInjector.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.packet; - -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Map; -import java.util.Set; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.Factory; -import net.sf.cglib.proxy.NoOp; - -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.events.ListenerOptions; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.player.PlayerInjectionHandler; -import com.comphenix.protocol.reflect.FieldAccessException; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.MethodInfo; -import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; -import com.comphenix.protocol.utility.EnhancerFactory; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.wrappers.WrappedIntHashMap; - -/** - * This class is responsible for adding or removing proxy objects that intercepts received packets. - * - * @author Kristian - */ -class ProxyPacketInjector implements PacketInjector { - public static final ReportType REPORT_CANNOT_FIND_READ_PACKET_METHOD = new ReportType("Cannot find read packet method for ID %s."); - public static final ReportType REPORT_UNKNOWN_ORIGIN_FOR_PACKET = new ReportType("Timeout: Unknown origin %s for packet %s. Are you using GamePhase.LOGIN?"); - - /** - * Represents a way to update the packet ID to class lookup table. - * @author Kristian - */ - private static interface PacketClassLookup { - public void setLookup(int packetID, Class clazz); - } - - private static class IntHashMapLookup implements PacketClassLookup { - private WrappedIntHashMap intHashMap; - - public IntHashMapLookup() throws IllegalAccessException { - initialize(); - } - - @Override - public void setLookup(int packetID, Class clazz) { - intHashMap.put(packetID, clazz); - } - - private void initialize() throws IllegalAccessException { - if (intHashMap == null) { - // We're looking for the first static field with a Minecraft-object. This should be a IntHashMap. - Field intHashMapField = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true). - getFieldByType("packetIdMap", MinecraftReflection.getIntHashMapClass()); - - try { - intHashMap = WrappedIntHashMap.fromHandle( - FieldUtils.readField(intHashMapField, (Object) null, true)); - } catch (IllegalArgumentException e) { - throw new RuntimeException("Minecraft is incompatible.", e); - } - } - } - } - - private static class ArrayLookup implements PacketClassLookup { - private Class[] array; - - public ArrayLookup() throws IllegalAccessException { - initialize(); - } - - @Override - public void setLookup(int packetID, Class clazz) { - array[packetID] = clazz; - } - - private void initialize() throws IllegalAccessException { - FuzzyReflection reflection = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()); - - // Is there a Class array with 256 elements instead? - for (Field field : reflection.getFieldListByType(Class[].class)) { - Class[] test = (Class[]) FieldUtils.readField(field, (Object)null); - - if (test.length == 256) { - array = test; - return; - } - } - throw new IllegalArgumentException( - "Unable to find an array with the type " + Class[].class + - " in " + MinecraftReflection.getPacketClass()); - } - } - - /** - * Matches the readPacketData(DataInputStream) method in Packet. - */ - private static FuzzyMethodContract READ_PACKET = FuzzyMethodContract.newBuilder(). - returnTypeVoid(). - parameterDerivedOf(DataInput.class). - parameterCount(1). - build(); - - private static PacketClassLookup lookup; - - // The packet filter manager - private ListenerInvoker manager; - - // Error reporter - private ErrorReporter reporter; - - // Allows us to determine the sender - private PlayerInjectionHandler playerInjection; - - // Share callback filter - private CallbackFilter filter; - - // Determine if the read packet method was found - private boolean readPacketIntercepted = false; - - public ProxyPacketInjector(ListenerInvoker manager, PlayerInjectionHandler playerInjection, - ErrorReporter reporter) throws FieldAccessException { - - this.manager = manager; - this.playerInjection = playerInjection; - this.reporter = reporter; - initialize(); - } - - @Override - public boolean isCancelled(Object packet) { - return ReadPacketModifier.isCancelled(packet); - } - - @Override - public void setCancelled(Object packet, boolean cancelled) { - if (cancelled) { - ReadPacketModifier.setOverride(packet, null); - } else { - ReadPacketModifier.removeOverride(packet); - } - } - - private void initialize() throws FieldAccessException { - if (lookup == null) { - try { - lookup = new IntHashMapLookup(); - } catch (Exception e1) { - - try { - lookup = new ArrayLookup(); - } catch (Exception e2) { - // Wow - throw new FieldAccessException(e1.getMessage() + ". Workaround failed too.", e2); - } - } - - // Should work fine now - } - } - - @Override - public void inputBuffersChanged(Set set) { - // No need to do anything - } - - @Override - @SuppressWarnings({"rawtypes", "deprecation"}) - public boolean addPacketHandler(PacketType type, Set options) { - final int packetID = type.getLegacyId(); - - if (hasPacketHandler(type)) - return false; - - Enhancer ex = EnhancerFactory.getInstance().createEnhancer(); - - // Unfortunately, we can't easily distinguish between these two functions: - // * Object lookup(int par1) - // * Object removeObject(int par1) - - // So, we'll use the classMapToInt registry instead. - Map overwritten = PacketRegistry.getOverwrittenPackets(); - Map previous = PacketRegistry.getPreviousPackets(); - Map registry = PacketRegistry.getPacketToID(); - Class old = PacketRegistry.getPacketClassFromType(type); - - // If this packet is not known - if (old == null) { - throw new IllegalStateException("Packet ID " + type + " is not a valid packet type in this version."); - } - // Check for previous injections - if (Factory.class.isAssignableFrom(old)) { - throw new IllegalStateException("Packet " + type + " has already been injected."); - } - - if (filter == null) { - readPacketIntercepted = false; - - filter = new CallbackFilter() { - @Override - public int accept(Method method) { - // Skip methods defined in Object - if (method.getDeclaringClass().equals(Object.class)) { - return 0; - } else if (READ_PACKET.isMatch(MethodInfo.fromMethod(method), null)) { - readPacketIntercepted = true; - return 1; - } else { - return 2; - } - } - }; - } - - // Subclass the specific packet class - ex.setSuperclass(old); - ex.setCallbackFilter(filter); - ex.setCallbackTypes(new Class[] { NoOp.class, ReadPacketModifier.class, ReadPacketModifier.class }); - Class proxy = ex.createClass(); - - // Create the proxy handlers - ReadPacketModifier modifierReadPacket = new ReadPacketModifier(packetID, this, reporter, true); - ReadPacketModifier modifierRest = new ReadPacketModifier(packetID, this, reporter, false); - - // Add a static reference - Enhancer.registerStaticCallbacks(proxy, new Callback[] { NoOp.INSTANCE, modifierReadPacket, modifierRest }); - - // Check that we found the read method - if (!readPacketIntercepted) { - reporter.reportWarning(this, - Report.newBuilder(REPORT_CANNOT_FIND_READ_PACKET_METHOD).messageParam(packetID)); - } - - // Override values - previous.put(packetID, old); - registry.put(proxy, packetID); - overwritten.put(packetID, proxy); - lookup.setLookup(packetID, proxy); - return true; - } - - @Override - @SuppressWarnings({"rawtypes", "deprecation"}) - public boolean removePacketHandler(PacketType type) { - final int packetID = type.getLegacyId(); - - if (!hasPacketHandler(type)) - return false; - - Map registry = PacketRegistry.getPacketToID(); - Map previous = PacketRegistry.getPreviousPackets(); - Map overwritten = PacketRegistry.getOverwrittenPackets(); - - Class old = previous.get(packetID); - Class proxy = PacketRegistry.getPacketClassFromType(type); - - lookup.setLookup(packetID, old); - previous.remove(packetID); - registry.remove(proxy); - overwritten.remove(packetID); - return true; - } - - /** - * Determine if the data a packet read must be buffered. - * @param packetId - the packet to check. - * @return TRUE if it does, FALSE otherwise. - */ - @Deprecated - public boolean requireInputBuffers(int packetId) { - return manager.requireInputBuffer(packetId); - } - - @SuppressWarnings("deprecation") - @Override - public boolean hasPacketHandler(PacketType type) { - return PacketRegistry.getPreviousPackets().containsKey(type.getLegacyId()); - } - - @SuppressWarnings("deprecation") - @Override - public Set getPacketHandlers() { - return PacketRegistry.toPacketTypes(PacketRegistry.getPreviousPackets().keySet(), Sender.CLIENT); - } - - // Called from the ReadPacketModified monitor - public PacketEvent packetRecieved(PacketContainer packet, InputStream input, byte[] buffered) { - if (playerInjection.canRecievePackets()) { - return playerInjection.handlePacketRecieved(packet, input, buffered); - } - - try { - Player client = playerInjection.getPlayerByConnection((DataInputStream) input); - - // Never invoke a event if we don't know where it's from - if (client != null) { - return packetRecieved(packet, client, buffered); - } else { - // The timeout elapsed! - reporter.reportDetailed(this, Report.newBuilder(REPORT_UNKNOWN_ORIGIN_FOR_PACKET).messageParam(input, packet.getType())); - return null; - } - - } catch (InterruptedException e) { - // We will ignore this - it occurs when a player disconnects - //reporter.reportDetailed(this, "Thread was interrupted.", e, packet, input); - return null; - } - } - - @Override - public PacketEvent packetRecieved(PacketContainer packet, Player client, byte[] buffered) { - NetworkMarker marker = buffered != null ? new LegacyNetworkMarker(ConnectionSide.CLIENT_SIDE, buffered, packet.getType()) : null; - PacketEvent event = PacketEvent.fromClient(manager, packet, marker, client); - - manager.invokePacketRecieving(event); - return event; - } - - @Override - @SuppressWarnings({"rawtypes", "deprecation"}) - public synchronized void cleanupAll() { - Map overwritten = PacketRegistry.getOverwrittenPackets(); - Map previous = PacketRegistry.getPreviousPackets(); - - // Remove every packet handler - for (Integer id : previous.keySet().toArray(new Integer[0])) { - removePacketHandler(PacketType.findLegacy(id, Sender.CLIENT)); - removePacketHandler(PacketType.findLegacy(id, Sender.SERVER)); - } - - overwritten.clear(); - previous.clear(); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/ReadPacketModifier.java b/src/main/java/com/comphenix/protocol/injector/packet/ReadPacketModifier.java deleted file mode 100644 index dc401dac..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/ReadPacketModifier.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.packet; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.util.Map; - -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.injector.NetworkProcessor; -import com.google.common.collect.MapMaker; - -class ReadPacketModifier implements MethodInterceptor { - public static final ReportType REPORT_CANNOT_HANDLE_CLIENT_PACKET = new ReportType("Cannot handle client packet."); - - // A cancel marker - private static final Object CANCEL_MARKER = new Object(); - - // Common for all packets of the same type - private ProxyPacketInjector packetInjector; - private int packetID; - - // Report errors - private ErrorReporter reporter; - private NetworkProcessor processor; - - // If this is a read packet data method - private boolean isReadPacketDataMethod; - - // Whether or not a packet has been cancelled - private static Map override = new MapMaker().weakKeys().makeMap(); - - public ReadPacketModifier(int packetID, ProxyPacketInjector packetInjector, ErrorReporter reporter, boolean isReadPacketDataMethod) { - this.packetID = packetID; - this.packetInjector = packetInjector; - this.reporter = reporter; - this.processor = new NetworkProcessor(reporter); - this.isReadPacketDataMethod = isReadPacketDataMethod; - } - - /** - * Remove any packet overrides. - * @param packet - the packet to rever - */ - public static void removeOverride(Object packet) { - override.remove(packet); - } - - /** - * Retrieve the packet that overrides the methods of the given packet. - * @param packet - the given packet. - * @return Overriden object. - */ - public static Object getOverride(Object packet) { - return override.get(packet); - } - - /** - * Set the packet instance to delegate to instead, or mark the packet as cancelled. - *

- * To undo a override, use {@link #removeOverride(Object)}. - * @param packet - the packet. - * @param override - the override method. NULL to cancel this packet. - */ - public static void setOverride(Object packet, Object overridePacket) { - override.put(packet, overridePacket != null ? overridePacket : CANCEL_MARKER); - } - - /** - * Determine if the given packet has been cancelled before. - * @param packet - the packet to check. - * @return TRUE if it has been cancelled, FALSE otherwise. - */ - public static boolean isCancelled(Object packet) { - return getOverride(packet) == CANCEL_MARKER; - } - - @SuppressWarnings("deprecation") - @Override - public Object intercept(Object thisObj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - // Atomic retrieval - Object overridenObject = override.get(thisObj); - Object returnValue = null; - - // We need this in order to get the correct player - InputStream input = isReadPacketDataMethod ? (InputStream) args[0] : null; - ByteArrayOutputStream bufferStream = null; - - // See if we need to buffer the read data - if (isReadPacketDataMethod && packetInjector.requireInputBuffers(packetID)) { - CaptureInputStream captured = new CaptureInputStream( - input, bufferStream = new ByteArrayOutputStream()); - - // Swap it with our custom stream - args[0] = new DataInputStream(captured); - } - - if (overridenObject != null) { - // This packet has been cancelled - if (overridenObject == CANCEL_MARKER) { - // So, cancel all void methods - if (method.getReturnType().equals(Void.TYPE)) - return null; - else // Revert to normal for everything else - overridenObject = thisObj; - } - - returnValue = proxy.invokeSuper(overridenObject, args); - } else { - returnValue = proxy.invokeSuper(thisObj, args); - } - - // Is this a readPacketData method? - if (isReadPacketDataMethod) { - // Swap back custom stream - args[0] = input; - - try { - byte[] buffer = bufferStream != null ? bufferStream.toByteArray() : null; - - // Let the people know - PacketType type = PacketType.findLegacy(packetID, Sender.CLIENT); - PacketContainer container = new PacketContainer(type, thisObj); - PacketEvent event = packetInjector.packetRecieved(container, input, buffer); - - // Handle override - if (event != null) { - Object result = event.getPacket().getHandle(); - - if (event.isCancelled()) { - override.put(thisObj, CANCEL_MARKER); - return returnValue; - } else if (!objectEquals(thisObj, result)) { - override.put(thisObj, result); - } - - // This is fine - received packets are enqueued in any case - NetworkMarker marker = NetworkMarker.getNetworkMarker(event); - processor.invokePostEvent(event, marker); - } - - } catch (OutOfMemoryError e) { - throw e; - } catch (ThreadDeath e) { - throw e; - } catch (Throwable e) { - // Minecraft cannot handle this error - reporter.reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_HANDLE_CLIENT_PACKET).callerParam(args[0]).error(e) - ); - } - } - return returnValue; - } - - private boolean objectEquals(Object a, Object b) { - return System.identityHashCode(a) != System.identityHashCode(b); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/WritePacketModifier.java b/src/main/java/com/comphenix/protocol/injector/packet/WritePacketModifier.java deleted file mode 100644 index 907e57f6..00000000 --- a/src/main/java/com/comphenix/protocol/injector/packet/WritePacketModifier.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.packet; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.lang.reflect.Method; -import java.util.Map; - -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.injector.NetworkProcessor; -import com.google.common.collect.MapMaker; - -public class WritePacketModifier implements MethodInterceptor { - public static final ReportType REPORT_CANNOT_WRITE_SERVER_PACKET = new ReportType("Cannot write server packet."); - - private static class ProxyInformation { - // Marker that contains custom writers - public final Object proxyObject; - public final PacketEvent event; - public final NetworkMarker marker; - - public ProxyInformation(Object proxyObject, PacketEvent event, NetworkMarker marker) { - this.proxyObject = proxyObject; - this.event = event; - this.marker = marker; - } - } - - private Map proxyLookup = new MapMaker().weakKeys().makeMap(); - - // Report errors - private final ErrorReporter reporter; - private final NetworkProcessor processor; - - // Whether or not this represents the write method - private boolean isWriteMethod; - - public WritePacketModifier(ErrorReporter reporter, boolean isWriteMethod) { - this.reporter = reporter; - this.processor = new NetworkProcessor(reporter); - this.isWriteMethod = isWriteMethod; - } - - /** - * Associate the given generated instance of a class and the given parameteters. - * @param generatedClass - the generated class. - * @param proxyObject - the object to call from the generated class. - * @param event - the packet event. - * @param marker - the network marker. - */ - public void register(Object generatedClass, Object proxyObject, PacketEvent event, NetworkMarker marker) { - proxyLookup.put(generatedClass, new ProxyInformation(proxyObject, event, marker)); - } - - @Override - public Object intercept(Object thisObj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - ProxyInformation information = proxyLookup.get(thisObj); - - if (information == null) { - // This is really bad - someone forgot to register the proxy - throw new RuntimeException("Cannot find proxy information for " + thisObj); - } - - if (isWriteMethod) { - // If every output handler has been removed - ignore everything - if (!information.marker.getOutputHandlers().isEmpty()) { - try { - DataOutput output = (DataOutput) args[0]; - - // First - we need the initial buffer - ByteArrayOutputStream outputBufferStream = new ByteArrayOutputStream(); - proxy.invoke(information.proxyObject, new Object[] { new DataOutputStream(outputBufferStream) }); - - // Let each handler prepare the actual output - byte[] outputBuffer = processor.processOutput(information.event, information.marker, - outputBufferStream.toByteArray()); - - // Write that output to the network stream - output.write(outputBuffer); - - // We're done - processor.invokePostEvent(information.event, information.marker); - return null; - - } catch (OutOfMemoryError e) { - throw e; - } catch (ThreadDeath e) { - throw e; - } catch (Throwable e) { - // Minecraft cannot handle this error - reporter.reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_WRITE_SERVER_PACKET).callerParam(args[0]).error(e) - ); - } - } - - // Invoke this write method first - proxy.invoke(information.proxyObject, args); - processor.invokePostEvent(information.event, information.marker); - return null; - } - - // Default to the super method - return proxy.invoke(information.proxyObject, args); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java b/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java deleted file mode 100644 index 9e3a832b..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Set; -import java.util.concurrent.ConcurrentMap; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket; -import com.comphenix.protocol.utility.EnhancerFactory; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.google.common.collect.MapMaker; - -/** - * The array list that notifies when packets are sent by the server. - * - * @author Kristian - */ -class InjectedArrayList extends ArrayList { - public static final ReportType REPORT_CANNOT_REVERT_CANCELLED_PACKET = new ReportType("Reverting cancelled packet failed."); - - /** - * Silly Eclipse. - */ - private static final long serialVersionUID = -1173865905404280990L; - - // Fake inverted proxy objects - private static ConcurrentMap delegateLookup = new MapMaker().weakKeys().makeMap(); - - private transient PlayerInjector injector; - private transient Set ignoredPackets; - - private transient InvertedIntegerCallback callback; - - public InjectedArrayList(PlayerInjector injector, Set ignoredPackets) { - this.injector = injector; - this.ignoredPackets = ignoredPackets; - this.callback = new InvertedIntegerCallback(); - } - - @Override - public boolean add(Object packet) { - - Object result = null; - - // Check for fake packets and ignored packets - if (packet instanceof FakePacket) { - return true; - } else if (ignoredPackets.contains(packet)) { - // Don't send it to the filters - result = ignoredPackets.remove(packet); - } else { - result = injector.handlePacketSending(packet); - } - - // A NULL packet indicate cancelling - try { - if (result != null) { - super.add(result); - } else { - // We'll use the FakePacket marker instead of preventing the filters - injector.sendServerPacket(createNegativePacket(packet), null, true); - } - - // Collection.add contract - return true; - - } catch (InvocationTargetException e) { - // Prefer to report this to the user, instead of risking sending it to Minecraft - ProtocolLibrary.getErrorReporter().reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_REVERT_CANCELLED_PACKET).error(e).callerParam(packet) - ); - - // Failure - return false; - } - } - - /** - * Used by a hack that reverses the effect of a cancelled packet. Returns a packet - * whereby every int method's return value is inverted (a => -a). - * - * @param source - packet to invert. - * @return The inverted packet. - */ - @SuppressWarnings("deprecation") - Object createNegativePacket(Object source) { - ListenerInvoker invoker = injector.getInvoker(); - - PacketType type = invoker.getPacketType(source); - - // We want to subtract the byte amount that were added to the running - // total of outstanding packets. Otherwise, cancelling too many packets - // might cause a "disconnect.overflow" error. - // - // We do that by constructing a special packet of the same type that returns - // a negative integer for all zero-parameter integer methods. This includes the - // size() method, which is used by the queue method to count the number of - // bytes to add. - // - // Essentially, we have: - // - // public class NegativePacket extends [a packet] { - // @Override - // public int size() { - // return -super.size(); - // } - // ect. - // } - Enhancer ex = EnhancerFactory.getInstance().createEnhancer(); - ex.setSuperclass(MinecraftReflection.getPacketClass()); - ex.setInterfaces(new Class[] { FakePacket.class } ); - ex.setUseCache(true); - ex.setCallbackType(InvertedIntegerCallback.class); - - Class proxyClass = ex.createClass(); - Enhancer.registerCallbacks(proxyClass, new Callback[] { callback }); - - try { - // Temporarily associate the fake packet class - invoker.registerPacketClass(proxyClass, type.getLegacyId()); - Object proxy = proxyClass.newInstance(); - - InjectedArrayList.registerDelegate(proxy, source); - return proxy; - - } catch (Exception e) { - // Don't pollute the throws tree - throw new RuntimeException("Cannot create fake class.", e); - } finally { - // Remove this association - invoker.unregisterPacketClass(proxyClass); - } - } - - /** - * Ensure that the inverted integer proxy uses the given object as source. - * @param proxy - inverted integer proxy. - * @param source - source object. - */ - private static void registerDelegate(Object proxy, Object source) { - delegateLookup.put(proxy, source); - } - - /** - * Inverts the integer result of every integer method. - * @author Kristian - */ - private class InvertedIntegerCallback implements MethodInterceptor { - @Override - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - final Object delegate = delegateLookup.get(obj); - - if (delegate == null) { - throw new IllegalStateException("Unable to find delegate source for " + obj); - } - - if (method.getReturnType().equals(int.class) && args.length == 0) { - Integer result = (Integer) proxy.invoke(delegate, args); - return -result; - } else { - return proxy.invoke(delegate, args); - } - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/InjectedServerConnection.java b/src/main/java/com/comphenix/protocol/injector/player/InjectedServerConnection.java deleted file mode 100644 index 95284548..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/InjectedServerConnection.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import net.sf.cglib.proxy.Factory; - -import org.bukkit.Server; - -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.injector.server.AbstractInputStreamLookup; -import com.comphenix.protocol.reflect.FieldAccessException; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.ObjectWriter; -import com.comphenix.protocol.reflect.VolatileField; -import com.comphenix.protocol.utility.MinecraftReflection; - -/** - * Used to ensure that the 1.3 server is referencing the correct server handler. - * - * @author Kristian - */ -public class InjectedServerConnection { - // A number of things can go wrong ... - public static final ReportType REPORT_CANNOT_FIND_MINECRAFT_SERVER = new ReportType("Cannot extract minecraft server from Bukkit."); - public static final ReportType REPORT_CANNOT_INJECT_SERVER_CONNECTION = new ReportType("Cannot inject into server connection. Bad things will happen."); - - public static final ReportType REPORT_CANNOT_FIND_LISTENER_THREAD = new ReportType("Cannot find listener thread in MinecraftServer."); - public static final ReportType REPORT_CANNOT_READ_LISTENER_THREAD = new ReportType("Unable to read the listener thread."); - - public static final ReportType REPORT_CANNOT_FIND_SERVER_CONNECTION = new ReportType("Unable to retrieve server connection"); - public static final ReportType REPORT_UNEXPECTED_THREAD_COUNT = new ReportType("Unexpected number of threads in %s: %s"); - public static final ReportType REPORT_CANNOT_FIND_NET_HANDLER_THREAD = new ReportType("Unable to retrieve net handler thread."); - public static final ReportType REPORT_INSUFFICENT_THREAD_COUNT = new ReportType("Unable to inject %s lists in %s."); - - public static final ReportType REPORT_CANNOT_COPY_OLD_TO_NEW = new ReportType("Cannot copy old %s to new."); - - private static Field listenerThreadField; - private static Field minecraftServerField; - private static Field listField; - private static Field dedicatedThreadField; - - private static Method serverConnectionMethod; - - private List listFields; - private List> replacedLists; - - // The current detected server socket - public enum ServerSocketType { - SERVER_CONNECTION, - LISTENER_THREAD, - } - - // Used to inject net handlers - private NetLoginInjector netLoginInjector; - - // Inject server connections - private AbstractInputStreamLookup socketInjector; - - // Detected by the initializer - private ServerSocketType socketType; - - private Server server; - private ErrorReporter reporter; - private boolean hasAttempted; - private boolean hasSuccess; - - private Object minecraftServer = null; - - public InjectedServerConnection(ErrorReporter reporter, AbstractInputStreamLookup socketInjector, Server server, NetLoginInjector netLoginInjector) { - this.listFields = new ArrayList(); - this.replacedLists = new ArrayList>(); - this.reporter = reporter; - this.server = server; - this.socketInjector = socketInjector; - this.netLoginInjector = netLoginInjector; - } - - /** - * Retrieve the current server connection. - * @param reporter - error reproter. - * @param server - the current server. - * @return The current server connection, or NULL if it hasn't been initialized yet. - * @throws FieldAccessException Reflection error. - */ - public static Object getServerConnection(ErrorReporter reporter, Server server) { - try { - // Now we are probably able to check for Netty - InjectedServerConnection inspector = new InjectedServerConnection(reporter, null, server, null); - return inspector.getServerConnection(); - } catch (IllegalAccessException e) { - throw new FieldAccessException("Reflection error.", e); - } catch (IllegalArgumentException e) { - throw new FieldAccessException("Corrupt data.", e); - } catch (InvocationTargetException e) { - throw new FieldAccessException("Minecraft error.", e); - } - } - - /** - * Initial reflective detective work. Will be automatically called by most methods in this class. - */ - public void initialize() { - // Only execute this method once - if (!hasAttempted) - hasAttempted = true; - else - return; - - if (minecraftServerField == null) - minecraftServerField = FuzzyReflection.fromObject(server, true). - getFieldByType("MinecraftServer", MinecraftReflection.getMinecraftServerClass()); - - try { - minecraftServer = FieldUtils.readField(minecraftServerField, server, true); - } catch (IllegalAccessException e1) { - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_FIND_MINECRAFT_SERVER)); - return; - } - - try { - if (serverConnectionMethod == null) - serverConnectionMethod = FuzzyReflection.fromClass(minecraftServerField.getType()). - getMethodByParameters("getServerConnection", - MinecraftReflection.getServerConnectionClass(), new Class[] {}); - // We're using Minecraft 1.3.1 - socketType = ServerSocketType.SERVER_CONNECTION; - - } catch (IllegalArgumentException e) { - // Minecraft 1.2.5 or lower - socketType = ServerSocketType.LISTENER_THREAD; - - } catch (Exception e) { - // Oh damn - inform the player - reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_INJECT_SERVER_CONNECTION).error(e)); - } - } - - /** - * Retrieve the known server socket type. - *

- * This depends on the version of CraftBukkit we are using. - * @return The server socket type. - */ - public ServerSocketType getServerSocketType() { - return socketType; - } - - /** - * Inject the connection interceptor into the correct server socket implementation. - */ - public void injectList() { - initialize(); - - if (socketType == ServerSocketType.SERVER_CONNECTION) { - injectServerConnection(); - } else if (socketType == ServerSocketType.LISTENER_THREAD) { - injectListenerThread(); - } else { - // Damn it - throw new IllegalStateException("Unable to detected server connection."); - } - } - - /** - * Retrieve the listener thread field. - */ - private void initializeListenerField() { - if (listenerThreadField == null) - listenerThreadField = FuzzyReflection.fromObject(minecraftServer). - getFieldByType("networkListenThread", MinecraftReflection.getNetworkListenThreadClass()); - } - - /** - * Retrieve the listener thread object, or NULL the server isn't using this socket implementation. - * @return The listener thread, or NULL. - * @throws IllegalAccessException Cannot access field. - * @throws RuntimeException Unexpected class structure - the field doesn't exist. - */ - public Object getListenerThread() throws RuntimeException, IllegalAccessException { - initialize(); - - if (socketType == ServerSocketType.LISTENER_THREAD) { - initializeListenerField(); - return listenerThreadField.get(minecraftServer); - } else { - return null; - } - } - - /** - * Retrieve the server connection object, or NULL if the server isn't using it as the socket implementation. - * @return The socket connection, or NULL. - * @throws IllegalAccessException If the reflective operation failed. - * @throws IllegalArgumentException If the reflective operation failed. - * @throws InvocationTargetException If the reflective operation failed. - */ - public Object getServerConnection() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - initialize(); - - if (socketType == ServerSocketType.SERVER_CONNECTION) - return serverConnectionMethod.invoke(minecraftServer); - else - return null; - } - - private void injectListenerThread() { - try { - initializeListenerField(); - } catch (RuntimeException e) { - reporter.reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_FIND_LISTENER_THREAD).callerParam(minecraftServer).error(e) - ); - return; - } - - Object listenerThread = null; - - // Attempt to get the thread - try { - listenerThread = getListenerThread(); - } catch (Exception e) { - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_READ_LISTENER_THREAD).error(e)); - return; - } - - // Inject the server socket too - injectServerSocket(listenerThread); - - // Just inject every list field we can get - injectEveryListField(listenerThread, 1); - hasSuccess = true; - } - - private void injectServerConnection() { - Object serverConnection = null; - - // Careful - we might fail - try { - serverConnection = getServerConnection(); - } catch (Exception e) { - reporter.reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_FIND_SERVER_CONNECTION).callerParam(minecraftServer).error(e) - ); - return; - } - - if (listField == null) - listField = FuzzyReflection.fromClass(serverConnectionMethod.getReturnType(), true). - getFieldByType("netServerHandlerList", List.class); - if (dedicatedThreadField == null) { - List matches = FuzzyReflection.fromObject(serverConnection, true). - getFieldListByType(Thread.class); - - // Verify the field count - if (matches.size() != 1) - reporter.reportWarning(this, - Report.newBuilder(REPORT_UNEXPECTED_THREAD_COUNT).messageParam(serverConnection.getClass(), matches.size()) - ); - else - dedicatedThreadField = matches.get(0); - } - - // Next, try to get the dedicated thread - try { - if (dedicatedThreadField != null) { - Object dedicatedThread = FieldUtils.readField(dedicatedThreadField, serverConnection, true); - - // Inject server socket and NetServerHandlers. - injectServerSocket(dedicatedThread); - injectEveryListField(dedicatedThread, 1); - } - } catch (IllegalAccessException e) { - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_FIND_NET_HANDLER_THREAD).error(e)); - } - - injectIntoList(serverConnection, listField); - hasSuccess = true; - } - - private void injectServerSocket(Object container) { - socketInjector.inject(container); - } - - /** - * Automatically inject into every List-compatible public or private field of the given object. - * @param container - container object with the fields to inject. - * @param minimum - the minimum number of fields we expect exists. - */ - private void injectEveryListField(Object container, int minimum) { - // Ok, great. Get every list field - List lists = FuzzyReflection.fromObject(container, true).getFieldListByType(List.class); - - for (Field list : lists) { - injectIntoList(container, list); - } - - // Warn about unexpected errors - if (lists.size() < minimum) { - reporter.reportWarning(this, Report.newBuilder(REPORT_INSUFFICENT_THREAD_COUNT).messageParam(minimum, container.getClass())); - } - } - - @SuppressWarnings("unchecked") - private void injectIntoList(Object instance, Field field) { - VolatileField listFieldRef = new VolatileField(field, instance, true); - List list = (List) listFieldRef.getValue(); - - // Careful not to inject twice - if (list instanceof ReplacedArrayList) { - replacedLists.add((ReplacedArrayList) list); - } else { - ReplacedArrayList injectedList = createReplacement(list); - - replacedLists.add(injectedList); - listFieldRef.setValue(injectedList); - listFields.add(listFieldRef); - } - } - - // Hack to avoid the "moved to quickly" error - private ReplacedArrayList createReplacement(List list) { - return new ReplacedArrayList(list) { - /** - * Shut up Eclipse! - */ - private static final long serialVersionUID = 2070481080950500367L; - - // Object writer we'll use - private final ObjectWriter writer = new ObjectWriter(); - - @Override - protected void onReplacing(Object inserting, Object replacement) { - // Is this a normal Minecraft object? - if (!(inserting instanceof Factory)) { - // If so, copy the content of the old element to the new - try { - writer.copyTo(inserting, replacement, inserting.getClass()); - } catch (OutOfMemoryError e) { - throw e; - } catch (ThreadDeath e) { - throw e; - } catch (Throwable e) { - reporter.reportDetailed(InjectedServerConnection.this, - Report.newBuilder(REPORT_CANNOT_COPY_OLD_TO_NEW).messageParam(inserting).callerParam(inserting, replacement).error(e) - ); - } - } - } - - @Override - protected void onInserting(Object inserting) { - // Ready for some login handler injection? - if (MinecraftReflection.isLoginHandler(inserting)) { - Object replaced = netLoginInjector.onNetLoginCreated(inserting); - - // Only replace if it has changed - if (inserting != replaced) - addMapping(inserting, replaced, true); - } - } - - @Override - protected void onRemoved(Object removing) { - // Clean up? - if (MinecraftReflection.isLoginHandler(removing)) { - netLoginInjector.cleanup(removing); - } - } - }; - } - - /** - * Replace the server handler instance kept by the "keep alive" object. - * @param oldHandler - old server handler. - * @param newHandler - new, proxied server handler. - */ - public void replaceServerHandler(Object oldHandler, Object newHandler) { - if (!hasAttempted) { - injectList(); - } - - if (hasSuccess) { - for (ReplacedArrayList replacedList : replacedLists) { - replacedList.addMapping(oldHandler, newHandler); - } - } - } - - /** - * Revert to the old vanilla server handler, if it has been replaced. - * @param oldHandler - old vanilla server handler. - */ - public void revertServerHandler(Object oldHandler) { - if (hasSuccess) { - for (ReplacedArrayList replacedList : replacedLists) { - replacedList.removeMapping(oldHandler); - } - } - } - - /** - * Undoes everything. - */ - public void cleanupAll() { - if (replacedLists.size() > 0) { - // Repair the underlying lists - for (ReplacedArrayList replacedList : replacedLists) { - replacedList.revertAll(); - } - for (VolatileField field : listFields) { - field.revertValue(); - } - - listFields.clear(); - replacedLists.clear(); - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/NetLoginInjector.java b/src/main/java/com/comphenix/protocol/injector/player/NetLoginInjector.java deleted file mode 100644 index 0deec025..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/NetLoginInjector.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.util.concurrent.ConcurrentMap; - -import org.bukkit.Server; -import org.bukkit.entity.Player; - -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.player.PlayerInjectionHandler.ConflictStrategy; -import com.comphenix.protocol.injector.server.TemporaryPlayerFactory; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.google.common.collect.Maps; - -/** - * Injects every NetLoginHandler created by the server. - * - * @author Kristian - */ -class NetLoginInjector { - public static final ReportType REPORT_CANNOT_HOOK_LOGIN_HANDLER = new ReportType("Unable to hook %s."); - public static final ReportType REPORT_CANNOT_CLEANUP_LOGIN_HANDLER = new ReportType("Cannot cleanup %s."); - - private ConcurrentMap injectedLogins = Maps.newConcurrentMap(); - - // Handles every hook - private ProxyPlayerInjectionHandler injectionHandler; - - // Create temporary players - private TemporaryPlayerFactory playerFactory = new TemporaryPlayerFactory(); - - // The current error reporter - private ErrorReporter reporter; - private Server server; - - public NetLoginInjector(ErrorReporter reporter, Server server, ProxyPlayerInjectionHandler injectionHandler) { - this.reporter = reporter; - this.server = server; - this.injectionHandler = injectionHandler; - } - - /** - * Invoked when a NetLoginHandler has been created. - * @param inserting - the new NetLoginHandler. - * @return An injected NetLoginHandler, or the original object. - */ - public Object onNetLoginCreated(Object inserting) { - try { - // Make sure we actually need to inject during this phase - if (!injectionHandler.isInjectionNecessary(GamePhase.LOGIN)) - return inserting; - - Player temporary = playerFactory.createTemporaryPlayer(server); - // Note that we bail out if there's an existing player injector - PlayerInjector injector = injectionHandler.injectPlayer( - temporary, inserting, ConflictStrategy.BAIL_OUT, GamePhase.LOGIN); - - if (injector != null) { - // Update injector as well - TemporaryPlayerFactory.setInjectorInPlayer(temporary, injector); - injector.updateOnLogin = true; - - // Save the login - injectedLogins.putIfAbsent(inserting, injector); - } - - // NetServerInjector can never work (currently), so we don't need to replace the NetLoginHandler - return inserting; - - } catch (OutOfMemoryError e) { - throw e; - } catch (ThreadDeath e) { - throw e; - } catch (Throwable e) { - // Minecraft can't handle this, so we'll deal with it here - reporter.reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_HOOK_LOGIN_HANDLER). - messageParam(MinecraftReflection.getNetLoginHandlerName()). - callerParam(inserting, injectionHandler). - error(e) - ); - return inserting; - } - } - - /** - * Invoked when a NetLoginHandler should be reverted. - * @param inserting - the original NetLoginHandler. - * @return An injected NetLoginHandler, or the original object. - */ - public synchronized void cleanup(Object removing) { - PlayerInjector injected = injectedLogins.get(removing); - - if (injected != null) { - try { - PlayerInjector newInjector = null; - Player player = injected.getPlayer(); - - // Clean up list - injectedLogins.remove(removing); - - // No need to clean up twice - if (injected.isClean()) - return; - - // Hack to clean up other references - newInjector = injectionHandler.getInjectorByNetworkHandler(injected.getNetworkManager()); - injectionHandler.uninjectPlayer(player); - - // Update NetworkManager - if (newInjector != null) { - if (injected instanceof NetworkObjectInjector) { - newInjector.setNetworkManager(injected.getNetworkManager(), true); - } - } - - } catch (OutOfMemoryError e) { - throw e; - } catch (ThreadDeath e) { - throw e; - } catch (Throwable e) { - // Don't leak this to Minecraft - reporter.reportDetailed(this, - Report.newBuilder(REPORT_CANNOT_CLEANUP_LOGIN_HANDLER). - messageParam(MinecraftReflection.getNetLoginHandlerName()). - callerParam(removing). - error(e) - ); - } - } - } - - /** - * Remove all injected hooks. - */ - public void cleanupAll() { - for (PlayerInjector injector : injectedLogins.values()) { - injector.cleanupAll(); - } - - injectedLogins.clear(); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/NetworkFieldInjector.java b/src/main/java/com/comphenix/protocol/injector/player/NetworkFieldInjector.java deleted file mode 100644 index 37e44421..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/NetworkFieldInjector.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.bukkit.entity.Player; - -import com.comphenix.protocol.Packets; -import com.comphenix.protocol.concurrency.IntegerSet; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.events.ListeningWhitelist; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PlayerInjectHooks; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.reflect.VolatileField; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.google.common.collect.Sets; - -/** - * Injection hook that overrides the packet queue lists in NetworkHandler. - * - * @author Kristian - */ -class NetworkFieldInjector extends PlayerInjector { - - /** - * Marker interface that indicates a packet is fake and should not be processed. - * @author Kristian - */ - public interface FakePacket { - // Nothing - } - - // After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.), - // CraftBukkit stopped redirecting map chunk and map chunk bulk packets to a separate queue. - // Thus, NetworkFieldInjector can safely handle every packet (though not perfectly - some packets - // will be slightly processed). - private MinecraftVersion safeVersion = new MinecraftVersion("1.4.4"); - - // Packets to ignore - private Set ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap()); - - // Overridden fields - private List overridenLists = new ArrayList(); - - // Sync field - private static Field syncField; - private Object syncObject; - - // Determine if we're listening - private IntegerSet sendingFilters; - - public NetworkFieldInjector(ErrorReporter reporter, Player player, ListenerInvoker manager, IntegerSet sendingFilters) { - super(reporter, player, manager); - this.sendingFilters = sendingFilters; - } - - @Override - protected boolean hasListener(int packetID) { - return sendingFilters.contains(packetID); - } - - @Override - public synchronized void initialize(Object injectionSource) throws IllegalAccessException { - super.initialize(injectionSource); - - // Get the sync field as well - if (hasInitialized) { - if (syncField == null) - syncField = FuzzyReflection.fromObject(networkManager, true).getFieldByType("java\\.lang\\.Object"); - syncObject = FieldUtils.readField(syncField, networkManager, true); - } - } - - @Override - public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException { - if (networkManager != null) { - try { - if (!filtered) { - ignoredPackets.add(packet); - } - if (marker != null) { - queuedMarkers.put(packet, marker); - } - - // Note that invocation target exception is a wrapper for a checked exception - queueMethod.invoke(networkManager, packet); - - } catch (IllegalArgumentException e) { - throw e; - } catch (InvocationTargetException e) { - throw e; - } catch (IllegalAccessException e) { - throw new IllegalStateException("Unable to access queue method.", e); - } - } else { - throw new IllegalStateException("Unable to load network mananager. Cannot send packet."); - } - } - - @Override - public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) { - if (version != null && version.compareTo(safeVersion) > 0) { - return null; - - } else { - @SuppressWarnings("deprecation") - int[] unsupported = { Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK }; - - // Unfortunately, we don't support chunk packets - if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(), unsupported)) { - return new UnsupportedListener("The NETWORK_FIELD_INJECTOR hook doesn't support map chunk listeners.", unsupported); - } else { - return null; - } - } - } - - @Override - public void injectManager() { - if (networkManager != null) { - - @SuppressWarnings("rawtypes") - StructureModifier list = networkModifier.withType(List.class); - - // Subclass both send queues - for (Field field : list.getFields()) { - VolatileField overwriter = new VolatileField(field, networkManager, true); - - @SuppressWarnings("unchecked") - List minecraftList = (List) overwriter.getOldValue(); - - synchronized(syncObject) { - // The list we'll be inserting - List hackedList = new InjectedArrayList(this, ignoredPackets); - - // Add every previously stored packet - for (Object packet : minecraftList) { - hackedList.add(packet); - } - - // Don' keep stale packets around - minecraftList.clear(); - overwriter.setValue(Collections.synchronizedList(hackedList)); - } - - overridenLists.add(overwriter); - } - } - } - - @Override - @SuppressWarnings("unchecked") - protected void cleanHook() { - // Clean up - for (VolatileField overriden : overridenLists) { - List minecraftList = (List) overriden.getOldValue(); - List hacketList = (List) overriden.getValue(); - - if (minecraftList == hacketList) { - return; - } - - // Get a lock before we modify the list - synchronized(syncObject) { - try { - // Copy over current packets - for (Object packet : (List) overriden.getValue()) { - minecraftList.add(packet); - } - } finally { - overriden.revertValue(); - } - } - } - overridenLists.clear(); - } - - @Override - public void handleDisconnect() { - // No need to do anything - } - - @Override - public boolean canInject(GamePhase phase) { - // All phases should work - return true; - } - - @Override - public PlayerInjectHooks getHookType() { - return PlayerInjectHooks.NETWORK_HANDLER_FIELDS; - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/NetworkObjectInjector.java b/src/main/java/com/comphenix/protocol/injector/player/NetworkObjectInjector.java deleted file mode 100644 index 41bf8e75..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/NetworkObjectInjector.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.LazyLoader; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - -import org.bukkit.Server; -import org.bukkit.entity.Player; - -import com.comphenix.protocol.Packets; -import com.comphenix.protocol.concurrency.IntegerSet; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.events.ListeningWhitelist; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PlayerInjectHooks; -import com.comphenix.protocol.injector.server.TemporaryPlayerFactory; -import com.comphenix.protocol.utility.EnhancerFactory; -import com.comphenix.protocol.utility.MinecraftVersion; - -/** - * Injection method that overrides the NetworkHandler itself, and its queue-method. - * - * @author Kristian - */ -public class NetworkObjectInjector extends PlayerInjector { - // Determine if we're listening - private IntegerSet sendingFilters; - - // After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.), - // CraftBukkit stopped redirecting map chunk and map chunk bulk packets to a separate queue. - // Thus, NetworkFieldInjector can safely handle every packet (though not perfectly - some packets - // will be slightly processed). - private MinecraftVersion safeVersion = new MinecraftVersion("1.4.4"); - - // Shared callback filter - avoid creating a new class every time - private volatile static CallbackFilter callbackFilter; - - // Temporary player factory - private static volatile TemporaryPlayerFactory tempPlayerFactory; - - /** - * Create a new network object injector. - *

- * Note: This class is intended to be internal. Do not use. - * @param reporter - the error reporter. - * @param player - the player Bukkit entity. - * @param invoker - the packet invoker. - * @param sendingFilters - list of permitted packet IDs. - * @throws IllegalAccessException If reflection failed. - */ - public NetworkObjectInjector(ErrorReporter reporter, Player player, - ListenerInvoker invoker, IntegerSet sendingFilters) throws IllegalAccessException { - - super(reporter, player, invoker); - this.sendingFilters = sendingFilters; - } - - @Override - protected boolean hasListener(int packetID) { - return sendingFilters.contains(packetID); - } - - /** - * Create a temporary player for use during login. - * @param server - Bukkit server. - * @return The temporary player. - */ - public Player createTemporaryPlayer(Server server) { - if (tempPlayerFactory == null) - tempPlayerFactory = new TemporaryPlayerFactory(); - - // Create and associate the fake player with this network injector - return tempPlayerFactory.createTemporaryPlayer(server, this); - } - - @Override - public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException { - Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue(); - - if (networkDelegate != null) { - try { - if (marker != null) { - queuedMarkers.put(packet, marker); - } - - // Note that invocation target exception is a wrapper for a checked exception - queueMethod.invoke(networkDelegate, packet); - - } catch (IllegalArgumentException e) { - throw e; - } catch (InvocationTargetException e) { - throw e; - } catch (IllegalAccessException e) { - throw new IllegalStateException("Unable to access queue method.", e); - } - } else { - throw new IllegalStateException("Unable to load network mananager. Cannot send packet."); - } - } - - @Override - public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) { - if (version != null && version.compareTo(safeVersion) > 0) { - return null; - - } else { - @SuppressWarnings("deprecation") - int[] unsupported = { Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK }; - - // Unfortunately, we don't support chunk packets - if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(), unsupported)) { - return new UnsupportedListener("The NETWORK_OBJECT_INJECTOR hook doesn't support map chunk listeners.", unsupported); - } else { - return null; - } - } - } - - @Override - public void injectManager() { - - if (networkManager != null) { - final Class networkInterface = networkManagerRef.getField().getType(); - final Object networkDelegate = networkManagerRef.getOldValue(); - - if (!networkInterface.isInterface()) { - throw new UnsupportedOperationException( - "Must use CraftBukkit 1.3.0 or later to inject into into NetworkMananger."); - } - - Callback queueFilter = new MethodInterceptor() { - @Override - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - Object packet = args[0]; - - if (packet != null) { - packet = handlePacketSending(packet); - - // A NULL packet indicate cancelling - if (packet != null) - args[0] = packet; - else - return null; - } - - // Delegate to our underlying class - return proxy.invokeSuper(networkDelegate, args); - } - }; - Callback dispatch = new LazyLoader() { - @Override - public Object loadObject() throws Exception { - return networkDelegate; - } - }; - - // Share callback filter - that way, we avoid generating a new class every time. - if (callbackFilter == null) { - callbackFilter = new CallbackFilter() { - @Override - public int accept(Method method) { - if (method.equals(queueMethod)) - return 0; - else - return 1; - } - }; - } - - // Create our proxy object - Enhancer ex = EnhancerFactory.getInstance().createEnhancer(); - ex.setSuperclass(networkInterface); - ex.setCallbacks(new Callback[] { queueFilter, dispatch }); - ex.setCallbackFilter(callbackFilter); - - // Inject it, if we can. - networkManagerRef.setValue(ex.create()); - } - } - - @Override - protected void cleanHook() { - // Clean up - if (networkManagerRef != null && networkManagerRef.isCurrentSet()) { - networkManagerRef.revertValue(); - } - } - - @Override - public void handleDisconnect() { - // No need to do anything - } - - @Override - public boolean canInject(GamePhase phase) { - // Works for all phases - return true; - } - - @Override - public PlayerInjectHooks getHookType() { - return PlayerInjectHooks.NETWORK_MANAGER_OBJECT; - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/NetworkServerInjector.java b/src/main/java/com/comphenix/protocol/injector/player/NetworkServerInjector.java deleted file mode 100644 index e1063f27..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/NetworkServerInjector.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.Factory; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; -import net.sf.cglib.proxy.NoOp; - -import org.bukkit.entity.Player; - -import com.comphenix.protocol.concurrency.IntegerSet; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PlayerInjectHooks; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.ObjectWriter; -import com.comphenix.protocol.reflect.VolatileField; -import com.comphenix.protocol.reflect.instances.DefaultInstances; -import com.comphenix.protocol.reflect.instances.ExistingGenerator; -import com.comphenix.protocol.utility.EnhancerFactory; -import com.comphenix.protocol.utility.MinecraftMethods; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.utility.MinecraftVersion; - -/** - * Represents a player hook into the NetServerHandler class. - * - * @author Kristian - */ -class NetworkServerInjector extends PlayerInjector { - // Disconnected field - public static final ReportType REPORT_ASSUMING_DISCONNECT_FIELD = new ReportType("Unable to find 'disconnected' field. Assuming %s."); - public static final ReportType REPORT_DISCONNECT_FIELD_MISSING = new ReportType("Cannot find disconnected field. Is ProtocolLib up to date?"); - public static final ReportType REPORT_DISCONNECT_FIELD_FAILURE = new ReportType("Unable to update disconnected field. Player quit event may be sent twice."); - - private volatile static CallbackFilter callbackFilter; - private volatile static boolean foundSendPacket; - - private volatile static Field disconnectField; - private InjectedServerConnection serverInjection; - - // Determine if we're listening - private IntegerSet sendingFilters; - - // Whether or not the player has disconnected - private boolean hasDisconnected; - - // Used to copy fields - private final ObjectWriter writer = new ObjectWriter(); - - public NetworkServerInjector( - ErrorReporter reporter, Player player, - ListenerInvoker invoker, IntegerSet sendingFilters, - InjectedServerConnection serverInjection) { - super(reporter, player, invoker); - this.sendingFilters = sendingFilters; - this.serverInjection = serverInjection; - } - - @Override - protected boolean hasListener(int packetID) { - return sendingFilters.contains(packetID); - } - - @Override - public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException { - Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue(); - - if (serverDelegate != null) { - try { - if (marker != null) { - queuedMarkers.put(packet, marker); - } - - // Note that invocation target exception is a wrapper for a checked exception - MinecraftMethods.getSendPacketMethod().invoke(serverDelegate, packet); - - } catch (IllegalArgumentException e) { - throw e; - } catch (InvocationTargetException e) { - throw e; - } catch (IllegalAccessException e) { - throw new IllegalStateException("Unable to access send packet method.", e); - } - } else { - throw new IllegalStateException("Unable to load server handler. Cannot send packet."); - } - } - - @Override - public void injectManager() { - if (serverHandlerRef == null) - throw new IllegalStateException("Cannot find server handler."); - // Don't inject twice - if (serverHandlerRef.getValue() instanceof Factory) - return; - - if (!tryInjectManager()) { - Class serverHandlerClass = MinecraftReflection.getPlayerConnectionClass(); - - // Try to override the proxied object - if (proxyServerField != null) { - serverHandlerRef = new VolatileField(proxyServerField, serverHandler, true); - serverHandler = serverHandlerRef.getValue(); - - if (serverHandler == null) - throw new RuntimeException("Cannot hook player: Inner proxy object is NULL."); - else - serverHandlerClass = serverHandler.getClass(); - - // Try again - if (tryInjectManager()) { - // It worked - probably - return; - } - } - - throw new RuntimeException( - "Cannot hook player: Unable to find a valid constructor for the " - + serverHandlerClass.getName() + " object."); - } - } - - private boolean tryInjectManager() { - Class serverClass = serverHandler.getClass(); - - Enhancer ex = EnhancerFactory.getInstance().createEnhancer(); - Callback sendPacketCallback = new MethodInterceptor() { - @Override - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - Object packet = args[0]; - - if (packet != null) { - packet = handlePacketSending(packet); - - // A NULL packet indicate cancelling - if (packet != null) - args[0] = packet; - else - return null; - } - - // Call the method directly - return proxy.invokeSuper(obj, args); - }; - }; - Callback noOpCallback = NoOp.INSTANCE; - - // Share callback filter - that way, we avoid generating a new class for - // every logged in player. - if (callbackFilter == null) { - callbackFilter = new SendMethodFilter(); - } - - ex.setSuperclass(serverClass); - ex.setCallbacks(new Callback[] { sendPacketCallback, noOpCallback }); - ex.setCallbackFilter(callbackFilter); - - // Find the Minecraft NetServerHandler superclass - Class minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass()); - ExistingGenerator generator = ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass); - DefaultInstances serverInstances = null; - - // Maybe the proxy instance can help? - Object proxyInstance = getProxyServerHandler(); - - // Use the existing server proxy when we create one - if (proxyInstance != null && proxyInstance != serverHandler) { - serverInstances = DefaultInstances.fromArray(generator, - ExistingGenerator.fromObjectArray(new Object[] { proxyInstance })); - } else { - serverInstances = DefaultInstances.fromArray(generator); - } - - serverInstances.setNonNull(true); - serverInstances.setMaximumRecursion(1); - - Object proxyObject = serverInstances.forEnhancer(ex).getDefault(serverClass); - - // Inject it now - if (proxyObject != null) { - // Did we override a sendPacket method? - if (!foundSendPacket) { - throw new IllegalArgumentException("Unable to find a sendPacket method in " + serverClass); - } - - serverInjection.replaceServerHandler(serverHandler, proxyObject); - serverHandlerRef.setValue(proxyObject); - return true; - } else { - return false; - } - } - - private Object getProxyServerHandler() { - if (proxyServerField != null && !proxyServerField.equals(serverHandlerRef.getField())) { - try { - return FieldUtils.readField(proxyServerField, serverHandler, true); - } catch (OutOfMemoryError e) { - throw e; - } catch (ThreadDeath e) { - throw e; - } catch (Throwable e) { - // Oh well - } - } - - return null; - } - - private Class getFirstMinecraftSuperClass(Class clazz) { - if (MinecraftReflection.isMinecraftClass(clazz)) - return clazz; - else if (clazz.equals(Object.class)) - return clazz; - else - return getFirstMinecraftSuperClass(clazz.getSuperclass()); - } - - @Override - protected void cleanHook() { - if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) { - writer.copyTo(serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass()); - serverHandlerRef.revertValue(); - - try { - if (getNetHandler() != null) { - // Restore packet listener - try { - FieldUtils.writeField(netHandlerField, networkManager, serverHandlerRef.getOldValue(), true); - } catch (IllegalAccessException e) { - // Oh well - e.printStackTrace(); - } - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - - // Prevent the PlayerQuitEvent from being sent twice - if (hasDisconnected) { - setDisconnect(serverHandlerRef.getValue(), true); - } - } - - serverInjection.revertServerHandler(serverHandler); - } - - @Override - public void handleDisconnect() { - hasDisconnected = true; - } - - /** - * Set the disconnected field in a NetServerHandler. - * @param handler - the NetServerHandler. - * @param value - the new value. - */ - private void setDisconnect(Object handler, boolean value) { - // Set it - try { - // Load the field - if (disconnectField == null) { - disconnectField = FuzzyReflection.fromObject(handler).getFieldByName("disconnected.*"); - } - FieldUtils.writeField(disconnectField, handler, value); - - } catch (IllegalArgumentException e) { - // Assume it's the first ... - if (disconnectField == null) { - disconnectField = FuzzyReflection.fromObject(handler).getFieldByType("disconnected", boolean.class); - reporter.reportWarning(this, Report.newBuilder(REPORT_ASSUMING_DISCONNECT_FIELD).messageParam(disconnectField)); - - // Try again - if (disconnectField != null) { - setDisconnect(handler, value); - return; - } - } - - // This is really bad - reporter.reportDetailed(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_MISSING).error(e)); - - } catch (IllegalAccessException e) { - reporter.reportWarning(this, Report.newBuilder(REPORT_DISCONNECT_FIELD_FAILURE).error(e)); - } - } - - @Override - public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) { - // We support everything - return null; - } - - @Override - public boolean canInject(GamePhase phase) { - // Doesn't work when logging in - return phase == GamePhase.PLAYING; - } - - @Override - public PlayerInjectHooks getHookType() { - return PlayerInjectHooks.NETWORK_SERVER_OBJECT; - } - - /** - * Represents a CallbackFilter that only matches the SendPacket method. - * @author Kristian - */ - private static class SendMethodFilter implements CallbackFilter { - private Method sendPacket = MinecraftMethods.getSendPacketMethod(); - - @Override - public int accept(Method method) { - if (isCallableEqual(sendPacket, method)) { - NetworkServerInjector.foundSendPacket = true; - return 0; - } else { - return 1; - } - } - - /** - * Determine if the two methods are equal in terms of call semantics. - *

- * Two methods are equal if they have the same name, parameter types and return type. - * @param first - first method. - * @param second - second method. - * @return TRUE if they are, FALSE otherwise. - */ - private boolean isCallableEqual(Method first, Method second) { - return first.getName().equals(second.getName()) && - first.getReturnType().equals(second.getReturnType()) && - Arrays.equals(first.getParameterTypes(), second.getParameterTypes()); - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java b/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java deleted file mode 100644 index 3c9879c1..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java +++ /dev/null @@ -1,760 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.io.DataInputStream; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.Map; - -import net.sf.cglib.proxy.Factory; - -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.injector.BukkitUnwrapper; -import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PlayerInjectHooks; -import com.comphenix.protocol.injector.packet.InterceptWritePacket; -import com.comphenix.protocol.injector.server.SocketInjector; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.reflect.VolatileField; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.google.common.collect.MapMaker; - -public abstract class PlayerInjector implements SocketInjector { - // Disconnect method related reports - public static final ReportType REPORT_ASSUME_DISCONNECT_METHOD = new ReportType("Cannot find disconnect method by name. Assuming %s."); - public static final ReportType REPORT_INVALID_ARGUMENT_DISCONNECT = new ReportType("Invalid argument passed to disconnect method: %s"); - public static final ReportType REPORT_CANNOT_ACCESS_DISCONNECT = new ReportType("Unable to access disconnect method."); - - public static final ReportType REPORT_CANNOT_CLOSE_SOCKET = new ReportType("Unable to close socket."); - public static final ReportType REPORT_ACCESS_DENIED_CLOSE_SOCKET = new ReportType("Insufficient permissions. Cannot close socket."); - - public static final ReportType REPORT_DETECTED_CUSTOM_SERVER_HANDLER = - new ReportType("Detected server handler proxy type by another plugin. Conflict may occur!"); - public static final ReportType REPORT_CANNOT_PROXY_SERVER_HANDLER = new ReportType("Unable to load server handler from proxy type."); - - public static final ReportType REPORT_CANNOT_UPDATE_PLAYER = new ReportType("Cannot update player in PlayerEvent."); - public static final ReportType REPORT_CANNOT_HANDLE_PACKET = new ReportType("Cannot handle server packet."); - - public static final ReportType REPORT_INVALID_NETWORK_MANAGER = new ReportType("NetworkManager doesn't appear to be valid."); - - // Net login handler stuff - private static Field netLoginNetworkField; - - // Different disconnect methods - private static Method loginDisconnect; - private static Method serverDisconnect; - - // Cache previously retrieved fields - protected static Field serverHandlerField; - protected static Field proxyServerField; - - protected static Field networkManagerField; - protected static Field netHandlerField; - protected static Field socketField; - protected static Field socketAddressField; - - private static Field inputField; - private static Field entityPlayerField; - - // Whether or not we're using a proxy type - private static boolean hasProxyType; - - // To add our injected array lists - protected static StructureModifier networkModifier; - - // And methods - protected static Method queueMethod; - protected static Method processMethod; - - protected volatile Player player; - protected boolean hasInitialized; - - // Reference to the player's network manager - protected VolatileField networkManagerRef; - protected VolatileField serverHandlerRef; - protected Object networkManager; - - // Current net handler - protected Object loginHandler; - protected Object serverHandler; - protected Object netHandler; - - // Current socket and address - protected Socket socket; - protected SocketAddress socketAddress; - - // The packet manager and filters - protected ListenerInvoker invoker; - - // Previous data input - protected DataInputStream cachedInput; - - // Handle errors - protected ErrorReporter reporter; - - // Previous markers - protected Map queuedMarkers = new MapMaker().weakKeys().makeMap(); - protected InterceptWritePacket writePacketInterceptor; - - // Whether or not the injector has been cleaned - private boolean clean; - - // Whether or not to update the current player on the first Packet1Login - boolean updateOnLogin; - volatile Player updatedPlayer; - - public PlayerInjector(ErrorReporter reporter, Player player, ListenerInvoker invoker) { - this.reporter = reporter; - this.player = player; - this.invoker = invoker; - this.writePacketInterceptor = invoker.getInterceptWritePacket(); - } - - /** - * Retrieve the notch (NMS) entity player object. - * @param player - the player to retrieve. - * @return Notch player object. - */ - protected Object getEntityPlayer(Player player) { - BukkitUnwrapper unwrapper = new BukkitUnwrapper(); - return unwrapper.unwrapItem(player); - } - - /** - * Initialize all fields for this player injector, if it hasn't already. - * @param injectionSource - Injection source - * @throws IllegalAccessException An error has occured. - */ - public void initialize(Object injectionSource) throws IllegalAccessException { - if (injectionSource == null) - throw new IllegalArgumentException("injectionSource cannot be NULL"); - - //Dispatch to the correct injection method - if (injectionSource instanceof Player) - initializePlayer((Player) injectionSource); - else if (MinecraftReflection.isLoginHandler(injectionSource)) - initializeLogin(injectionSource); - else - throw new IllegalArgumentException("Cannot initialize a player hook using a " + injectionSource.getClass().getName()); - } - - /** - * Initialize the player injector using an actual player instance. - * @param player - the player to hook. - */ - public void initializePlayer(Player player) { - Object notchEntity = getEntityPlayer(player); - - // Save the player too - this.player = player; - - if (!hasInitialized) { - // Do this first, in case we encounter an exception - hasInitialized = true; - - // Retrieve the server handler - if (serverHandlerField == null) { - serverHandlerField = FuzzyReflection.fromObject(notchEntity).getFieldByType( - "NetServerHandler", MinecraftReflection.getPlayerConnectionClass()); - proxyServerField = getProxyField(notchEntity, serverHandlerField); - } - - // Yo dawg - serverHandlerRef = new VolatileField(serverHandlerField, notchEntity); - serverHandler = serverHandlerRef.getValue(); - - // Next, get the network manager - if (networkManagerField == null) - networkManagerField = FuzzyReflection.fromObject(serverHandler).getFieldByType( - "networkManager", MinecraftReflection.getNetworkManagerClass()); - initializeNetworkManager(networkManagerField, serverHandler); - } - } - - /** - * Initialize the player injector from a NetLoginHandler. - * @param netLoginHandler - the net login handler to inject. - */ - public void initializeLogin(Object netLoginHandler) { - if (!hasInitialized) { - // Just in case - if (!MinecraftReflection.isLoginHandler(netLoginHandler)) - throw new IllegalArgumentException("netLoginHandler (" + netLoginHandler + ") is not a " + - MinecraftReflection.getNetLoginHandlerName()); - - hasInitialized = true; - loginHandler = netLoginHandler; - - if (netLoginNetworkField == null) - netLoginNetworkField = FuzzyReflection.fromObject(netLoginHandler). - getFieldByType("networkManager", MinecraftReflection.getNetworkManagerClass()); - initializeNetworkManager(netLoginNetworkField, netLoginHandler); - } - } - - private void initializeNetworkManager(Field reference, Object container) { - networkManagerRef = new VolatileField(reference, container); - networkManager = networkManagerRef.getValue(); - - // No, don't do it - if (networkManager instanceof Factory) { - return; - } - - // Create the network manager modifier from the actual object type - if (networkManager != null && networkModifier == null) - networkModifier = new StructureModifier(networkManager.getClass(), null, false); - - // And the queue method - if (queueMethod == null) - queueMethod = FuzzyReflection.fromClass(reference.getType()). - getMethodByParameters("queue", MinecraftReflection.getPacketClass()); - } - - /** - * Retrieve whether or not the server handler is a proxy object. - * @return TRUE if it is, FALSE otherwise. - */ - protected boolean hasProxyServerHandler() { - return hasProxyType; - } - - /** - * Retrieve the current network manager. - * @return Current network manager. - */ - public Object getNetworkManager() { - return networkManagerRef.getValue(); - } - - /** - * Retrieve the current server handler (PlayerConnection). - * @return Current server handler. - */ - public Object getServerHandler() { - return serverHandlerRef.getValue(); - } - - /** - * Set the current network manager. - * @param value - new network manager. - * @param force - whether or not to save this value. - */ - public void setNetworkManager(Object value, boolean force) { - networkManagerRef.setValue(value); - - if (force) - networkManagerRef.saveValue(); - initializeNetworkManager(networkManagerField, serverHandler); - } - - /** - * Retrieve the associated socket of this player. - * @return The associated socket. - * @throws IllegalAccessException If we're unable to read the socket field. - */ - @Override - public Socket getSocket() throws IllegalAccessException { - try { - if (socketField == null) - socketField = FuzzyReflection.fromObject(networkManager, true). - getFieldListByType(Socket.class).get(0); - if (socket == null) - socket = (Socket) FieldUtils.readField(socketField, networkManager, true); - return socket; - - } catch (IndexOutOfBoundsException e) { - throw new IllegalAccessException("Unable to read the socket field."); - } - } - - /** - * Retrieve the associated remote address of a player. - * @return The associated remote address. - * @throws IllegalAccessException If we're unable to read the socket address field. - */ - @Override - public SocketAddress getAddress() throws IllegalAccessException { - try { - if (socketAddressField == null) - socketAddressField = FuzzyReflection.fromObject(networkManager, true). - getFieldListByType(SocketAddress.class).get(0); - if (socketAddress == null) - socketAddress = (SocketAddress) FieldUtils.readField(socketAddressField, networkManager, true); - return socketAddress; - - } catch (IndexOutOfBoundsException e) { - // Inform about the state of the network manager too - reporter.reportWarning( - this, Report.newBuilder(REPORT_INVALID_NETWORK_MANAGER).callerParam(networkManager).build()); - throw new IllegalAccessException("Unable to read the socket address field."); - } - } - - /** - * Attempt to disconnect the current client. - * @param message - the message to display. - * @throws InvocationTargetException If disconnection failed. - */ - @Override - public void disconnect(String message) throws InvocationTargetException { - // Get a non-null handler - boolean usingNetServer = serverHandler != null; - - Object handler = usingNetServer ? serverHandler : loginHandler; - Method disconnect = usingNetServer ? serverDisconnect : loginDisconnect; - - // Execute disconnect on it - if (handler != null) { - if (disconnect == null) { - try { - disconnect = FuzzyReflection.fromObject(handler).getMethodByName("disconnect.*"); - } catch (IllegalArgumentException e) { - // Just assume it's the first String method - disconnect = FuzzyReflection.fromObject(handler).getMethodByParameters("disconnect", String.class); - reporter.reportWarning(this, Report.newBuilder(REPORT_ASSUME_DISCONNECT_METHOD).messageParam(disconnect)); - } - - // Save the method for later - if (usingNetServer) - serverDisconnect = disconnect; - else - loginDisconnect = disconnect; - } - - try { - disconnect.invoke(handler, message); - return; - } catch (IllegalArgumentException e) { - reporter.reportDetailed(this, Report.newBuilder(REPORT_INVALID_ARGUMENT_DISCONNECT).error(e).messageParam(message).callerParam(handler)); - } catch (IllegalAccessException e) { - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_ACCESS_DISCONNECT).error(e)); - } - } - - // Fuck it - try { - Socket socket = getSocket(); - - try { - socket.close(); - } catch (IOException e) { - reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_CLOSE_SOCKET).error(e).callerParam(socket)); - } - - } catch (IllegalAccessException e) { - reporter.reportWarning(this, Report.newBuilder(REPORT_ACCESS_DENIED_CLOSE_SOCKET).error(e)); - } - } - - private Field getProxyField(Object notchEntity, Field serverField) { - try { - Object currentHandler = FieldUtils.readField(serverHandlerField, notchEntity, true); - - // This is bad - if (currentHandler == null) - throw new ServerHandlerNull(); - - // See if this isn't a standard net handler class - if (!isStandardMinecraftNetHandler(currentHandler)) { - // This is our proxy object - if (currentHandler instanceof Factory) - return null; - - hasProxyType = true; - reporter.reportWarning(this, Report.newBuilder(REPORT_DETECTED_CUSTOM_SERVER_HANDLER).callerParam(serverField)); - - // No? Is it a Proxy type? - try { - FuzzyReflection reflection = FuzzyReflection.fromObject(currentHandler, true); - - // It might be - return reflection.getFieldByType("NetServerHandler", MinecraftReflection.getPlayerConnectionClass()); - - } catch (RuntimeException e) { - // Damn - } - } - - } catch (IllegalAccessException e) { - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_PROXY_SERVER_HANDLER).error(e).callerParam(notchEntity, serverField)); - } - - // Nope, just go with it - return null; - } - - /** - * Determine if a given object is a standard Minecraft net handler. - * @param obj the object to test. - * @return TRUE if it is, FALSE otherwise. - */ - private boolean isStandardMinecraftNetHandler(Object obj) { - if (obj == null) - return false; - Class clazz = obj.getClass(); - - return MinecraftReflection.getNetLoginHandlerClass().equals(clazz) || - MinecraftReflection.getPlayerConnectionClass().equals(clazz); - } - - /** - * Retrieves the current net handler for this player. - * @return Current net handler. - * @throws IllegalAccessException Unable to find or retrieve net handler. - */ - protected Object getNetHandler() throws IllegalAccessException { - return getNetHandler(false); - } - - /** - * Retrieves the current net handler for this player. - * @param refresh - Whether or not to refresh - * @return Current net handler. - * @throws IllegalAccessException Unable to find or retrieve net handler. - * @return The current net handler for this player - */ - protected Object getNetHandler(boolean refresh) throws IllegalAccessException { - // What a mess - try { - if (netHandlerField == null) - netHandlerField = FuzzyReflection.fromClass(networkManager.getClass(), true). - getFieldByType("NetHandler", MinecraftReflection.getNetHandlerClass()); - } catch (RuntimeException e1) { - // Swallow it - } - - // Second attempt - if (netHandlerField == null) { - try { - // Well, that sucks. Try just Minecraft objects then. - netHandlerField = FuzzyReflection.fromClass(networkManager.getClass(), true). - getFieldByType(MinecraftReflection.getMinecraftObjectRegex()); - - } catch (RuntimeException e2) { - throw new IllegalAccessException("Cannot locate net handler. " + e2.getMessage()); - } - } - - // Get the handler - if (netHandler == null || refresh) - netHandler = FieldUtils.readField(netHandlerField, networkManager, true); - return netHandler; - } - - /** - * Retrieve the stored entity player from a given NetHandler. - * @param netHandler - the nethandler to retrieve it from. - * @return The stored entity player. - * @throws IllegalAccessException If the reflection failed. - */ - private Object getEntityPlayer(Object netHandler) throws IllegalAccessException { - if (entityPlayerField == null) - entityPlayerField = FuzzyReflection.fromObject(netHandler).getFieldByType( - "EntityPlayer", MinecraftReflection.getEntityPlayerClass()); - return FieldUtils.readField(entityPlayerField, netHandler); - } - - /** - * Processes the given packet as if it was transmitted by the current player. - * @param packet - packet to process. - * @throws IllegalAccessException If the reflection machinery failed. - * @throws InvocationTargetException If the underlying method caused an error. - */ - public void processPacket(Object packet) throws IllegalAccessException, InvocationTargetException { - - Object netHandler = getNetHandler(); - - // Get the process method - if (processMethod == null) { - try { - processMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()). - getMethodByParameters("processPacket", netHandlerField.getType()); - } catch (RuntimeException e) { - throw new IllegalArgumentException("Cannot locate process packet method: " + e.getMessage()); - } - } - - // We're ready - try { - processMethod.invoke(packet, netHandler); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Method " + processMethod.getName() + " is not compatible."); - } catch (InvocationTargetException e) { - throw e; - } - } - - /** - * Send a packet to the client. - * @param packet - server packet to send. - * @param marker - the network marker. - * @param filtered - whether or not the packet will be filtered by our listeners. - * @throws InvocationTargetException If an error occured when sending the packet. - */ - @Override - public abstract void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException; - - /** - * Inject a hook to catch packets sent to the current player. - */ - public abstract void injectManager(); - - /** - * Remove all hooks and modifications. - */ - public final void cleanupAll() { - if (!clean) { - cleanHook(); - writePacketInterceptor.cleanup(); - } - clean = true; - } - - /** - * Clean up after the player has disconnected. - */ - public abstract void handleDisconnect(); - - /** - * Override to add custom cleanup behavior. - */ - protected abstract void cleanHook(); - - /** - * Determine whether or not this hook has already been cleaned. - * @return TRUE if it has, FALSE otherwise. - */ - public boolean isClean() { - return clean; - } - - /** - * Determine if this inject method can even be attempted. - * @param state - Game phase - * @return TRUE if can be attempted, though possibly with failure, FALSE otherwise. - */ - public abstract boolean canInject(GamePhase state); - - /** - * Retrieve the hook type this class represents. - * @return Hook type this class represents. - */ - public abstract PlayerInjectHooks getHookType(); - - /** - * Invoked before a new listener is registered. - *

- * The player injector should only return a non-null value if some or all of the packet IDs are unsupported. - * @param version - the current Minecraft version, or NULL if unknown. - * @param listener - the listener that is about to be registered. - * @return A error message with the unsupported packet IDs, or NULL if this listener is valid. - */ - public abstract UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener); - - /** - * Allows a packet to be sent by the listeners. - * @param packet - packet to sent. - * @return The given packet, or the packet replaced by the listeners. - */ - @SuppressWarnings({ "deprecation", "null" }) - public Object handlePacketSending(Object packet) { - try { - // Get the packet ID too - Integer id = invoker.getPacketID(packet); - Player currentPlayer = player; - - // Hack #1 - if (updateOnLogin) { - if (updatedPlayer == null) { - try { - final Object handler = getNetHandler(true); - - // Is this a net server class? - if (MinecraftReflection.getPlayerConnectionClass().isAssignableFrom(handler.getClass())) { - setUpdatedPlayer( - (Player) MinecraftReflection.getBukkitEntity(getEntityPlayer(handler)) - ); - } - } catch (IllegalAccessException e) { - reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLAYER).error(e).callerParam(packet)); - } - } - - // This will only occur in the NetLoginHandler injection - if (updatedPlayer != null) { - currentPlayer = updatedPlayer; - updateOnLogin = false; - } - } - - // Make sure we're listening - if (id != null && hasListener(id)) { - NetworkMarker marker = queuedMarkers.remove(packet); - - // A packet has been sent guys! - PacketType type = PacketType.findLegacy(id, Sender.SERVER); - PacketContainer container = new PacketContainer(type, packet); - PacketEvent event = PacketEvent.fromServer(invoker, container, marker, currentPlayer); - invoker.invokePacketSending(event); - - // Cancelling is pretty simple. Just ignore the packet. - if (event.isCancelled()) - return null; - - // Right, remember to replace the packet again - Object result = event.getPacket().getHandle(); - marker = NetworkMarker.getNetworkMarker(event); - - // See if we need to proxy the write method - if (result != null && (NetworkMarker.hasOutputHandlers(marker) || NetworkMarker.hasPostListeners(marker))) { - result = writePacketInterceptor.constructProxy(result, event, marker); - } - return result; - } - - } catch (OutOfMemoryError e) { - throw e; - } catch (ThreadDeath e) { - throw e; - } catch (Throwable e) { - reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_HANDLE_PACKET).error(e).callerParam(packet)); - } - - return packet; - } - - /** - * Determine if the given injector is listening for this packet ID. - * @param packetID - packet ID to check. - * @return TRUE if it is, FALSE oterhwise. - */ - protected abstract boolean hasListener(int packetID); - - /** - * Retrieve the current player's input stream. - * @param cache - whether or not to cache the result of this method. - * @return The player's input stream. - */ - public DataInputStream getInputStream(boolean cache) { - // And the data input stream that we'll use to identify a player - if (networkManager == null) - throw new IllegalStateException("Network manager is NULL."); - if (inputField == null) - inputField = FuzzyReflection.fromObject(networkManager, true). - getFieldByType("java\\.io\\.DataInputStream"); - - // Get the associated input stream - try { - if (cache && cachedInput != null) - return cachedInput; - - // Save to cache - cachedInput = (DataInputStream) FieldUtils.readField(inputField, networkManager, true); - return cachedInput; - - } catch (IllegalAccessException e) { - throw new RuntimeException("Unable to read input stream.", e); - } - } - - /** - * Retrieve the hooked player. - */ - @Override - public Player getPlayer() { - return player; - } - - /** - * Set the hooked player. - *

- * Should only be called during the creation of the injector. - * @param player - the new hooked player. - */ - public void setPlayer(Player player) { - this.player = player; - } - - /** - * Object that can invoke the packet events. - * @return Packet event invoker. - */ - public ListenerInvoker getInvoker() { - return invoker; - } - - /** - * Retrieve the hooked player object OR the more up-to-date player instance. - * @return The hooked player, or a more up-to-date instance. - */ - @Override - public Player getUpdatedPlayer() { - if (updatedPlayer != null) - return updatedPlayer; - else - return player; - } - - @Override - public void transferState(SocketInjector delegate) { - // Do nothing - } - - @Override - public void setUpdatedPlayer(Player updatedPlayer) { - this.updatedPlayer = updatedPlayer; - } - - /** - * Indicates that a player's NetServerHandler or PlayerConnection was NULL. - *

- * This is usually because the player has just logged out, or due to it being a "fake" player in MCPC+/Cauldron. - * @author Kristian - */ - public static class ServerHandlerNull extends IllegalAccessError { - private static final long serialVersionUID = 1L; - - public ServerHandlerNull() { - super("Unable to fetch server handler: was NUll."); - } - - public ServerHandlerNull(String s) { - super(s); - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectorBuilder.java b/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectorBuilder.java deleted file mode 100644 index 3319d5c6..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectorBuilder.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.comphenix.protocol.injector.player; - -import java.util.Set; - -import javax.annotation.Nonnull; - -import org.bukkit.Bukkit; -import org.bukkit.Server; - -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PacketFilterManager; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; - -/** - * Constructor for different player injectors. - * - * @author Kristian - */ -public class PlayerInjectorBuilder { - public static PlayerInjectorBuilder newBuilder() { - return new PlayerInjectorBuilder(); - } - - protected PlayerInjectorBuilder() { - // Use the static method. - } - - protected ErrorReporter reporter; - protected Predicate injectionFilter; - protected ListenerInvoker invoker; - protected Set packetListeners; - protected Server server; - protected MinecraftVersion version; - - /** - * The error reporter used by the created injector. - * @param reporter - new error reporter. - * @return This builder, for chaining. - */ - public PlayerInjectorBuilder reporter(@Nonnull ErrorReporter reporter) { - Preconditions.checkNotNull(reporter, "reporter cannot be NULL"); - this.reporter = reporter; - return this; - } - - /** - * The injection filter that is used to determine if it is necessary to perform - * injection during a certain phase. - * @param injectionFilter - filter predicate. - * @return This builder, for chaining. - */ - @Nonnull - public PlayerInjectorBuilder injectionFilter(@Nonnull Predicate injectionFilter) { - Preconditions.checkNotNull(injectionFilter, "injectionFilter cannot be NULL"); - this.injectionFilter = injectionFilter; - return this; - } - - /** - * The packet stream invoker. - * @param invoker - the invoker. - * @return This builder, for chaining. - */ - public PlayerInjectorBuilder invoker(@Nonnull ListenerInvoker invoker) { - Preconditions.checkNotNull(invoker, "invoker cannot be NULL"); - this.invoker = invoker; - return this; - } - - /** - * Set the set of packet listeners. - * @param packetListeners - packet listeners. - * @return This builder, for chaining. - */ - @Nonnull - public PlayerInjectorBuilder packetListeners(@Nonnull Set packetListeners) { - Preconditions.checkNotNull(packetListeners, "packetListeners cannot be NULL"); - this.packetListeners = packetListeners; - return this; - } - - /** - * Set the Bukkit server used for scheduling. - * @param server - the Bukkit server. - * @return This builder, for chaining. - */ - public PlayerInjectorBuilder server(@Nonnull Server server) { - Preconditions.checkNotNull(server, "server cannot be NULL"); - this.server = server; - return this; - } - - /** - * Set the current Minecraft version. - * @param version - the current Minecraft version, or NULL if unknown. - * @return This builder, for chaining. - */ - public PlayerInjectorBuilder version(MinecraftVersion version) { - this.version = version; - return this; - } - - /** - * Called before an object is created with this builder. - */ - private void initializeDefaults() { - ProtocolManager manager = ProtocolLibrary.getProtocolManager(); - - // Initialize with default values if we can - if (reporter == null) - reporter = ProtocolLibrary.getErrorReporter(); - if (invoker == null) - invoker = (PacketFilterManager) manager; - if (server == null) - server = Bukkit.getServer(); - if (injectionFilter == null) - throw new IllegalStateException("injectionFilter must be initialized."); - if (packetListeners == null) - throw new IllegalStateException("packetListeners must be initialized."); - } - - /** - * Construct the injection handler. - *

- * Any builder parameter marked as NON-NULL is essential and must be initialized. - * @return The constructed injection handler using the current parameters. - */ - public PlayerInjectionHandler buildHandler() { - // Fill any default fields - initializeDefaults(); - - return new ProxyPlayerInjectionHandler( - reporter, injectionFilter, - invoker, packetListeners, server, version); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java b/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java deleted file mode 100644 index d19d5a8c..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java +++ /dev/null @@ -1,763 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import io.netty.channel.Channel; - -import java.io.DataInputStream; -import java.io.InputStream; -import java.lang.ref.WeakReference; -import java.lang.reflect.InvocationTargetException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; - -import net.sf.cglib.proxy.Factory; - -import org.bukkit.Server; -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.Packets; -import com.comphenix.protocol.concurrency.BlockingHashMap; -import com.comphenix.protocol.concurrency.IntegerSet; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.ListenerOptions; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.injector.GamePhase; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PlayerInjectHooks; -import com.comphenix.protocol.injector.PlayerLoggedOutException; -import com.comphenix.protocol.injector.packet.PacketRegistry; -import com.comphenix.protocol.injector.server.AbstractInputStreamLookup; -import com.comphenix.protocol.injector.server.BukkitSocketInjector; -import com.comphenix.protocol.injector.server.InputStreamLookupBuilder; -import com.comphenix.protocol.injector.server.SocketInjector; -import com.comphenix.protocol.utility.MinecraftProtocolVersion; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.comphenix.protocol.utility.SafeCacheBuilder; -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.collect.Maps; - -/** - * Responsible for injecting into a player's sendPacket method. - * - * @author Kristian - */ -class ProxyPlayerInjectionHandler implements PlayerInjectionHandler { - // Warnings and errors - public static final ReportType REPORT_UNSUPPPORTED_LISTENER = new ReportType("Cannot fully register listener for %s: %s"); - - // Fallback to older player hook types - public static final ReportType REPORT_PLAYER_HOOK_FAILED = new ReportType("Player hook %s failed."); - public static final ReportType REPORT_SWITCHED_PLAYER_HOOK = new ReportType("Switching to %s instead."); - - public static final ReportType REPORT_HOOK_CLEANUP_FAILED = new ReportType("Cleaing up after player hook failed."); - public static final ReportType REPORT_CANNOT_REVERT_HOOK = new ReportType("Unable to fully revert old injector. May cause conflicts."); - - // Server connection injection - private InjectedServerConnection serverInjection; - - // Server socket injection - private AbstractInputStreamLookup inputStreamLookup; - - // NetLogin injector - private NetLoginInjector netLoginInjector; - - // The last successful player hook - private WeakReference lastSuccessfulHook; - - // Dummy injection - private ConcurrentMap dummyInjectors = - SafeCacheBuilder.newBuilder(). - expireAfterWrite(30, TimeUnit.SECONDS). - build(BlockingHashMap.newInvalidCacheLoader()); - - // Player injection - private Map playerInjection = Maps.newConcurrentMap(); - - // Player injection types - private volatile PlayerInjectHooks loginPlayerHook = PlayerInjectHooks.NETWORK_SERVER_OBJECT; - private volatile PlayerInjectHooks playingPlayerHook = PlayerInjectHooks.NETWORK_SERVER_OBJECT; - - // Error reporter - private ErrorReporter reporter; - - // Whether or not we're closing - private boolean hasClosed; - - // Used to invoke events - private ListenerInvoker invoker; - - // Current Minecraft version - private MinecraftVersion version; - - // Enabled packet filters - private IntegerSet sendingFilters = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1); - - // List of packet listeners - private Set packetListeners; - - // Used to filter injection attempts - private Predicate injectionFilter; - - public ProxyPlayerInjectionHandler( - ErrorReporter reporter, Predicate injectionFilter, - ListenerInvoker invoker, Set packetListeners, Server server, MinecraftVersion version) { - - this.reporter = reporter; - this.invoker = invoker; - this.injectionFilter = injectionFilter; - this.packetListeners = packetListeners; - this.version = version; - - this.inputStreamLookup = InputStreamLookupBuilder.newBuilder(). - server(server). - reporter(reporter). - build(); - - // Create net login injectors and the server connection injector - this.netLoginInjector = new NetLoginInjector(reporter, server, this); - this.serverInjection = new InjectedServerConnection(reporter, inputStreamLookup, server, netLoginInjector); - serverInjection.injectList(); - } - - @Override - public int getProtocolVersion(Player player) { - // Just use the server version - return MinecraftProtocolVersion.getCurrentVersion(); - } - - /** - * Retrieves how the server packets are read. - * @return Injection method for reading server packets. - */ - @Override - public PlayerInjectHooks getPlayerHook() { - return getPlayerHook(GamePhase.PLAYING); - } - - /** - * Retrieves how the server packets are read. - * @param phase - the current game phase. - * @return Injection method for reading server packets. - */ - @Override - public PlayerInjectHooks getPlayerHook(GamePhase phase) { - switch (phase) { - case LOGIN: - return loginPlayerHook; - case PLAYING: - return playingPlayerHook; - default: - throw new IllegalArgumentException("Cannot retrieve injection hook for both phases at the same time."); - } - } - - @Override - public boolean hasMainThreadListener(PacketType type) { - return sendingFilters.contains(type.getLegacyId()); - } - - /** - * Sets how the server packets are read. - * @param playerHook - the new injection method for reading server packets. - */ - @Override - public void setPlayerHook(PlayerInjectHooks playerHook) { - setPlayerHook(GamePhase.PLAYING, playerHook); - } - - /** - * Sets how the server packets are read. - * @param phase - the current game phase. - * @param playerHook - the new injection method for reading server packets. - */ - @Override - public void setPlayerHook(GamePhase phase, PlayerInjectHooks playerHook) { - if (phase.hasLogin()) - loginPlayerHook = playerHook; - if (phase.hasPlaying()) - playingPlayerHook = playerHook; - - // Make sure the current listeners are compatible - checkListener(packetListeners); - } - - @Override - public void addPacketHandler(PacketType type, Set options) { - sendingFilters.add(type.getLegacyId()); - } - - @Override - public void removePacketHandler(PacketType type) { - sendingFilters.remove(type.getLegacyId()); - } - - /** - * Used to construct a player hook. - * @param player - the player to hook. - * @param hook - the hook type. - * @return A new player hoook - * @throws IllegalAccessException Unable to do our reflection magic. - */ - private PlayerInjector getHookInstance(Player player, PlayerInjectHooks hook) throws IllegalAccessException { - // Construct the correct player hook - switch (hook) { - case NETWORK_HANDLER_FIELDS: - return new NetworkFieldInjector(reporter, player, invoker, sendingFilters); - case NETWORK_MANAGER_OBJECT: - return new NetworkObjectInjector(reporter, player, invoker, sendingFilters); - case NETWORK_SERVER_OBJECT: - return new NetworkServerInjector(reporter, player, invoker, sendingFilters, serverInjection); - default: - throw new IllegalArgumentException("Cannot construct a player injector."); - } - } - - /** - * Retrieve a player by its DataInput connection. - * @param inputStream - the associated DataInput connection. - * @return The player we found. - */ - @Override - public Player getPlayerByConnection(DataInputStream inputStream) { - // Wait until the connection owner has been established - SocketInjector injector = inputStreamLookup.waitSocketInjector(inputStream); - - if (injector != null) { - return injector.getPlayer(); - } else { - return null; - } - } - - /** - * Helper function that retrieves the injector type of a given player injector. - * @param injector - injector type. - * @return The injector type. - */ - private PlayerInjectHooks getInjectorType(PlayerInjector injector) { - return injector != null ? injector.getHookType() : PlayerInjectHooks.NONE; - } - - /** - * Initialize a player hook, allowing us to read server packets. - *

- * This call will be ignored if there's no listener that can receive the given events. - * @param player - player to hook. - * @param strategy - how to handle previous player injections. - */ - @Override - public void injectPlayer(Player player, ConflictStrategy strategy) { - // Inject using the player instance itself - if (isInjectionNecessary(GamePhase.PLAYING)) { - injectPlayer(player, player, strategy, GamePhase.PLAYING); - } - } - - /** - * Determine if it's truly necessary to perform the given player injection. - * @param phase - current game phase. - * @return TRUE if we should perform the injection, FALSE otherwise. - */ - public boolean isInjectionNecessary(GamePhase phase) { - return injectionFilter.apply(phase); - } - - /** - * Initialize a player hook, allowing us to read server packets. - *

- * This method will always perform the instructed injection. - * - * @param player - player to hook. - * @param injectionPoint - the object to use during the injection process. - * @param phase - the current game phase. - * @return The resulting player injector, or NULL if the injection failed. - */ - PlayerInjector injectPlayer(Player player, Object injectionPoint, ConflictStrategy stategy, GamePhase phase) { - if (player == null) - throw new IllegalArgumentException("Player cannot be NULL."); - if (injectionPoint == null) - throw new IllegalArgumentException("injectionPoint cannot be NULL."); - if (phase == null) - throw new IllegalArgumentException("phase cannot be NULL."); - - // Unfortunately, due to NetLoginHandler, multiple threads may potentially call this method. - synchronized (player) { - return injectPlayerInternal(player, injectionPoint, stategy, phase); - } - } - - // Unsafe variant of the above - private PlayerInjector injectPlayerInternal(Player player, Object injectionPoint, ConflictStrategy stategy, GamePhase phase) { - PlayerInjector injector = playerInjection.get(player); - PlayerInjectHooks tempHook = getPlayerHook(phase); - PlayerInjectHooks permanentHook = tempHook; - - // The given player object may be fake, so be careful! - - // See if we need to inject something else - boolean invalidInjector = injector != null ? !injector.canInject(phase) : true; - - // Don't inject if the class has closed - if (!hasClosed && (tempHook != getInjectorType(injector) || invalidInjector)) { - while (tempHook != PlayerInjectHooks.NONE) { - // Whether or not the current hook method failed completely - boolean hookFailed = false; - - // Remove the previous hook, if any - cleanupHook(injector); - - try { - injector = getHookInstance(player, tempHook); - - // Make sure this injection method supports the current game phase - if (injector.canInject(phase)) { - injector.initialize(injectionPoint); - - // Get socket and socket injector - SocketAddress address = injector.getAddress(); - - // Ignore logged out players - if (address == null) - return null; - - SocketInjector previous = inputStreamLookup.peekSocketInjector(address); - Socket socket = injector.getSocket(); - - // Close any previously associated hooks before we proceed - if (previous != null && !(player instanceof Factory)) { - switch (stategy) { - case OVERRIDE: - uninjectPlayer(previous.getPlayer(), true); - break; - case BAIL_OUT: - return null; - } - } - injector.injectManager(); - - saveAddressLookup(address, socket, injector); - break; - } - - } catch (PlayerLoggedOutException e) { - throw e; - - } catch (Exception e) { - // Mark this injection attempt as a failure - reporter.reportDetailed(this, - Report.newBuilder(REPORT_PLAYER_HOOK_FAILED).messageParam(tempHook).callerParam(player, injectionPoint, phase).error(e) - ); - hookFailed = true; - } - - // Choose the previous player hook type - tempHook = PlayerInjectHooks.values()[tempHook.ordinal() - 1]; - - if (hookFailed) - reporter.reportWarning(this, Report.newBuilder(REPORT_SWITCHED_PLAYER_HOOK).messageParam(tempHook)); - - // Check for UTTER FAILURE - if (tempHook == PlayerInjectHooks.NONE) { - cleanupHook(injector); - injector = null; - hookFailed = true; - } - - // Should we set the default hook method too? - if (hookFailed) { - permanentHook = tempHook; - } - } - - // Update values - if (injector != null) - lastSuccessfulHook = new WeakReference(injector); - if (permanentHook != getPlayerHook(phase)) - setPlayerHook(phase, tempHook); - - // Save injector - if (injector != null) { - playerInjection.put(player, injector); - } - } - - return injector; - } - - private void saveAddressLookup(SocketAddress address, Socket socket, SocketInjector injector) { - SocketAddress socketAddress = socket != null ? socket.getRemoteSocketAddress() : null; - - if (socketAddress != null && !Objects.equal(socketAddress, address)) { - // Save this version as well - inputStreamLookup.setSocketInjector(socketAddress, injector); - } - // Save injector - inputStreamLookup.setSocketInjector(address, injector); - } - - private void cleanupHook(PlayerInjector injector) { - // Clean up as much as possible - try { - if (injector != null) - injector.cleanupAll(); - } catch (Exception ex) { - reporter.reportDetailed(this, Report.newBuilder(REPORT_HOOK_CLEANUP_FAILED).callerParam(injector).error(ex)); - } - } - - /** - * Invoke special routines for handling disconnect before a player is uninjected. - * @param player - player to process. - */ - @Override - public void handleDisconnect(Player player) { - PlayerInjector injector = getInjector(player); - - if (injector != null) { - injector.handleDisconnect(); - } - } - - @Override - public void updatePlayer(Player player) { - SocketAddress address = player.getAddress(); - - // Ignore logged out players - if (address != null) { - SocketInjector injector = inputStreamLookup.peekSocketInjector(address); - - if (injector != null) { - injector.setUpdatedPlayer(player); - } else { - inputStreamLookup.setSocketInjector(player.getAddress(), - new BukkitSocketInjector(player)); - } - } - } - - /** - * Unregisters the given player. - * @param player - player to unregister. - * @return TRUE if a player has been uninjected, FALSE otherwise. - */ - @Override - public boolean uninjectPlayer(Player player) { - return uninjectPlayer(player, false); - } - - /** - * Unregisters the given player. - * @param player - player to unregister. - * @param prepareNextHook - whether or not we need to fix any lingering hooks. - * @return TRUE if a player has been uninjected, FALSE otherwise. - */ - private boolean uninjectPlayer(Player player, boolean prepareNextHook) { - if (!hasClosed && player != null) { - - PlayerInjector injector = playerInjection.remove(player); - - if (injector != null) { - injector.cleanupAll(); - - // Remove the "hooked" network manager in our instance as well - if (prepareNextHook && injector instanceof NetworkObjectInjector) { - try { - PlayerInjector dummyInjector = getHookInstance(player, PlayerInjectHooks.NETWORK_SERVER_OBJECT); - dummyInjector.initializePlayer(player); - dummyInjector.setNetworkManager(injector.getNetworkManager(), true); - - } catch (IllegalAccessException e) { - // Let the user know - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_REVERT_HOOK).error(e)); - } - } - - return true; - } - } - - return false; - } - - /** - * Unregisters a player by the given address. - *

- * If the server handler has been created before we've gotten a chance to unject the player, - * the method will try a workaround to remove the injected hook in the NetServerHandler. - * - * @param address - address of the player to unregister. - * @return TRUE if a player has been uninjected, FALSE otherwise. - */ - @Override - public boolean uninjectPlayer(InetSocketAddress address) { - if (!hasClosed && address != null) { - SocketInjector injector = inputStreamLookup.peekSocketInjector(address); - - // Clean up - if (injector != null) - uninjectPlayer(injector.getPlayer(), true); - return true; - } - - return false; - } - - /** - * Send the given packet to the given receiver. - * @param receiver - the player receiver. - * @param packet - the packet to send. - * @param filters - whether or not to invoke the packet filters. - * @throws InvocationTargetException If an error occured during sending. - */ - @Override - public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException { - SocketInjector injector = getInjector(receiver); - - // Send the packet, or drop it completely - if (injector != null) { - injector.sendServerPacket(packet.getHandle(), marker, filters); - } else { - throw new PlayerLoggedOutException(String.format( - "Unable to send packet %s (%s): Player %s has logged out.", - packet.getType(), packet, receiver - )); - } - } - - /** - * Recieve a packet as if it were sent by the given player. - * @param player - the sender. - * @param mcPacket - the packet to process. - * @throws IllegalAccessException If the reflection machinery failed. - * @throws InvocationTargetException If the underlying method caused an error. - */ - @Override - public void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException { - PlayerInjector injector = getInjector(player); - - // Process the given packet, or simply give up - if (injector != null) - injector.processPacket(mcPacket); - else - throw new PlayerLoggedOutException(String.format( - "Unable to receieve packet %s. Player %s has logged out.", - mcPacket, player - )); - } - - /** - * Retrieve the injector associated with this player. - * @param player - the player to find. - * @return The injector, or NULL if not found. - */ - private PlayerInjector getInjector(Player player) { - PlayerInjector injector = playerInjection.get(player); - - if (injector == null) { - // Try getting it from the player itself - SocketAddress address = player.getAddress(); - - // Must have logged out - there's nothing we can do - if (address == null) - return null; - - // Look that up without blocking - SocketInjector result = inputStreamLookup.peekSocketInjector(address); - - // Ensure that it is non-null and a player injector - if (result instanceof PlayerInjector) - return (PlayerInjector) result; - else - // Make a dummy injector them - return createDummyInjector(player); - - } else { - return injector; - } - } - - /** - * Construct a simple dummy injector incase none has been constructed. - * @param player - the CraftPlayer to construct for. - * @return A dummy injector, or NULL if the given player is not a CraftPlayer. - */ - private PlayerInjector createDummyInjector(Player player) { - if (!MinecraftReflection.getCraftPlayerClass().isAssignableFrom(player.getClass())) { - // No - this is not safe - return null; - } - - try { - PlayerInjector dummyInjector = getHookInstance(player, PlayerInjectHooks.NETWORK_SERVER_OBJECT); - dummyInjector.initializePlayer(player); - - // This probably means the player has disconnected - if (dummyInjector.getSocket() == null) { - return null; - } - - inputStreamLookup.setSocketInjector(dummyInjector.getAddress(), dummyInjector); - dummyInjectors.put(player, dummyInjector); - return dummyInjector; - - } catch (IllegalAccessException e) { - throw new RuntimeException("Cannot access fields.", e); - } - } - - /** - * Retrieve a player injector by looking for its NetworkManager. - * @param networkManager - current network manager. - * @return Related player injector. - */ - PlayerInjector getInjectorByNetworkHandler(Object networkManager) { - // That's not legal - if (networkManager == null) - return null; - - // O(n) is okay in this instance. This is only a backup solution. - for (PlayerInjector injector : playerInjection.values()) { - if (injector.getNetworkManager() == networkManager) - return injector; - } - - // None found - return null; - } - - @Override - public boolean canRecievePackets() { - return false; - } - - @Override - public PacketEvent handlePacketRecieved(PacketContainer packet, InputStream input, byte[] buffered) { - throw new UnsupportedOperationException("Proxy injection cannot handle received packets."); - } - - /** - * Determine if the given listeners are valid. - * @param listeners - listeners to check. - */ - @Override - public void checkListener(Set listeners) { - // Make sure the current listeners are compatible - if (getLastSuccessfulHook() != null) { - for (PacketListener listener : listeners) { - checkListener(listener); - } - } - } - - /** - * Retrieve the last successful hook. - *

- * May be NULL if the hook has been uninjected. - * @return Last successful hook. - */ - private PlayerInjector getLastSuccessfulHook() { - return lastSuccessfulHook != null ? lastSuccessfulHook.get() : null; - } - - /** - * Determine if a listener is valid or not. - *

- * If not, a warning will be printed to the console. - * @param listener - listener to check. - */ - @Override - public void checkListener(PacketListener listener) { - PlayerInjector last = getLastSuccessfulHook(); - - if (last != null) { - UnsupportedListener result = last.checkListener(version, listener); - - // We won't prevent the listener, as it may still have valid packets - if (result != null) { - reporter.reportWarning(this, - Report.newBuilder(REPORT_UNSUPPPORTED_LISTENER).messageParam(PacketAdapter.getPluginName(listener), result) - ); - - // These are illegal - for (int packetID : result.getPackets()) { - removePacketHandler(PacketType.findLegacy(packetID, Sender.CLIENT)); - removePacketHandler(PacketType.findLegacy(packetID, Sender.SERVER)); - } - } - } - } - - /** - * Retrieve the current list of registered sending listeners. - * @return List of the sending listeners's packet IDs. - */ - @Override - public Set getSendingFilters() { - return PacketRegistry.toPacketTypes(sendingFilters.toSet(), Sender.SERVER); - } - - @Override - public void close() { - // Guard - if (hasClosed || playerInjection == null) - return; - - // Remove everything - for (PlayerInjector injection : playerInjection.values()) { - if (injection != null) { - injection.cleanupAll(); - } - } - - // Remove server handler - if (inputStreamLookup != null) - inputStreamLookup.cleanupAll(); - if (serverInjection != null) - serverInjection.cleanupAll(); - if (netLoginInjector != null) - netLoginInjector.cleanupAll(); - inputStreamLookup = null; - serverInjection = null; - netLoginInjector = null; - hasClosed = true; - - playerInjection.clear(); - invoker = null; - } - - @Override - public Channel getChannel(Player player) { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/ReplacedArrayList.java b/src/main/java/com/comphenix/protocol/injector/player/ReplacedArrayList.java deleted file mode 100644 index 9caa56f4..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/ReplacedArrayList.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -import com.google.common.base.Objects; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; - -/** - * Represents an array list that wraps another list, while automatically replacing one element with another. - *

- * The replaced elements can be recovered. - * - * @author Kristian - * @param - type of the elements we're replacing. - */ -class ReplacedArrayList extends ArrayList { - /** - * Generated by Eclipse. - */ - private static final long serialVersionUID = 1008492765999744804L; - - private BiMap replaceMap = HashBiMap.create(); - private List underlyingList; - - public ReplacedArrayList(List underlyingList) { - this.underlyingList = underlyingList; - } - - /** - * Invoked when a element inserted is replaced. - * @param inserting - the element inserted. - * @param replacement - the element that it should replace. - */ - protected void onReplacing(TKey inserting, TKey replacement) { - // Default is to do nothing. - } - - /** - * Invoked when an element is being inserted. - *

- * This should be used to add a "replace" map. - * @param inserting - the element to insert. - */ - protected void onInserting(TKey inserting) { - // Default is again nothing - } - - /** - * Invoked when an element is being removed. - * @param removing - the element being removed. - */ - protected void onRemoved(TKey removing) { - // Do nothing - } - - @Override - public boolean add(TKey element) { - onInserting(element); - - if (replaceMap.containsKey(element)) { - TKey replacement = replaceMap.get(element); - onReplacing(element, replacement); - return delegate().add(replacement); - } else { - return delegate().add(element); - } - } - - @Override - public void add(int index, TKey element) { - onInserting(element); - - if (replaceMap.containsKey(element)) { - TKey replacement = replaceMap.get(element); - onReplacing(element, replacement); - delegate().add(index, replacement); - } else { - delegate().add(index, element); - } - } - - @Override - public boolean addAll(Collection collection) { - int oldSize = size(); - - for (TKey element : collection) - add(element); - return size() != oldSize; - } - - @Override - public boolean addAll(int index, Collection elements) { - int oldSize = size(); - - for (TKey element : elements) - add(index++, element); - return size() != oldSize; - } - - @SuppressWarnings("unchecked") - @Override - public boolean remove(Object object) { - boolean success = delegate().remove(object); - - if (success) - onRemoved((TKey) object); - return success; - } - - @Override - public TKey remove(int index) { - TKey removed = delegate().remove(index); - - if (removed != null) - onRemoved(removed); - return removed; - } - - @Override - public boolean removeAll(Collection collection) { - int oldSize = size(); - - // Use the remove method - for (Object element : collection) - remove(element); - return size() != oldSize; - } - - protected List delegate() { - return underlyingList; - } - - @Override - public void clear() { - for (TKey element : delegate()) - onRemoved(element); - - delegate().clear(); - } - - @Override - public boolean contains(Object o) { - return delegate().contains(o); - } - - @Override - public boolean containsAll(Collection c) { - return delegate().containsAll(c); - } - - @Override - public TKey get(int index) { - return delegate().get(index); - } - - @Override - public int indexOf(Object o) { - return delegate().indexOf(o); - } - - @Override - public boolean isEmpty() { - return delegate().isEmpty(); - } - - @Override - public Iterator iterator() { - return delegate().iterator(); - } - - @Override - public int lastIndexOf(Object o) { - return delegate().lastIndexOf(o); - } - - @Override - public ListIterator listIterator() { - return delegate().listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - return delegate().listIterator(index); - } - - @Override - public boolean retainAll(Collection c) { - int oldSize = size(); - - for (Iterator it = delegate().iterator(); it.hasNext(); ) { - TKey current = it.next(); - - // Remove elements that are not in the list - if (!c.contains(current)) { - it.remove(); - onRemoved(current); - } - } - return size() != oldSize; - } - - @Override - public TKey set(int index, TKey element) { - // Make sure to replace the element - if (replaceMap.containsKey(element)) { - TKey replacement = replaceMap.get(element); - onReplacing(element, replacement); - return delegate().set(index, replacement); - } else { - return delegate().set(index, element); - } - } - - @Override - public int size() { - return delegate().size(); - } - - @Override - public List subList(int fromIndex, int toIndex) { - return delegate().subList(fromIndex, toIndex); - } - - @Override - public Object[] toArray() { - return delegate().toArray(); - } - - @Override - public T[] toArray(T[] a) { - return delegate().toArray(a); - } - - /** - * Add a replace rule. - *

- * This automatically replaces every existing element. - * @param target - instance to find. - * @param replacement - instance to replace with. - */ - public synchronized void addMapping(TKey target, TKey replacement) { - addMapping(target, replacement, false); - } - - /** - * Retrieve the old value, if it exists. - * @param target - the key. - * @return The value that was replaced, or NULL. - */ - public TKey getMapping(TKey target) { - return replaceMap.get(target); - } - - /** - * Add a replace rule. - *

- * This automatically replaces every existing element. - * @param target - instance to find. - * @param replacement - instance to replace with. - * @param ignoreExisting - whether or not to ignore the existing elements. - */ - public synchronized void addMapping(TKey target, TKey replacement, boolean ignoreExisting) { - replaceMap.put(target, replacement); - - // Replace existing elements - if (!ignoreExisting) { - replaceAll(target, replacement); - } - } - - /** - * Revert the given mapping. - * @param target - the instance we replaced. - * @return The old mapped value, or NULL if nothing was replaced. - */ - public synchronized TKey removeMapping(TKey target) { - // Make sure the mapping exist - if (replaceMap.containsKey(target)) { - TKey replacement = replaceMap.get(target); - replaceMap.remove(target); - - // Revert existing elements - replaceAll(replacement, target); - return replacement; - } - return null; - } - - /** - * Swap the new replaced value with its old value. - * @param target - the instance we replaced. - * @param The old mapped value, or NULL if nothing was swapped. - */ - public synchronized TKey swapMapping(TKey target) { - // Make sure the mapping exist - TKey replacement = removeMapping(target); - - // Add the reverse - if (replacement != null) { - replaceMap.put(replacement, target); - } - return replacement; - } - - /** - * Replace all instances of the given object. - * @param find - object to find. - * @param replace - object to replace it with. - */ - public synchronized void replaceAll(TKey find, TKey replace) { - for (int i = 0; i < underlyingList.size(); i++) { - if (Objects.equal(underlyingList.get(i), find)) { - onReplacing(find, replace); - underlyingList.set(i, replace); - } - } - } - - /** - * Undo all replacements. - */ - public synchronized void revertAll() { - - // No need to do anything else - if (replaceMap.size() < 1) - return; - - BiMap inverse = replaceMap.inverse(); - - for (int i = 0; i < underlyingList.size(); i++) { - TKey replaced = underlyingList.get(i); - - if (inverse.containsKey(replaced)) { - TKey original = inverse.get(replaced); - onReplacing(replaced, original); - underlyingList.set(i, original); - } - } - - replaceMap.clear(); - } - - @Override - protected void finalize() throws Throwable { - revertAll(); - super.finalize(); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/player/UnsupportedListener.java b/src/main/java/com/comphenix/protocol/injector/player/UnsupportedListener.java deleted file mode 100644 index 121428d8..00000000 --- a/src/main/java/com/comphenix/protocol/injector/player/UnsupportedListener.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -package com.comphenix.protocol.injector.player; - -import java.util.Arrays; - -import com.google.common.base.Joiner; - -/** - * Represents an error message from a player injector. - * - * @author Kristian - */ -class UnsupportedListener { - private String message; - private int[] packets; - - /** - * Create a new error message. - * @param message - the message. - * @param packets - unsupported packets. - */ - public UnsupportedListener(String message, int[] packets) { - super(); - this.message = message; - this.packets = packets; - } - - /** - * Retrieve the error message. - * @return Error message. - */ - public String getMessage() { - return message; - } - - /** - * Retrieve all unsupported packets. - * @return Unsupported packets. - */ - public int[] getPackets() { - return packets; - } - - @Override - public String toString() { - return String.format("%s (%s)", message, Joiner.on(", ").join(Arrays.asList(packets))); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/spigot/DummyPacketInjector.java b/src/main/java/com/comphenix/protocol/injector/spigot/DummyPacketInjector.java deleted file mode 100644 index 645d1abc..00000000 --- a/src/main/java/com/comphenix/protocol/injector/spigot/DummyPacketInjector.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.comphenix.protocol.injector.spigot; - -import java.util.Set; - -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.concurrency.PacketTypeSet; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.google.common.collect.Sets; - -/** - * Dummy packet injector that simply delegates to its parent Spigot packet injector or receiving filters. - * - * @author Kristian - */ -class DummyPacketInjector extends AbstractPacketInjector { - private SpigotPacketInjector injector; - private PacketTypeSet lastBufferedPackets = new PacketTypeSet(); - - public DummyPacketInjector(SpigotPacketInjector injector, PacketTypeSet reveivedFilters) { - super(reveivedFilters); - this.injector = injector; - } - - @Override - public void inputBuffersChanged(Set set) { - Set removed = Sets.difference(lastBufferedPackets.values(), set); - Set added = Sets.difference(set, lastBufferedPackets.values()); - - // Update the proxy packet injector - for (PacketType packet : removed) { - injector.getProxyPacketInjector().removePacketHandler(packet); - } - for (PacketType packet : added) { - injector.getProxyPacketInjector().addPacketHandler(packet, null); - } - } - - @Override - public PacketEvent packetRecieved(PacketContainer packet, Player client, byte[] buffered) { - return injector.packetReceived(packet, client, buffered); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java b/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java deleted file mode 100644 index 801fd84e..00000000 --- a/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.comphenix.protocol.injector.spigot; - -import io.netty.channel.Channel; - -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.InetSocketAddress; - -import org.bukkit.entity.Player; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.concurrency.PacketTypeSet; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.utility.MinecraftProtocolVersion; - -/** - * Dummy player handler that simply delegates to its parent Spigot packet injector. - * - * @author Kristian - */ -class DummyPlayerHandler extends AbstractPlayerHandler { - private SpigotPacketInjector injector; - - @Override - public int getProtocolVersion(Player player) { - // Just use the server version - return MinecraftProtocolVersion.getCurrentVersion(); - } - - public DummyPlayerHandler(SpigotPacketInjector injector, PacketTypeSet sendingFilters) { - super(sendingFilters); - this.injector = injector; - } - - @Override - public boolean uninjectPlayer(InetSocketAddress address) { - return true; - } - - @Override - public boolean uninjectPlayer(Player player) { - injector.uninjectPlayer(player); - return true; - } - - @Override - public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException { - injector.sendServerPacket(receiver, packet, marker, filters); - } - - @Override - public void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException { - injector.processPacket(player, mcPacket); - } - - @Override - public void injectPlayer(Player player, ConflictStrategy strategy) { - // We don't care about strategy - injector.injectPlayer(player); - } - - @Override - public boolean hasMainThreadListener(PacketType type) { - return sendingFilters.contains(type); - } - - @Override - public void handleDisconnect(Player player) { - // Just ignore - } - - @Override - public PacketEvent handlePacketRecieved(PacketContainer packet, InputStream input, byte[] buffered) { - // Associate this buffered data - if (buffered != null) { - injector.saveBuffered(packet.getHandle(), buffered); - } - return null; - } - - @Override - public void updatePlayer(Player player) { - // Do nothing - } - - @Override - public Channel getChannel(Player player) { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketInjector.java b/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketInjector.java deleted file mode 100644 index a31fcfcc..00000000 --- a/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketInjector.java +++ /dev/null @@ -1,672 +0,0 @@ -package com.comphenix.protocol.injector.spigot; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentMap; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.Factory; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; -import net.sf.cglib.proxy.NoOp; - -import org.bukkit.Bukkit; -import org.bukkit.Server; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.concurrency.PacketTypeSet; -import com.comphenix.protocol.error.DelegatedErrorReporter; -import com.comphenix.protocol.error.ErrorReporter; -import com.comphenix.protocol.error.Report; -import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.injector.ListenerInvoker; -import com.comphenix.protocol.injector.PacketFilterManager; -import com.comphenix.protocol.injector.PlayerLoggedOutException; -import com.comphenix.protocol.injector.packet.LegacyNetworkMarker; -import com.comphenix.protocol.injector.packet.PacketInjector; -import com.comphenix.protocol.injector.player.NetworkObjectInjector; -import com.comphenix.protocol.injector.player.PlayerInjectionHandler; -import com.comphenix.protocol.reflect.FieldUtils; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.MethodInfo; -import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; -import com.comphenix.protocol.utility.EnhancerFactory; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.MapMaker; -import com.google.common.collect.Maps; - -/** - * Offload all the work to Spigot, if possible. - * - * @author Kristian - */ -public class SpigotPacketInjector implements SpigotPacketListener { - public static final ReportType REPORT_CANNOT_CLEANUP_SPIGOT = new ReportType("Cannot cleanup Spigot listener."); - - // Lazily retrieve the spigot listener class - private static volatile Class spigotListenerClass; - private static volatile boolean classChecked; - - // Retrieve the entity player from a PlayerConnection - private static volatile Field playerConnectionPlayer; - - // Packets that are not to be processed by the filters - private Set ignoredPackets = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); - - /** - * The amount of ticks to wait before removing all traces of a player. - */ - private static final int CLEANUP_DELAY = 100; - - // The listener we will register on Spigot. - // Unfortunately, due to the use of PlayerConnection, INetworkManager and Packet, we're - // unable to reference it directly. But with CGLib, it shouldn't cost us much. - private Object dynamicListener; - - // Reference to ProtocolLib - private Plugin plugin; - - // Different sending filters - private PacketTypeSet queuedFilters; - private PacketTypeSet reveivedFilters; - - // NetworkManager to injector and player - private ConcurrentMap networkManagerInjector = Maps.newConcurrentMap(); - - // Player to injector - private ConcurrentMap playerInjector = Maps.newConcurrentMap(); - - // For handling read buffered packet data - private Map readBufferedPackets = new MapMaker().weakKeys().makeMap(); - - // Responsible for informing the PL packet listeners - private ListenerInvoker invoker; - private ErrorReporter reporter; - private Server server; - - // The proxy packet injector - private PacketInjector proxyPacketInjector; - - // Background task - private static final int BACKGROUND_DELAY = 30 * PacketFilterManager.TICKS_PER_SECOND; - private int backgroundId; - - /** - * Create a new spigot injector. - * @param reporter - error reporter - * @param invoker - listener invoker - * @param server - server - */ - public SpigotPacketInjector(ErrorReporter reporter, ListenerInvoker invoker, Server server) { - this.reporter = reporter; - this.invoker = invoker; - this.server = server; - this.queuedFilters = new PacketTypeSet(); - this.reveivedFilters = new PacketTypeSet(); - } - - /** - * Retrieve the underlying listener invoker. - * @return The invoker. - */ - public ListenerInvoker getInvoker() { - return invoker; - } - - /** - * Set the real proxy packet injector. - * @param proxyPacketInjector - the real injector. - */ - public void setProxyPacketInjector(PacketInjector proxyPacketInjector) { - this.proxyPacketInjector = proxyPacketInjector; - } - - /** - * Retrieve the real proxy packet injector. - * @return The real injector. - */ - public PacketInjector getProxyPacketInjector() { - return proxyPacketInjector; - } - - /** - * Retrieve the spigot packet listener class. - * @return The listener class. - */ - private static Class getSpigotListenerClass() { - if (!classChecked) { - try { - spigotListenerClass = SpigotPacketInjector.class.getClassLoader().loadClass("org.spigotmc.netty.PacketListener"); - } catch (ClassNotFoundException e) { - return null; - } finally { - // We've given it a try now - classChecked = true; - } - } - return spigotListenerClass; - } - - /** - * Retrieve the register packet listener method. - * @return The method used to register a packet listener. - */ - private static Method getRegisterMethod() { - Class clazz = getSpigotListenerClass(); - - if (clazz != null) { - try { - return clazz.getMethod("register", clazz, Plugin.class); - } catch (SecurityException e) { - // If this happens, then ... we're doomed - throw new RuntimeException("Reflection is not allowed.", e); - } catch (NoSuchMethodException e) { - throw new IllegalStateException("Cannot find register() method in " + clazz, e); - } - } - - // Also bad - throw new IllegalStateException("Spigot could not be found!"); - } - - /** - * Determine if there is a Spigot packet listener. - * @return Spigot packet listener. - */ - public static boolean canUseSpigotListener() { - return getSpigotListenerClass() != null; - } - - /** - * Register the Spigot packet injector. - * @param plugin - the parent plugin. - * @return TRUE if we registered the plugin, FALSE otherwise. - */ - public boolean register(Plugin plugin) { - if (hasRegistered()) - return false; - - // Save the plugin too - this.plugin = plugin; - - final Callback[] callbacks = new Callback[3]; - final boolean[] found = new boolean[3]; - - // Packets received from the clients - callbacks[0] = new MethodInterceptor() { - @Override - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - return SpigotPacketInjector.this.packetReceived(args[0], args[1], args[2]); - } - }; - // Packet sent/queued - callbacks[1] = new MethodInterceptor() { - @Override - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - return SpigotPacketInjector.this.packetQueued(args[0], args[1], args[2]); - } - }; - - // Don't care for everything else - callbacks[2] = NoOp.INSTANCE; - - Enhancer enhancer = EnhancerFactory.getInstance().createEnhancer(); - enhancer.setSuperclass(getSpigotListenerClass()); - enhancer.setCallbacks(callbacks); - enhancer.setCallbackFilter(new CallbackFilter() { - @Override - public int accept(Method method) { - // We'll be pretty stringent - if (matchMethod("packetReceived", method)) { - found[0] = true; - return 0; - } else if (matchMethod("packetQueued", method)) { - found[1] = true; - return 1; - } else { - found[2] = true; - return 2; - } - } - }); - dynamicListener = enhancer.create(); - - // Verify methods - if (!found[0]) - throw new IllegalStateException("Unable to find a valid packet receiver in Spigot."); - if (!found[1]) - throw new IllegalStateException("Unable to find a valid packet queue in Spigot."); - - // Lets register it too - try { - getRegisterMethod().invoke(null, dynamicListener, plugin); - } catch (Exception e) { - throw new RuntimeException("Cannot register Spigot packet listener.", e); - } - - // Remember to register background task - backgroundId = createBackgroundTask(); - - // If we succeed - return true; - } - - /** - * Create and register a background task. - * @return The background task ID. - */ - private int createBackgroundTask() { - return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() { - @Override - public void run() { - cleanupInjectors(); - } - }, BACKGROUND_DELAY, BACKGROUND_DELAY); - } - - /** - * Ensure that all disconnected injectors are removed from memory. - */ - private void cleanupInjectors() { - for (NetworkObjectInjector injector : networkManagerInjector.values()) { - try { - if (injector.getSocket() != null && injector.getSocket().isClosed()) { - cleanupInjector(injector); - } - } catch (Exception e) { - reporter.reportMinimal(plugin, "cleanupInjectors", e); - - // What? - cleanupInjector(injector); - } - } - } - - /** - * Remove a given network object injector. - * @param injector - the injector. - */ - private void cleanupInjector(final NetworkObjectInjector injector) { - // Clean up - playerInjector.remove(injector.getPlayer()); - playerInjector.remove(injector.getUpdatedPlayer()); - networkManagerInjector.remove(injector.getNetworkManager()); - } - - /** - * Determine if the given method is a valid packet receiver or queued method. - * @param methodName - the expected name of the method. - * @param method - the method we're testing. - * @return TRUE if this is a correct method, FALSE otherwise. - */ - private boolean matchMethod(String methodName, Method method) { - return FuzzyMethodContract.newBuilder(). - nameExact(methodName). - parameterCount(3). - parameterSuperOf(MinecraftReflection.getNetHandlerClass(), 1). - parameterSuperOf(MinecraftReflection.getPacketClass(), 2). - returnTypeExact(MinecraftReflection.getPacketClass()). - build(). - isMatch(MethodInfo.fromMethod(method), null); - } - - /** - * Determine if the Spigot packet listener has been registered. - * @return TRUE if it has, FALSE otherwise. - */ - public boolean hasRegistered() { - return dynamicListener != null; - } - - /** - * Retrieve the dummy player injection handler. - * @return Dummy player injection handler. - */ - public PlayerInjectionHandler getPlayerHandler() { - return new DummyPlayerHandler(this, queuedFilters); - } - - /** - * Retrieve the dummy packet injection handler. - * @return Dummy packet injection handler. - */ - public PacketInjector getPacketInjector() { - return new DummyPacketInjector(this, reveivedFilters); - } - - /** - * Retrieve the currently registered injector for the given player. - * @param player - injected player. - * @param createNew - whether or not to create a new injector if the current is missing. - * @return The injector. - */ - NetworkObjectInjector getInjector(Player player, boolean createNew) { - NetworkObjectInjector injector = playerInjector.get(player); - - if (injector == null && createNew) { - // Check for temporary players .. - if ((player instanceof Factory)) - throw new IllegalArgumentException("Cannot inject tempoary player " + player); - - try { - NetworkObjectInjector created = new NetworkObjectInjector( - filterImpossibleWarnings(reporter), null, invoker, null); - - created.initializePlayer(player); - - if (created.getNetworkManager() == null) - throw new PlayerLoggedOutException("Player " + player + " has logged out."); - injector = saveInjector(created.getNetworkManager(), created); - - } catch (IllegalAccessException e) { - throw new RuntimeException("Cannot create dummy injector.", e); - } - } - return injector; - } - - /** - * Retrieve or create a registered injector for the given network manager and connection. - * @param networkManager - a INetworkManager object. - * @param connection - a Connection (PlayerConnection, PendingConnection) object. - * @return The created NetworkObjectInjector with a temporary player. - */ - NetworkObjectInjector getInjector(Object networkManager, Object connection) { - NetworkObjectInjector dummyInjector = networkManagerInjector.get(networkManager); - - if (dummyInjector == null) { - // Inject the network manager - try { - NetworkObjectInjector created = new NetworkObjectInjector( - filterImpossibleWarnings(reporter), null, invoker, null); - - if (MinecraftReflection.isLoginHandler(connection)) { - created.initialize(connection); - created.setPlayer(created.createTemporaryPlayer(server)); - } else if (MinecraftReflection.isServerHandler(connection)) { - // Get the player instead - if (playerConnectionPlayer == null) - playerConnectionPlayer = FuzzyReflection.fromObject(connection). - getFieldByType("player", MinecraftReflection.getEntityPlayerClass()); - Object entityPlayer = playerConnectionPlayer.get(connection); - - created.initialize(MinecraftReflection.getBukkitEntity(entityPlayer)); - - } else { - throw new IllegalArgumentException("Unregonized connection in NetworkManager."); - } - - dummyInjector = saveInjector(networkManager, created); - - } catch (IllegalAccessException e) { - throw new RuntimeException("Cannot create dummy injector.", e); - } - } - - return dummyInjector; - } - - /** - * Return a delegated error reporter that ignores certain warnings that are irrelevant on Spigot. - * @param reporter - error reporter to delegate. - * @return The filtered error reporter. - */ - private ErrorReporter filterImpossibleWarnings(ErrorReporter reporter) { - return new DelegatedErrorReporter(reporter) { - @Override - protected Report filterReport(Object sender, Report report, boolean detailed) { - // This doesn't matter - ignore it - if (report.getType() == NetworkObjectInjector.REPORT_DETECTED_CUSTOM_SERVER_HANDLER) - return null; - return report; - } - }; - } - - /** - * Save a given player injector for later. - * @param networkManager - the associated network manager. - * @param created - the created network object creator. - * @return Any other network injector that came before us. - */ - private NetworkObjectInjector saveInjector(Object networkManager, NetworkObjectInjector created) { - // Concurrency - use the same injector! - NetworkObjectInjector result = networkManagerInjector.putIfAbsent(networkManager, created); - - if (result == null) { - result = created; - } - - // Save the player as well - playerInjector.put(created.getPlayer(), created); - return result; - } - - /** - * Save the buffered serialized input packet. - * @param handle - the associated packet. - * @param buffered - the buffere data to save. - */ - public void saveBuffered(Object handle, byte[] buffered) { - readBufferedPackets.put(handle, buffered); - } - - @Override - public Object packetReceived(Object networkManager, Object connection, Object packet) { - if (reveivedFilters.contains(packet.getClass())) { - @SuppressWarnings("deprecation") - Integer id = invoker.getPacketID(packet); - - // Check for ignored packets - if (ignoredPackets.remove(packet)) { - return packet; - } - - Player sender = getInjector(networkManager, connection).getUpdatedPlayer(); - PacketType type = PacketType.findLegacy(id, Sender.CLIENT); - PacketContainer container = new PacketContainer(type, packet); - PacketEvent event = packetReceived(container, sender, readBufferedPackets.get(packet)); - - if (!event.isCancelled()) - return event.getPacket().getHandle(); - else - return null; // Cancel - } - // Don't change anything - return packet; - } - - @Override - public Object packetQueued(Object networkManager, Object connection, Object packet) { - if (queuedFilters.contains(packet.getClass())) { - @SuppressWarnings("deprecation") - Integer id = invoker.getPacketID(packet); - - // Check for ignored packets - if (ignoredPackets.remove(packet)) { - return packet; - } - - Player reciever = getInjector(networkManager, connection).getUpdatedPlayer(); - PacketType type = PacketType.findLegacy(id, Sender.SERVER); - PacketContainer container = new PacketContainer(type, packet); - PacketEvent event = packetQueued(container, reciever); - - if (!event.isCancelled()) - return event.getPacket().getHandle(); - else - return null; // Cancel - } - // Don't change anything - return packet; - } - - /** - * Called to inform the event listeners of a queued packet. - * @param packet - the packet that is to be sent. - * @param receiver - the receiver of this packet. - * @return The packet event that was used. - */ - PacketEvent packetQueued(PacketContainer packet, Player receiver) { - PacketEvent event = PacketEvent.fromServer(this, packet, receiver); - - invoker.invokePacketSending(event); - return event; - } - - /** - * Called to inform the event listeners of a received packet. - * @param packet - the packet that has been receieved. - * @param sender - the client packet. - * @return The packet event that was used. - */ - PacketEvent packetReceived(PacketContainer packet, Player sender, byte[] buffered) { - NetworkMarker marker = buffered != null ? new LegacyNetworkMarker(ConnectionSide.CLIENT_SIDE, buffered, packet.getType()) : null; - PacketEvent event = PacketEvent.fromClient(this, packet, marker, sender); - - invoker.invokePacketRecieving(event); - return event; - } - - /** - * Called when a player has logged in properly. - * @param player - the player that has logged in. - */ - void injectPlayer(Player player) { - try { - NetworkObjectInjector dummy = new NetworkObjectInjector( - filterImpossibleWarnings(reporter), player, invoker, null); - dummy.initializePlayer(player); - - // Save this player for the network manager - NetworkObjectInjector realInjector = networkManagerInjector.get(dummy.getNetworkManager()); - - if (realInjector != null) { - // Update all future references - realInjector.setUpdatedPlayer(player); - playerInjector.put(player, realInjector); - } else { - // Ah - in that case, save this injector - saveInjector(dummy.getNetworkManager(), dummy); - } - - } catch (IllegalAccessException e) { - throw new RuntimeException("Cannot inject " + player); - } - } - - /** - * Uninject the given player. - * @param player - the player to uninject. - */ - void uninjectPlayer(Player player) { - final NetworkObjectInjector injector = getInjector(player, false); - - if (player != null && injector != null) { - Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { - @Override - public void run() { - cleanupInjector(injector); - } - }, CLEANUP_DELAY); - } - } - - /** - * Invoked when a plugin wants to sent a packet. - * @param receiver - the packet receiver. - * @param packet - the packet to transmit. - * @param marker - the network marker object. - * @param filters - whether or not to invoke the packet listeners. - * @throws InvocationTargetException If anything went wrong. - */ - void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException { - NetworkObjectInjector networkObject = getInjector(receiver, true); - - // If TRUE, process this packet like any other - if (filters) - ignoredPackets.remove(packet.getHandle()); - else - ignoredPackets.add(packet.getHandle()); - - networkObject.sendServerPacket(packet.getHandle(), marker, filters); - } - - /** - * Invoked when a plugin wants to simulate receiving a packet. - * @param player - the supposed sender. - * @param mcPacket - the packet to receieve. - * @throws IllegalAccessException Reflection is not permitted. - * @throws InvocationTargetException Minecraft threw an exception. - */ - void processPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException { - NetworkObjectInjector networkObject = getInjector(player, true); - - // We will always ignore this packet - ignoredPackets.add(mcPacket); - networkObject.processPacket(mcPacket); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void cleanupListener() { - Class listenerClass = getSpigotListenerClass(); - - // Yeah ... there's no easy way to remove the listener - synchronized (listenerClass) { - try { - Field listenersField = FieldUtils.getField(listenerClass, "listeners", true); - Field bakedField = FieldUtils.getField(listenerClass, "baked", true); - - Map listenerMap = (Map) listenersField.get(null); - List listenerArray = Lists.newArrayList((Object[]) bakedField.get(null)); - - listenerMap.remove(dynamicListener); - listenerArray.remove(dynamicListener); - - // Save the array back - bakedField.set(null, Iterables.toArray(listenerArray, (Class)listenerClass)); - - // Success - dynamicListener = null; - } catch (Exception e) { - reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_CLEANUP_SPIGOT). - callerParam(dynamicListener).error(e)); - } - } - } - - /** - * Invoked when the server is cleaning up. - */ - public void cleanupAll() { - // Cleanup the Spigot listener - if (dynamicListener != null) { - cleanupListener(); - } - if (backgroundId >= 0) { - Bukkit.getScheduler().cancelTask(backgroundId); - backgroundId = -1; - } - - // Cleanup network marker - if (proxyPacketInjector != null) { - proxyPacketInjector.cleanupAll(); - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketListener.java b/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketListener.java deleted file mode 100644 index ce9e3b83..00000000 --- a/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketListener.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.comphenix.protocol.injector.spigot; - -/** - * Represents a proxy for a Spigot packet listener. - * - * @author Kristian - */ -interface SpigotPacketListener { - /** - * Called when a packet has been received and is about to be handled by the - * current Connection. - *

- * The returned packet will be the packet passed on for handling, or in the case of - * null being returned, not handled at all. - * - * @param networkManager - the NetworkManager receiving the packet - * @param connection - the connection which will handle the packet - * @param packet - the received packet - * @return the packet to be handled, or null to cancel - */ - public Object packetReceived(Object networkManager, Object connection, Object packet); - - /** - * Called when a packet is queued to be sent. - *

- * The returned packet will be the packet sent. In the case of null being returned, - * the packet will not be sent. - * @param networkManager - the NetworkManager which will send the packet - * @param connection - the connection which queued the packet - * @param packet - the queue packet - * @return the packet to be sent, or null if the packet will not be sent. - */ - public Object packetQueued(Object networkManager, Object connection, Object packet); -} diff --git a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 33698974..867eee84 100644 --- a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -1313,11 +1313,9 @@ public class MinecraftReflection { } /** - * Retrieve the WatchableObject class. + * Retrieve the WatchableObject class. Replaced by {@link #getDataWatcherItemClass()} * @return The WatchableObject class. - * @deprecated Replaced by {@link #getDataWatcherItemClass()} */ - @Deprecated public static Class getWatchableObjectClass() { return getDataWatcherItemClass(); } diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java index 9df22e89..4c96530a 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java @@ -257,11 +257,9 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab public abstract Material getType(); /** - * Gets this BlockData's legacy data + * Gets this BlockData's legacy data. Not recommended on 1.13+ * @return The legacy data - * @deprecated By the flattening in 1.13. Fine on lower versions. */ - @Deprecated public abstract int getData(); /** @@ -271,20 +269,16 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab public abstract void setType(Material material); /** - * Sets this BlockData's legacy data + * Sets this BlockData's legacy data. Not recommended on 1.13+ * @param data The new legacy data - * @deprecated By the flattening in 1.13. Fine on lower versions. */ - @Deprecated public abstract void setData(int data); /** - * Sets this BlockData's type and legacy data + * Sets this BlockData's type and legacy data. Not recommended on 1.13+ * @param material The new Bukkit material * @param data The new legacy data - * @deprecated By the flattening in 1.13. Fine on lower versions. */ - @Deprecated public abstract void setTypeAndData(Material material, int data); public abstract WrappedBlockData deepClone(); diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java index 08cd8935..ef6f3fcb 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java @@ -16,7 +16,6 @@ import com.google.common.base.Preconditions; * @author Kristian * @deprecated IntHashMap no longer exists */ -@Deprecated public class WrappedIntHashMap extends AbstractWrapper { private static Method PUT_METHOD; private static Method GET_METHOD;