From 8d814d2d9ced9c84ab6ca81dacd965d86ecb8ffe Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Mon, 6 May 2013 18:37:08 +0200 Subject: [PATCH] Implement "isOnline" for temporary players. This corrects the issue seen on http://pastebin.com/C4D8jsja --- .../server/TemporaryPlayerFactory.java | 392 +++++++++--------- 1 file changed, 197 insertions(+), 195 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/TemporaryPlayerFactory.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/TemporaryPlayerFactory.java index 91d1fed6..8c2e0e05 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/TemporaryPlayerFactory.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/server/TemporaryPlayerFactory.java @@ -1,195 +1,197 @@ -/* - * 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.server; - -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.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; -import net.sf.cglib.proxy.NoOp; - -import org.bukkit.Server; -import org.bukkit.entity.Player; - -import com.comphenix.protocol.injector.PacketConstructor; -import com.comphenix.protocol.reflect.FieldAccessException; - -/** - * Create fake player instances that represents pre-authenticated clients. - */ -public class TemporaryPlayerFactory { - // Helpful constructors - private final PacketConstructor chatPacket; - - // Prevent too many class creations - private static CallbackFilter callbackFilter; - - public TemporaryPlayerFactory() { - chatPacket = PacketConstructor.DEFAULT.withPacket(3, new Object[] { "DEMO" }); - } - - /** - * Retrieve the injector from a given player if it contains one. - * @param player - the player that may contain a reference to a player injector. - * @return The referenced player injector, or NULL if none can be found. - */ - public static SocketInjector getInjectorFromPlayer(Player player) { - if (player instanceof InjectorContainer) { - return ((InjectorContainer) player).getInjector(); - } - return null; - } - - /** - * Set the player injector, if possible. - * @param player - the player to update. - * @param injector - the injector to store. - */ - public static void setInjectorInPlayer(Player player, SocketInjector injector) { - ((InjectorContainer) player).setInjector(injector); - } - - /** - * Construct a temporary player that supports a subset of every player command. - *

- * Supported methods include: - *

- *

