From 7948f7508fc6326d23c26dc6b57e39794b88207e Mon Sep 17 00:00:00 2001 From: RaphiMC <50594595+RaphiMC@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:32:24 +0200 Subject: [PATCH] Added option to fake accept resource packs --- .../viaproxy/ViaProxyConfig.java | 14 +++ .../client2proxy/Client2ProxyHandler.java | 3 + .../ResourcePackPacketHandler.java | 18 ++- .../ResourcePackSpooferPacketHandler.java | 116 ++++++++++++++++++ .../raphimc/viaproxy/ui/impl/AdvancedTab.java | 9 ++ .../raphimc/viaproxy/ui/impl/GeneralTab.java | 2 + .../assets/viaproxy/language/de_DE.properties | 2 + .../assets/viaproxy/language/en_US.properties | 2 + .../resources/assets/viaproxy/viaproxy.yml | 4 + 9 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackSpooferPacketHandler.java diff --git a/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java b/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java index ad40fa4..679a531 100644 --- a/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java +++ b/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java @@ -73,6 +73,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. private final OptionSpec optionResourcePackUrl; private final OptionSpec optionWildcardDomainHandling; private final OptionSpec optionSimpleVoiceChatSupport; + private final OptionSpec optionFakeAcceptResourcePacks; private SocketAddress bindAddress = AddressUtil.parse("0.0.0.0:25568", null); private SocketAddress targetAddress = AddressUtil.parse("127.0.0.1:25565", null); @@ -94,6 +95,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. private String resourcePackUrl = ""; private WildcardDomainHandling wildcardDomainHandling = WildcardDomainHandling.NONE; private boolean simpleVoiceChatSupport = false; + private boolean fakeAcceptResourcePacks = false; public ViaProxyConfig(final File configFile) { super(configFile, LOGGER); @@ -120,6 +122,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.optionResourcePackUrl = this.optionParser.accepts("resource-pack-url").withRequiredArg().ofType(String.class).defaultsTo(this.resourcePackUrl); this.optionWildcardDomainHandling = this.optionParser.accepts("wildcard-domain-handling").withRequiredArg().ofType(WildcardDomainHandling.class).defaultsTo(this.wildcardDomainHandling); this.optionSimpleVoiceChatSupport = this.optionParser.accepts("simple-voice-chat-support").withRequiredArg().ofType(Boolean.class).defaultsTo(this.simpleVoiceChatSupport); + this.optionFakeAcceptResourcePacks = this.optionParser.accepts("fake-accept-resource-packs").withRequiredArg().ofType(Boolean.class).defaultsTo(this.fakeAcceptResourcePacks); } @Override @@ -153,6 +156,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.resourcePackUrl = this.getString("resource-pack-url", this.resourcePackUrl); this.wildcardDomainHandling = WildcardDomainHandling.byName(this.getString("wildcard-domain-handling", this.wildcardDomainHandling.name())); this.simpleVoiceChatSupport = this.getBoolean("simple-voice-chat-support", this.simpleVoiceChatSupport); + this.fakeAcceptResourcePacks = this.getBoolean("fake-accept-resource-packs", this.fakeAcceptResourcePacks); } public void loadFromArguments(final String[] args) throws IOException { @@ -190,6 +194,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.resourcePackUrl = options.valueOf(this.optionResourcePackUrl); this.wildcardDomainHandling = options.valueOf(this.optionWildcardDomainHandling); this.simpleVoiceChatSupport = options.valueOf(this.optionSimpleVoiceChatSupport); + this.fakeAcceptResourcePacks = options.valueOf(this.optionFakeAcceptResourcePacks); ViaProxy.EVENT_MANAGER.call(new PostOptionsParseEvent(options)); return; } catch (OptionException e) { @@ -406,6 +411,15 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.set("simple-voice-chat-support", simpleVoiceChatSupport); } + public boolean shouldFakeAcceptResourcePacks() { + return this.fakeAcceptResourcePacks; + } + + public void setFakeAcceptResourcePacks(final boolean fakeAcceptResourcePacks) { + this.fakeAcceptResourcePacks = fakeAcceptResourcePacks; + this.set("fake-accept-resource-packs", fakeAcceptResourcePacks); + } + private void checkTargetVersion() { if (this.targetVersion == null) { this.targetVersion = ProtocolTranslator.AUTO_DETECT_PROTOCOL; diff --git a/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyHandler.java b/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyHandler.java index 020e12a..4b02163 100644 --- a/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyHandler.java +++ b/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyHandler.java @@ -229,6 +229,9 @@ public class Client2ProxyHandler extends SimpleChannelInboundHandler { if (ViaProxy.getConfig().shouldSupportSimpleVoiceChat() && serverVersion.newerThan(ProtocolVersion.v1_14) && clientVersion.newerThan(ProtocolVersion.v1_14)) { this.proxyConnection.getPacketHandlers().add(new SimpleVoiceChatPacketHandler(this.proxyConnection)); } + if (ViaProxy.getConfig().shouldFakeAcceptResourcePacks() && serverVersion.newerThanOrEqualTo(LegacyProtocolVersion.r1_3_1tor1_3_2)) { + this.proxyConnection.getPacketHandlers().add(new ResourcePackSpooferPacketHandler(this.proxyConnection)); + } if (clientVersion.newerThanOrEqualTo(ProtocolVersion.v1_8)) { this.proxyConnection.getPacketHandlers().add(new BrandCustomPayloadPacketHandler(this.proxyConnection)); } diff --git a/src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackPacketHandler.java b/src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackPacketHandler.java index 10071ed..702f0e7 100644 --- a/src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackPacketHandler.java +++ b/src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackPacketHandler.java @@ -33,6 +33,7 @@ import net.raphimc.viaproxy.proxy.session.ProxyConnection; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.UUID; import java.util.concurrent.TimeUnit; public class ResourcePackPacketHandler extends PacketHandler { @@ -63,7 +64,22 @@ public class ResourcePackPacketHandler extends PacketHandler { private void sendResourcePack() { if (!ViaProxy.getConfig().getResourcePackUrl().isBlank()) { this.proxyConnection.getChannel().eventLoop().schedule(() -> { - if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_8)) { + if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_3)) { + final ByteBuf resourcePackPushPacket = Unpooled.buffer(); + PacketTypes.writeVarInt(resourcePackPushPacket, MCPackets.S2C_RESOURCE_PACK_PUSH.getId(this.proxyConnection.getClientVersion().getVersion())); + PacketTypes.writeUuid(resourcePackPushPacket, UUID.randomUUID()); // pack id + PacketTypes.writeString(resourcePackPushPacket, ViaProxy.getConfig().getResourcePackUrl()); // url + PacketTypes.writeString(resourcePackPushPacket, ""); // hash + resourcePackPushPacket.writeBoolean(Via.getConfig().isForcedUse1_17ResourcePack()); // required + final JsonElement promptMessage = Via.getConfig().get1_17ResourcePackPrompt(); + if (promptMessage != null) { + resourcePackPushPacket.writeBoolean(true); // has message + PacketTypes.writeString(resourcePackPushPacket, promptMessage.toString()); // message + } else { + resourcePackPushPacket.writeBoolean(false); // has message + } + this.proxyConnection.getC2P().writeAndFlush(resourcePackPushPacket).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } else if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_8)) { final ByteBuf resourcePackPacket = Unpooled.buffer(); PacketTypes.writeVarInt(resourcePackPacket, MCPackets.S2C_RESOURCE_PACK.getId(this.proxyConnection.getClientVersion().getVersion())); PacketTypes.writeString(resourcePackPacket, ViaProxy.getConfig().getResourcePackUrl()); // url diff --git a/src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackSpooferPacketHandler.java b/src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackSpooferPacketHandler.java new file mode 100644 index 0000000..b53dcb3 --- /dev/null +++ b/src/main/java/net/raphimc/viaproxy/proxy/packethandler/ResourcePackSpooferPacketHandler.java @@ -0,0 +1,116 @@ +/* + * This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy + * Copyright (C) 2021-2024 RK_01/RaphiMC and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.raphimc.viaproxy.proxy.packethandler; + +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import net.raphimc.netminecraft.constants.ConnectionState; +import net.raphimc.netminecraft.constants.MCPackets; +import net.raphimc.netminecraft.packet.IPacket; +import net.raphimc.netminecraft.packet.PacketTypes; +import net.raphimc.netminecraft.packet.UnknownPacket; +import net.raphimc.viabedrock.protocol.data.enums.java.ResourcePackAction; +import net.raphimc.viaproxy.proxy.session.ProxyConnection; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class ResourcePackSpooferPacketHandler extends PacketHandler { + + private final int s2cResourcePackId; + private final int s2cConfigResourcePackId; + private final int resourcePackPushId; + private final int configResourcePackPushId; + private final int resourcePackPopId; + private final int configResourcePackPopId; + private final int c2sResourcePackId; + private final int c2sConfigResourcePackId; + + private final Set resourcePacks = new HashSet<>(); + + public ResourcePackSpooferPacketHandler(ProxyConnection proxyConnection) { + super(proxyConnection); + + this.s2cResourcePackId = MCPackets.S2C_RESOURCE_PACK.getId(this.proxyConnection.getClientVersion().getVersion()); + this.s2cConfigResourcePackId = MCPackets.S2C_CONFIG_RESOURCE_PACK.getId(this.proxyConnection.getClientVersion().getVersion()); + this.resourcePackPushId = MCPackets.S2C_RESOURCE_PACK_PUSH.getId(this.proxyConnection.getClientVersion().getVersion()); + this.configResourcePackPushId = MCPackets.S2C_CONFIG_RESOURCE_PACK_PUSH.getId(this.proxyConnection.getClientVersion().getVersion()); + this.resourcePackPopId = MCPackets.S2C_RESOURCE_PACK_POP.getId(this.proxyConnection.getClientVersion().getVersion()); + this.configResourcePackPopId = MCPackets.S2C_CONFIG_RESOURCE_PACK_POP.getId(this.proxyConnection.getClientVersion().getVersion()); + this.c2sResourcePackId = MCPackets.C2S_RESOURCE_PACK.getId(this.proxyConnection.getClientVersion().getVersion()); + this.c2sConfigResourcePackId = MCPackets.C2S_CONFIG_RESOURCE_PACK.getId(this.proxyConnection.getClientVersion().getVersion()); + } + + @Override + public boolean handleP2S(IPacket packet, List listeners) { + if (packet instanceof UnknownPacket unknownPacket + && (unknownPacket.packetId == this.resourcePackPushId && this.proxyConnection.getP2sConnectionState() == ConnectionState.PLAY + || unknownPacket.packetId == this.configResourcePackPushId && this.proxyConnection.getP2sConnectionState() == ConnectionState.CONFIGURATION)) { + final ByteBuf data = Unpooled.wrappedBuffer(unknownPacket.data); + final UUID packId = PacketTypes.readUuid(data); // pack id + this.resourcePacks.add(packId); + this.sendResponse(packId, null, ResourcePackAction.ACCEPTED.ordinal()); + for (UUID resourcePack : this.resourcePacks) { + this.sendResponse(resourcePack, null, ResourcePackAction.SUCCESSFULLY_LOADED.ordinal()); + } + return false; + } else if (packet instanceof UnknownPacket unknownPacket + && (unknownPacket.packetId == this.resourcePackPopId && this.proxyConnection.getP2sConnectionState() == ConnectionState.PLAY + || unknownPacket.packetId == this.configResourcePackPopId && this.proxyConnection.getP2sConnectionState() == ConnectionState.CONFIGURATION)) { + final ByteBuf data = Unpooled.wrappedBuffer(unknownPacket.data); + if (data.readBoolean()) { // has pack id + final UUID packId = PacketTypes.readUuid(data); // pack id + this.resourcePacks.remove(packId); + } else { + this.resourcePacks.clear(); + } + for (UUID resourcePack : this.resourcePacks) { + this.sendResponse(resourcePack, null, ResourcePackAction.SUCCESSFULLY_LOADED.ordinal()); + } + return false; + } else if (packet instanceof UnknownPacket unknownPacket + && (unknownPacket.packetId == this.s2cResourcePackId && this.proxyConnection.getP2sConnectionState() == ConnectionState.PLAY + || unknownPacket.packetId == this.s2cConfigResourcePackId && this.proxyConnection.getP2sConnectionState() == ConnectionState.CONFIGURATION)) { + final ByteBuf data = Unpooled.wrappedBuffer(unknownPacket.data); + PacketTypes.readString(data, Short.MAX_VALUE); // url + final String hash = PacketTypes.readString(data, 40); // hash + this.sendResponse(null, hash, ResourcePackAction.ACCEPTED.ordinal()); + this.sendResponse(null, hash, ResourcePackAction.SUCCESSFULLY_LOADED.ordinal()); + return false; + } + + return true; + } + + private void sendResponse(final UUID packId, final String hash, final int status) { + final ByteBuf resourcePackResponse = Unpooled.buffer(); + PacketTypes.writeVarInt(resourcePackResponse, this.proxyConnection.getP2sConnectionState() == ConnectionState.PLAY ? this.c2sResourcePackId : this.c2sConfigResourcePackId); + if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_3)) { + PacketTypes.writeUuid(resourcePackResponse, packId); // pack id + } else if (this.proxyConnection.getClientVersion().olderThanOrEqualTo(ProtocolVersion.v1_9)) { + PacketTypes.writeString(resourcePackResponse, hash); // hash + } + PacketTypes.writeVarInt(resourcePackResponse, status); // status + this.proxyConnection.getChannel().writeAndFlush(resourcePackResponse).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } + +} diff --git a/src/main/java/net/raphimc/viaproxy/ui/impl/AdvancedTab.java b/src/main/java/net/raphimc/viaproxy/ui/impl/AdvancedTab.java index 090610e..02b9b69 100644 --- a/src/main/java/net/raphimc/viaproxy/ui/impl/AdvancedTab.java +++ b/src/main/java/net/raphimc/viaproxy/ui/impl/AdvancedTab.java @@ -50,6 +50,7 @@ public class AdvancedTab extends UITab { JCheckBox ignorePacketTranslationErrors; JCheckBox allowBetaPinging; JCheckBox simpleVoiceChatSupport; + JCheckBox fakeAcceptResourcePacks; JButton viaVersionDumpButton; JButton uploadLogsButton; @@ -133,6 +134,13 @@ public class AdvancedTab extends UITab { this.simpleVoiceChatSupport.setSelected(ViaProxy.getConfig().shouldSupportSimpleVoiceChat()); checkboxes.add(this.simpleVoiceChatSupport); } + { + this.fakeAcceptResourcePacks = new JCheckBox(I18n.get("tab.advanced.fake_accept_resource_packs.label")); + this.fakeAcceptResourcePacks.setToolTipText(I18n.get("tab.advanced.fake_accept_resource_packs.tooltip")); + this.fakeAcceptResourcePacks.setSelected(false); + this.fakeAcceptResourcePacks.setSelected(ViaProxy.getConfig().shouldFakeAcceptResourcePacks()); + checkboxes.add(this.fakeAcceptResourcePacks); + } GBC.create(body).grid(0, gridy++).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, BODY_BLOCK_PADDING).fill(GBC.BOTH).weight(1, 1).add(checkboxes); parent.add(body, BorderLayout.NORTH); @@ -210,6 +218,7 @@ public class AdvancedTab extends UITab { ViaProxy.getConfig().setIgnoreProtocolTranslationErrors(this.ignorePacketTranslationErrors.isSelected()); ViaProxy.getConfig().setAllowBetaPinging(this.allowBetaPinging.isSelected()); ViaProxy.getConfig().setSimpleVoiceChatSupport(this.simpleVoiceChatSupport.isSelected()); + ViaProxy.getConfig().setFakeAcceptResourcePacks(this.fakeAcceptResourcePacks.isSelected()); } } diff --git a/src/main/java/net/raphimc/viaproxy/ui/impl/GeneralTab.java b/src/main/java/net/raphimc/viaproxy/ui/impl/GeneralTab.java index e7efe30..dad921d 100644 --- a/src/main/java/net/raphimc/viaproxy/ui/impl/GeneralTab.java +++ b/src/main/java/net/raphimc/viaproxy/ui/impl/GeneralTab.java @@ -212,6 +212,8 @@ public class GeneralTab extends UITab { this.viaProxyWindow.advancedTab.chatSigning.setEnabled(state); this.viaProxyWindow.advancedTab.ignorePacketTranslationErrors.setEnabled(state); this.viaProxyWindow.advancedTab.allowBetaPinging.setEnabled(state); + this.viaProxyWindow.advancedTab.simpleVoiceChatSupport.setEnabled(state); + this.viaProxyWindow.advancedTab.fakeAcceptResourcePacks.setEnabled(state); if (state) this.serverVersion.getActionListeners()[0].actionPerformed(null); } diff --git a/src/main/resources/assets/viaproxy/language/de_DE.properties b/src/main/resources/assets/viaproxy/language/de_DE.properties index 74cb2c4..be56c30 100644 --- a/src/main/resources/assets/viaproxy/language/de_DE.properties +++ b/src/main/resources/assets/viaproxy/language/de_DE.properties @@ -58,6 +58,8 @@ tab.advanced.allow_beta_pinging.label=Aktiviere Pings für <= b1.7.3 tab.advanced.allow_beta_pinging.tooltip=Aktiviert das Pingen für <= b1.7.3 Server. Das könnte zu Problemen bei Servern, welche zu schnelle Verbindungen blockieren führen. tab.advanced.simple_voice_chat_support.label=Simple Voice Chat Unterstützung tab.advanced.simple_voice_chat_support.tooltip=Aktiviert lesen und ändern der Simple Voice Chat Mod Pakete. +tab.advanced.fake_accept_resource_packs.label=Überspringe Resourcenpakete +tab.advanced.fake_accept_resource_packs.tooltip=Akzeptiere Resourcenpakete ohne diese dem Client zu senden.\nDiese Option ist erforderlich um auf Servern zu spielen, welche Resourcenpakete benötigen, diese aber vom Client aufgrund der unterschiedlichen Version nicht geladen werden können. tab.advanced.create_viaversion_dump.label=ViaVersion Dump erstellen tab.advanced.create_viaversion_dump.success=Der ViaVersion Dump Link wurde in die Zwischenablage kopiert. tab.advanced.upload_latest_log.label=Neueste Log-Datei hochladen diff --git a/src/main/resources/assets/viaproxy/language/en_US.properties b/src/main/resources/assets/viaproxy/language/en_US.properties index 741fae7..f94c765 100644 --- a/src/main/resources/assets/viaproxy/language/en_US.properties +++ b/src/main/resources/assets/viaproxy/language/en_US.properties @@ -58,6 +58,8 @@ tab.advanced.allow_beta_pinging.label=Allow <= b1.7.3 pinging tab.advanced.allow_beta_pinging.tooltip=Enabling this will allow you to ping <= b1.7.3 servers. This may cause issues with servers that block too frequent connections. tab.advanced.simple_voice_chat_support.label=Simple Voice Chat Support tab.advanced.simple_voice_chat_support.tooltip=Enables handling and rewriting of Simple Voice Chat mod packets. +tab.advanced.fake_accept_resource_packs.label=Fake accept resource packs +tab.advanced.fake_accept_resource_packs.tooltip=Accepts resource packs from the server without showing a prompt to the client.\nThis is required for servers that require a resource pack, but the client can't load it due to version differences. tab.advanced.create_viaversion_dump.label=Create ViaVersion dump tab.advanced.create_viaversion_dump.success=Copied ViaVersion dump link to clipboard. tab.advanced.upload_latest_log.label=Upload latest log file diff --git a/src/main/resources/assets/viaproxy/viaproxy.yml b/src/main/resources/assets/viaproxy/viaproxy.yml index 942cbc2..60f8846 100644 --- a/src/main/resources/assets/viaproxy/viaproxy.yml +++ b/src/main/resources/assets/viaproxy/viaproxy.yml @@ -75,5 +75,9 @@ wildcard-domain-handling: "none" # Enables handling and rewriting of Simple Voice Chat mod packets. simple-voice-chat-support: false # +# Accepts resource packs from the server without showing a prompt to the client. +# This is required for servers that require a resource pack, but the client can't load it due to version differences. +fake-accept-resource-packs: false +# # Configuration version. Do not change this. config-version: 1