Refactored the hacked array list out of the player injector.

This commit is contained in:
Kristian S. Stangeland 2012-09-15 01:58:13 +02:00
parent f2effab907
commit 85f7360109
2 changed files with 116 additions and 84 deletions

View File

@ -0,0 +1,115 @@
package com.comphenix.protocol.injector;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Set;
import net.minecraft.server.Packet;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import com.comphenix.protocol.injector.PlayerInjector.FakePacket;
/**
* The array list that notifies when packets are sent by the server.
*
* @author Kristian
*/
class InjectedArrayList extends ArrayList<Packet> {
/**
* Silly Eclipse.
*/
private static final long serialVersionUID = -1173865905404280990L;
private PlayerInjector injector;
private Set<Packet> ignoredPackets;
private ClassLoader classLoader;
public InjectedArrayList(ClassLoader classLoader, PlayerInjector injector, Set<Packet> ignoredPackets) {
this.classLoader = classLoader;
this.injector = injector;
this.ignoredPackets = ignoredPackets;
}
@Override
public boolean add(Packet packet) {
Packet result = null;
// Check for fake packets and ignored packets
if (packet instanceof FakePacket) {
return true;
} else if (ignoredPackets.contains(packet)) {
ignoredPackets.remove(packet);
} else {
result = injector.handlePacketRecieved(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), true);
}
// Collection.add contract
return true;
} catch (InvocationTargetException e) {
throw new RuntimeException("Reverting cancelled packet failed.", e.getTargetException());
}
}
/**
* 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.
*/
Packet createNegativePacket(Packet source) {
Enhancer ex = new Enhancer();
Class<?> type = source.getClass();
// 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.
// }
ex.setInterfaces(new Class[] { FakePacket.class } );
ex.setUseCache(true);
ex.setClassLoader(classLoader);
ex.setSuperclass(type);
ex.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.getReturnType().equals(int.class) && args.length == 0) {
Integer result = (Integer) proxy.invokeSuper(obj, args);
return -result;
} else {
return proxy.invokeSuper(obj, args);
}
}
});
return (Packet) ex.create();
}
}

View File

@ -29,9 +29,6 @@ import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.server.EntityPlayer;
import net.minecraft.server.Packet;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
@ -219,7 +216,6 @@ class PlayerInjector {
}
}
@SuppressWarnings("serial")
public void injectManager() {
if (networkManager != null) {
@ -236,38 +232,7 @@ class PlayerInjector {
synchronized(minecraftList) {
// The list we'll be inserting
List<Packet> hackedList = new ArrayList<Packet>() {
@Override
public boolean add(Packet packet) {
Packet result = null;
// Check for fake packets and ignored packets
if (packet instanceof FakePacket) {
return true;
} else if (ignoredPackets.contains(packet)) {
ignoredPackets.remove(packet);
} else {
result = handlePacketRecieved(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
sendServerPacket(createNegativePacket(packet), true);
}
// Collection.add contract
return true;
} catch (InvocationTargetException e) {
throw new RuntimeException("Reverting cancelled packet failed.", e.getTargetException());
}
}
};
List<Packet> hackedList = new InjectedArrayList(manager.getClassLoader(), this, ignoredPackets);
// Add every previously stored packet
for (Packet packet : minecraftList) {
@ -284,54 +249,6 @@ class PlayerInjector {
}
}
/**
* 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.
*/
private Packet createNegativePacket(Packet source) {
Enhancer ex = new Enhancer();
Class<?> type = source.getClass();
// 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.
// }
ex.setInterfaces(new Class[] { FakePacket.class } );
ex.setUseCache(true);
ex.setClassLoader(manager.getClassLoader());
ex.setSuperclass(type);
ex.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.getReturnType().equals(int.class) && args.length == 0) {
Integer result = (Integer) proxy.invokeSuper(obj, args);
return -result;
} else {
return proxy.invokeSuper(obj, args);
}
}
});
return (Packet) ex.create();
}
/**
* Allows a packet to be recieved by the listeners.
* @param packet - packet to recieve.