Archiviert
13
0

Implement "isOnline" for temporary players.

This corrects the issue seen on http://pastebin.com/C4D8jsja
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2013-05-06 18:37:08 +02:00
Ursprung 0fc6396974
Commit 8d814d2d9c

Datei anzeigen

@ -1,195 +1,197 @@
/* /*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland * Copyright (C) 2012 Kristian S. Stangeland
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * 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 * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * 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; * 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. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * 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; * 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 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.injector.server; package com.comphenix.protocol.injector.server;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp; import net.sf.cglib.proxy.NoOp;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.injector.PacketConstructor; import com.comphenix.protocol.injector.PacketConstructor;
import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldAccessException;
/** /**
* Create fake player instances that represents pre-authenticated clients. * Create fake player instances that represents pre-authenticated clients.
*/ */
public class TemporaryPlayerFactory { public class TemporaryPlayerFactory {
// Helpful constructors // Helpful constructors
private final PacketConstructor chatPacket; private final PacketConstructor chatPacket;
// Prevent too many class creations // Prevent too many class creations
private static CallbackFilter callbackFilter; private static CallbackFilter callbackFilter;
public TemporaryPlayerFactory() { public TemporaryPlayerFactory() {
chatPacket = PacketConstructor.DEFAULT.withPacket(3, new Object[] { "DEMO" }); chatPacket = PacketConstructor.DEFAULT.withPacket(3, new Object[] { "DEMO" });
} }
/** /**
* Retrieve the injector from a given player if it contains one. * Retrieve the injector from a given player if it contains one.
* @param player - the player that may contain a reference to a player injector. * @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. * @return The referenced player injector, or NULL if none can be found.
*/ */
public static SocketInjector getInjectorFromPlayer(Player player) { public static SocketInjector getInjectorFromPlayer(Player player) {
if (player instanceof InjectorContainer) { if (player instanceof InjectorContainer) {
return ((InjectorContainer) player).getInjector(); return ((InjectorContainer) player).getInjector();
} }
return null; return null;
} }
/** /**
* Set the player injector, if possible. * Set the player injector, if possible.
* @param player - the player to update. * @param player - the player to update.
* @param injector - the injector to store. * @param injector - the injector to store.
*/ */
public static void setInjectorInPlayer(Player player, SocketInjector injector) { public static void setInjectorInPlayer(Player player, SocketInjector injector) {
((InjectorContainer) player).setInjector(injector); ((InjectorContainer) player).setInjector(injector);
} }
/** /**
* Construct a temporary player that supports a subset of every player command. * Construct a temporary player that supports a subset of every player command.
* <p> * <p>
* Supported methods include: * Supported methods include:
* <ul> * <ul>
* <li>getPlayer()</li> * <li>getPlayer()</li>
* <li>getAddress()</li> * <li>getAddress()</li>
* <li>getServer()</li> * <li>getServer()</li>
* <li>chat(String)</li> * <li>chat(String)</li>
* <li>sendMessage(String)</li> * <li>sendMessage(String)</li>
* <li>sendMessage(String[])</li> * <li>sendMessage(String[])</li>
* <li>kickPlayer(String)</li> * <li>kickPlayer(String)</li>
* </ul> * </ul>
* <p> * <p>
* Note that a temporary player has not yet been assigned a name, and thus cannot be * Note that a temporary player has not yet been assigned a name, and thus cannot be
* uniquely identified. Use the address instead. * uniquely identified. Use the address instead.
* @param injector - the player injector used. * @param injector - the player injector used.
* @param server - the current server. * @param server - the current server.
* @return A temporary player instance. * @return A temporary player instance.
*/ */
public Player createTemporaryPlayer(final Server server) { public Player createTemporaryPlayer(final Server server) {
// Default implementation // Default implementation
Callback implementation = new MethodInterceptor() { Callback implementation = new MethodInterceptor() {
@Override @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName(); String methodName = method.getName();
SocketInjector injector = ((InjectorContainer) obj).getInjector(); SocketInjector injector = ((InjectorContainer) obj).getInjector();
if (injector == null) if (injector == null)
throw new IllegalStateException("Unable to find injector."); throw new IllegalStateException("Unable to find injector.");
// Use the socket to get the address // Use the socket to get the address
if (methodName.equalsIgnoreCase("getName")) if (methodName.equalsIgnoreCase("isOnline"))
return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]"; return injector.getSocket() != null && injector.getSocket().isConnected();
if (methodName.equalsIgnoreCase("getPlayer")) if (methodName.equalsIgnoreCase("getName"))
return injector.getUpdatedPlayer(); return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]";
if (methodName.equalsIgnoreCase("getAddress")) if (methodName.equalsIgnoreCase("getPlayer"))
return injector.getAddress(); return injector.getUpdatedPlayer();
if (methodName.equalsIgnoreCase("getServer")) if (methodName.equalsIgnoreCase("getAddress"))
return server; return injector.getAddress();
if (methodName.equalsIgnoreCase("getServer"))
try { return server;
// Handle send message methods
if (methodName.equalsIgnoreCase("chat") || methodName.equalsIgnoreCase("sendMessage")) { try {
Object argument = args[0]; // Handle send message methods
if (methodName.equalsIgnoreCase("chat") || methodName.equalsIgnoreCase("sendMessage")) {
// Dynamic overloading Object argument = args[0];
if (argument instanceof String) {
return sendMessage(injector, (String) argument); // Dynamic overloading
} else if (argument instanceof String[]) { if (argument instanceof String) {
for (String message : (String[]) argument) { return sendMessage(injector, (String) argument);
sendMessage(injector, message); } else if (argument instanceof String[]) {
} for (String message : (String[]) argument) {
return null; sendMessage(injector, message);
} }
} return null;
} catch (InvocationTargetException e) { }
throw e.getCause(); }
} } catch (InvocationTargetException e) {
throw e.getCause();
// Also, handle kicking }
if (methodName.equalsIgnoreCase("kickPlayer")) {
injector.disconnect((String) args[0]); // Also, handle kicking
return null; 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."); // 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() { // Shared callback filter
@Override if (callbackFilter == null) {
public int accept(Method method) { callbackFilter = new CallbackFilter() {
// Do not override the object method or the superclass methods @Override
if (method.getDeclaringClass().equals(Object.class) || public int accept(Method method) {
method.getDeclaringClass().equals(InjectorContainer.class)) // Do not override the object method or the superclass methods
return 0; if (method.getDeclaringClass().equals(Object.class) ||
else method.getDeclaringClass().equals(InjectorContainer.class))
return 1; return 0;
} else
}; return 1;
} }
};
// CGLib is amazing }
Enhancer ex = new Enhancer();
ex.setSuperclass(InjectorContainer.class); // CGLib is amazing
ex.setInterfaces(new Class[] { Player.class }); Enhancer ex = new Enhancer();
ex.setCallbacks(new Callback[] { NoOp.INSTANCE, implementation }); ex.setSuperclass(InjectorContainer.class);
ex.setCallbackFilter(callbackFilter); ex.setInterfaces(new Class[] { Player.class });
ex.setCallbacks(new Callback[] { NoOp.INSTANCE, implementation });
return (Player) ex.create(); 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. * Construct a temporary player with the given associated socket injector.
* @return The temporary player. * @param server - the parent server.
*/ * @param injector - the referenced socket injector.
public Player createTemporaryPlayer(Server server, SocketInjector injector) { * @return The temporary player.
Player temporary = createTemporaryPlayer(server); */
public Player createTemporaryPlayer(Server server, SocketInjector injector) {
((InjectorContainer) temporary).setInjector(injector); Player temporary = createTemporaryPlayer(server);
return temporary;
} ((InjectorContainer) temporary).setInjector(injector);
return temporary;
/** }
* Send a message to the given client.
* @param injector - the injector representing the client. /**
* @param message - a message. * Send a message to the given client.
* @return Always NULL. * @param injector - the injector representing the client.
* @throws InvocationTargetException If the message couldn't be sent. * @param message - a message.
* @throws FieldAccessException If we were unable to construct the message packet. * @return Always NULL.
*/ * @throws InvocationTargetException If the message couldn't be sent.
private Object sendMessage(SocketInjector injector, String message) throws InvocationTargetException, FieldAccessException { * @throws FieldAccessException If we were unable to construct the message packet.
injector.sendServerPacket(chatPacket.createPacket(message).getHandle(), false); */
return null; private Object sendMessage(SocketInjector injector, String message) throws InvocationTargetException, FieldAccessException {
} injector.sendServerPacket(chatPacket.createPacket(message).getHandle(), false);
} return null;
}
}