Added option to send a ViaVersion connection details custom payload to the server

This commit is contained in:
RaphiMC 2025-03-31 00:34:08 +02:00
parent ec44742236
commit a17daa87ba
No known key found for this signature in database
GPG key ID: 0F6BB0657A03AC94
4 changed files with 96 additions and 25 deletions
src/main/java/net/raphimc/viaproxy

View file

@ -190,6 +190,13 @@ public class ViaProxyConfig {
})
private boolean workAroundConfigStatePacketQueue = false;
@Option("send-connection-details")
@Description({
"If enabled, ViaProxy will send a connection details custom payload packet to the server.",
"This includes the actual client version as well as the ViaProxy version."
})
private boolean sendConnectionDetails = false;
public static ViaProxyConfig create(final File configFile) {
final ConfigLoader<ViaProxyConfig> configLoader = new ConfigLoader<>(ViaProxyConfig.class);
configLoader.getConfigOptions().setResetInvalidOptions(true).setRewriteConfig(true).setCommentSpacing(1);
@ -494,6 +501,15 @@ public class ViaProxyConfig {
this.save();
}
public boolean shouldSendConnectionDetails() {
return this.sendConnectionDetails;
}
public void setSendConnectionDetails(final boolean sendConnectionDetails) {
this.sendConnectionDetails = sendConnectionDetails;
this.save();
}
@Validator("target-version")
private ProtocolVersion validateTargetVersion(final ProtocolVersion targetVersion) {
if (targetVersion == null) {

View file

@ -22,6 +22,7 @@ import com.google.common.net.HostAndPort;
import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.storage.CookieStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.VersionType;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
@ -277,7 +278,12 @@ public class Client2ProxyHandler extends SimpleChannelInboundHandler<Packet> {
if (clientVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_3) && serverVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_3)) {
this.proxyConnection.getPacketHandlers().add(new ChatSignaturePacketHandler(this.proxyConnection));
}
this.proxyConnection.getPacketHandlers().add(new ResourcePackPacketHandler(this.proxyConnection));
if (!ViaProxy.getConfig().getResourcePackUrl().isBlank()) {
this.proxyConnection.getPacketHandlers().add(new ResourcePackPacketHandler(this.proxyConnection));
}
if (ViaProxy.getConfig().shouldSendConnectionDetails() && !serverVersion.equals(clientVersion) && serverVersion.newerThanOrEqualTo(ProtocolVersion.v1_8) && serverVersion.getVersionType() == VersionType.RELEASE) {
this.proxyConnection.getPacketHandlers().add(new ViaVersionConnectionDetailsPacketHandler(this.proxyConnection));
}
this.proxyConnection.getPacketHandlers().add(new UnexpectedPacketHandler(this.proxyConnection));
Logger.u_info("connect", this.proxyConnection, "[" + clientVersion.getName() + " <-> " + serverVersion.getName() + "] Connecting to " + AddressUtil.toString(serverAddress));

View file

@ -64,31 +64,29 @@ public class ResourcePackPacketHandler extends PacketHandler {
}
private void sendResourcePack() {
if (!ViaProxy.getConfig().getResourcePackUrl().isBlank()) {
this.proxyConnection.getChannel().eventLoop().schedule(() -> {
try {
final String url = ViaProxy.getConfig().getResourcePackUrl();
final boolean required = Via.getConfig().isForcedUse1_17ResourcePack();
final TextComponent message;
if (Via.getConfig().get1_17ResourcePackPrompt() != null) {
message = TextComponentSerializer.LATEST.deserialize(Via.getConfig().get1_17ResourcePackPrompt().toString());
} else {
message = null;
}
if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_3)) {
this.proxyConnection.getC2P().writeAndFlush(new S2CPlayResourcePackPushPacket(UUID.randomUUID(), url, "", required, message)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
} else if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_8)) {
this.proxyConnection.getC2P().writeAndFlush(new S2CPlayResourcePackPacket(url, "", required, message)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
} else if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_7_2)) {
final byte[] data = url.getBytes(StandardCharsets.UTF_8);
this.proxyConnection.getC2P().writeAndFlush(new S2CPlayCustomPayloadPacket("MC|RPack", data)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
} catch (Throwable e) {
Logger.LOGGER.warn("Failed to send resource pack", e);
this.proxyConnection.getChannel().eventLoop().schedule(() -> {
try {
final String url = ViaProxy.getConfig().getResourcePackUrl();
final boolean required = Via.getConfig().isForcedUse1_17ResourcePack();
final TextComponent message;
if (Via.getConfig().get1_17ResourcePackPrompt() != null) {
message = TextComponentSerializer.LATEST.deserialize(Via.getConfig().get1_17ResourcePackPrompt().toString());
} else {
message = null;
}
}, 250, TimeUnit.MILLISECONDS);
}
if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_3)) {
this.proxyConnection.getC2P().writeAndFlush(new S2CPlayResourcePackPushPacket(UUID.randomUUID(), url, "", required, message)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
} else if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_8)) {
this.proxyConnection.getC2P().writeAndFlush(new S2CPlayResourcePackPacket(url, "", required, message)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
} else if (this.proxyConnection.getClientVersion().newerThanOrEqualTo(ProtocolVersion.v1_7_2)) {
final byte[] data = url.getBytes(StandardCharsets.UTF_8);
this.proxyConnection.getC2P().writeAndFlush(new S2CPlayCustomPayloadPacket("MC|RPack", data)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
} catch (Throwable e) {
Logger.LOGGER.warn("Failed to send resource pack", e);
}
}, 250, TimeUnit.MILLISECONDS);
}
}

View file

@ -0,0 +1,51 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2025 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 <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viaproxy.proxy.packethandler;
import com.viaversion.viaversion.connection.ConnectionDetails;
import io.netty.channel.ChannelFutureListener;
import net.raphimc.netminecraft.constants.ConnectionState;
import net.raphimc.netminecraft.constants.MCPackets;
import net.raphimc.netminecraft.packet.Packet;
import net.raphimc.netminecraft.packet.UnknownPacket;
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
import java.util.List;
public class ViaVersionConnectionDetailsPacketHandler extends PacketHandler {
private final int joinGameId;
public ViaVersionConnectionDetailsPacketHandler(ProxyConnection proxyConnection) {
super(proxyConnection);
this.joinGameId = MCPackets.S2C_LOGIN.getId(this.proxyConnection.getClientVersion().getVersion());
}
@Override
public boolean handleP2S(Packet packet, List<ChannelFutureListener> listeners) {
if (packet instanceof UnknownPacket unknownPacket && this.proxyConnection.getP2sConnectionState() == ConnectionState.PLAY) {
if (unknownPacket.packetId == this.joinGameId) {
ConnectionDetails.sendConnectionDetails(this.proxyConnection.getUserConnection(), ConnectionDetails.APP_CHANNEL);
}
}
return true;
}
}