- * Note that a temporary player has not yet been assigned a name, and thus cannot be - * uniquely identified. Use the address instead. - * @param injector - the player injector used. - * @param server - the current server. - * @return A temporary player instance. - */ - public Player createTemporaryPlayer(final Server server) { - - // Default implementation - Callback implementation = new MethodInterceptor() { - @Override - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - - String methodName = method.getName(); - SocketInjector injector = ((InjectorContainer) obj).getInjector(); - - if (injector == null) - throw new IllegalStateException("Unable to find injector."); - - // Use the socket to get the address - if (methodName.equalsIgnoreCase("getName")) - return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]"; - if (methodName.equalsIgnoreCase("getPlayer")) - return injector.getUpdatedPlayer(); - if (methodName.equalsIgnoreCase("getAddress")) - return injector.getAddress(); - if (methodName.equalsIgnoreCase("getServer")) - return server; - - try { - // Handle send message methods - if (methodName.equalsIgnoreCase("chat") || methodName.equalsIgnoreCase("sendMessage")) { - Object argument = args[0]; - - // Dynamic overloading - if (argument instanceof String) { - return sendMessage(injector, (String) argument); - } else if (argument instanceof String[]) { - for (String message : (String[]) argument) { - sendMessage(injector, message); - } - return null; - } - } - } catch (InvocationTargetException e) { - throw e.getCause(); - } - - // Also, handle kicking - if (methodName.equalsIgnoreCase("kickPlayer")) { - injector.disconnect((String) args[0]); - return null; - } - - // Ignore all other methods - throw new UnsupportedOperationException( - "The method " + method.getName() + " is not supported for temporary players."); - } - }; - - // Shared callback filter - if (callbackFilter == null) { - callbackFilter = new CallbackFilter() { - @Override - public int accept(Method method) { - // Do not override the object method or the superclass methods - if (method.getDeclaringClass().equals(Object.class) || - method.getDeclaringClass().equals(InjectorContainer.class)) - return 0; - else - return 1; - } - }; - } - - // CGLib is amazing - Enhancer ex = new Enhancer(); - ex.setSuperclass(InjectorContainer.class); - ex.setInterfaces(new Class[] { Player.class }); - ex.setCallbacks(new Callback[] { NoOp.INSTANCE, implementation }); - ex.setCallbackFilter(callbackFilter); - - return (Player) ex.create(); - } - - /** - * Construct a temporary player with the given associated socket injector. - * @param server - the parent server. - * @param injector - the referenced socket injector. - * @return The temporary player. - */ - public Player createTemporaryPlayer(Server server, SocketInjector injector) { - Player temporary = createTemporaryPlayer(server); - - ((InjectorContainer) temporary).setInjector(injector); - return temporary; - } - - /** - * Send a message to the given client. - * @param injector - the injector representing the client. - * @param message - a message. - * @return Always NULL. - * @throws InvocationTargetException If the message couldn't be sent. - * @throws FieldAccessException If we were unable to construct the message packet. - */ - private Object sendMessage(SocketInjector injector, String message) throws InvocationTargetException, FieldAccessException { - injector.sendServerPacket(chatPacket.createPacket(message).getHandle(), false); - return null; - } -} +/* + * 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.server; + +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.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; +import net.sf.cglib.proxy.NoOp; + +import org.bukkit.Server; +import org.bukkit.entity.Player; + +import com.comphenix.protocol.injector.PacketConstructor; +import com.comphenix.protocol.reflect.FieldAccessException; + +/** + * Create fake player instances that represents pre-authenticated clients. + */ +public class TemporaryPlayerFactory { + // Helpful constructors + private final PacketConstructor chatPacket; + + // Prevent too many class creations + private static CallbackFilter callbackFilter; + + public TemporaryPlayerFactory() { + chatPacket = PacketConstructor.DEFAULT.withPacket(3, new Object[] { "DEMO" }); + } + + /** + * Retrieve the injector from a given player if it contains one. + * @param player - the player that may contain a reference to a player injector. + * @return The referenced player injector, or NULL if none can be found. + */ + public static SocketInjector getInjectorFromPlayer(Player player) { + if (player instanceof InjectorContainer) { + return ((InjectorContainer) player).getInjector(); + } + return null; + } + + /** + * Set the player injector, if possible. + * @param player - the player to update. + * @param injector - the injector to store. + */ + public static void setInjectorInPlayer(Player player, SocketInjector injector) { + ((InjectorContainer) player).setInjector(injector); + } + + /** + * Construct a temporary player that supports a subset of every player command. + *

+ * Supported methods include: + *

+ *

+ * Note that a temporary player has not yet been assigned a name, and thus cannot be + * uniquely identified. Use the address instead. + * @param injector - the player injector used. + * @param server - the current server. + * @return A temporary player instance. + */ + public Player createTemporaryPlayer(final Server server) { + + // Default implementation + Callback implementation = new MethodInterceptor() { + @Override + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + + String methodName = method.getName(); + SocketInjector injector = ((InjectorContainer) obj).getInjector(); + + if (injector == null) + throw new IllegalStateException("Unable to find injector."); + + // Use the socket to get the address + if (methodName.equalsIgnoreCase("isOnline")) + return injector.getSocket() != null && injector.getSocket().isConnected(); + if (methodName.equalsIgnoreCase("getName")) + return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]"; + if (methodName.equalsIgnoreCase("getPlayer")) + return injector.getUpdatedPlayer(); + if (methodName.equalsIgnoreCase("getAddress")) + return injector.getAddress(); + if (methodName.equalsIgnoreCase("getServer")) + return server; + + try { + // Handle send message methods + if (methodName.equalsIgnoreCase("chat") || methodName.equalsIgnoreCase("sendMessage")) { + Object argument = args[0]; + + // Dynamic overloading + if (argument instanceof String) { + return sendMessage(injector, (String) argument); + } else if (argument instanceof String[]) { + for (String message : (String[]) argument) { + sendMessage(injector, message); + } + return null; + } + } + } catch (InvocationTargetException e) { + throw e.getCause(); + } + + // Also, handle kicking + if (methodName.equalsIgnoreCase("kickPlayer")) { + injector.disconnect((String) args[0]); + return null; + } + + // Ignore all other methods + throw new UnsupportedOperationException( + "The method " + method.getName() + " is not supported for temporary players."); + } + }; + + // Shared callback filter + if (callbackFilter == null) { + callbackFilter = new CallbackFilter() { + @Override + public int accept(Method method) { + // Do not override the object method or the superclass methods + if (method.getDeclaringClass().equals(Object.class) || + method.getDeclaringClass().equals(InjectorContainer.class)) + return 0; + else + return 1; + } + }; + } + + // CGLib is amazing + Enhancer ex = new Enhancer(); + ex.setSuperclass(InjectorContainer.class); + ex.setInterfaces(new Class[] { Player.class }); + ex.setCallbacks(new Callback[] { NoOp.INSTANCE, implementation }); + ex.setCallbackFilter(callbackFilter); + + return (Player) ex.create(); + } + + /** + * Construct a temporary player with the given associated socket injector. + * @param server - the parent server. + * @param injector - the referenced socket injector. + * @return The temporary player. + */ + public Player createTemporaryPlayer(Server server, SocketInjector injector) { + Player temporary = createTemporaryPlayer(server); + + ((InjectorContainer) temporary).setInjector(injector); + return temporary; + } + + /** + * Send a message to the given client. + * @param injector - the injector representing the client. + * @param message - a message. + * @return Always NULL. + * @throws InvocationTargetException If the message couldn't be sent. + * @throws FieldAccessException If we were unable to construct the message packet. + */ + private Object sendMessage(SocketInjector injector, String message) throws InvocationTargetException, FieldAccessException { + injector.sendServerPacket(chatPacket.createPacket(message).getHandle(), false); + return null; + } +}