Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Started work on revamped protocol registry
Dieser Commit ist enthalten in:
Ursprung
ba7ba70f4b
Commit
602ed04dee
@ -0,0 +1,100 @@
|
||||
package com.velocitypowered.proxy.network.registry.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.Packet;
|
||||
import com.velocitypowered.proxy.network.packet.PacketReader;
|
||||
import com.velocitypowered.proxy.network.packet.PacketWriter;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryBuilder.PacketMapping;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Provides a packet registry map that is "dense", ideal for registries that are tightly packed
|
||||
* together by ID. Lookups for readers are very fast (O(1)) and for writers uses an embedded
|
||||
* open-addressing, probing hash map to conserve memory.
|
||||
*/
|
||||
public class DensePacketRegistryMap implements PacketRegistryMap {
|
||||
|
||||
private final PacketReader<?>[] readersById;
|
||||
private final PacketWriter[] writersByClass;
|
||||
private final Class<?>[] classesById;
|
||||
|
||||
public DensePacketRegistryMap(Int2ObjectMap<PacketMapping<?>> mappings) {
|
||||
int size = mappings.keySet().stream().mapToInt(x -> x).max().orElse(0) + 1;
|
||||
|
||||
this.readersById = new PacketReader[size];
|
||||
this.writersByClass = new PacketWriter[size * 2];
|
||||
this.classesById = new Class[size * 2];
|
||||
|
||||
for (PacketMapping<?> value : mappings.values()) {
|
||||
this.readersById[value.id] = value.reader;
|
||||
this.place(value.packetClass, value.writer);
|
||||
}
|
||||
}
|
||||
|
||||
private void place(Class<?> key, PacketWriter<?> value) {
|
||||
int bucket = findEmpty(key);
|
||||
this.writersByClass[bucket] = value;
|
||||
this.classesById[bucket] = key;
|
||||
}
|
||||
|
||||
private int findEmpty(Class<?> key) {
|
||||
int start = key.hashCode() % this.classesById.length;
|
||||
int index = start;
|
||||
|
||||
for (;;) {
|
||||
if (this.classesById[index] == null || this.classesById[index].equals(key)) {
|
||||
// It's available, so no chance that this value exists anywhere in the map.
|
||||
return index;
|
||||
}
|
||||
|
||||
if ((index = (index + 1) % this.classesById.length) == start) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int index(Class<?> key) {
|
||||
int start = key.hashCode() % this.classesById.length;
|
||||
int index = start;
|
||||
|
||||
for (;;) {
|
||||
if (this.classesById[index] == null) {
|
||||
// It's available, so no chance that this value exists anywhere in the map.
|
||||
return -1;
|
||||
}
|
||||
if (key.equals(this.classesById[index])) {
|
||||
return index;
|
||||
}
|
||||
|
||||
// Conflict, keep probing ...
|
||||
if ((index = (index + 1) % this.classesById.length) == start) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Packet readPacket(int id, ByteBuf buf, ProtocolVersion version) {
|
||||
if (id < 0 || id >= this.readersById.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.readersById[id].read(buf, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P extends Packet> void writePacket(P packet, ByteBuf buf, ProtocolVersion version) {
|
||||
int id = this.index(packet.getClass());
|
||||
if (id != -1) {
|
||||
this.writersByClass[id].write(buf, packet, version);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find id for packet of type %s in protocol %s",
|
||||
packet.getClass().getName(), version
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.velocitypowered.proxy.network.registry.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.Packet;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class EmptyPacketRegistryMap implements PacketRegistryMap {
|
||||
|
||||
public static final EmptyPacketRegistryMap INSTANCE = new EmptyPacketRegistryMap();
|
||||
|
||||
private EmptyPacketRegistryMap() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Packet readPacket(int id, ByteBuf buf, ProtocolVersion version) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P extends Packet> void writePacket(P packet, ByteBuf buf, ProtocolVersion version) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find id for packet of type %s in protocol %s",
|
||||
packet.getClass().getName(), version
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.velocitypowered.proxy.network.registry.packet;
|
||||
|
||||
import com.velocitypowered.proxy.network.packet.Packet;
|
||||
import com.velocitypowered.proxy.network.packet.PacketReader;
|
||||
import com.velocitypowered.proxy.network.packet.PacketWriter;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class PacketRegistryBuilder {
|
||||
|
||||
private final Int2ObjectMap<PacketMapping<?>> mappings;
|
||||
private boolean dense = false;
|
||||
|
||||
public PacketRegistryBuilder() {
|
||||
this.mappings = new Int2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
||||
public PacketRegistryBuilder(
|
||||
Int2ObjectMap<PacketMapping<?>> mappings, boolean dense) {
|
||||
this.mappings = new Int2ObjectOpenHashMap<>(mappings);
|
||||
this.dense = dense;
|
||||
}
|
||||
|
||||
public <P extends Packet> PacketRegistryBuilder register(int id, Class<P> packetClass,
|
||||
PacketWriter<P> writer) {
|
||||
mappings.put(id, new PacketMapping(id, packetClass, writer, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
public <P extends Packet> PacketRegistryBuilder register(int id, Class<P> packetClass,
|
||||
PacketWriter<P> writer, PacketReader<P> reader) {
|
||||
mappings.put(id, new PacketMapping(id, packetClass, writer, reader));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PacketRegistryBuilder dense() {
|
||||
this.dense = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PacketRegistryBuilder copy() {
|
||||
return new PacketRegistryBuilder(this.mappings, this.dense);
|
||||
}
|
||||
|
||||
public PacketRegistryMap build() {
|
||||
if (this.dense) {
|
||||
return new DensePacketRegistryMap(mappings);
|
||||
} else {
|
||||
return new RegularPacketRegistryMap(mappings);
|
||||
}
|
||||
}
|
||||
|
||||
static final class PacketMapping<P extends Packet> {
|
||||
|
||||
int id;
|
||||
final Class<P> packetClass;
|
||||
final PacketWriter<P> writer;
|
||||
final @Nullable PacketReader<P> reader;
|
||||
|
||||
PacketMapping(int id, Class<P> packetClass,
|
||||
PacketWriter<P> writer,
|
||||
@Nullable PacketReader<P> reader) {
|
||||
this.id = id;
|
||||
this.packetClass = packetClass;
|
||||
this.writer = writer;
|
||||
this.reader = reader;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.velocitypowered.proxy.network.registry.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.Packet;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public interface PacketRegistryMap {
|
||||
@Nullable Packet readPacket(final int id, ByteBuf buf, ProtocolVersion version);
|
||||
|
||||
<P extends Packet> void writePacket(P packet, ByteBuf buf, ProtocolVersion version);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.velocitypowered.proxy.network.registry.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.Packet;
|
||||
import com.velocitypowered.proxy.network.packet.PacketReader;
|
||||
import com.velocitypowered.proxy.network.packet.PacketWriter;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryBuilder.PacketMapping;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* The canonical implementation of the packet registry map.
|
||||
*/
|
||||
public class RegularPacketRegistryMap implements PacketRegistryMap {
|
||||
|
||||
private final Int2ObjectMap<PacketReader<?>> readersById;
|
||||
private final Int2ObjectMap<PacketWriter<?>> writersById;
|
||||
private final Object2IntMap<Class<?>> classesById;
|
||||
|
||||
public RegularPacketRegistryMap(Int2ObjectMap<PacketMapping<?>> mappings) {
|
||||
int size = mappings.size();
|
||||
|
||||
this.readersById = new Int2ObjectOpenHashMap<>(size);
|
||||
this.writersById = new Int2ObjectOpenHashMap<>(size);
|
||||
this.classesById = new Object2IntOpenHashMap<>(size);
|
||||
this.classesById.defaultReturnValue(Integer.MIN_VALUE);
|
||||
|
||||
for (PacketMapping<?> value : mappings.values()) {
|
||||
if (value.reader != null) {
|
||||
this.readersById.put(value.id, value.reader);
|
||||
}
|
||||
|
||||
this.writersById.put(value.id, value.writer);
|
||||
this.classesById.put(value.packetClass, value.id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Packet readPacket(int id, ByteBuf buf, ProtocolVersion version) {
|
||||
PacketReader<?> reader = this.readersById.get(id);
|
||||
if (reader == null) {
|
||||
return null;
|
||||
}
|
||||
return reader.read(buf, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P extends Packet> void writePacket(P packet, ByteBuf buf, ProtocolVersion version) {
|
||||
int packetId = this.classesById.getInt(packet.getClass());
|
||||
if (packetId == Integer.MIN_VALUE) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find id for packet of type %s in protocol %s",
|
||||
packet.getClass().getName(), version
|
||||
));
|
||||
}
|
||||
|
||||
PacketWriter writer = this.writersById.get(packetId);
|
||||
assert writer != null;
|
||||
writer.write(buf, packet, version);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.velocitypowered.proxy.network.registry.protocol;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.PacketDirection;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryMap;
|
||||
|
||||
public interface ProtocolRegistry {
|
||||
PacketRegistryMap lookup(PacketDirection direction, ProtocolVersion version);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.velocitypowered.proxy.network.registry.protocol;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.PacketDirection;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryMap;
|
||||
|
||||
/**
|
||||
* A flat protocol registry that does not care about the protocol version.
|
||||
*/
|
||||
public class SimpleProtocolRegistry implements ProtocolRegistry {
|
||||
|
||||
private final PacketRegistryMap serverbound;
|
||||
private final PacketRegistryMap clientbound;
|
||||
|
||||
public SimpleProtocolRegistry(
|
||||
PacketRegistryMap serverbound,
|
||||
PacketRegistryMap clientbound) {
|
||||
this.serverbound = serverbound;
|
||||
this.clientbound = clientbound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketRegistryMap lookup(PacketDirection direction, ProtocolVersion version) {
|
||||
if (direction == PacketDirection.SERVERBOUND) {
|
||||
return this.serverbound;
|
||||
} else if (direction == PacketDirection.CLIENTBOUND) {
|
||||
return this.clientbound;
|
||||
} else {
|
||||
throw new NullPointerException("direction");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.velocitypowered.proxy.network.registry.protocol;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.PacketDirection;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A version-aware protocol registry.
|
||||
*/
|
||||
public class VersionSpecificProtocolRegistry implements ProtocolRegistry {
|
||||
|
||||
private final Map<ProtocolVersion, PacketRegistryMap> serverboundByVersion;
|
||||
private final Map<ProtocolVersion, PacketRegistryMap> clientboundByVersion;
|
||||
|
||||
public VersionSpecificProtocolRegistry() {
|
||||
this.serverboundByVersion = new EnumMap<>(ProtocolVersion.class);
|
||||
this.clientboundByVersion = new EnumMap<>(ProtocolVersion.class);
|
||||
}
|
||||
|
||||
public VersionSpecificProtocolRegistry register(ProtocolVersion min, ProtocolVersion max,
|
||||
PacketRegistryMap serverbound, PacketRegistryMap clientbound) {
|
||||
for (ProtocolVersion version : EnumSet.range(min, max)) {
|
||||
this.serverboundByVersion.put(version, serverbound);
|
||||
this.clientboundByVersion.put(version, clientbound);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketRegistryMap lookup(PacketDirection direction, ProtocolVersion version) {
|
||||
if (direction == PacketDirection.SERVERBOUND) {
|
||||
return this.serverboundByVersion.get(version);
|
||||
} else if (direction == PacketDirection.CLIENTBOUND) {
|
||||
return this.clientboundByVersion.get(version);
|
||||
} else {
|
||||
throw new NullPointerException("direction");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.velocitypowered.proxy.network.registry.state;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundStatusPingPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundStatusResponsePacket;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundHandshakePacket;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundStatusPingPacket;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundStatusRequestPacket;
|
||||
import com.velocitypowered.proxy.network.registry.packet.EmptyPacketRegistryMap;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryBuilder;
|
||||
import com.velocitypowered.proxy.network.registry.protocol.ProtocolRegistry;
|
||||
import com.velocitypowered.proxy.network.registry.protocol.SimpleProtocolRegistry;
|
||||
import com.velocitypowered.proxy.network.registry.protocol.VersionSpecificProtocolRegistry;
|
||||
|
||||
public class ProtocolStates {
|
||||
public static final ProtocolRegistry HANDSHAKE;
|
||||
public static final ProtocolRegistry STATUS;
|
||||
public static final ProtocolRegistry LOGIN;
|
||||
|
||||
static {
|
||||
HANDSHAKE = new SimpleProtocolRegistry(
|
||||
new PacketRegistryBuilder()
|
||||
.dense()
|
||||
.register(0x00, ServerboundHandshakePacket.class, ServerboundHandshakePacket.ENCODER,
|
||||
ServerboundHandshakePacket.DECODER)
|
||||
.build(),
|
||||
EmptyPacketRegistryMap.INSTANCE);
|
||||
|
||||
STATUS = new SimpleProtocolRegistry(
|
||||
new PacketRegistryBuilder()
|
||||
.dense()
|
||||
.register(0x00, ServerboundStatusRequestPacket.class,
|
||||
ServerboundStatusRequestPacket.ENCODER,
|
||||
ServerboundStatusRequestPacket.DECODER)
|
||||
.register(0x01, ServerboundStatusPingPacket.class,
|
||||
ServerboundStatusPingPacket.ENCODER,
|
||||
ServerboundStatusPingPacket.DECODER)
|
||||
.build(),
|
||||
new PacketRegistryBuilder()
|
||||
.dense()
|
||||
.register(0x00, ClientboundStatusResponsePacket.class,
|
||||
ClientboundStatusResponsePacket.ENCODER,
|
||||
ClientboundStatusResponsePacket.DECODER)
|
||||
.register(0x01, ClientboundStatusPingPacket.class,
|
||||
ClientboundStatusPingPacket.ENCODER,
|
||||
ClientboundStatusPingPacket.DECODER)
|
||||
.build());
|
||||
|
||||
LOGIN = new VersionSpecificProtocolRegistry()
|
||||
.register(ProtocolVersion.MINECRAFT_1_7_2, ProtocolVersion.MINECRAFT_1_8,
|
||||
Version172To176.SERVERBOUND_LOGIN, Version172To176.CLIENTBOUND_LOGIN);
|
||||
}
|
||||
|
||||
private ProtocolStates() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.velocitypowered.proxy.network.registry.state;
|
||||
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundDisconnectPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundEncryptionRequestPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundServerLoginSuccessPacket;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundEncryptionResponsePacket;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundServerLoginPacket;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundTabCompleteRequestPacket;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryBuilder;
|
||||
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryMap;
|
||||
|
||||
public class Version172To176 {
|
||||
private Version172To176() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static final PacketRegistryMap SERVERBOUND_LOGIN = new PacketRegistryBuilder()
|
||||
.dense()
|
||||
.register(0x00, ServerboundServerLoginPacket.class, ServerboundServerLoginPacket.ENCODER,
|
||||
ServerboundServerLoginPacket.DECODER)
|
||||
.register(0x01, ServerboundEncryptionResponsePacket.class,
|
||||
ServerboundEncryptionResponsePacket.ENCODER, ServerboundEncryptionResponsePacket.DECODER)
|
||||
.build();
|
||||
|
||||
public static final PacketRegistryMap CLIENTBOUND_LOGIN = new PacketRegistryBuilder()
|
||||
.dense()
|
||||
.register(0x00, ClientboundDisconnectPacket.class, ClientboundDisconnectPacket.ENCODER,
|
||||
ClientboundDisconnectPacket.DECODER)
|
||||
.register(0x01, ClientboundEncryptionRequestPacket.class,
|
||||
ClientboundEncryptionRequestPacket.ENCODER, ClientboundEncryptionRequestPacket.DECODER)
|
||||
.register(0x02, ClientboundServerLoginSuccessPacket.class,
|
||||
ClientboundServerLoginSuccessPacket.ENCODER, ClientboundServerLoginSuccessPacket.DECODER)
|
||||
.build();
|
||||
|
||||
public static final PacketRegistryMap SERVERBOUND_PLAY = new PacketRegistryBuilder()
|
||||
.register(0x14, ServerboundTabCompleteRequestPacket.class,
|
||||
ServerboundTabCompleteRequestPacket.ENCODER, ServerboundTabCompleteRequestPacket.DECODER)
|
||||
.build();
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.velocitypowered.proxy.network.registry.version;
|
||||
|
||||
public class GenericVersions {
|
||||
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren