mirror of
https://github.com/ViaVersion/ViaFabric.git
synced 2024-12-18 15:47:46 +01:00
parent
43c62a5d9c
commit
3fead84f59
18
README.md
18
README.md
@ -44,7 +44,10 @@ Adding [ViaBackwards](https://viaversion.com/backwards) (and optionally [ViaRewi
|
||||
|
||||
|
||||
**How can I install ViaBackwards/ViaRewind?:**
|
||||
- Just drop it into mods folder. Make sure you are using versions compatible with the ViaVersion version you are using. ViaVersion-DEV/ViaBackwards-DEV/ViaRewind-DEV and ViaVersion/ViaBackwards/ViaRewind CI builds are only compatible to each other if they have the same label (``-DEV`` or empty).
|
||||
- Just drop them into mods folder. Make sure you are using versions compatible with the ViaVersion version you are using.
|
||||
- There are reposts on CurseForge:
|
||||
- https://www.curseforge.com/minecraft/mc-mods/viabackwards
|
||||
- https://www.curseforge.com/minecraft/mc-mods/viarewind
|
||||
|
||||
|
||||
**What versions can ViaVersion, ViaBackwards and ViaRewind translate?:**
|
||||
@ -78,14 +81,21 @@ Adding [ViaBackwards](https://viaversion.com/backwards) (and optionally [ViaRewi
|
||||
|
||||
**Alternatives to this mod:**
|
||||
- [ClientViaVersion](https://github.com/Gerrygames/ClientViaVersion): This discontinued client-side plugin for The 5zig Mod implemented ViaVersion, ViaBackwards and ViaRewind for 1.7.10, 1.8.9, 1.12 and 1.12.2 clients, allowing them to connect to 1.7-1.12.2 servers. It also had a protocol translation for 1.7 servers, which there's an updated version at https://github.com/KennyTV/ViaVersion/tree/hack (unsupported).
|
||||
- [multiconnect](https://www.curseforge.com/minecraft/mc-mods/multiconnect): This client-side Fabric mod does also accept older protocols and fixes some differences between versions, which ViaFabric doesn't. Currently, it goes down to 1.10. (2020-06-23)
|
||||
- [multiconnect](https://www.curseforge.com/minecraft/mc-mods/multiconnect): This client-side Fabric mod does also accept older protocols and fixes some differences between versions, which ViaFabric doesn't. Currently, it goes down to 1.11 (stable) and 1.9.2 (experimental). (2020-10-16) (Supports only latest Minecraft client version)
|
||||
- [Protocol4](https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/minecraft-mods/2299203-protocol4-1-0-2-allows-1-7-10-clients-to-connect): This LiteLoader client-side mod allows your 1.7.10 client to connect to 1.7.x servers.
|
||||
- [ProtocolSupport](https://protocol.support/): This Bukkit plugin allows clients to connect from older versions (down to 1.4.7).
|
||||
- [ViaVersion](https://viaversion.com): ViaVersion can run as a plugin for BungeeCord, CraftBukkit, SpongeCommon and Velocity servers.
|
||||
|
||||
|
||||
**How can I disable client-side ViaFabric?:**
|
||||
- You can disable it by resetting the anti-cheat warning in config file or by setting protocol version to -1
|
||||
- You can disable it in the menu or by setting global protocol version to -1 (this will keep per-server translations still enabled)
|
||||
|
||||
|
||||
**How to use protocol auto detector?:**
|
||||
- For using globally, set the protocol to AUTO or -2. For using in a specific server: ddns.example.com._v-2.viafabric
|
||||
- The protocol auto detector will try to ping with the client native protocol version so if you have ViaVersion or similar in the server it will use the translator, differently than multiconnect which uses -1 version, which may get the native server version.
|
||||
- It may block the network thread up to 1 second.
|
||||
- The versions are cached for 100 seconds.
|
||||
|
||||
|
||||
**How can I set the version for specific servers?:**
|
||||
@ -93,7 +103,7 @@ Adding [ViaBackwards](https://viaversion.com/backwards) (and optionally [ViaRewi
|
||||
|
||||
|
||||
**Does it work with multiconnect at same time on client?:**
|
||||
- Yes, ViaFabric can be used with multiconnect. ViaFabric will send to their version auto detector their closest supported version. (multiconnect beta-supported versions (currently 1.10) aren't used)
|
||||
- Yes, ViaFabric can be used with multiconnect. ViaFabric will send to their version auto detector their closest supported version. (multiconnect beta-supported versions (currently 1.10 and 1.9) aren't used)
|
||||
- Example of setups:
|
||||
- (1.8 server) <-> (disabled ViaFabric) <-> (auto detected 1.8 server - multiconnect) = doesn't work because multiconnect doesn't support it
|
||||
- (1.8 server) <-> (forced 1.8 - ViaFabric - suggests 1.11) <-> (detected 1.11 server - multiconnect) = works, ViaVersion translating 1.8 -> 1.11 and multiconnect accepting 1.11
|
||||
|
@ -49,6 +49,7 @@ import us.myles.ViaVersion.ViaManager;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.MappingDataLoader;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -99,6 +100,7 @@ public class ViaFabric implements ModInitializer {
|
||||
Via.getManager().init();
|
||||
|
||||
ProtocolRegistry.registerBaseProtocol(ViaFabricHostnameProtocol.INSTANCE, Range.lessThan(Integer.MIN_VALUE));
|
||||
ProtocolVersion.register(new ProtocolVersion(-2, "AUTO"));
|
||||
|
||||
FabricLoader.getInstance().getEntrypoints("viafabric:via_api_initialized", Runnable.class).forEach(Runnable::run);
|
||||
|
||||
|
@ -68,7 +68,6 @@ public class VRConfig extends Config {
|
||||
}
|
||||
|
||||
public int getClientSideVersion() {
|
||||
if (!isClientSideEnabled()) return -1;
|
||||
return getInt(CLIENT_SIDE_VERSION, -1);
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,7 @@ public class ViaConfigScreen extends Screen {
|
||||
answer -> {
|
||||
if (answer) {
|
||||
ViaFabric.config.setClientSideEnabled(true);
|
||||
ViaFabric.config.setClientSideVersion(-2); // AUTO
|
||||
ViaFabric.config.saveConfig();
|
||||
widget.setMessage(getClientSideText());
|
||||
}
|
||||
|
@ -25,11 +25,13 @@
|
||||
|
||||
package com.github.creeper123123321.viafabric.mixin.client;
|
||||
|
||||
import com.github.creeper123123321.viafabric.protocol.ViaFabricHostnameProtocol;
|
||||
import com.github.creeper123123321.viafabric.ViaFabric;
|
||||
import com.github.creeper123123321.viafabric.handler.CommonTransformer;
|
||||
import com.github.creeper123123321.viafabric.handler.clientside.VRDecodeHandler;
|
||||
import com.github.creeper123123321.viafabric.handler.clientside.VREncodeHandler;
|
||||
import com.github.creeper123123321.viafabric.platform.VRClientSideUserConnection;
|
||||
import com.github.creeper123123321.viafabric.protocol.ViaFabricHostnameProtocol;
|
||||
import com.github.creeper123123321.viafabric.service.ProtocolAutoDetector;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@ -39,6 +41,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@Mixin(targets = "net.minecraft.network.ClientConnection$1")
|
||||
public class MixinClientConnectionChInit {
|
||||
@Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false)
|
||||
@ -47,8 +51,17 @@ public class MixinClientConnectionChInit {
|
||||
UserConnection user = new VRClientSideUserConnection(channel);
|
||||
new ProtocolPipeline(user).add(ViaFabricHostnameProtocol.INSTANCE);
|
||||
|
||||
channel.pipeline().addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new VREncodeHandler(user));
|
||||
channel.pipeline().addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new VRDecodeHandler(user));
|
||||
channel.pipeline()
|
||||
.addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new VREncodeHandler(user))
|
||||
.addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new VRDecodeHandler(user));
|
||||
|
||||
if (channel.remoteAddress() != null) {
|
||||
try {
|
||||
ProtocolAutoDetector.SERVER_VER.get(((SocketChannel) channel).remoteAddress()); // Let's cache it before we need it, and hope we'll not block netty thread
|
||||
} catch (ExecutionException e) {
|
||||
ViaFabric.JLOGGER.warning("Protocol auto detector error: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ package com.github.creeper123123321.viafabric.providers;
|
||||
import com.github.creeper123123321.viafabric.ViaFabric;
|
||||
import com.github.creeper123123321.viafabric.ViaFabricAddress;
|
||||
import com.github.creeper123123321.viafabric.platform.VRClientSideUserConnection;
|
||||
import com.github.creeper123123321.viafabric.service.ProtocolAutoDetector;
|
||||
import com.github.creeper123123321.viafabric.util.ProtocolUtils;
|
||||
import com.google.common.primitives.Ints;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
@ -48,10 +49,11 @@ import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class VRVersionProvider extends VersionProvider {
|
||||
private Set<Integer> multiconnectSupportedVersions = null;
|
||||
private int[] multiconnectSupportedVersions = null;
|
||||
|
||||
{
|
||||
try {
|
||||
@ -67,13 +69,14 @@ public class VRVersionProvider extends VersionProvider {
|
||||
} catch (NoSuchMethodException e) {
|
||||
isMulticonnectBeta = null;
|
||||
}
|
||||
multiconnectSupportedVersions = new TreeSet<>();
|
||||
Set<Integer> vers = new TreeSet<>();
|
||||
for (Object protocol : protocols) {
|
||||
// Do not use versions with beta multiconnect support, which may have stability issues
|
||||
if (isMulticonnectBeta == null || !(Boolean) isMulticonnectBeta.invoke(protocol)) {
|
||||
multiconnectSupportedVersions.add((Integer) getValue.invoke(protocol));
|
||||
vers.add((Integer) getValue.invoke(protocol));
|
||||
}
|
||||
}
|
||||
multiconnectSupportedVersions = vers.stream().mapToInt(Integer::intValue).toArray();
|
||||
ViaFabric.JLOGGER.info("ViaFabric will integrate with multiconnect");
|
||||
}
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException
|
||||
@ -84,24 +87,36 @@ public class VRVersionProvider extends VersionProvider {
|
||||
@Override
|
||||
public int getServerProtocol(UserConnection connection) throws Exception {
|
||||
if (connection instanceof VRClientSideUserConnection) {
|
||||
ProtocolInfo info = Objects.requireNonNull(connection.getProtocolInfo());
|
||||
|
||||
if (!ViaFabric.config.isClientSideEnabled()) {
|
||||
return info.getProtocolVersion();
|
||||
}
|
||||
|
||||
int serverVer = ViaFabric.config.getClientSideVersion();
|
||||
SocketAddress addr = connection.getChannel().remoteAddress();
|
||||
|
||||
if (addr instanceof InetSocketAddress && ViaFabric.config.isClientSideEnabled()) {
|
||||
if (addr instanceof InetSocketAddress) {
|
||||
int addrVersion = new ViaFabricAddress().parse(((InetSocketAddress) addr).getHostName()).protocol;
|
||||
if (addrVersion != 0) serverVer = addrVersion;
|
||||
|
||||
try {
|
||||
if (serverVer == -2) {
|
||||
// sadly we'll need to block netty thread, we'll need to be fast
|
||||
return ProtocolAutoDetector.SERVER_VER.get((InetSocketAddress) addr).get(1, TimeUnit.SECONDS).getId();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ViaFabric.JLOGGER.warning("Couldn't auto detect: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
if (connection.getChannel() != null) {
|
||||
ProtocolInfo info = Objects.requireNonNull(connection.getProtocolInfo());
|
||||
boolean blocked = checkAddressBlocked(addr);
|
||||
boolean supported = ProtocolUtils.isSupported(serverVer, info.getProtocolVersion());
|
||||
|
||||
boolean blocked = checkAddressBlocked(addr);
|
||||
boolean supported = ProtocolUtils.isSupported(serverVer, info.getProtocolVersion());
|
||||
handleMulticonnectPing(connection, info, blocked, supported, serverVer);
|
||||
|
||||
handleMulticonnectPing(connection, info, blocked, supported, serverVer);
|
||||
if (blocked || !supported) serverVer = info.getProtocolVersion();
|
||||
|
||||
if (serverVer == -1 || blocked) return info.getProtocolVersion();
|
||||
}
|
||||
return serverVer;
|
||||
}
|
||||
return super.getServerProtocol(connection);
|
||||
@ -125,7 +140,7 @@ public class VRVersionProvider extends VersionProvider {
|
||||
ViaFabric.JLOGGER.info("Sending " + ProtocolVersion.getProtocol(multiconnectSuggestion) + " for multiconnect version detector");
|
||||
PacketWrapper newAnswer = new PacketWrapper(0x00, null, connection);
|
||||
newAnswer.write(Type.STRING, "{\"version\":{\"name\":\"viafabric integration\",\"protocol\":" + multiconnectSuggestion + "}}");
|
||||
newAnswer.send(info.getPipeline().contains(BaseProtocol1_16.class) ? BaseProtocol1_16.class : BaseProtocol1_7.class);
|
||||
newAnswer.send(info.getPipeline().contains(BaseProtocol1_16.class) ? BaseProtocol1_16.class : BaseProtocol1_7.class, true, true);
|
||||
throw CancelException.generate();
|
||||
}
|
||||
}
|
||||
@ -133,7 +148,7 @@ public class VRVersionProvider extends VersionProvider {
|
||||
private int getVersionForMulticonnect(int clientSideVersion) {
|
||||
// https://github.com/ViaVersion/ViaVersion/blob/master/velocity/src/main/java/us/myles/ViaVersion/velocity/providers/VelocityVersionProvider.java
|
||||
// multiconnect supports it
|
||||
int[] compatibleProtocols = multiconnectSupportedVersions.stream().mapToInt(Integer::intValue).toArray();
|
||||
int[] compatibleProtocols = multiconnectSupportedVersions;
|
||||
if (Arrays.binarySearch(compatibleProtocols, clientSideVersion) >= 0)
|
||||
return clientSideVersion;
|
||||
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018- creeper123123321 <https://creeper123123321.keybase.pub/>
|
||||
* Copyright (c) 2019- contributors <https://github.com/ViaVersion/ViaFabric/graphs/contributors>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.github.creeper123123321.viafabric.service;
|
||||
|
||||
import com.github.creeper123123321.viafabric.ViaFabric;
|
||||
import com.github.creeper123123321.viafabric.ViaFabricAddress;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.network.*;
|
||||
import net.minecraft.network.listener.ClientQueryPacketListener;
|
||||
import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.query.QueryRequestC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.query.QueryPongS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class ProtocolAutoDetector {
|
||||
public static LoadingCache<InetSocketAddress, CompletableFuture<ProtocolVersion>> SERVER_VER = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(100, TimeUnit.SECONDS)
|
||||
.build(CacheLoader.from((address) -> {
|
||||
CompletableFuture<ProtocolVersion> future = new CompletableFuture<>();
|
||||
|
||||
try {
|
||||
final ClientConnection clientConnection = new ClientConnection(NetworkSide.CLIENTBOUND);
|
||||
|
||||
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address.getHostString());
|
||||
|
||||
ChannelFuture ch = new Bootstrap()
|
||||
.group(ClientConnection.CLIENT_IO_GROUP.get())
|
||||
.channel(NioSocketChannel.class)
|
||||
.handler(new ChannelInitializer<Channel>() {
|
||||
protected void initChannel(Channel channel) {
|
||||
try {
|
||||
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||
channel.config().setOption(ChannelOption.IP_TOS, 0x18); // Stolen from Velocity, low delay, high reliability
|
||||
} catch (ChannelException ignored) {
|
||||
}
|
||||
|
||||
channel.pipeline()
|
||||
.addLast("timeout", new ReadTimeoutHandler(30))
|
||||
.addLast("splitter", new SplitterHandler())
|
||||
.addLast("decoder", new DecoderHandler(NetworkSide.CLIENTBOUND))
|
||||
.addLast("prepender", new SizePrepender())
|
||||
.addLast("encoder", new PacketEncoder(NetworkSide.SERVERBOUND))
|
||||
.addLast("packet_handler", clientConnection);
|
||||
}
|
||||
})
|
||||
.connect(address);
|
||||
|
||||
ch.addListener(future1 -> {
|
||||
if (!future1.isSuccess()) {
|
||||
future.completeExceptionally(future1.cause());
|
||||
} else {
|
||||
ch.channel().eventLoop().execute(() -> { // needs to execute after channel init
|
||||
clientConnection.setPacketListener(new ClientQueryPacketListener() {
|
||||
@Override
|
||||
public void onResponse(QueryResponseS2CPacket packet) {
|
||||
ProtocolVersion ver = ProtocolVersion.getProtocol(packet.getServerMetadata().getVersion()
|
||||
.getProtocolVersion());
|
||||
future.complete(ver);
|
||||
ViaFabric.JLOGGER.info("Auto-detected " + ver + " for " + address);
|
||||
clientConnection.disconnect(LiteralText.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPong(QueryPongS2CPacket packet) {
|
||||
clientConnection.disconnect(new LiteralText("Pong not requested!"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(Text reason) {
|
||||
future.completeExceptionally(new IllegalStateException(reason.asString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientConnection getConnection() {
|
||||
return clientConnection;
|
||||
}
|
||||
});
|
||||
|
||||
clientConnection.send(new HandshakeC2SPacket(viaAddr.realAddress,
|
||||
address.getPort(), NetworkState.STATUS));
|
||||
clientConnection.send(new QueryRequestC2SPacket());
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (Throwable throwable) {
|
||||
future.completeExceptionally(throwable);
|
||||
}
|
||||
|
||||
return future;
|
||||
}));
|
||||
}
|
@ -37,9 +37,8 @@ public class ProtocolUtils {
|
||||
}
|
||||
|
||||
public static String getProtocolName(int id) {
|
||||
ProtocolVersion ver = ProtocolVersion.getProtocol(id);
|
||||
if (ver == null) return Integer.toString(id);
|
||||
return ver.getName();
|
||||
if (!ProtocolVersion.isRegistered(id)) return Integer.toString(id);
|
||||
return ProtocolVersion.getProtocol(id).getName();
|
||||
}
|
||||
|
||||
public static boolean isStartOfProtocolText(String s) {
|
||||
|
Loading…
Reference in New Issue
Block a user