Allow for multiple base protocols per version (#4106)

This commit is contained in:
EnZaXD 2024-08-21 14:35:19 +02:00 committed by GitHub
parent 6ad3beca76
commit bc57512ca2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 157 additions and 116 deletions

View File

@ -73,13 +73,13 @@ public interface ProtocolManager {
Protocol getBaseProtocol(); Protocol getBaseProtocol();
/** /**
* Returns the base protocol for a specific server protocol version. * Returns the base protocols for a specific server protocol version.
* The standard base protocols deal with status and login packets for userconnection initialization. * The standard base protocols deal with status and login packets for userconnection initialization.
* *
* @param serverVersion server protocol version * @param serverVersion server protocol version
* @return base protocol for the given server protocol version if present, else null * @return base protocols for the given server protocol version if present, else null
*/ */
@Nullable Protocol getBaseProtocol(ProtocolVersion serverVersion); List<Protocol> getBaseProtocols(ProtocolVersion serverVersion);
/** /**
* Returns an immutable collection of registered protocols. * Returns an immutable collection of registered protocols.

View File

@ -38,9 +38,9 @@ import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.VersionType; import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl; import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
import com.viaversion.viaversion.protocol.packet.VersionedPacketTransformerImpl; import com.viaversion.viaversion.protocol.packet.VersionedPacketTransformerImpl;
import com.viaversion.viaversion.protocols.base.BaseProtocol; import com.viaversion.viaversion.protocols.base.InitialBaseProtocol;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_16; import com.viaversion.viaversion.protocols.base.v1_7.ClientboundBaseProtocol1_7;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_7; import com.viaversion.viaversion.protocols.base.v1_7.ServerboundBaseProtocol1_7;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21; import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_10to1_11.Protocol1_10To1_11; import com.viaversion.viaversion.protocols.v1_10to1_11.Protocol1_10To1_11;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.Protocol1_11_1To1_12; import com.viaversion.viaversion.protocols.v1_11_1to1_12.Protocol1_11_1To1_12;
@ -109,7 +109,7 @@ import java.util.logging.Level;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
public class ProtocolManagerImpl implements ProtocolManager { public class ProtocolManagerImpl implements ProtocolManager {
private static final Protocol BASE_PROTOCOL = new BaseProtocol(); private static final Protocol BASE_PROTOCOL = new InitialBaseProtocol();
// Input Version -> Output Version & Protocol (Allows fast lookup) // Input Version -> Output Version & Protocol (Allows fast lookup)
private final Object2ObjectMap<ProtocolVersion, Object2ObjectMap<ProtocolVersion, Protocol>> registryMap = new Object2ObjectOpenHashMap<>(32); private final Object2ObjectMap<ProtocolVersion, Object2ObjectMap<ProtocolVersion, Protocol>> registryMap = new Object2ObjectOpenHashMap<>(32);
@ -137,8 +137,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
// Base Protocol // Base Protocol
BASE_PROTOCOL.initialize(); BASE_PROTOCOL.initialize();
BASE_PROTOCOL.register(Via.getManager().getProviders()); BASE_PROTOCOL.register(Via.getManager().getProviders());
registerBaseProtocol(new BaseProtocol1_7(), Range.closedOpen(ProtocolVersion.v1_7_2, ProtocolVersion.v1_16)); registerBaseProtocol(new ClientboundBaseProtocol1_7(), Range.atLeast(ProtocolVersion.v1_7_2));
registerBaseProtocol(new BaseProtocol1_16(), Range.atLeast(ProtocolVersion.v1_16)); registerBaseProtocol(new ServerboundBaseProtocol1_7(), Range.atLeast(ProtocolVersion.v1_7_2));
registerProtocol(new Protocol1_8To1_9(), ProtocolVersion.v1_9, ProtocolVersion.v1_8); registerProtocol(new Protocol1_8To1_9(), ProtocolVersion.v1_9, ProtocolVersion.v1_8);
registerProtocol(new Protocol1_9To1_9_1(), Arrays.asList(ProtocolVersion.v1_9_1, ProtocolVersion.v1_9_2), ProtocolVersion.v1_9); registerProtocol(new Protocol1_9To1_9_1(), Arrays.asList(ProtocolVersion.v1_9_1, ProtocolVersion.v1_9_2), ProtocolVersion.v1_9);
@ -365,13 +365,14 @@ public class ProtocolManagerImpl implements ProtocolManager {
} }
@Override @Override
public @Nullable Protocol getBaseProtocol(ProtocolVersion serverVersion) { public List<Protocol> getBaseProtocols(ProtocolVersion serverVersion) {
final List<Protocol> list = new ArrayList<>();
for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : Lists.reverse(baseProtocols)) { for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : Lists.reverse(baseProtocols)) {
if (rangeProtocol.key().contains(serverVersion)) { if (rangeProtocol.key().contains(serverVersion)) {
return rangeProtocol.value(); list.add(rangeProtocol.value());
} }
} }
return null; return list;
} }
@Override @Override

View File

@ -1,30 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion 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 com.viaversion.viaversion.protocols.base;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import java.util.UUID;
public class BaseProtocol1_16 extends BaseProtocol1_7 {
@Override
protected UUID passthroughLoginUUID(final PacketWrapper wrapper) {
return wrapper.passthrough(Types.UUID);
}
}

View File

@ -39,22 +39,28 @@ import com.viaversion.viaversion.protocol.version.BaseVersionProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket; import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider; import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket; import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> { /**
* Initial base protocol which is kept always in the pipeline.
* <p>
* State tracking for configuration state is done via {@link AbstractProtocol#registerConfigurationChangeHandlers()}
*/
public class InitialBaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
private static final int STATUS_INTENT = 1; private static final int STATUS_INTENT = 1;
private static final int LOGIN_INTENT = 2; private static final int LOGIN_INTENT = 2;
private static final int TRANSFER_INTENT = 3; private static final int TRANSFER_INTENT = 3;
public BaseProtocol() { public InitialBaseProtocol() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class); super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
// Handshake Packet // Setup protocol pipeline + track initial state
registerServerbound(ServerboundHandshakePackets.CLIENT_INTENTION, wrapper -> { registerServerbound(ServerboundHandshakePackets.CLIENT_INTENTION, wrapper -> {
int protocolVersion = wrapper.passthrough(Types.VAR_INT); int protocolVersion = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.STRING); // Server Address wrapper.passthrough(Types.STRING); // Server Address
@ -92,12 +98,11 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
// Add Base Protocol // Add Base Protocol
ProtocolPipeline pipeline = info.getPipeline(); ProtocolPipeline pipeline = info.getPipeline();
// Special versions might compare equal to normal versions and would break this getter // Special versions might compare equal to normal versions and would break this getter,
// platforms need to add the base protocols manually in this case
if (serverProtocol.getVersionType() != VersionType.SPECIAL) { if (serverProtocol.getVersionType() != VersionType.SPECIAL) {
final Protocol baseProtocol = protocolManager.getBaseProtocol(serverProtocol); for (final Protocol protocol : protocolManager.getBaseProtocols(serverProtocol)) {
// Platforms might add their base protocol manually (e.g. SPECIAL versions) pipeline.add(protocol);
if (baseProtocol != null) {
pipeline.add(baseProtocol);
} }
} }
@ -123,6 +128,7 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
Via.getPlatform().getLogger().info("Protocol pipeline: " + pipeline.pipes()); Via.getPlatform().getLogger().info("Protocol pipeline: " + pipeline.pipes());
} }
// Set initial state
if (state == STATUS_INTENT) { if (state == STATUS_INTENT) {
info.setState(State.STATUS); info.setState(State.STATUS);
} else if (state == LOGIN_INTENT) { } else if (state == LOGIN_INTENT) {

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.viaversion.viaversion.protocols.base; package com.viaversion.viaversion.protocols.base.v1_7;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@ -26,7 +26,6 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.AbstractProtocol; import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider; import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
@ -35,25 +34,25 @@ import com.viaversion.viaversion.api.protocol.version.VersionProvider;
import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocol.ProtocolManagerImpl; import com.viaversion.viaversion.protocol.ProtocolManagerImpl;
import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton; import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ClientboundStatusPackets;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket; import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider; import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket; import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.GsonUtil; import com.viaversion.viaversion.util.GsonUtil;
import io.netty.channel.ChannelFuture;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> { public class ClientboundBaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public BaseProtocol1_7() { public ClientboundBaseProtocol1_7() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class); super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
} }
@Override @Override
protected void registerPackets() { protected void registerPackets() {
// Handle server pinging sent by the client
registerClientbound(ClientboundStatusPackets.STATUS_RESPONSE, new PacketHandlers() { registerClientbound(ClientboundStatusPackets.STATUS_RESPONSE, new PacketHandlers() {
@Override @Override
public void register() { public void register() {
@ -128,60 +127,27 @@ public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, Bas
} }
}); });
// Login Success Packet // Track player name/uuid and setup connection + track state
registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> { registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
ProtocolInfo info = wrapper.user().getProtocolInfo();
if (info.protocolVersion().olderThan(ProtocolVersion.v1_20_2)) { // On 1.20.2+, wait for the login ack
info.setState(State.PLAY);
}
UUID uuid = passthroughLoginUUID(wrapper);
info.setUuid(uuid);
String username = wrapper.passthrough(Types.STRING);
info.setUsername(username);
// Add to ported clients
Via.getManager().getConnectionManager().onLoginSuccess(wrapper.user());
if (!info.getPipeline().hasNonBaseProtocols()) { // Only base protocol
wrapper.user().setActive(false);
}
if (Via.getManager().isDebug()) {
// Print out the route to console
Via.getPlatform().getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
username,
info.protocolVersion().getName(),
Joiner.on(", ").join(info.getPipeline().pipes(), ", ")
});
}
});
// Login Start Packet
registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> {
final UserConnection user = wrapper.user();
final ProtocolVersion protocol = user.getProtocolInfo().protocolVersion();
if (Via.getConfig().blockedProtocolVersions().contains(protocol)) {
if (!user.getChannel().isOpen() || !user.shouldApplyBlockProtocol()) {
return;
}
wrapper.cancel(); // cancel current
final String disconnectMessage = ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg());
final PacketWrapper disconnectPacket = PacketWrapper.create(ClientboundLoginPackets.LOGIN_DISCONNECT, user);
disconnectPacket.write(Types.COMPONENT, ComponentUtil.plainToJson(disconnectMessage));
// Send and close
final ChannelFuture future = disconnectPacket.sendFuture(null);
future.addListener(f -> user.getChannel().close());
}
});
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo(); final ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setState(State.CONFIGURATION);
if (info.serverProtocolVersion().olderThan(ProtocolVersion.v1_16)) {
String uuidString = wrapper.passthrough(Types.STRING);
if (uuidString.length() == 32) { // Trimmed UUIDs are 32 characters
// Trimmed
uuidString = addDashes(uuidString);
}
info.setUuid(UUID.fromString(uuidString));
} else {
final UUID uuid = wrapper.passthrough(Types.UUID);
info.setUuid(uuid);
}
final String username = wrapper.passthrough(Types.STRING);
info.setUsername(username);
// Setup connection
onLoginSuccess(wrapper.user());
}); });
} }
@ -199,13 +165,28 @@ public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, Bas
return idBuff.toString(); return idBuff.toString();
} }
protected UUID passthroughLoginUUID(PacketWrapper wrapper) { public static void onLoginSuccess(final UserConnection connection) {
String uuidString = wrapper.passthrough(Types.STRING); final ProtocolInfo info = connection.getProtocolInfo();
if (uuidString.length() == 32) { // Trimmed UUIDs are 32 characters if (info.protocolVersion().olderThan(ProtocolVersion.v1_20_2)) { // On 1.20.2+, wait for the login ack
// Trimmed info.setState(State.PLAY);
uuidString = addDashes(uuidString); }
// Add to ported clients
Via.getManager().getConnectionManager().onLoginSuccess(connection);
if (!info.getPipeline().hasNonBaseProtocols()) { // Only base protocol
connection.setActive(false);
}
if (Via.getManager().isDebug()) {
// Print out the route to console
Via.getPlatform().getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
info.getUsername(),
info.protocolVersion().getName(),
Joiner.on(", ").join(info.getPipeline().pipes(), ", ")
});
} }
return UUID.fromString(uuidString);
} }
@Override @Override

