Skip to content

Commit 1e73df8

Browse files
authored
Initial support for 1.21.5 (#3381)
1 parent 4314a55 commit 1e73df8

24 files changed

+771
-447
lines changed

build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plugins {
1212
group = "com.comphenix.protocol"
1313
description = "Provides access to the Minecraft protocol"
1414

15-
val mcVersion = "1.21.4"
15+
val mcVersion = "1.21.5"
1616
val isSnapshot = version.toString().endsWith("-SNAPSHOT")
1717
val buildNumber = System.getenv("BUILD_NUMBER") ?: ""
1818
val isJenkins = buildNumber.isNotEmpty()
@@ -51,7 +51,7 @@ dependencies {
5151
compileOnly("org.spigotmc:spigot-api:${mcVersion}-R0.1-SNAPSHOT")
5252
compileOnly("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT:remapped-mojang")
5353
compileOnly("io.netty:netty-all:4.0.23.Final")
54-
compileOnly("net.kyori:adventure-text-serializer-gson:4.14.0")
54+
compileOnly("net.kyori:adventure-text-serializer-gson:4.19.0")
5555
compileOnly("com.googlecode.json-simple:json-simple:1.1.1")
5656

5757
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")

src/main/java/com/comphenix/protocol/PacketType.java

+136-127
Large diffs are not rendered by default.

src/main/java/com/comphenix/protocol/ProtocolLibrary.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ public class ProtocolLibrary {
3535
/**
3636
* The maximum version ProtocolLib has been tested with.
3737
*/
38-
public static final String MAXIMUM_MINECRAFT_VERSION = "1.21.1";
38+
// TODO(fix): once all tests pass again change this to latest version
39+
public static final String MAXIMUM_MINECRAFT_VERSION = "1.21.4";
3940

4041
/**
41-
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.20.4) was released.
42+
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.21.4) was released.
4243
*/
43-
public static final String MINECRAFT_LAST_RELEASE_DATE = "2024-08-08";
44+
public static final String MINECRAFT_LAST_RELEASE_DATE = "2024-12-03";
4445

4546
private static Plugin plugin;
4647
private static ProtocolConfig config;

src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java

+13-211
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
import java.lang.reflect.Field;
2121
import java.lang.reflect.Modifier;
22-
import java.lang.reflect.ParameterizedType;
23-
import java.lang.reflect.Type;
2422
import java.util.ArrayList;
2523
import java.util.Collections;
2624
import java.util.HashMap;
@@ -31,18 +29,15 @@
3129
import java.util.Optional;
3230
import java.util.Set;
3331
import java.util.concurrent.ConcurrentHashMap;
34-
import java.util.function.Function;
3532

3633
import javax.annotation.Nullable;
3734

3835
import com.comphenix.protocol.PacketType;
3936
import com.comphenix.protocol.PacketType.Sender;
4037
import com.comphenix.protocol.ProtocolLogger;
38+
import com.comphenix.protocol.injector.packet.internal.ProtocolRegistry_1_20_5;
4139
import com.comphenix.protocol.reflect.FuzzyReflection;
4240
import com.comphenix.protocol.reflect.StructureModifier;
43-
import com.comphenix.protocol.reflect.accessors.Accessors;
44-
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
45-
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
4641
import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract;
4742
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
4843
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
@@ -70,7 +65,7 @@ static void reset() {
7065
*
7166
* @author Kristian
7267
*/
73-
private static class Register {
68+
public static class Register {
7469
// The main lookup table
7570
final Map<PacketType, Optional<Class<?>>> typeToClass = new ConcurrentHashMap<>();
7671

@@ -82,14 +77,18 @@ private static class Register {
8277
volatile Set<PacketType> clientPackets = new HashSet<>();
8378
final List<MapContainer> containers = new ArrayList<>();
8479

85-
public Register() {
80+
private Register() {
8681
}
8782

88-
public void registerPacket(PacketType type, Class<?> clazz, Sender sender) {
89-
typeToClass.put(type, Optional.of(clazz));
83+
public void registerPacket(PacketType type, Class<?> packetClass, Sender sender, WrappedStreamCodec codec) {
84+
typeToClass.put(type, Optional.of(packetClass));
85+
classToType.put(packetClass, type);
9086

91-
classToType.put(clazz, type);
92-
protocolClassToType.computeIfAbsent(type.getProtocol(), __ -> new ConcurrentHashMap<>()).put(clazz, type);
87+
if (codec != null) {
88+
classToCodec.put(packetClass, codec);
89+
}
90+
91+
protocolClassToType.computeIfAbsent(type.getProtocol(), __ -> new ConcurrentHashMap<>()).put(packetClass, type);
9392

9493
if (sender == Sender.CLIENT) {
9594
clientPackets.add(type);
@@ -293,206 +292,9 @@ private static synchronized Register createRegisterV1_15_0() {
293292
return result;
294293
}
295294

296-
@SuppressWarnings("unchecked")
297295
private static synchronized Register createRegisterV1_20_5() {
298-
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
299-
300-
// PacketType<?> to class map
301-
final Map<Object, Class<?>> packetTypeMap = new HashMap<>();
302-
303-
// List of all class containing PacketTypes
304-
String[] packetTypesClassNames = new String[] {
305-
"common.CommonPacketTypes",
306-
"configuration.ConfigurationPacketTypes",
307-
"cookie.CookiePacketTypes",
308-
"game.GamePacketTypes",
309-
"handshake.HandshakePacketTypes",
310-
"login.LoginPacketTypes",
311-
"ping.PingPacketTypes",
312-
"status.StatusPacketTypes"
313-
};
314-
315-
Class<?> packetTypeClass = MinecraftReflection.getMinecraftClass("network.protocol.PacketType");
316-
317-
for (String packetTypesClassName : packetTypesClassNames) {
318-
Class<?> packetTypesClass = MinecraftReflection
319-
.getOptionalNMS("network.protocol." + packetTypesClassName)
320-
.orElse(null);
321-
if (packetTypesClass == null) {
322-
ProtocolLogger.debug("Can't find PacketType class: {0}, will skip it", packetTypesClassName);
323-
continue;
324-
}
325-
326-
// check every field for "static final PacketType<?>"
327-
for (Field field : packetTypesClass.getDeclaredFields()) {
328-
try {
329-
if (!Modifier.isFinal(field.getModifiers()) || !Modifier.isStatic(field.getModifiers())) {
330-
continue;
331-
}
332-
333-
Object packetType = field.get(null);
334-
if (!packetTypeClass.isInstance(packetType)) {
335-
continue;
336-
}
337-
338-
// retrieve the generic type T of the PacketType<T> field
339-
Type packet = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
340-
if (packet instanceof Class<?>) {
341-
packetTypeMap.put(packetType, (Class<?>) packet);
342-
}
343-
} catch (Exception e) {
344-
e.printStackTrace();
345-
continue;
346-
}
347-
}
348-
}
349-
350-
// ID to Packet class maps
351-
final Map<Object, Map<Class<?>, Integer>> serverMaps = new LinkedHashMap<>();
352-
final Map<Object, Map<Class<?>, Integer>> clientMaps = new LinkedHashMap<>();
353-
354-
// global registry instance
355296
final Register result = new Register();
356-
357-
// List of all class containing ProtocolInfos
358-
String[] protocolClassNames = new String[] {
359-
"configuration.ConfigurationProtocols",
360-
"game.GameProtocols",
361-
"handshake.HandshakeProtocols",
362-
"login.LoginProtocols",
363-
"status.StatusProtocols"
364-
};
365-
366-
Class<?> protocolInfoClass = MinecraftReflection.getProtocolInfoClass();
367-
Class<?> protocolInfoUnboundClass = MinecraftReflection.getProtocolInfoUnboundClass();
368-
Class<?> streamCodecClass = MinecraftReflection.getStreamCodecClass();
369-
Class<?> idCodecClass = MinecraftReflection.getMinecraftClass("network.codec.IdDispatchCodec");
370-
Class<?> idCodecEntryClass = MinecraftReflection.getMinecraftClass("network.codec.IdDispatchCodec$Entry", "network.codec.IdDispatchCodec$b");
371-
Class<?> protocolDirectionClass = MinecraftReflection.getPacketFlowClass();
372-
373-
Function<?, ?> emptyFunction = input -> input;
374-
375-
FuzzyReflection protocolInfoReflection = FuzzyReflection.fromClass(protocolInfoClass);
376-
377-
MethodAccessor protocolAccessor = Accessors.getMethodAccessor(protocolInfoReflection
378-
.getMethodByReturnTypeAndParameters("id", MinecraftReflection.getEnumProtocolClass(), new Class[0]));
379-
380-
MethodAccessor directionAccessor = Accessors.getMethodAccessor(protocolInfoReflection
381-
.getMethodByReturnTypeAndParameters("flow", protocolDirectionClass, new Class[0]));
382-
383-
MethodAccessor codecAccessor = Accessors.getMethodAccessor(
384-
protocolInfoReflection.getMethodByReturnTypeAndParameters("codec", streamCodecClass, new Class[0]));
385-
386-
MethodAccessor bindAccessor = Accessors.getMethodAccessor(FuzzyReflection.fromClass(protocolInfoUnboundClass)
387-
.getMethodByReturnTypeAndParameters("bind", protocolInfoClass, new Class[] { Function.class }));
388-
389-
FuzzyReflection idCodecReflection = FuzzyReflection.fromClass(idCodecClass, true);
390-
391-
FieldAccessor byIdAccessor = Accessors.getFieldAccessor(idCodecReflection
392-
.getField(FuzzyFieldContract.newBuilder().typeDerivedOf(List.class).build()));
393-
394-
FieldAccessor toIdAccessor = Accessors.getFieldAccessor(idCodecReflection
395-
.getField(FuzzyFieldContract.newBuilder().typeDerivedOf(Map.class).build()));
396-
397-
FuzzyReflection idCodecEntryReflection = FuzzyReflection.fromClass(idCodecEntryClass, true);
398-
399-
MethodAccessor idCodecEntryTypeAccessor = Accessors.getMethodAccessor(idCodecEntryReflection
400-
.getMethodByReturnTypeAndParameters("type", Object.class, new Class[0]));
401-
402-
MethodAccessor idCodecEntrySerializerAccessor = Accessors.getMethodAccessor(idCodecEntryReflection
403-
.getMethodByReturnTypeAndParameters("serializer", streamCodecClass, new Class[0]));
404-
405-
for (String protocolClassName : protocolClassNames) {
406-
Class<?> protocolClass = MinecraftReflection
407-
.getOptionalNMS("network.protocol." + protocolClassName)
408-
.orElse(null);
409-
if (protocolClass == null) {
410-
ProtocolLogger.debug("Can't find protocol class: {0}, will skip it", protocolClassName);
411-
continue;
412-
}
413-
414-
for (Field field : protocolClass.getDeclaredFields()) {
415-
try {
416-
// ignore none static and final fields
417-
if (!Modifier.isFinal(field.getModifiers()) || !Modifier.isStatic(field.getModifiers())) {
418-
continue;
419-
}
420-
421-
Object protocolInfo = field.get(null);
422-
423-
// bind unbound ProtocolInfo to empty function to get real ProtocolInfo
424-
if (protocolInfoUnboundClass.isInstance(protocolInfo)) {
425-
protocolInfo = bindAccessor.invoke(protocolInfo, new Object[] { emptyFunction });
426-
}
427-
428-
// ignore any field that isn't a ProtocolInfo
429-
if (!protocolInfoClass.isInstance(protocolInfo)) {
430-
continue;
431-
}
432-
433-
// get codec and check if codec is instance of IdDispatchCodec
434-
// since that is the only support codec as of now
435-
Object codec = codecAccessor.invoke(protocolInfo);
436-
if (!idCodecClass.isInstance(codec)) {
437-
continue;
438-
}
439-
440-
// retrieve packetTypeMap and convert it to packetIdMap
441-
Map<Class<?>, Integer> packetMap = new HashMap<>();
442-
List<Object> serializerList = (List<Object>) byIdAccessor.get(codec);
443-
Map<Object, Integer> packetTypeIdMap = (Map<Object, Integer>) toIdAccessor.get(codec);
444-
445-
for (Map.Entry<Object, Integer> entry : packetTypeIdMap.entrySet()) {
446-
Class<?> packetClass = packetTypeMap.get(entry.getKey());
447-
if (packetClass == null) {
448-
throw new RuntimeException("packetType missing packet " + entry.getKey());
449-
}
450-
451-
packetMap.put(packetClass, entry.getValue());
452-
}
453-
454-
// retrieve packet codecs for packet construction and write methods
455-
for (Object entry : serializerList) {
456-
Object packetType = idCodecEntryTypeAccessor.invoke(entry);
457-
458-
Class<?> packetClass = packetTypeMap.get(packetType);
459-
if (packetClass == null) {
460-
throw new RuntimeException("packetType missing packet " + packetType);
461-
}
462-
463-
Object serializer = idCodecEntrySerializerAccessor.invoke(entry);
464-
result.classToCodec.put(packetClass, new WrappedStreamCodec(serializer));
465-
}
466-
467-
// get EnumProtocol and Direction of protocol info
468-
Object protocol = protocolAccessor.invoke(protocolInfo);
469-
String direction = directionAccessor.invoke(protocolInfo).toString();
470-
471-
if (direction.contains("CLIENTBOUND")) { // Sent by Server
472-
serverMaps.put(protocol, packetMap);
473-
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
474-
clientMaps.put(protocol, packetMap);
475-
}
476-
} catch (Exception e) {
477-
e.printStackTrace();
478-
continue;
479-
}
480-
}
481-
}
482-
483-
for (Object protocol : protocols) {
484-
Enum<?> enumProtocol = (Enum<?>) protocol;
485-
PacketType.Protocol equivalent = PacketType.Protocol.fromVanilla(enumProtocol);
486-
487-
// Associate known types
488-
if (serverMaps.containsKey(protocol)) {
489-
associatePackets(result, reverse(serverMaps.get(protocol)), equivalent, Sender.SERVER);
490-
}
491-
if (clientMaps.containsKey(protocol)) {
492-
associatePackets(result, reverse(clientMaps.get(protocol)), equivalent, Sender.CLIENT);
493-
}
494-
}
495-
297+
ProtocolRegistry_1_20_5.fillRegister(result);
496298
return result;
497299
}
498300

@@ -517,7 +319,7 @@ protected static void associatePackets(Register register, Map<Integer, Class<?>>
517319
PacketType type = PacketType.fromCurrent(protocol, sender, packetId, packetClass);
518320

519321
try {
520-
register.registerPacket(type, packetClass, sender);
322+
register.registerPacket(type, packetClass, sender, null);
521323
} catch (Exception ex) {
522324
ProtocolLogger.debug("Encountered an exception associating packet " + type, ex);
523325
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.comphenix.protocol.injector.packet.internal;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
import com.comphenix.protocol.reflect.FuzzyReflection;
7+
import com.comphenix.protocol.reflect.accessors.Accessors;
8+
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
9+
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
10+
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
11+
import com.comphenix.protocol.utility.MinecraftReflection;
12+
import com.comphenix.protocol.wrappers.AbstractWrapper;
13+
import com.comphenix.protocol.wrappers.WrappedStreamCodec;
14+
15+
/**
16+
* Class only works for version 1.20.5+
17+
*/
18+
public class IdCodecWrapper extends AbstractWrapper {
19+
20+
private static final Class<?> ID_CODEC_CLASS;
21+
private static final FieldAccessor BY_ID_ACCESSOR;
22+
23+
private static final Class<?> ID_CODEC_ENTRY_CLASS;
24+
private static final MethodAccessor ENTRY_TYPE_ACCESSOR;
25+
private static final MethodAccessor ENTRY_SERIALIZER_ACCESSOR;
26+
27+
static {
28+
ID_CODEC_CLASS = MinecraftReflection.getMinecraftClass("network.codec.IdDispatchCodec");
29+
BY_ID_ACCESSOR = Accessors.getFieldAccessor(FuzzyReflection.fromClass(ID_CODEC_CLASS, true)
30+
.getField(FuzzyFieldContract.newBuilder().typeDerivedOf(List.class).build()));
31+
32+
ID_CODEC_ENTRY_CLASS = Arrays.stream(ID_CODEC_CLASS.getNestMembers())
33+
.filter(Class::isRecord)
34+
.findFirst()
35+
.orElseThrow(() -> new RuntimeException("Failed to find entry class for: " + ID_CODEC_CLASS));
36+
37+
FuzzyReflection entryReflection = FuzzyReflection.fromClass(ID_CODEC_ENTRY_CLASS, true);
38+
ENTRY_TYPE_ACCESSOR = Accessors.getMethodAccessor(entryReflection
39+
.getMethodByReturnTypeAndParameters("type", Object.class, new Class[0]));
40+
ENTRY_SERIALIZER_ACCESSOR = Accessors.getMethodAccessor(entryReflection
41+
.getMethodByReturnTypeAndParameters("serializer", MinecraftReflection.getStreamCodecClass(), new Class[0]));
42+
}
43+
44+
public IdCodecWrapper(Object handle) {
45+
super(ID_CODEC_CLASS);
46+
setHandle(handle);
47+
}
48+
49+
public List<Entry> getById() {
50+
// list represents a packet-id to {type, codec} lookup
51+
List<?> byId = (List<?>) BY_ID_ACCESSOR.get(this.handle);
52+
return byId.stream().map(Entry::new).toList();
53+
}
54+
55+
public class Entry extends AbstractWrapper {
56+
57+
public Entry(Object handle) {
58+
super(ID_CODEC_ENTRY_CLASS);
59+
setHandle(handle);
60+
}
61+
62+
public Object type() {
63+
return ENTRY_TYPE_ACCESSOR.invoke(this.handle);
64+
}
65+
66+
public WrappedStreamCodec serializer() {
67+
Object serializer = ENTRY_SERIALIZER_ACCESSOR.invoke(this.handle);
68+
return new WrappedStreamCodec(serializer);
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)