update readme, parse .viafabric before autodetect, close #89 by stealing viaversion-velocity code

This commit is contained in:
creeper123123321 2021-01-11 12:02:03 -03:00
parent 98d9052aaf
commit db57b474d9
8 changed files with 142 additions and 51 deletions

View File

@ -21,17 +21,19 @@ or registry synchronization (fabric-registry-sync mod).
| Dependency | Download | | Dependency | Download |
| ----------------------------------------- | ------------------------------------------------------------------------------------------ | | ----------------------------------------- | ------------------------------------------------------------------------------------------ |
| (Bundled 3.2.0 release) ViaVersion 3.2.0+ | https://ci.viaversion.com/job/ViaVersion/ or https://ci.viaversion.com/job/ViaVersion-DEV/ | | (Bundled 3.2.1 release) ViaVersion 3.2.1+ | https://ci.viaversion.com/job/ViaVersion/ or https://ci.viaversion.com/job/ViaVersion-DEV/ |
| (Bundled) Cotton Client Commands | https://www.curseforge.com/minecraft/mc-mods/cotton-client-commands | | (Bundled) Cotton Client Commands | https://www.curseforge.com/minecraft/mc-mods/cotton-client-commands |
| (Optional) Fabric Command API v1/v0 | https://www.curseforge.com/minecraft/mc-mods/fabric-api | | (Optional) Fabric Command API v1/v0 | https://www.curseforge.com/minecraft/mc-mods/fabric-api |
| (Optional) Fabric Lifecycle Events v1/v0 | https://www.curseforge.com/minecraft/mc-mods/fabric-api |
| Fabric Resource Loader v0 | https://www.curseforge.com/minecraft/mc-mods/fabric-api | | Fabric Resource Loader v0 | https://www.curseforge.com/minecraft/mc-mods/fabric-api |
**1.8.9 Dependencies:** **1.8.9 Dependencies:**
| Dependency | Download | | Dependency | Download |
| ----------------------------------------- | ------------------------------------------------------------------------------------------ | | ----------------------------------------- | ------------------------------------------------------------------------------------------ |
| (Bundled 3.2.0 release) ViaVersion 3.2.0+ | https://ci.viaversion.com/job/ViaVersion/ or https://ci.viaversion.com/job/ViaVersion-DEV/ | | (Bundled 3.2.1 release) ViaVersion 3.2.1+ | https://ci.viaversion.com/job/ViaVersion/ or https://ci.viaversion.com/job/ViaVersion-DEV/ |
| (Optional) Fabric Commands v0 | https://www.curseforge.com/minecraft/mc-mods/legacy-fabric-api | | (Optional) Fabric Commands v0 | https://www.curseforge.com/minecraft/mc-mods/legacy-fabric-api |
| (Optional) Fabric Lifecycle Events v1 | https://www.curseforge.com/minecraft/mc-mods/legacy-fabric-api |
| Fabric Resource Loader v0 | https://www.curseforge.com/minecraft/mc-mods/legacy-fabric-api | | Fabric Resource Loader v0 | https://www.curseforge.com/minecraft/mc-mods/legacy-fabric-api |
@ -102,6 +104,12 @@ Adding [ViaBackwards](https://viaversion.com/backwards) (and optionally [ViaRewi
- [ViaVersion](https://viaversion.com): ViaVersion can run as a plugin for BungeeCord, CraftBukkit, SpongeCommon and Velocity servers. - [ViaVersion](https://viaversion.com): ViaVersion can run as a plugin for BungeeCord, CraftBukkit, SpongeCommon and Velocity servers.
**Cool things to try:**
- [Geyser](https://geysermc.org/): Plugins, Fabric mod and a standalone proxy for Bedrock edition translation.
- [PolyMc](https://github.com/TheEpicBlock/PolyMc): Fabric mods which translates modded items and blocks, allowing
vanilla to connect using resource packs.
**How can I disable client-side ViaFabric?:** **How can I disable client-side ViaFabric?:**
- You can disable it in the menu or by setting global protocol version to -1 (this will keep per-server translations still enabled) - You can disable it in the menu or by setting global protocol version to -1 (this will keep per-server translations still enabled)

View File

@ -25,7 +25,39 @@
package com.github.creeper123123321.viafabric.handler; package com.github.creeper123123321.viafabric.handler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageDecoder;
import us.myles.ViaVersion.util.PipelineUtil;
import java.lang.reflect.InvocationTargetException;
public class CommonTransformer { public class CommonTransformer {
public static final String HANDLER_DECODER_NAME = "via-decoder"; public static final String HANDLER_DECODER_NAME = "via-decoder";
public static final String HANDLER_ENCODER_NAME = "via-encoder"; public static final String HANDLER_ENCODER_NAME = "via-encoder";
public static void decompress(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
ChannelHandler handler = ctx.pipeline().get("decompress");
ByteBuf decompressed = handler instanceof MessageToMessageDecoder
? (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder<?>) handler, ctx, buf).get(0)
: (ByteBuf) PipelineUtil.callDecode((ByteToMessageDecoder) handler, ctx, buf).get(0);
try {
buf.clear().writeBytes(decompressed);
} finally {
decompressed.release();
}
}
public static void compress(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
ByteBuf compressed = ctx.alloc().buffer();
try {
PipelineUtil.callEncode((MessageToByteEncoder<?>) ctx.pipeline().get("compress"), ctx, buf, compressed);
buf.clear().writeBytes(compressed);
} finally {
compressed.release();
}
}
} }

View File

@ -34,11 +34,14 @@ import us.myles.ViaVersion.exception.CancelCodecException;
import us.myles.ViaVersion.exception.CancelDecoderException; import us.myles.ViaVersion.exception.CancelDecoderException;
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
public class FabricDecodeHandler extends MessageToMessageDecoder<ByteBuf> { public class FabricDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
private final UserConnection info; private final UserConnection info;
private boolean handledCompression;
private boolean skipDoubleTransform;
public FabricDecodeHandler(UserConnection info) { public FabricDecodeHandler(UserConnection info) {
this.info = info; this.info = info;
@ -48,8 +51,15 @@ public class FabricDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
return info; return info;
} }
// https://github.com/ViaVersion/ViaVersion/blob/master/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityDecodeHandler.java
@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 {
if (skipDoubleTransform) {
skipDoubleTransform = false;
out.add(bytebuf.retain());
return;
}
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null); if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
if (!info.shouldTransformPacket()) { if (!info.shouldTransformPacket()) {
out.add(bytebuf.retain()); out.add(bytebuf.retain());
@ -58,13 +68,40 @@ public class FabricDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
try { try {
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
info.transformIncoming(transformedBuf, CancelDecoderException::generate); info.transformIncoming(transformedBuf, CancelDecoderException::generate);
if (needsCompress) {
CommonTransformer.compress(ctx, transformedBuf);
skipDoubleTransform = true;
}
out.add(transformedBuf.retain()); out.add(transformedBuf.retain());
} finally { } finally {
transformedBuf.release(); transformedBuf.release();
} }
} }
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
if (handledCompression) return false;
int decoderIndex = ctx.pipeline().names().indexOf("decompress");
if (decoderIndex == -1) return false;
handledCompression = true;
if (decoderIndex > ctx.pipeline().names().indexOf("via-decoder")) {
// Need to decompress this packet due to bad order
CommonTransformer.decompress(ctx, buf);
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
ctx.pipeline().remove(encoder);
ctx.pipeline().remove(decoder);
ctx.pipeline().addAfter("compress", "via-encoder", encoder);
ctx.pipeline().addAfter("decompress", "via-decoder", decoder);
return true;
}
return false;
}
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return;

View File

@ -34,18 +34,20 @@ import us.myles.ViaVersion.exception.CancelCodecException;
import us.myles.ViaVersion.exception.CancelEncoderException; import us.myles.ViaVersion.exception.CancelEncoderException;
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
public class FabricEncodeHandler extends MessageToMessageEncoder<ByteBuf> { public class FabricEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
private final UserConnection info; private final UserConnection info;
private boolean handledCompression;
public FabricEncodeHandler(UserConnection info) { public FabricEncodeHandler(UserConnection info) {
this.info = info; this.info = info;
} }
@Override @Override
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, final List<Object> out) throws Exception { protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
if (!info.checkOutgoingPacket()) throw CancelEncoderException.generate(null); if (!info.checkOutgoingPacket()) throw CancelEncoderException.generate(null);
if (!info.shouldTransformPacket()) { if (!info.shouldTransformPacket()) {
out.add(bytebuf.retain()); out.add(bytebuf.retain());
@ -54,13 +56,39 @@ public class FabricEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
try { try {
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
info.transformOutgoing(transformedBuf, CancelEncoderException::generate); info.transformOutgoing(transformedBuf, CancelEncoderException::generate);
if (needsCompress) {
CommonTransformer.compress(ctx, transformedBuf);
}
out.add(transformedBuf.retain()); out.add(transformedBuf.retain());
} finally { } finally {
transformedBuf.release(); transformedBuf.release();
} }
} }
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
if (handledCompression) return false;
int encoderIndex = ctx.pipeline().names().indexOf("compress");
if (encoderIndex == -1) return false;
handledCompression = true;
if (encoderIndex > ctx.pipeline().names().indexOf("via-encoder")) {
// Need to decompress this packet due to bad order
CommonTransformer.decompress(ctx, buf);
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
ctx.pipeline().remove(encoder);
ctx.pipeline().remove(decoder);
ctx.pipeline().addAfter("compress", "via-encoder", encoder);
ctx.pipeline().addAfter("decompress", "via-decoder", decoder);
return true;
}
return false;
}
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return;

View File

@ -35,7 +35,6 @@ import us.myles.ViaVersion.api.Pair;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -48,7 +47,6 @@ public class ProtocolDetectionHandler extends ChannelDuplexHandler {
public void channelActive(ChannelHandlerContext ctx) throws Exception { public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx); super.channelActive(ctx);
if (ctx.channel().remoteAddress() instanceof InetSocketAddress) { if (ctx.channel().remoteAddress() instanceof InetSocketAddress) {
try {
ScheduledFuture<?> timeoutRun = ctx.executor().schedule(() -> { ScheduledFuture<?> timeoutRun = ctx.executor().schedule(() -> {
ViaFabric.JLOGGER.warning("Timeout for protocol auto-detection in " ViaFabric.JLOGGER.warning("Timeout for protocol auto-detection in "
+ ctx.channel().remoteAddress() + " server"); + ctx.channel().remoteAddress() + " server");
@ -56,15 +54,12 @@ public class ProtocolDetectionHandler extends ChannelDuplexHandler {
drainQueue(ctx); drainQueue(ctx);
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
}, 10, TimeUnit.SECONDS); }, 10, TimeUnit.SECONDS);
ProtocolAutoDetector.SERVER_VER.get(((InetSocketAddress) ctx.channel().remoteAddress())) ProtocolAutoDetector.detectVersion(((InetSocketAddress) ctx.channel().remoteAddress()))
.whenComplete((obj, ex) -> { .whenComplete((obj, ex) -> {
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
timeoutRun.cancel(false); timeoutRun.cancel(false);
}); });
// Let's cache it before we need it // Let's cache it before we need it
} catch (ExecutionException e) {
ViaFabric.JLOGGER.warning("Protocol auto detector error: " + e);
}
} }
} }

View File

@ -25,25 +25,19 @@
package com.github.creeper123123321.viafabric.mixin.pipeline; package com.github.creeper123123321.viafabric.mixin.pipeline;
import com.github.creeper123123321.viafabric.handler.CommonTransformer;
import com.github.creeper123123321.viafabric.handler.FabricDecodeHandler;
import com.github.creeper123123321.viafabric.handler.FabricEncodeHandler;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientConnection.class) @Mixin(ClientConnection.class)
public class MixinClientConnection { public class MixinClientConnection {
@Shadow private Channel channel; @Shadow
private Channel channel;
@Redirect( @Redirect(
method = "exceptionCaught", method = "exceptionCaught",
@ -59,21 +53,4 @@ public class MixinClientConnection {
logger.debug(message, t); logger.debug(message, t);
} }
} }
@Inject(method = "setCompressionThreshold", at = @At(
value = "RETURN",
remap = false
))
private void fixCompressionOrder(int compressionThreshold, CallbackInfo ci) {
if (channel.pipeline().get(FabricEncodeHandler.class) == null) return;
if (channel.pipeline().names().indexOf("compress")
< channel.pipeline().names().indexOf(CommonTransformer.HANDLER_ENCODER_NAME)) {
return; // Order is correct or compression is disabled
}
// Fixes the handler order
FabricDecodeHandler decode = channel.pipeline().remove(FabricDecodeHandler.class);
FabricEncodeHandler encode = channel.pipeline().remove(FabricEncodeHandler.class);
channel.pipeline().addAfter("decompress", "via-decoder", decode);
channel.pipeline().addAfter("compress", "via-encoder", encode);
}
} }

View File

@ -102,7 +102,7 @@ public class VRVersionProvider extends VersionProvider {
if (serverVer == -2) { if (serverVer == -2) {
// Hope protocol was autodetected // Hope protocol was autodetected
ProtocolVersion autoVer = ProtocolVersion autoVer =
ProtocolAutoDetector.SERVER_VER.get((InetSocketAddress) addr).getNow(null); ProtocolAutoDetector.detectVersion((InetSocketAddress) addr).getNow(null);
if (autoVer != null) { if (autoVer != null) {
serverVer = autoVer.getId(); serverVer = autoVer.getId();
} }

View File

@ -47,13 +47,17 @@ import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import us.myles.ViaVersion.api.protocol.ProtocolVersion; import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class ProtocolAutoDetector { public class ProtocolAutoDetector {
public static LoadingCache<InetSocketAddress, CompletableFuture<ProtocolVersion>> SERVER_VER = CacheBuilder.newBuilder() private static LoadingCache<InetSocketAddress, CompletableFuture<ProtocolVersion>> SERVER_VER = CacheBuilder.newBuilder()
.expireAfterAccess(100, TimeUnit.SECONDS) .expireAfterAccess(100, TimeUnit.SECONDS)
.build(CacheLoader.from((address) -> { .build(CacheLoader.from((address) -> {
CompletableFuture<ProtocolVersion> future = new CompletableFuture<>(); CompletableFuture<ProtocolVersion> future = new CompletableFuture<>();
@ -61,8 +65,6 @@ public class ProtocolAutoDetector {
try { try {
final ClientConnection clientConnection = new ClientConnection(NetworkSide.CLIENTBOUND); final ClientConnection clientConnection = new ClientConnection(NetworkSide.CLIENTBOUND);
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address.getHostString());
ChannelFuture ch = new Bootstrap() ChannelFuture ch = new Bootstrap()
.group(ClientConnection.CLIENT_IO_GROUP.get()) .group(ClientConnection.CLIENT_IO_GROUP.get())
.channel(NioSocketChannel.class) .channel(NioSocketChannel.class)
@ -121,7 +123,7 @@ public class ProtocolAutoDetector {
} }
}); });
clientConnection.send(new HandshakeC2SPacket(viaAddr.realAddress, clientConnection.send(new HandshakeC2SPacket(address.getHostString(),
address.getPort(), NetworkState.STATUS)); address.getPort(), NetworkState.STATUS));
clientConnection.send(new QueryRequestC2SPacket()); clientConnection.send(new QueryRequestC2SPacket());
}); });
@ -133,4 +135,16 @@ public class ProtocolAutoDetector {
return future; return future;
})); }));
public static CompletableFuture<ProtocolVersion> detectVersion(InetSocketAddress address) {
try {
InetSocketAddress real = new InetSocketAddress(InetAddress.getByAddress
(new ViaFabricAddress().parse(address.getHostString()).realAddress,
address.getAddress().getAddress()), address.getPort());
return SERVER_VER.get(real);
} catch (UnknownHostException | ExecutionException e) {
ViaFabric.JLOGGER.log(Level.WARNING, "Protocol auto detector error: ", e);
return CompletableFuture.completedFuture(null);
}
}
} }