View File

@ -0,0 +1,83 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion 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 com.viaversion.viaversion.protocols.base.v1_7;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import io.netty.channel.ChannelFuture;
public class ServerboundBaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public ServerboundBaseProtocol1_7() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
}
@Override
protected void registerPackets() {
// State tracking
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setState(State.CONFIGURATION);
});
// Handle blocked version disconnect
registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> {
final UserConnection user = wrapper.user();
final ProtocolVersion protocol = user.getProtocolInfo().protocolVersion();
if (Via.getConfig().blockedProtocolVersions().contains(protocol)) {
if (!user.getChannel().isOpen() || !user.shouldApplyBlockProtocol()) {
return;
}
wrapper.cancel(); // cancel current
final String disconnectMessage = ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg());
final PacketWrapper disconnectPacket = PacketWrapper.create(ClientboundLoginPackets.LOGIN_DISCONNECT, user);
disconnectPacket.write(Types.COMPONENT, ComponentUtil.plainToJson(disconnectMessage));
// Send and close
final ChannelFuture future = disconnectPacket.sendFuture(null);
future.addListener(f -> user.getChannel().close());
}
});
}
@Override
public boolean isBaseProtocol() {
return true;
}
@Override
protected PacketTypesProvider<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> createPacketTypesProvider() {
return BasePacketTypesProvider.INSTANCE;
}
}