mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-25 19:45:21 +01:00
Netty handler tidy
This commit is contained in:
parent
d58959fcca
commit
a8a1e9448e
@ -3,19 +3,15 @@ package us.myles.ViaVersion.bukkit.handlers;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||||
import us.myles.ViaVersion.exception.CancelException;
|
import us.myles.ViaVersion.exception.CancelDecoderException;
|
||||||
import us.myles.ViaVersion.packets.Direction;
|
|
||||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
|
||||||
import us.myles.ViaVersion.util.PipelineUtil;
|
import us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BukkitDecodeHandler extends ByteToMessageDecoder {
|
public class BukkitDecodeHandler extends ByteToMessageDecoder {
|
||||||
|
|
||||||
private final ByteToMessageDecoder minecraftDecoder;
|
private final ByteToMessageDecoder minecraftDecoder;
|
||||||
private final UserConnection info;
|
private final UserConnection info;
|
||||||
|
|
||||||
@ -26,64 +22,40 @@ public class BukkitDecodeHandler extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
||||||
// use transformers
|
if (!info.checkIncomingPacket()) {
|
||||||
if (bytebuf.readableBytes() > 0) {
|
bytebuf.clear(); // Don't accumulate
|
||||||
// Ignore if pending disconnect
|
throw CancelDecoderException.generate(null);
|
||||||
if (info.isPendingDisconnect()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Increment received
|
|
||||||
boolean second = info.incrementReceived();
|
|
||||||
// Check PPS
|
|
||||||
if (second) {
|
|
||||||
if (info.handlePPS())
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.isActive()) {
|
ByteBuf draft = null;
|
||||||
// Handle ID
|
|
||||||
int id = Type.VAR_INT.read(bytebuf);
|
|
||||||
// Transform
|
|
||||||
ByteBuf newPacket = ctx.alloc().buffer();
|
|
||||||
try {
|
try {
|
||||||
if (id == PacketWrapper.PASSTHROUGH_ID) {
|
if (info.shouldTransformPacket()) {
|
||||||
newPacket.writeBytes(bytebuf);
|
draft = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
} else {
|
info.transformIncoming(draft, CancelDecoderException::generate);
|
||||||
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 {
|
try {
|
||||||
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
|
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, draft == null ? bytebuf : draft));
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof Exception) {
|
if (e.getCause() instanceof Exception) {
|
||||||
throw (Exception) e.getCause();
|
throw (Exception) e.getCause();
|
||||||
|
} else if (e.getCause() instanceof Error) {
|
||||||
|
throw (Error) e.getCause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (info.isActive()) {
|
if (draft != null) {
|
||||||
bytebuf.release();
|
draft.release();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (PipelineUtil.containsCause(cause, CancelDecoderException.class)) return; // ProtocolLib compat
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
|
if (!NMSUtil.isDebugPropertySet()) {
|
||||||
|
cause.printStackTrace(); // Print if CB doesn't already do it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,22 +3,18 @@ package us.myles.ViaVersion.bukkit.handlers;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
|
||||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||||
import us.myles.ViaVersion.exception.CancelException;
|
import us.myles.ViaVersion.exception.CancelEncoderException;
|
||||||
import us.myles.ViaVersion.handlers.ChannelHandlerContextWrapper;
|
import us.myles.ViaVersion.handlers.ChannelHandlerContextWrapper;
|
||||||
import us.myles.ViaVersion.handlers.ViaHandler;
|
import us.myles.ViaVersion.handlers.ViaHandler;
|
||||||
import us.myles.ViaVersion.packets.Direction;
|
|
||||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
|
||||||
import us.myles.ViaVersion.util.PipelineUtil;
|
import us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHandler {
|
public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHandler {
|
||||||
private static Field versionField = null;
|
private static Field versionField;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
@ -51,6 +47,8 @@ public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHand
|
|||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof Exception) {
|
if (e.getCause() instanceof Exception) {
|
||||||
throw (Exception) e.getCause();
|
throw (Exception) e.getCause();
|
||||||
|
} else if (e.getCause() instanceof Error) {
|
||||||
|
throw (Error) e.getCause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,35 +57,17 @@ public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHand
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void transform(ByteBuf bytebuf) throws Exception {
|
public void transform(ByteBuf bytebuf) throws Exception {
|
||||||
if (bytebuf.readableBytes() == 0) {
|
info.checkOutgoingPacket();
|
||||||
return; // Someone Already Decoded It!
|
if (!info.shouldTransformPacket()) return;
|
||||||
}
|
info.transformOutgoing(bytebuf, CancelEncoderException::generate);
|
||||||
// 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
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (PipelineUtil.containsCause(cause, CancelEncoderException.class)) return; // ProtocolLib compat
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
|
if (!NMSUtil.isDebugPropertySet()) {
|
||||||
|
cause.printStackTrace(); // Print if CB doesn't already do it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,17 @@ import org.bukkit.Bukkit;
|
|||||||
public class NMSUtil {
|
public class NMSUtil {
|
||||||
private static final String BASE = Bukkit.getServer().getClass().getPackage().getName();
|
private static final String BASE = Bukkit.getServer().getClass().getPackage().getName();
|
||||||
private static final String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
private static final String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
||||||
|
private static final boolean DEBUG_PROPERTY = loadDebugProperty();
|
||||||
|
|
||||||
|
private static boolean loadDebugProperty() {
|
||||||
|
try {
|
||||||
|
Class<?> serverClass = nms("MinecraftServer");
|
||||||
|
Object server = serverClass.getDeclaredMethod("getServer").invoke(null);
|
||||||
|
return (boolean) serverClass.getMethod("isDebugging").invoke(server);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Class<?> nms(String className) throws ClassNotFoundException {
|
public static Class<?> nms(String className) throws ClassNotFoundException {
|
||||||
return Class.forName(NMS + "." + className);
|
return Class.forName(NMS + "." + className);
|
||||||
@ -17,4 +28,11 @@ public class NMSUtil {
|
|||||||
public static String getVersion() {
|
public static String getVersion() {
|
||||||
return BASE.substring(BASE.lastIndexOf('.') + 1);
|
return BASE.substring(BASE.lastIndexOf('.') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if debug=true is set in the server.properties (added by CB)
|
||||||
|
*/
|
||||||
|
public static boolean isDebugPropertySet() {
|
||||||
|
return DEBUG_PROPERTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,13 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
import us.myles.ViaVersion.exception.CancelDecoderException;
|
||||||
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.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class BungeeDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
public class BungeeDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
||||||
|
|
||||||
private final UserConnection info;
|
private final UserConnection info;
|
||||||
|
|
||||||
public BungeeDecodeHandler(UserConnection info) {
|
public BungeeDecodeHandler(UserConnection info) {
|
||||||
@ -25,55 +19,24 @@ public class BungeeDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
protected void decode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
// use transformers
|
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
|
||||||
if (bytebuf.readableBytes() > 0) {
|
if (!info.shouldTransformPacket()) {
|
||||||
// Ignore if pending disconnect
|
out.add(bytebuf.retain());
|
||||||
if (info.isPendingDisconnect()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Increment received
|
|
||||||
boolean second = info.incrementReceived();
|
|
||||||
// Check PPS
|
|
||||||
if (second) {
|
|
||||||
if (info.handlePPS())
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.isActive()) {
|
ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
// Handle ID
|
|
||||||
int id = Type.VAR_INT.read(bytebuf);
|
|
||||||
// Transform
|
|
||||||
ByteBuf newPacket = ctx.alloc().buffer();
|
|
||||||
try {
|
try {
|
||||||
if (id == PacketWrapper.PASSTHROUGH_ID) {
|
info.transformIncoming(draft, CancelDecoderException::generate);
|
||||||
newPacket.writeBytes(bytebuf);
|
out.add(draft.retain());
|
||||||
} else {
|
} finally {
|
||||||
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
|
draft.release();
|
||||||
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
|
|
||||||
protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper);
|
|
||||||
wrapper.writeToBuffer(newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
bytebuf.clear();
|
|
||||||
bytebuf = newPacket;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
// Clear Buffer
|
|
||||||
bytebuf.clear();
|
|
||||||
// Release Packet, be free!
|
|
||||||
newPacket.release();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bytebuf.retain();
|
|
||||||
}
|
|
||||||
|
|
||||||
out.add(bytebuf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (cause instanceof CancelDecoderException) return;
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,84 +4,80 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.Via;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
|
||||||
import us.myles.ViaVersion.bungee.util.BungeePipelineUtil;
|
import us.myles.ViaVersion.bungee.util.BungeePipelineUtil;
|
||||||
import us.myles.ViaVersion.exception.CancelException;
|
import us.myles.ViaVersion.exception.CancelEncoderException;
|
||||||
import us.myles.ViaVersion.packets.Direction;
|
|
||||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
|
||||||
import us.myles.ViaVersion.util.PipelineUtil;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class BungeeEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
public class BungeeEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
||||||
private final UserConnection info;
|
private final UserConnection info;
|
||||||
private boolean handledCompression = false;
|
private boolean handledCompression;
|
||||||
|
|
||||||
public BungeeEncodeHandler(UserConnection info) {
|
public BungeeEncodeHandler(UserConnection info) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
if (bytebuf.readableBytes() == 0) {
|
info.checkOutgoingPacket();
|
||||||
throw Via.getManager().isDebug() ? new CancelException() : CancelException.CACHED;
|
if (!info.shouldTransformPacket()) {
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
|
try {
|
||||||
|
boolean needsCompress = handleCompressionOrder(ctx, draft);
|
||||||
|
info.transformOutgoing(draft, CancelEncoderException::generate);
|
||||||
|
|
||||||
|
if (needsCompress) {
|
||||||
|
recompress(ctx, draft);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.add(draft.retain());
|
||||||
|
} finally {
|
||||||
|
draft.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf draft) {
|
||||||
boolean needsCompress = false;
|
boolean needsCompress = false;
|
||||||
if (!handledCompression) {
|
if (!handledCompression) {
|
||||||
if (ctx.pipeline().names().indexOf("compress") > ctx.pipeline().names().indexOf("via-encoder")) {
|
if (ctx.pipeline().names().indexOf("compress") > ctx.pipeline().names().indexOf("via-encoder")) {
|
||||||
// Need to decompress this packet due to bad order
|
// Need to decompress this packet due to bad order
|
||||||
bytebuf = BungeePipelineUtil.decompress(ctx, bytebuf);
|
ByteBuf decompressed = BungeePipelineUtil.decompress(ctx, draft);
|
||||||
ChannelHandler encoder = ctx.pipeline().get("via-decoder");
|
try {
|
||||||
ChannelHandler decoder = ctx.pipeline().get("via-encoder");
|
draft.clear().writeBytes(decompressed);
|
||||||
ctx.pipeline().remove(encoder);
|
} finally {
|
||||||
ctx.pipeline().remove(decoder);
|
decompressed.release();
|
||||||
ctx.pipeline().addAfter("decompress", "via-decoder", encoder);
|
}
|
||||||
ctx.pipeline().addAfter("compress", "via-encoder", decoder);
|
ChannelHandler dec = ctx.pipeline().get("via-decoder");
|
||||||
|
ChannelHandler enc = ctx.pipeline().get("via-encoder");
|
||||||
|
ctx.pipeline().remove(dec);
|
||||||
|
ctx.pipeline().remove(enc);
|
||||||
|
ctx.pipeline().addAfter("decompress", "via-decoder", dec);
|
||||||
|
ctx.pipeline().addAfter("compress", "via-encoder", enc);
|
||||||
needsCompress = true;
|
needsCompress = true;
|
||||||
handledCompression = true;
|
handledCompression = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Increment sent
|
return needsCompress;
|
||||||
info.incrementSent();
|
}
|
||||||
|
|
||||||
if (info.isActive()) {
|
|
||||||
// Handle ID
|
|
||||||
int id = Type.VAR_INT.read(bytebuf);
|
|
||||||
// Transform
|
|
||||||
ByteBuf oldPacket = bytebuf.copy();
|
|
||||||
bytebuf.clear();
|
|
||||||
|
|
||||||
|
private void recompress(ChannelHandlerContext ctx, ByteBuf draft) {
|
||||||
|
ByteBuf compressed = BungeePipelineUtil.compress(ctx, draft);
|
||||||
try {
|
try {
|
||||||
PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info);
|
draft.clear().writeBytes(compressed);
|
||||||
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
|
|
||||||
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
|
|
||||||
wrapper.writeToBuffer(bytebuf);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
bytebuf.clear();
|
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
oldPacket.release();
|
compressed.release();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsCompress) {
|
|
||||||
ByteBuf old = bytebuf;
|
|
||||||
bytebuf = BungeePipelineUtil.compress(ctx, bytebuf);
|
|
||||||
old.release();
|
|
||||||
out.add(bytebuf);
|
|
||||||
} else {
|
|
||||||
out.add(bytebuf.retain());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (cause instanceof CancelEncoderException) return;
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ import us.myles.ViaVersion.api.PacketWrapper;
|
|||||||
import us.myles.ViaVersion.api.Via;
|
import us.myles.ViaVersion.api.Via;
|
||||||
import us.myles.ViaVersion.api.ViaVersionConfig;
|
import us.myles.ViaVersion.api.ViaVersionConfig;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
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.protocols.base.ProtocolInfo;
|
||||||
import us.myles.ViaVersion.util.PipelineUtil;
|
import us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
@ -18,6 +20,7 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class UserConnection {
|
public class UserConnection {
|
||||||
private static final AtomicLong IDS = new AtomicLong();
|
private static final AtomicLong IDS = new AtomicLong();
|
||||||
@ -190,6 +193,8 @@ public class UserConnection {
|
|||||||
channel.close(); // =)
|
channel.close(); // =)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
getChannel().close(); // Just disconnect, we don't know what the connection is
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,6 +345,81 @@ public class UserConnection {
|
|||||||
this.warnings = warnings;
|
this.warnings = warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitors serverbound packets.
|
||||||
|
*
|
||||||
|
* @return false if this packet should be cancelled
|
||||||
|
*/
|
||||||
|
public boolean checkIncomingPacket() {
|
||||||
|
// Ignore if pending disconnect
|
||||||
|
if (pendingDisconnect) return false;
|
||||||
|
// Increment received + Check PPS
|
||||||
|
return !incrementReceived() || !handlePPS();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitors clientbound packets.
|
||||||
|
*/
|
||||||
|
public void checkOutgoingPacket() {
|
||||||
|
incrementSent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if packets needs transforming.
|
||||||
|
*
|
||||||
|
* @return if packets should be passed through
|
||||||
|
*/
|
||||||
|
public boolean shouldTransformPacket() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the clientbound packet contained in draft ByteBuf.
|
||||||
|
*
|
||||||
|
* @param draft ByteBuf with packet id and packet contents
|
||||||
|
* @param cancelSupplier Function called with original CancelException for generating the Exception used when
|
||||||
|
* packet is cancelled
|
||||||
|
* @throws Exception when transforming failed or this packet is cancelled
|
||||||
|
*/
|
||||||
|
public void transformOutgoing(ByteBuf draft, Function<Throwable, Exception> cancelSupplier) throws Exception {
|
||||||
|
if (!draft.isReadable()) return;
|
||||||
|
transform(draft, Direction.OUTGOING, cancelSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the serverbound packet contained in draft ByteBuf.
|
||||||
|
*
|
||||||
|
* @param draft ByteBuf with packet id and packet contents
|
||||||
|
* @param cancelSupplier Function called with original CancelException for generating the Exception used when
|
||||||
|
* packet is cancelled
|
||||||
|
* @throws Exception when transforming failed or this packet is cancelled
|
||||||
|
*/
|
||||||
|
public void transformIncoming(ByteBuf draft, Function<Throwable, Exception> cancelSupplier) throws Exception {
|
||||||
|
if (!draft.isReadable()) return;
|
||||||
|
transform(draft, Direction.INCOMING, cancelSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transform(ByteBuf draft, Direction direction, Function<Throwable, Exception> cancelSupplier) throws Exception {
|
||||||
|
int id = Type.VAR_INT.read(draft);
|
||||||
|
if (id == PacketWrapper.PASSTHROUGH_ID) return;
|
||||||
|
|
||||||
|
PacketWrapper wrapper = new PacketWrapper(id, draft, this);
|
||||||
|
ProtocolInfo protInfo = get(ProtocolInfo.class);
|
||||||
|
try {
|
||||||
|
protInfo.getPipeline().transform(direction, protInfo.getState(), wrapper);
|
||||||
|
} catch (CancelException ex) {
|
||||||
|
throw cancelSupplier.apply(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf transformed = draft.alloc().buffer();
|
||||||
|
try {
|
||||||
|
wrapper.writeToBuffer(transformed);
|
||||||
|
draft.clear().writeBytes(transformed);
|
||||||
|
} finally {
|
||||||
|
transformed.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -435,7 +435,7 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (packetWrapper.isCancelled()) {
|
if (packetWrapper.isCancelled()) {
|
||||||
throw Via.getManager().isDebug() ? new CancelException() : CancelException.CACHED;
|
throw CancelException.generate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package us.myles.ViaVersion.exception;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.DecoderException;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for cancelling packets in decode handlers
|
||||||
|
*/
|
||||||
|
public class CancelDecoderException extends DecoderException {
|
||||||
|
public static final CancelDecoderException CACHED = new CancelDecoderException("CACHED") {
|
||||||
|
@Override
|
||||||
|
public synchronized Throwable fillInStackTrace() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public CancelDecoderException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelDecoderException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelDecoderException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelDecoderException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cached CancelDecoderException or a new instance when {@link us.myles.ViaVersion.ViaManager}#isDebug() is true
|
||||||
|
* @param cause cause for being used when a new instance is creeated
|
||||||
|
* @return a CancelDecoderException instance
|
||||||
|
*/
|
||||||
|
public static CancelDecoderException generate(Throwable cause) {
|
||||||
|
if (Via.getManager().isDebug()) return new CancelDecoderException(cause);
|
||||||
|
return CACHED;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package us.myles.ViaVersion.exception;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.EncoderException;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for cancelling packets in encode handlers
|
||||||
|
*/
|
||||||
|
public class CancelEncoderException extends EncoderException {
|
||||||
|
public static final CancelEncoderException CACHED = new CancelEncoderException("CACHED") {
|
||||||
|
@Override
|
||||||
|
public synchronized Throwable fillInStackTrace() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public CancelEncoderException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelEncoderException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelEncoderException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelEncoderException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cached CancelEncoderException or a new instance when {@link us.myles.ViaVersion.ViaManager}#isDebug() is true
|
||||||
|
* @param cause cause for being used when a new instance is creeated
|
||||||
|
* @return a CancelEncoderException instance
|
||||||
|
*/
|
||||||
|
public static CancelEncoderException generate(Throwable cause) {
|
||||||
|
if (Via.getManager().isDebug()) return new CancelEncoderException(cause);
|
||||||
|
return CACHED;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,10 @@
|
|||||||
package us.myles.ViaVersion.exception;
|
package us.myles.ViaVersion.exception;
|
||||||
|
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for cancelling packets
|
||||||
|
*/
|
||||||
public class CancelException extends Exception {
|
public class CancelException extends Exception {
|
||||||
public static final CancelException CACHED = new CancelException("Cached - Enable /viaver debug to not use cached exception") {
|
public static final CancelException CACHED = new CancelException("Cached - Enable /viaver debug to not use cached exception") {
|
||||||
@Override
|
@Override
|
||||||
@ -26,4 +31,13 @@ public class CancelException extends Exception {
|
|||||||
public CancelException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
public CancelException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cached CancelException or a new instance when {@link us.myles.ViaVersion.ViaManager}#isDebug() is true
|
||||||
|
* @return a CancelException instance
|
||||||
|
*/
|
||||||
|
public static CancelException generate() {
|
||||||
|
if (Via.getManager().isDebug()) return new CancelException();
|
||||||
|
return CACHED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
public interface ViaHandler {
|
public interface ViaHandler {
|
||||||
public void transform(ByteBuf bytebuf) throws Exception;
|
void transform(ByteBuf bytebuf) throws Exception;
|
||||||
|
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
|
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,8 @@ package us.myles.ViaVersion.sponge.handlers;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
import us.myles.ViaVersion.exception.CancelDecoderException;
|
||||||
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 us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@ -26,64 +22,37 @@ public class SpongeDecodeHandler extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
||||||
// use transformers
|
if (!info.checkIncomingPacket()) {
|
||||||
if (bytebuf.readableBytes() > 0) {
|
bytebuf.clear(); // Don't accumulate
|
||||||
// Ignore if pending disconnect
|
throw CancelDecoderException.generate(null);
|
||||||
if (info.isPendingDisconnect()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Increment received
|
|
||||||
boolean second = info.incrementReceived();
|
|
||||||
// Check PPS
|
|
||||||
if (second) {
|
|
||||||
if (info.handlePPS())
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.isActive()) {
|
ByteBuf draft = null;
|
||||||
// Handle ID
|
|
||||||
int id = Type.VAR_INT.read(bytebuf);
|
|
||||||
// Transform
|
|
||||||
ByteBuf newPacket = ctx.alloc().buffer();
|
|
||||||
try {
|
try {
|
||||||
if (id == PacketWrapper.PASSTHROUGH_ID) {
|
if (info.shouldTransformPacket()) {
|
||||||
newPacket.writeBytes(bytebuf);
|
draft = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
} else {
|
info.transformIncoming(draft, CancelDecoderException::generate);
|
||||||
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 (Throwable e) {
|
|
||||||
// Clear Buffer
|
|
||||||
bytebuf.clear();
|
|
||||||
// Release Packet, be free!
|
|
||||||
newPacket.release();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// call minecraft decoder
|
|
||||||
try {
|
try {
|
||||||
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
|
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, draft == null ? bytebuf : draft));
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof Exception) {
|
if (e.getCause() instanceof Exception) {
|
||||||
throw (Exception) e.getCause();
|
throw (Exception) e.getCause();
|
||||||
|
} else if (e.getCause() instanceof Error) {
|
||||||
|
throw (Error) e.getCause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (info.isActive()) {
|
if (draft != null) {
|
||||||
bytebuf.release();
|
draft.release();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (cause instanceof CancelDecoderException) return;
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,69 +3,52 @@ package us.myles.ViaVersion.sponge.handlers;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.Via;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
import us.myles.ViaVersion.exception.CancelEncoderException;
|
||||||
import us.myles.ViaVersion.exception.CancelException;
|
import us.myles.ViaVersion.handlers.ChannelHandlerContextWrapper;
|
||||||
import us.myles.ViaVersion.packets.Direction;
|
import us.myles.ViaVersion.handlers.ViaHandler;
|
||||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
|
||||||
import us.myles.ViaVersion.util.PipelineUtil;
|
import us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
public class SpongeEncodeHandler extends MessageToByteEncoder {
|
public class SpongeEncodeHandler extends MessageToByteEncoder<Object> implements ViaHandler {
|
||||||
private final UserConnection info;
|
private final UserConnection info;
|
||||||
private final MessageToByteEncoder minecraftEncoder;
|
private final MessageToByteEncoder<?> minecraftEncoder;
|
||||||
|
|
||||||
public SpongeEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
|
public SpongeEncodeHandler(UserConnection info, MessageToByteEncoder<?> minecraftEncoder) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this.minecraftEncoder = minecraftEncoder;
|
this.minecraftEncoder = minecraftEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
||||||
// handle the packet type
|
// handle the packet type
|
||||||
if (!(o instanceof ByteBuf)) {
|
if (!(o instanceof ByteBuf)) {
|
||||||
// call minecraft encoder
|
// call minecraft encoder
|
||||||
try {
|
try {
|
||||||
PipelineUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf);
|
PipelineUtil.callEncode(this.minecraftEncoder, new ChannelHandlerContextWrapper(ctx, this), o, bytebuf);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof Exception) {
|
if (e.getCause() instanceof Exception) {
|
||||||
throw (Exception) e.getCause();
|
throw (Exception) e.getCause();
|
||||||
|
} else if (e.getCause() instanceof Error) {
|
||||||
|
throw (Error) e.getCause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bytebuf.readableBytes() == 0) {
|
|
||||||
throw Via.getManager().isDebug() ? new CancelException() : CancelException.CACHED;
|
|
||||||
}
|
|
||||||
// Increment sent
|
|
||||||
info.incrementSent();
|
|
||||||
if (info.isActive()) {
|
|
||||||
// Handle ID
|
|
||||||
int id = Type.VAR_INT.read(bytebuf);
|
|
||||||
// Transform
|
|
||||||
ByteBuf oldPacket = bytebuf.copy();
|
|
||||||
bytebuf.clear();
|
|
||||||
|
|
||||||
try {
|
transform(bytebuf);
|
||||||
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 (Throwable e) {
|
|
||||||
bytebuf.clear();
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
oldPacket.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transform(ByteBuf bytebuf) throws Exception {
|
||||||
|
info.checkOutgoingPacket();
|
||||||
|
if (!info.shouldTransformPacket()) return;
|
||||||
|
info.transformOutgoing(bytebuf, CancelEncoderException::generate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (cause instanceof CancelEncoderException) return;
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,8 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
import us.myles.ViaVersion.exception.CancelDecoderException;
|
||||||
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.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -24,54 +19,24 @@ public class VelocityDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
// use transformers
|
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
|
||||||
if (bytebuf.readableBytes() > 0) {
|
if (!info.shouldTransformPacket()) {
|
||||||
// Ignore if pending disconnect
|
out.add(bytebuf.retain());
|
||||||
if (info.isPendingDisconnect()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Increment received
|
|
||||||
boolean second = info.incrementReceived();
|
ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
// 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 {
|
try {
|
||||||
if (id == PacketWrapper.PASSTHROUGH_ID) {
|
info.transformIncoming(draft, CancelDecoderException::generate);
|
||||||
newPacket.writeBytes(bytebuf);
|
out.add(draft.retain());
|
||||||
} else {
|
} finally {
|
||||||
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
|
draft.release();
|
||||||
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
|
|
||||||
protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper);
|
|
||||||
wrapper.writeToBuffer(newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
bytebuf.clear();
|
|
||||||
bytebuf = newPacket;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
// Clear Buffer
|
|
||||||
bytebuf.clear();
|
|
||||||
// Release Packet, be free!
|
|
||||||
newPacket.release();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bytebuf.retain();
|
|
||||||
}
|
|
||||||
|
|
||||||
out.add(bytebuf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (cause instanceof CancelDecoderException) return;
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,11 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
|
||||||
import us.myles.ViaVersion.api.Via;
|
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
import us.myles.ViaVersion.exception.CancelEncoderException;
|
||||||
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 us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
@ -28,14 +24,38 @@ public class VelocityEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
if (bytebuf.readableBytes() == 0) {
|
info.checkOutgoingPacket();
|
||||||
throw Via.getManager().isDebug() ? new CancelException() : CancelException.CACHED;
|
if (!info.shouldTransformPacket()) {
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
|
try {
|
||||||
|
boolean needsCompress = handleCompressionOrder(ctx, draft);
|
||||||
|
|
||||||
|
info.transformOutgoing(draft, CancelEncoderException::generate);
|
||||||
|
|
||||||
|
if (needsCompress) {
|
||||||
|
recompress(ctx, draft);
|
||||||
|
}
|
||||||
|
out.add(draft.retain());
|
||||||
|
} finally {
|
||||||
|
draft.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf draft) throws InvocationTargetException {
|
||||||
boolean needsCompress = false;
|
boolean needsCompress = false;
|
||||||
if (!handledCompression
|
if (!handledCompression
|
||||||
&& ctx.pipeline().names().indexOf("compression-encoder") > ctx.pipeline().names().indexOf("via-encoder")) {
|
&& ctx.pipeline().names().indexOf("compression-encoder") > ctx.pipeline().names().indexOf("via-encoder")) {
|
||||||
// Need to decompress this packet due to bad order
|
// Need to decompress this packet due to bad order
|
||||||
bytebuf = (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder) ctx.pipeline().get("compression-decoder"), ctx, bytebuf).get(0);
|
ByteBuf decompressed = (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder<?>) ctx.pipeline().get("compression-decoder"), ctx, draft).get(0);
|
||||||
|
try {
|
||||||
|
draft.clear().writeBytes(decompressed);
|
||||||
|
} finally {
|
||||||
|
decompressed.release();
|
||||||
|
}
|
||||||
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
|
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
|
||||||
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
|
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
|
||||||
ctx.pipeline().remove(encoder);
|
ctx.pipeline().remove(encoder);
|
||||||
@ -44,51 +64,23 @@ public class VelocityEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
|||||||
ctx.pipeline().addAfter("compression-decoder", "via-decoder", decoder);
|
ctx.pipeline().addAfter("compression-decoder", "via-decoder", decoder);
|
||||||
needsCompress = true;
|
needsCompress = true;
|
||||||
handledCompression = true;
|
handledCompression = true;
|
||||||
} else {
|
|
||||||
bytebuf.retain();
|
|
||||||
}
|
}
|
||||||
// Increment sent
|
return needsCompress;
|
||||||
info.incrementSent();
|
}
|
||||||
|
|
||||||
|
private void recompress(ChannelHandlerContext ctx, ByteBuf draft) throws InvocationTargetException {
|
||||||
if (info.isActive()) {
|
ByteBuf compressed = ctx.alloc().buffer();
|
||||||
// Handle ID
|
|
||||||
int id = Type.VAR_INT.read(bytebuf);
|
|
||||||
// Transform
|
|
||||||
ByteBuf newPacket = bytebuf.alloc().buffer();
|
|
||||||
try {
|
try {
|
||||||
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
|
PipelineUtil.callEncode((MessageToByteEncoder<?>) ctx.pipeline().get("compression-encoder"), ctx, draft, compressed);
|
||||||
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
|
draft.clear().writeBytes(compressed);
|
||||||
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
|
|
||||||
|
|
||||||
wrapper.writeToBuffer(newPacket);
|
|
||||||
|
|
||||||
bytebuf.clear();
|
|
||||||
bytebuf.release();
|
|
||||||
bytebuf = newPacket;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
bytebuf.clear();
|
|
||||||
bytebuf.release();
|
|
||||||
newPacket.release();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsCompress) {
|
|
||||||
ByteBuf old = bytebuf;
|
|
||||||
bytebuf = ctx.alloc().buffer();
|
|
||||||
try {
|
|
||||||
PipelineUtil.callEncode((MessageToByteEncoder) ctx.pipeline().get("compression-encoder"), ctx, old, bytebuf);
|
|
||||||
} finally {
|
} finally {
|
||||||
old.release();
|
compressed.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.add(bytebuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
if (cause instanceof CancelEncoderException) return;
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user