Change reflection to NMSUtil, and start work on Bungee (doesn't work)

This commit is contained in:
Myles 2016-09-26 13:50:20 +01:00
parent 42efc736c3
commit 42edffb309
18 changed files with 335 additions and 178 deletions

View File

@ -17,6 +17,7 @@ import us.myles.ViaVersion.api.platform.ViaPlatform;
import us.myles.ViaVersion.bukkit.*; import us.myles.ViaVersion.bukkit.*;
import us.myles.ViaVersion.classgenerator.ClassGenerator; import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.dump.PluginInfo; import us.myles.ViaVersion.dump.PluginInfo;
import us.myles.ViaVersion.util.NMSUtil;
import us.myles.ViaVersion.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.ArrayList; import java.util.ArrayList;
@ -76,7 +77,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform {
// Check if it's a spigot build with a protocol mod // Check if it's a spigot build with a protocol mod
try { try {
compatSpigotBuild = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null; compatSpigotBuild = NMSUtil.nms("PacketEncoder").getDeclaredField("version") != null;
} catch (Exception e) { } catch (Exception e) {
compatSpigotBuild = false; compatSpigotBuild = false;
} }

View File

@ -5,6 +5,7 @@ import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.util.NMSUtil;
import us.myles.ViaVersion.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -19,10 +20,10 @@ public class BukkitViaBulkChunkTranslator extends BulkChunkTranslatorProvider {
static { static {
try { try {
mapChunkBulkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunkBulk")); mapChunkBulkRef = new ReflectionUtil.ClassReflection(NMSUtil.nms("PacketPlayOutMapChunkBulk"));
mapChunkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunk")); mapChunkRef = new ReflectionUtil.ClassReflection(NMSUtil.nms("PacketPlayOutMapChunk"));
if (((ViaVersionPlugin) Via.getPlatform()).isSpigot()) { if (((ViaVersionPlugin) Via.getPlatform()).isSpigot()) {
obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, ReflectionUtil.nms("World")); obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, NMSUtil.nms("World"));
} }
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
// Ignore as server is probably 1.9+ // Ignore as server is probably 1.9+

View File

@ -11,6 +11,7 @@ import us.myles.ViaVersion.api.platform.ViaInjector;
import us.myles.ViaVersion.handlers.ViaVersionInitializer; import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.util.ConcurrentList; import us.myles.ViaVersion.util.ConcurrentList;
import us.myles.ViaVersion.util.ListWrapper; import us.myles.ViaVersion.util.ListWrapper;
import us.myles.ViaVersion.util.NMSUtil;
import us.myles.ViaVersion.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -128,9 +129,9 @@ public class BukkitViaInjector implements ViaInjector {
@Override @Override
public int getServerProtocolVersion() throws Exception { public int getServerProtocolVersion() throws Exception {
try { try {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer"); Class<?> serverClazz = NMSUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer"); Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Class<?> pingClazz = ReflectionUtil.nms("ServerPing"); Class<?> pingClazz = NMSUtil.nms("ServerPing");
Object ping = null; Object ping = null;
// Search for ping method // Search for ping method
for (Field f : serverClazz.getDeclaredFields()) { for (Field f : serverClazz.getDeclaredFields()) {
@ -173,7 +174,7 @@ public class BukkitViaInjector implements ViaInjector {
} }
public static Object getServerConnection() throws Exception { public static Object getServerConnection() throws Exception {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer"); Class<?> serverClazz = NMSUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer"); Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = null; Object connection = null;
for (Method m : serverClazz.getDeclaredMethods()) { for (Method m : serverClazz.getDeclaredMethods()) {

View File

@ -7,6 +7,7 @@ import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
import us.myles.ViaVersion.util.NMSUtil;
import us.myles.ViaVersion.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -28,7 +29,7 @@ public class BukkitViaMovementTransmitter extends MovementTransmitterProvider {
Class<?> idlePacketClass; Class<?> idlePacketClass;
try { try {
idlePacketClass = ReflectionUtil.nms("PacketPlayInFlying"); idlePacketClass = NMSUtil.nms("PacketPlayInFlying");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
return; // We'll hope this is 1.9.4+ return; // We'll hope this is 1.9.4+
} }
@ -45,19 +46,19 @@ public class BukkitViaMovementTransmitter extends MovementTransmitterProvider {
} }
if (USE_NMS) { if (USE_NMS) {
try { try {
getHandle = ReflectionUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle"); getHandle = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
} catch (NoSuchMethodException | ClassNotFoundException e) { } catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e); throw new RuntimeException("Couldn't find CraftPlayer", e);
} }
try { try {
connection = ReflectionUtil.nms("EntityPlayer").getDeclaredField("playerConnection"); connection = NMSUtil.nms("EntityPlayer").getDeclaredField("playerConnection");
} catch (NoSuchFieldException | ClassNotFoundException e) { } catch (NoSuchFieldException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find Player Connection", e); throw new RuntimeException("Couldn't find Player Connection", e);
} }
try { try {
handleFlying = ReflectionUtil.nms("PlayerConnection").getDeclaredMethod("a", idlePacketClass); handleFlying = NMSUtil.nms("PlayerConnection").getDeclaredMethod("a", idlePacketClass);
} catch (NoSuchMethodException | ClassNotFoundException e) { } catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e); throw new RuntimeException("Couldn't find CraftPlayer", e);
} }

View File

@ -8,6 +8,7 @@ import org.bukkit.plugin.Plugin;
import us.myles.ViaVersion.api.ViaVersion; import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.handlers.ViaDecodeHandler; import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler; import us.myles.ViaVersion.handlers.ViaEncodeHandler;
import us.myles.ViaVersion.util.NMSUtil;
import us.myles.ViaVersion.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
public class ClassGenerator { public class ClassGenerator {
@ -27,8 +28,8 @@ public class ClassGenerator {
} }
if (ViaVersion.getInstance().isCompatSpigotBuild()) { if (ViaVersion.getInstance().isCompatSpigotBuild()) {
Class decodeSuper = ReflectionUtil.nms("PacketDecoder"); Class decodeSuper = NMSUtil.nms("PacketDecoder");
Class encodeSuper = ReflectionUtil.nms("PacketEncoder"); Class encodeSuper = NMSUtil.nms("PacketEncoder");
// Generate the classes // Generate the classes
addSpigotCompatibility(pool, ViaDecodeHandler.class, decodeSuper); addSpigotCompatibility(pool, ViaDecodeHandler.class, decodeSuper);
addSpigotCompatibility(pool, ViaEncodeHandler.class, encodeSuper); addSpigotCompatibility(pool, ViaEncodeHandler.class, encodeSuper);

View File

@ -23,6 +23,7 @@ import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position; import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8; import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.util.NMSUtil;
import us.myles.ViaVersion.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
import java.io.DataOutput; import java.io.DataOutput;
@ -88,7 +89,7 @@ public class CommandBlockListener extends ViaListener {
return; return;
CommandBlock cmd = (CommandBlock) b.getState(); CommandBlock cmd = (CommandBlock) b.getState();
Object tileEntityCommand = ReflectionUtil.get(cmd, "commandBlock", ReflectionUtil.nms("TileEntityCommand")); Object tileEntityCommand = ReflectionUtil.get(cmd, "commandBlock", NMSUtil.nms("TileEntityCommand"));
Object updatePacket = ReflectionUtil.invoke(tileEntityCommand, "getUpdatePacket"); Object updatePacket = ReflectionUtil.invoke(tileEntityCommand, "getUpdatePacket");
PacketWrapper wrapper = generatePacket(updatePacket, getUserConnection(player)); PacketWrapper wrapper = generatePacket(updatePacket, getUserConnection(player));
@ -98,12 +99,12 @@ public class CommandBlockListener extends ViaListener {
private PacketWrapper generatePacket(Object updatePacket, UserConnection usr) throws Exception { private PacketWrapper generatePacket(Object updatePacket, UserConnection usr) throws Exception {
PacketWrapper wrapper = new PacketWrapper(0x09, null, usr); // Update block entity PacketWrapper wrapper = new PacketWrapper(0x09, null, usr); // Update block entity
long[] pos = getPosition(ReflectionUtil.get(updatePacket, "a", ReflectionUtil.nms("BlockPosition"))); long[] pos = getPosition(ReflectionUtil.get(updatePacket, "a", NMSUtil.nms("BlockPosition")));
wrapper.write(Type.POSITION, new Position(pos[0], pos[1], pos[2])); //Block position wrapper.write(Type.POSITION, new Position(pos[0], pos[1], pos[2])); //Block position
wrapper.write(Type.BYTE, (byte) 2); // Action id always 2 wrapper.write(Type.BYTE, (byte) 2); // Action id always 2
CompoundTag nbt = getNBT(ReflectionUtil.get(updatePacket, "c", ReflectionUtil.nms("NBTTagCompound"))); CompoundTag nbt = getNBT(ReflectionUtil.get(updatePacket, "c", NMSUtil.nms("NBTTagCompound")));
if (nbt == null) { if (nbt == null) {
wrapper.write(Type.BYTE, (byte) 0); //If nbt is null. Use 0 as nbt wrapper.write(Type.BYTE, (byte) 0); //If nbt is null. Use 0 as nbt
return wrapper; return wrapper;
@ -125,12 +126,12 @@ public class CommandBlockListener extends ViaListener {
} }
private boolean isR1() { private boolean isR1() {
return ReflectionUtil.getVersion().equals("v1_8_R1"); return NMSUtil.getVersion().equals("v1_8_R1");
} }
private CompoundTag getNBT(Object obj) throws Exception { private CompoundTag getNBT(Object obj) throws Exception {
ByteBuf buf = Unpooled.buffer(); ByteBuf buf = Unpooled.buffer();
Method m = ReflectionUtil.nms("NBTCompressedStreamTools").getMethod("a", ReflectionUtil.nms("NBTTagCompound"), DataOutput.class); Method m = NMSUtil.nms("NBTCompressedStreamTools").getMethod("a", NMSUtil.nms("NBTTagCompound"), DataOutput.class);
m.invoke(null, obj, new DataOutputStream(new ByteBufOutputStream(buf))); m.invoke(null, obj, new DataOutputStream(new ByteBufOutputStream(buf)));
try { try {
return Type.NBT.read(buf); return Type.NBT.read(buf);

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion.util;
import org.bukkit.Bukkit;
public class NMSUtil {
private static String BASE = Bukkit.getServer().getClass().getPackage().getName();
private static String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
public static Class<?> nms(String className) throws ClassNotFoundException {
return Class.forName(NMS + "." + className);
}
public static Class<?> obc(String className) throws ClassNotFoundException {
return Class.forName(BASE + "." + className);
}
public static String getVersion() {
return BASE.substring(BASE.lastIndexOf('.') + 1);
}
}

View File

@ -1,145 +0,0 @@
package us.myles.ViaVersion.util;
import com.google.common.collect.Maps;
import org.bukkit.Bukkit;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public class ReflectionUtil {
private static String BASE = Bukkit.getServer().getClass().getPackage().getName();
private static String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
public static Class<?> nms(String className) throws ClassNotFoundException {
return Class.forName(NMS + "." + className);
}
public static Class<?> obc(String className) throws ClassNotFoundException {
return Class.forName(BASE + "." + className);
}
public static String getVersion() {
return BASE.substring(BASE.lastIndexOf('.') + 1);
}
public static Object invokeStatic(Class<?> clazz, String method) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method m = clazz.getDeclaredMethod(method);
return m.invoke(null);
}
public static Object invoke(Object o, String method) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method m = o.getClass().getDeclaredMethod(method);
return m.invoke(o);
}
public static <T> T getStatic(Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return (T) field.get(null);
}
public static <T> T getSuper(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getSuperclass().getDeclaredField(f);
field.setAccessible(true);
return (T) field.get(o);
}
public static <T> T get(Object instance, Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return (T) field.get(instance);
}
public static <T> T get(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getDeclaredField(f);
field.setAccessible(true);
return (T) field.get(o);
}
public static <T> T getPublic(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getField(f);
field.setAccessible(true);
return (T) field.get(o);
}
public static void set(Object o, String f, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getDeclaredField(f);
field.setAccessible(true);
field.set(o, value);
}
public static final class ClassReflection {
private final Class<?> handle;
private final Map<String, Field> fields = Maps.newConcurrentMap();
private final Map<String, Method> methods = Maps.newConcurrentMap();
public ClassReflection(Class<?> handle) {
this(handle, true);
}
public ClassReflection(Class<?> handle, boolean recursive) {
this.handle = handle;
scanFields(handle, recursive);
scanMethods(handle, recursive);
}
private void scanFields(Class<?> host, boolean recursive) {
if (host.getSuperclass() != null && recursive) {
scanFields(host.getSuperclass(), true);
}
for (Field field : host.getDeclaredFields()) {
field.setAccessible(true);
fields.put(field.getName(), field);
}
}
private void scanMethods(Class<?> host, boolean recursive) {
if (host.getSuperclass() != null && recursive) {
scanMethods(host.getSuperclass(), true);
}
for (Method method : host.getDeclaredMethods()) {
method.setAccessible(true);
methods.put(method.getName(), method);
}
}
public Object newInstance() throws IllegalAccessException, InstantiationException {
return handle.newInstance();
}
public Field getField(String name) {
return fields.get(name);
}
public void setFieldValue(String fieldName, Object instance, Object value) throws IllegalAccessException {
getField(fieldName).set(instance, value);
}
public <T> T getFieldValue(String fieldName, Object instance, Class<T> type) throws IllegalAccessException {
return type.cast(getField(fieldName).get(instance));
}
public <T> T invokeMethod(Class<T> type, String methodName, Object instance, Object... args) throws InvocationTargetException, IllegalAccessException {
return type.cast(getMethod(methodName).invoke(instance, args));
}
public Method getMethod(String name) {
return methods.get(name);
}
public Collection<Field> getFields() {
return Collections.unmodifiableCollection(fields.values());
}
public Collection<Method> getMethods() {
return Collections.unmodifiableCollection(methods.values());
}
}
}

View File

@ -25,18 +25,23 @@
</build> </build>
<dependencies> <dependencies>
<!-- BungeeCord --> <!-- BungeeCord API -->
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>1.10-SNAPSHOT</version> <version>1.10-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- BungeeCord Proxy -->
<dependency> <dependency>
<groupId>us.myles</groupId> <groupId>net.md-5</groupId>
<artifactId>viaversion-common</artifactId> <artifactId>bungeecord-proxy</artifactId>
<version>1.0.0-ALPHA-modules</version> <version>1.4.7-SNAPSHOT</version>
<scope>provided</scope>
</dependency> </dependency>
<!-- Common Module -->
<dependency> <dependency>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<artifactId>viaversion-common</artifactId> <artifactId>viaversion-common</artifactId>

View File

@ -28,10 +28,7 @@ public class Bungee extends Plugin implements ViaPlatform {
public void onLoad() { public void onLoad() {
api = new BungeeViaAPI(); api = new BungeeViaAPI();
config = new BungeeConfigProvider(); config = new BungeeConfigProvider();
} // Init platform
@Override
public void onEnable() {
Via.init(ViaManager.builder() Via.init(ViaManager.builder()
.platform(this) .platform(this)
.injector(new BungeeViaInjector()) .injector(new BungeeViaInjector())
@ -39,6 +36,12 @@ public class Bungee extends Plugin implements ViaPlatform {
.build()); .build());
} }
@Override
public void onEnable() {
// Inject
Via.getManager().init();
}
@Override @Override
public String getPlatformName() { public String getPlatformName() {
return "BungeeCord"; return "BungeeCord";

View File

@ -1,18 +1,38 @@
package us.myles.ViaVersion.bungee; package us.myles.ViaVersion.bungee;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import net.md_5.bungee.netty.PipelineUtils;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.platform.ViaInjector; import us.myles.ViaVersion.api.platform.ViaInjector;
import us.myles.ViaVersion.bungee.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.util.ReflectionUtil;
public class BungeeViaInjector implements ViaInjector { public class BungeeViaInjector implements ViaInjector {
@Override @Override
public void inject() throws Exception { public void inject() throws Exception {
try {
try {
ChannelInitializer<Channel> oldInit = PipelineUtils.SERVER_CHILD;
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
ReflectionUtil.setStatic(PipelineUtils.class, "SERVER_CHILD", newInit);
} catch (NoSuchFieldException e) {
throw new Exception("Unable to find core component 'childHandler', please check your plugins. issue: ");
}
} catch (Exception e) {
Via.getPlatform().getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
throw e;
}
} }
@Override @Override
public void uninject() throws Exception { public void uninject() {
// TODO: Uninject from players currently online
Via.getPlatform().getLogger().severe("ViaVersion cannot remove itself from Bungee without a reboot!");
} }
@Override @Override
public int getServerProtocolVersion() throws Exception { public int getServerProtocolVersion() throws Exception {
return 47; return 47;

View File

@ -0,0 +1,89 @@
package us.myles.ViaVersion.bungee.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.PipelineUtil;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class ViaDecodeHandler extends ByteToMessageDecoder {
private final ByteToMessageDecoder minecraftDecoder;
private final UserConnection info;
public ViaDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
this.info = info;
this.minecraftDecoder = minecraftDecoder;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
// use transformers
if (bytebuf.readableBytes() > 0) {
// Ignore if pending disconnect
if (info.isPendingDisconnect()) {
return;
}
// Increment received
boolean second = info.incrementReceived();
// Check PPS
if (second) {
if (info.handlePPS())
return;
}
if (info.isActive()) {
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
ByteBuf newPacket = ctx.alloc().buffer();
try {
if (id == PacketWrapper.PASSTHROUGH_ID) {
newPacket.writeBytes(bytebuf);
} else {
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper);
wrapper.writeToBuffer(newPacket);
}
bytebuf.clear();
bytebuf = newPacket;
} catch (Exception e) {
// Clear Buffer
bytebuf.clear();
// Release Packet, be free!
newPacket.release();
throw e;
}
}
// call minecraft decoder
try {
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause();
}
} finally {
if (info.isActive()) {
bytebuf.release();
}
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}

View File

@ -0,0 +1,70 @@
package us.myles.ViaVersion.bungee.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.PipelineUtil;
import java.lang.reflect.InvocationTargetException;
public class ViaEncodeHandler extends MessageToByteEncoder {
private final UserConnection info;
private final MessageToByteEncoder minecraftEncoder;
public ViaEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
this.info = info;
this.minecraftEncoder = minecraftEncoder;
}
@Override
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
// handle the packet type
if (!(o instanceof ByteBuf)) {
// call minecraft encoder
try {
PipelineUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause();
}
}
}
if (bytebuf.readableBytes() == 0) {
throw new CancelException();
}
// Increment sent
info.incrementSent();
if (info.isActive()) {
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
ByteBuf oldPacket = bytebuf.copy();
bytebuf.clear();
try {
PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info);
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
wrapper.writeToBuffer(bytebuf);
} catch (Exception e) {
bytebuf.clear();
throw e;
} finally {
oldPacket.release();
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}

View File

@ -0,0 +1,35 @@
package us.myles.ViaVersion.bungee.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.List;
public class ViaPacketHandler extends MessageToMessageEncoder {
private final UserConnection info;
public ViaPacketHandler(UserConnection info) {
this.info = info;
}
@Override
protected void encode(ChannelHandlerContext ctx, Object o, List list) throws Exception {
// Split chunks bulk packet up in to single chunks packets before it reached the encoder.
// This will prevent issues with several plugins and other protocol handlers due to the chunks being sent twice.
// It also sends the chunks in the right order possible resolving some issues with added chunks/block/entity data.
if (!(o instanceof ByteBuf)) {
info.setLastPacket(o);
/* This transformer is more for fixing issues which we find hard at packet level :) */
if (info.isActive()) {
if (info.get(ProtocolInfo.class).getPipeline().filter(o, list)) {
return;
}
}
}
list.add(o);
}
}

View File

@ -0,0 +1,48 @@
package us.myles.ViaVersion.bungee.handlers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
import java.lang.reflect.Method;
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelInitializer<Channel> original;
private Method method;
public ViaVersionInitializer(ChannelInitializer<Channel> oldInit) {
this.original = oldInit;
try {
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
this.method.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public ChannelInitializer<Channel> getOriginal() {
return original;
}
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
UserConnection info = new UserConnection(socketChannel);
// init protocol
new ProtocolPipeline(info);
// Add originals
this.method.invoke(this.original, socketChannel);
// Add our transformers
MessageToByteEncoder encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ByteToMessageDecoder decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
socketChannel.pipeline().replace("encoder", "encoder", encoder);
socketChannel.pipeline().replace("decoder", "decoder", decoder);
socketChannel.pipeline().addAfter("packet_handler", "viaversion_packet_handler", chunkHandler);
}
}

View File

@ -1,4 +1,4 @@
package us.myles.ViaVersion.sponge.util; package us.myles.ViaVersion.util;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -27,6 +27,12 @@ public class ReflectionUtil {
return (T) field.get(null); return (T) field.get(null);
} }
public static void setStatic(Class<?> clazz, String f, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
field.set(null, value);
}
public static <T> T getSuper(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException { public static <T> T getSuper(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getSuperclass().getDeclaredField(f); Field field = o.getClass().getSuperclass().getDeclaredField(f);
field.setAccessible(true); field.setAccessible(true);
@ -58,6 +64,7 @@ public class ReflectionUtil {
field.set(o, value); field.set(o, value);
} }
public static final class ClassReflection { public static final class ClassReflection {
private final Class<?> handle; private final Class<?> handle;
private final Map<String, Field> fields = Maps.newConcurrentMap(); private final Map<String, Field> fields = Maps.newConcurrentMap();

View File

@ -10,12 +10,11 @@ import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.platform.ViaInjector; import us.myles.ViaVersion.api.platform.ViaInjector;
import us.myles.ViaVersion.sponge.handlers.ViaVersionInitializer; import us.myles.ViaVersion.sponge.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.sponge.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
import us.myles.ViaVersion.util.ListWrapper; import us.myles.ViaVersion.util.ListWrapper;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -4,7 +4,7 @@ import com.google.common.collect.Lists;
import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.sponge.util.ReflectionUtil; import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;