Decided to use one version. Compatibility with other can be achieved woth protocol hack on proxy side

This commit is contained in:
Nanit 2020-11-26 23:09:40 +02:00
parent 6350181dfc
commit e029336cf0
21 changed files with 96 additions and 109 deletions

View File

@ -7,7 +7,6 @@ import io.netty.channel.ChannelInboundHandlerAdapter;
import ru.nanit.limbo.LimboConfig;
import ru.nanit.limbo.protocol.packets.login.*;
import ru.nanit.limbo.protocol.packets.play.*;
import ru.nanit.limbo.protocol.registry.Version;
import ru.nanit.limbo.protocol.pipeline.PacketDecoder;
import ru.nanit.limbo.protocol.pipeline.PacketEncoder;
import ru.nanit.limbo.protocol.packets.PacketHandshake;
@ -15,6 +14,7 @@ import ru.nanit.limbo.protocol.packets.status.PacketStatusPing;
import ru.nanit.limbo.protocol.packets.status.PacketStatusRequest;
import ru.nanit.limbo.protocol.packets.status.PacketStatusResponse;
import ru.nanit.limbo.protocol.registry.State;
import ru.nanit.limbo.protocol.registry.Version;
import ru.nanit.limbo.server.LimboServer;
import ru.nanit.limbo.util.Logger;
import ru.nanit.limbo.util.UuidUtil;
@ -29,6 +29,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
private final Channel channel;
private State state;
private Version clientVersion;
private UUID uuid;
private String username;
@ -66,12 +67,12 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
public void handlePacket(Object packet){
if (packet instanceof PacketHandshake){
PacketHandshake handshake = (PacketHandshake) packet;
State state = State.getById(handshake.getNextState());
updateStateAndVersion(state, handshake.getVersion());
updateState(State.getById(handshake.getNextState()));
clientVersion = handshake.getVersion();
}
if (packet instanceof PacketStatusRequest){
sendPacket(new PacketStatusResponse());
sendPacket(new PacketStatusResponse(server.getConnectionsCount()));
}
if (packet instanceof PacketStatusPing){
@ -84,6 +85,11 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
return;
}
if (!clientVersion.equals(Version.getCurrentSupported())){
disconnect("Incompatible client version");
return;
}
this.username = ((PacketLoginStart) packet).getUsername();
this.uuid = UuidUtil.getOfflineModeUuid(this.username);
@ -96,7 +102,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
updateState(State.PLAY);
server.addConnection(this);
Logger.info("Player %s connected", this.username);
Logger.info("Player %s connected (%s)", this.username, channel.remoteAddress());
sendJoinPackets();
}
@ -179,16 +185,4 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
channel.pipeline().get(PacketDecoder.class).updateState(state);
channel.pipeline().get(PacketEncoder.class).updateState(state);
}
public void updateStateAndVersion(State state, Version version){
PacketDecoder decoder = channel.pipeline().get(PacketDecoder.class);
PacketEncoder encoder = channel.pipeline().get(PacketEncoder.class);
decoder.updateVersion(version);
decoder.updateState(state);
encoder.updateVersion(version);
encoder.updateState(state);
this.state = state;
}
}

View File

@ -1,11 +1,9 @@
package ru.nanit.limbo.protocol;
import ru.nanit.limbo.protocol.registry.Version;
public interface Packet {
void encode(ByteMessage msg, Version version);
void encode(ByteMessage msg);
void decode(ByteMessage msg, Version version);
void decode(ByteMessage msg);
}

View File

@ -1,11 +1,9 @@
package ru.nanit.limbo.protocol;
import ru.nanit.limbo.protocol.registry.Version;
public interface PacketIn extends Packet {
@Override
default void encode(ByteMessage msg, Version version) {
default void encode(ByteMessage msg) {
// Can be ignored for incoming packets
}

View File

@ -1,11 +1,9 @@
package ru.nanit.limbo.protocol;
import ru.nanit.limbo.protocol.registry.Version;
public interface PacketOut extends Packet {
@Override
default void decode(ByteMessage msg, Version version) {
default void decode(ByteMessage msg) {
// Can be ignored for outgoing packets
}

View File

@ -44,7 +44,7 @@ public class PacketHandshake implements Packet {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeVarInt(this.version.getProtocolNumber());
msg.writeString(host);
msg.writeShort(port);
@ -52,7 +52,7 @@ public class PacketHandshake implements Packet {
}
@Override
public void decode(ByteMessage msg, Version version) {
public void decode(ByteMessage msg) {
this.version = Version.of(msg.readVarInt());
this.host = msg.readString();
this.port = msg.readUnsignedShort();

View File

@ -2,7 +2,6 @@ package ru.nanit.limbo.protocol.packets.login;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketDisconnect implements PacketOut {
@ -13,7 +12,7 @@ public class PacketDisconnect implements PacketOut {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeString(String.format("{\"text\": \"%s\"}", reason));
}

View File

@ -1,7 +1,6 @@
package ru.nanit.limbo.protocol.packets.login;
import ru.nanit.limbo.protocol.*;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketLoginStart implements PacketIn {
@ -12,7 +11,7 @@ public class PacketLoginStart implements PacketIn {
}
@Override
public void decode(ByteMessage msg, Version version) {
public void decode(ByteMessage msg) {
this.username = msg.readString();
}

View File

@ -2,7 +2,6 @@ package ru.nanit.limbo.protocol.packets.login;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
import java.util.UUID;
@ -20,7 +19,7 @@ public class PacketLoginSuccess implements PacketOut {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeUuid(uuid);
msg.writeString(username);
}

View File

@ -2,7 +2,6 @@ package ru.nanit.limbo.protocol.packets.play;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
import java.util.UUID;
@ -40,7 +39,7 @@ public class PacketBossBar implements PacketOut {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeUuid(uuid);
msg.writeVarInt(0); // Create bossbar
msg.writeString(title);

View File

@ -2,7 +2,6 @@ package ru.nanit.limbo.protocol.packets.play;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
import java.util.UUID;
@ -25,7 +24,7 @@ public class PacketChatMessage implements PacketOut {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeString(jsonData);
msg.writeByte(position.index);
msg.writeUuid(sender);

View File

@ -3,7 +3,6 @@ package ru.nanit.limbo.protocol.packets.play;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketJoinGame implements PacketOut {
@ -84,7 +83,7 @@ public class PacketJoinGame implements PacketOut {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeInt(entityId);
msg.writeBoolean(isHardcore);
msg.writeByte(gameMode);

View File

@ -2,7 +2,6 @@ package ru.nanit.limbo.protocol.packets.play;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.Packet;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketKeepAlive implements Packet {
@ -17,12 +16,12 @@ public class PacketKeepAlive implements Packet {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeLong(id);
}
@Override
public void decode(ByteMessage msg, Version version) {
public void decode(ByteMessage msg) {
this.id = msg.readLong();
}

View File

@ -2,7 +2,6 @@ package ru.nanit.limbo.protocol.packets.play;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketPlayerPositionAndLook implements PacketOut {
@ -43,7 +42,7 @@ public class PacketPlayerPositionAndLook implements PacketOut {
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeDouble(x);
msg.writeDouble(y);
msg.writeDouble(z);

View File

@ -2,19 +2,18 @@ package ru.nanit.limbo.protocol.packets.status;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.Packet;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketStatusPing implements Packet {
private long randomId;
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
msg.writeLong(randomId);
}
@Override
public void decode(ByteMessage msg, Version version) {
public void decode(ByteMessage msg) {
this.randomId = msg.readLong();
}

View File

@ -1,12 +1,11 @@
package ru.nanit.limbo.protocol.packets.status;
import ru.nanit.limbo.protocol.*;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketStatusRequest implements PacketIn {
@Override
public void decode(ByteMessage msg, Version version) {
public void decode(ByteMessage msg) {
}

View File

@ -8,11 +8,20 @@ public class PacketStatusResponse implements PacketOut {
private static final String TEMPLATE = "{ \"version\": { \"name\": \"%s\", \"protocol\": %d }, \"players\": { \"max\": %d, \"online\": %d, \"sample\": [] }, \"description\": %s }";
private int online;
public PacketStatusResponse(){ }
public PacketStatusResponse(int online){
this.online = online;
}
@Override
public void encode(ByteMessage msg, Version version) {
public void encode(ByteMessage msg) {
String ver = LimboConfig.getPingData().getVersion();
String desc = LimboConfig.getPingData().getDescription();
String json = getResponseJson(ver, version.getProtocolNumber(), LimboConfig.getMaxPlayers(), 0, desc);
String json = getResponseJson(ver, Version.getCurrentSupported().getProtocolNumber(),
LimboConfig.getMaxPlayers(), online, desc);
msg.writeString(json);
}

View File

@ -5,18 +5,15 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import ru.nanit.limbo.protocol.*;
import ru.nanit.limbo.protocol.registry.State;
import ru.nanit.limbo.protocol.registry.Version;
import ru.nanit.limbo.util.Logger;
import java.util.List;
public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
private State.PacketVersionRegistry.PacketIdRegistry<?> mappings;
private Version version;
private State.PacketRegistry mappings;
public PacketDecoder(){
updateVersion(Version.getMinimal());
updateState(State.HANDSHAKING);
}
@ -30,7 +27,7 @@ public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
if (packet != null){
try {
packet.decode(msg, mappings.getVersion());
packet.decode(msg);
} catch (Exception e){
Logger.warning("Cannot decode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
}
@ -41,12 +38,8 @@ public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
}
}
public void updateVersion(Version version){
this.version = version;
}
public void updateState(State state){
this.mappings = state.serverBound.getRegistry(version);
this.mappings = state.serverBound;
}
}

View File

@ -5,26 +5,23 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.Packet;
import ru.nanit.limbo.protocol.registry.Version;
import ru.nanit.limbo.protocol.registry.State;
import ru.nanit.limbo.util.Logger;
public class PacketEncoder extends MessageToByteEncoder<Packet> {
private State.PacketVersionRegistry.PacketIdRegistry<?> mappings;
private Version version;
private State.PacketRegistry registry;
public PacketEncoder(){
updateVersion(Version.getMinimal());
updateState(State.HANDSHAKING);
}
@Override
protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) throws Exception {
if (mappings == null) return;
if (registry == null) return;
ByteMessage msg = new ByteMessage(out);
int packetId = mappings.getPacketId(packet.getClass());
int packetId = registry.getPacketId(packet.getClass());
if (packetId == -1){
Logger.warning("Undefined packet class: %s", packet.getClass().getName());
@ -34,18 +31,14 @@ public class PacketEncoder extends MessageToByteEncoder<Packet> {
msg.writeVarInt(packetId);
try {
packet.encode(msg, version);
packet.encode(msg);
} catch (Exception e){
Logger.warning("Cannot encode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
}
}
public void updateVersion(Version version){
this.version = version;
}
public void updateState(State state){
this.mappings = state.clientBound.getRegistry(version);
this.registry = state.clientBound;
}
}

View File

@ -16,39 +16,35 @@ public enum State {
HANDSHAKING(0){
{
serverBound.register(Version.getMinimal(), 0x00, PacketHandshake::new);
serverBound.register(0x00, PacketHandshake::new);
}
},
STATUS(1){
{
serverBound.register(Version.getMinimal(), 0x01, PacketStatusPing::new);
serverBound.register(Version.getMinimal(), 0x00, PacketStatusRequest::new);
clientBound.register(Version.getMinimal(), 0x00, PacketStatusResponse::new);
clientBound.register(Version.getMinimal(), 0x01, PacketStatusPing::new);
serverBound.register(0x01, PacketStatusPing::new);
serverBound.register(0x00, PacketStatusRequest::new);
clientBound.register(0x00, PacketStatusResponse::new);
clientBound.register(0x01, PacketStatusPing::new);
}
},
LOGIN(2){
{
serverBound.register(Version.getMinimal(), 0x00, PacketLoginStart::new);
clientBound.register(Version.getMinimal(), 0x00, PacketDisconnect::new);
clientBound.register(Version.getMinimal(), 0x02, PacketLoginSuccess::new);
serverBound.register(0x00, PacketLoginStart::new);
clientBound.register(0x00, PacketDisconnect::new);
clientBound.register(0x02, PacketLoginSuccess::new);
}
},
PLAY(3){
{
serverBound.register(Version.V1_16_4, 0x10, PacketKeepAlive::new);
clientBound.register(Version.V1_16_4, 0x24, PacketJoinGame::new);
clientBound.register(Version.V1_16_4, 0x34, PacketPlayerPositionAndLook::new);
clientBound.register(Version.V1_16_4, 0x1F, PacketKeepAlive::new);
clientBound.register(Version.V1_16_4, 0x0E, PacketChatMessage::new);
clientBound.register(Version.V1_16_4, 0x0C, PacketBossBar::new);
serverBound.register(0x10, PacketKeepAlive::new);
clientBound.register(0x24, PacketJoinGame::new);
clientBound.register(0x34, PacketPlayerPositionAndLook::new);
clientBound.register(0x1F, PacketKeepAlive::new);
clientBound.register(0x0E, PacketChatMessage::new);
clientBound.register(0x0C, PacketBossBar::new);
}
};
private final int stateId;
public final PacketVersionRegistry serverBound = new PacketVersionRegistry();
public final PacketVersionRegistry clientBound = new PacketVersionRegistry();
private static final Map<Integer, State> STATE_BY_ID = new HashMap<>();
static {
@ -57,6 +53,10 @@ public enum State {
}
}
private final int stateId;
public final PacketRegistry serverBound = new PacketRegistry();
public final PacketRegistry clientBound = new PacketRegistry();
State(int stateId){
this.stateId = stateId;
}
@ -65,6 +65,31 @@ public enum State {
return STATE_BY_ID.get(stateId);
}
public static class PacketRegistry {
private final Map<Integer, Supplier<?>> packetsById = new HashMap<>();
private final Map<Class<?>, Integer> packetIdByClass = new HashMap<>();
public Packet getPacket(int packetId){
Supplier<?> supplier = packetsById.get(packetId);
return supplier == null ? null : (Packet) supplier.get();
}
public int getPacketId(Class<?> packetClass){
return packetIdByClass.getOrDefault(packetClass, -1);
}
public void register(int packetId, Supplier<?> supplier){
packetsById.put(packetId, supplier);
packetIdByClass.put(supplier.get().getClass(), packetId);
}
}
/*
Temporary don't needed
public static class PacketVersionRegistry {
private final Map<Version, PacketIdRegistry<?>> MAPPINGS = new HashMap<>();
@ -109,6 +134,6 @@ public enum State {
}
}
}*/
}

View File

@ -1,6 +1,5 @@
package ru.nanit.limbo.protocol.registry;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@ -44,8 +43,8 @@ public enum Version {
}
}
public static Version getMinimal(){
return V1_9;
public static Version getCurrentSupported(){
return V1_16_4;
}
public static Version of(int protocolNumber){
@ -62,16 +61,4 @@ public enum Version {
return this.protocolNumber;
}
public Version getClosest(Collection<Version> available){
Version closest = getMinimal();
for (Version version : available){
if (version.protocolNumber > closest.protocolNumber && version.protocolNumber < this.protocolNumber){
closest = version;
}
}
return closest;
}
}

View File

@ -18,6 +18,8 @@ ping-version=NanoLimbo
ping-description={"text": "NanoLimbo"}
# Player info forwarding support. Available types: NONE, LEGACY, MODERN
# MODERN - Velocity native forwarding type.
# LEGACY - BungeeCord forwarding type (Velocity supports it too)
ip-forwarding=LEGACY
# If you use MODERN type of forwarding, enter your secret code here