Skip to content

Commit 8ba1dc1

Browse files
committed
Start 1.20.4 update
1 parent 80a0979 commit 8ba1dc1

22 files changed

+206
-99
lines changed

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ repositories {
3434

3535
dependencies {
3636
implementation 'net.bytebuddy:byte-buddy:1.14.9'
37-
compileOnly 'org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT'
38-
compileOnly 'org.spigotmc:spigot:1.20.2-R0.1-SNAPSHOT'
37+
compileOnly 'org.spigotmc:spigot-api:1.20.4-R0.1-SNAPSHOT'
38+
compileOnly 'org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT'
3939
compileOnly 'io.netty:netty-all:4.0.23.Final'
4040
compileOnly 'net.kyori:adventure-text-serializer-gson:4.13.0'
4141
compileOnly 'com.googlecode.json-simple:json-simple:1.1.1'
@@ -46,7 +46,7 @@ dependencies {
4646
testImplementation 'org.mockito:mockito-core:5.6.0'
4747
testImplementation 'io.netty:netty-common:4.1.97.Final'
4848
testImplementation 'io.netty:netty-transport:4.1.97.Final'
49-
testImplementation 'org.spigotmc:spigot:1.20.2-R0.1-SNAPSHOT'
49+
testImplementation 'org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT'
5050
testImplementation 'net.kyori:adventure-text-serializer-gson:4.13.0'
5151
testImplementation 'net.kyori:adventure-text-serializer-plain:4.13.1'
5252
}

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ public class ProtocolLibrary {
3737
/**
3838
* The maximum version ProtocolLib has been tested with.
3939
*/
40-
public static final String MAXIMUM_MINECRAFT_VERSION = "1.20.2";
40+
public static final String MAXIMUM_MINECRAFT_VERSION = "1.20.24";
4141

4242
/**
43-
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.20.2) was released.
43+
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.20.4) was released.
4444
*/
45-
public static final String MINECRAFT_LAST_RELEASE_DATE = "2023-09-21";
45+
public static final String MINECRAFT_LAST_RELEASE_DATE = "2023-12-07";
4646

4747
/**
4848
* Plugins that are currently incompatible with ProtocolLib.

src/main/java/com/comphenix/protocol/injector/StructureCache.java

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,37 @@ public static Object newNullDataSerializer() {
159159
return TRICKED_DATA_SERIALIZER_BASE.invoke(new ZeroBuffer());
160160
}
161161

162+
static void initTrickDataSerializer() {
163+
// create an empty instance of a nbt tag compound / text compound that we can re-use when needed
164+
Object textCompound = WrappedChatComponent.fromText("").getHandle();
165+
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
166+
// base builder which intercepts a few methods
167+
DynamicType.Builder<?> baseBuilder = ByteBuddyFactory.getInstance()
168+
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
169+
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerBase")
170+
.method(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())
171+
.and(ElementMatchers.returns(ElementMatchers.isSubTypeOf(MinecraftReflection.getNBTBaseClass()))))
172+
.intercept(FixedValue.value(compound))
173+
.method(ElementMatchers.returns(MinecraftReflection.getIChatBaseComponentClass()))
174+
.intercept(FixedValue.value(textCompound))
175+
.method(ElementMatchers.returns(PublicKey.class).and(ElementMatchers.takesNoArguments()))
176+
.intercept(FixedValue.nullValue());
177+
Class<?> serializerBase = baseBuilder.make()
178+
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
179+
.getLoaded();
180+
TRICKED_DATA_SERIALIZER_BASE = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
181+
182+
// extended builder which intercepts the read string method as well
183+
Class<?> withStringIntercept = baseBuilder
184+
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerJson")
185+
.method(ElementMatchers.returns(String.class).and(ElementMatchers.takesArguments(int.class)))
186+
.intercept(FixedValue.value("{}"))
187+
.make()
188+
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
189+
.getLoaded();
190+
TRICKED_DATA_SERIALIZER_JSON = Accessors.getConstructorAccessor(withStringIntercept, ByteBuf.class);
191+
}
192+
162193
/**
163194
* Creates a packet data serializer sub-class if needed to allow the fixed read of a NbtTagCompound because of a
164195
* null check in the MapChunk packet constructor.
@@ -174,43 +205,13 @@ public static boolean tryInitTrickDataSerializer() {
174205
}
175206

176207
try {
177-
// create an empty instance of a nbt tag compound / text compound that we can re-use when needed
178-
Object textCompound = WrappedChatComponent.fromText("").getHandle();
179-
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
180-
// base builder which intercepts a few methods
181-
DynamicType.Builder<?> baseBuilder = ByteBuddyFactory.getInstance()
182-
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
183-
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerBase")
184-
.method(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())
185-
.and(ElementMatchers.returns(ElementMatchers.isSubTypeOf(MinecraftReflection.getNBTBaseClass()))))
186-
.intercept(FixedValue.value(compound))
187-
.method(ElementMatchers.returns(MinecraftReflection.getIChatBaseComponentClass()))
188-
.intercept(FixedValue.value(textCompound))
189-
.method(ElementMatchers.returns(PublicKey.class).and(ElementMatchers.takesNoArguments()))
190-
.intercept(FixedValue.nullValue());
191-
Class<?> serializerBase = baseBuilder.make()
192-
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
193-
.getLoaded();
194-
TRICKED_DATA_SERIALIZER_BASE = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
195-
196-
// extended builder which intercepts the read string method as well
197-
Class<?> withStringIntercept = baseBuilder
198-
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerJson")
199-
.method(ElementMatchers.returns(String.class).and(ElementMatchers.takesArguments(int.class)))
200-
.intercept(FixedValue.value("{}"))
201-
.make()
202-
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
203-
.getLoaded();
204-
TRICKED_DATA_SERIALIZER_JSON = Accessors.getConstructorAccessor(withStringIntercept, ByteBuf.class);
205-
206-
// worked
208+
initTrickDataSerializer();
207209
return true;
208210
} catch (Exception ignored) {
209211
} finally {
210212
TRICK_TRIED = true;
211213
}
212214

213-
// didn't work
214215
return false;
215216
}
216217
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ public class PacketRegistry {
4141
// Whether or not the registry has been initialized
4242
private static volatile boolean INITIALIZED = false;
4343

44+
static void reset() {
45+
synchronized (registryLock) {
46+
INITIALIZED = false;
47+
}
48+
}
49+
4450
/**
4551
* Represents a register we are currently building.
4652
* @author Kristian
@@ -314,7 +320,7 @@ private static void associate(PacketType type, Class<?> clazz) {
314320
/**
315321
* Initializes the packet registry.
316322
*/
317-
private static void initialize() {
323+
static void initialize() {
318324
if (INITIALIZED) {
319325
return;
320326
}

src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,7 @@ public static Class<?> getMinecraftClass(String className) {
13901390
* @param aliases Potential aliases
13911391
* @return Optional that may contain the class
13921392
*/
1393-
private static Optional<Class<?>> getOptionalNMS(String className, String... aliases) {
1393+
public static Optional<Class<?>> getOptionalNMS(String className, String... aliases) {
13941394
if (minecraftPackage == null) {
13951395
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
13961396
}

src/main/java/com/comphenix/protocol/utility/MinecraftVersion.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
* @author Kristian
3737
*/
3838
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
39+
/**
40+
* Version 1.20.4 - the decorated pot update
41+
*/
42+
public static final MinecraftVersion v1_20_4 = new MinecraftVersion("1.20.4");
3943

4044
/**
4145
* Version 1.20.2 - the update that added the configuration protocol phase.
@@ -135,7 +139,7 @@ public final class MinecraftVersion implements Comparable<MinecraftVersion>, Ser
135139
/**
136140
* The latest release version of minecraft.
137141
*/
138-
public static final MinecraftVersion LATEST = CONFIG_PHASE_PROTOCOL_UPDATE;
142+
public static final MinecraftVersion LATEST = v1_20_4;
139143

140144
// used when serializing
141145
private static final long serialVersionUID = -8695133558996459770L;

src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.gson.JsonObject;
44
import java.io.StringReader;
5+
import java.util.Optional;
56

67
import org.bukkit.ChatColor;
78

@@ -10,7 +11,10 @@
1011
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
1112
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
1213
import com.comphenix.protocol.utility.MinecraftReflection;
14+
import com.comphenix.protocol.utility.MinecraftVersion;
15+
1316
import com.google.common.base.Preconditions;
17+
import net.minecraft.network.chat.IChatBaseComponent;
1418

1519
/**
1620
* Represents a chat component added in Minecraft 1.7.2
@@ -20,6 +24,8 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
2024
private static final Class<?> SERIALIZER = MinecraftReflection.getChatSerializerClass();
2125
private static final Class<?> COMPONENT = MinecraftReflection.getIChatBaseComponentClass();
2226
private static final Class<?> GSON_CLASS = MinecraftReflection.getMinecraftGsonClass();
27+
private static final Optional<Class<?>> MUTABLE_COMPONENT_CLASS
28+
= MinecraftReflection.getOptionalNMS("network.chat.IChatMutableComponent");
2329

2430
private static Object GSON = null;
2531
private static MethodAccessor DESERIALIZE = null;
@@ -38,13 +44,18 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
3844

3945
GSON = Accessors.getFieldAccessor(fuzzy.getFieldByType("gson", GSON_CLASS)).get(null);
4046

41-
try {
42-
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getChatDeserializer(), true)
43-
.getMethodByReturnTypeAndParameters("deserialize", Object.class, new Class<?>[] { GSON_CLASS, String.class, Class.class, boolean.class }));
44-
} catch (IllegalArgumentException ex) {
45-
// We'll handle it in the ComponentParser
46-
DESERIALIZE = null;
47-
}
47+
if (MinecraftVersion.v1_20_4.atOrAbove()) {
48+
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(SERIALIZER, false)
49+
.getMethodByReturnTypeAndParameters("fromJsonLenient", MUTABLE_COMPONENT_CLASS.get(), String.class));
50+
} else {
51+
try {
52+
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getChatDeserializer(), true)
53+
.getMethodByReturnTypeAndParameters("deserialize", Object.class, new Class<?>[] { GSON_CLASS, String.class, Class.class, boolean.class }));
54+
} catch (IllegalArgumentException ex) {
55+
// We'll handle it in the ComponentParser
56+
DESERIALIZE = null;
57+
}
58+
}
4859

4960
// Get a component from a standard Minecraft message
5061
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class, boolean.class);
@@ -58,6 +69,10 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
5869
}
5970

6071
private static Object deserialize(String json) {
72+
if (MinecraftVersion.v1_20_4.atOrAbove()) {
73+
return DESERIALIZE.invoke(null, json);
74+
}
75+
6176
// Should be non-null on 1.9 and up
6277
if (DESERIALIZE != null) {
6378
return DESERIALIZE.invoke(null, GSON, json, COMPONENT, true);

src/test/java/com/comphenix/protocol/BukkitInitialization.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.comphenix.protocol.reflect.accessors.Accessors;
88
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
99
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
10+
1011
import com.google.common.util.concurrent.MoreExecutors;
1112
import net.minecraft.SharedConstants;
1213
import net.minecraft.commands.CommandDispatcher;
@@ -28,16 +29,19 @@
2829
import net.minecraft.world.flag.FeatureFlags;
2930
import net.minecraft.world.item.enchantment.Enchantments;
3031
import org.apache.logging.log4j.LogManager;
31-
import org.bukkit.*;
32-
import org.bukkit.craftbukkit.v1_20_R2.CraftLootTable;
33-
import org.bukkit.craftbukkit.v1_20_R2.CraftRegistry;
34-
import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
35-
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
36-
import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemFactory;
37-
import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers;
38-
import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey;
39-
import org.bukkit.craftbukkit.v1_20_R2.util.Versioning;
40-
import org.bukkit.enchantments.Enchantment;
32+
import org.bukkit.Bukkit;
33+
import org.bukkit.Keyed;
34+
import org.bukkit.NamespacedKey;
35+
import org.bukkit.Server;
36+
import org.bukkit.World;
37+
import org.bukkit.craftbukkit.v1_20_R3.CraftLootTable;
38+
import org.bukkit.craftbukkit.v1_20_R3.CraftRegistry;
39+
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
40+
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
41+
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemFactory;
42+
import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers;
43+
import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
44+
import org.bukkit.craftbukkit.v1_20_R3.util.Versioning;
4145
import org.spigotmc.SpigotWorldConfig;
4246

4347
import static org.mockito.ArgumentMatchers.any;
@@ -102,12 +106,13 @@ private void initialize() {
102106
resourcePackRepository.c() /* getAvailablePacks() */ .stream().map(ResourcePackLoader::e /* openFull() */).collect(Collectors.toList()));
103107
LayeredRegistryAccess<RegistryLayer> layeredRegistryAccess = RegistryLayer.a(); // .createRegistryAccess()
104108
layeredRegistryAccess = WorldLoader.b(resourceManager, layeredRegistryAccess, RegistryLayer.b /* WORLDGEN */, RegistryDataLoader.a /* WORLDGEN_REGISTRIES */); // .loadAndReplaceLayer()
105-
IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().c(); // .compositeAccess().freeze()
109+
IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().d(); // .compositeAccess().freeze()
110+
// IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().c(); // .compositeAccess().freeze()
106111

107112
DataPackResources dataPackResources = DataPackResources.a(
108113
resourceManager,
109114
registryCustom,
110-
FeatureFlags.d.a() /* REGISTRY.allFlags() */,
115+
FeatureFlagSet.a() /* REGISTRY.allFlags() */,
111116
CommandDispatcher.ServerType.b /* DEDICATED */,
112117
0,
113118
MoreExecutors.directExecutor(),
@@ -166,7 +171,7 @@ private void initialize() {
166171

167172
// Init Enchantments
168173
Enchantments.A.getClass();
169-
Enchantment.stopAcceptingRegistrations();
174+
// Enchantment.stopAcceptingRegistrations();
170175

171176
initialized = true;
172177
}

src/test/java/com/comphenix/protocol/PacketTypeTest.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public static void beforeClass() {
4545
BukkitInitialization.initializeAll();
4646

4747
// I'm well aware this is jank, but it does in fact work correctly and give the desired result
48-
/*PacketType.onDynamicCreate = className -> {
48+
/* PacketType.onDynamicCreate = className -> {
4949
throw new RuntimeException("Dynamically generated packet " + className);
50-
};*/
50+
}; */
5151
}
5252

5353
@AfterAll
@@ -342,21 +342,22 @@ public void ensureTypesAreCorrect() throws Exception {
342342
}
343343
}
344344

345-
@Test
346-
public void testPacketCreation() {
347-
boolean fail = false;
348-
for (PacketType type : PacketType.values()) {
349-
if (type.isSupported()) {
350-
try {
351-
new PacketContainer(type);
352-
} catch (Exception ex) {
353-
ex.printStackTrace();
354-
fail = true;
355-
}
356-
}
357-
}
358-
assertFalse(fail, "Packet type(s) failed to instantiate");
359-
}
345+
@Test
346+
public void testPacketCreation() {
347+
List<PacketType> failed = new ArrayList<>();
348+
for (PacketType type : PacketType.values()) {
349+
if (!type.isSupported()) {
350+
continue;
351+
}
352+
353+
try {
354+
new PacketContainer(type);
355+
} catch (Exception ex) {
356+
failed.add(type);
357+
}
358+
}
359+
assertTrue(failed.isEmpty(), "Failed to create: " + failed);
360+
}
360361

361362
@Test
362363
public void testPacketBundleWriting() {
@@ -365,7 +366,7 @@ public void testPacketBundleWriting() {
365366
List<PacketContainer> bundle = new ArrayList<>();
366367

367368
PacketContainer chatMessage = new PacketContainer(PacketType.Play.Server.SYSTEM_CHAT);
368-
chatMessage.getStrings().write(0, WrappedChatComponent.fromText("Test").getJson());
369+
chatMessage.getChatComponents().write(0, WrappedChatComponent.fromText("Test"));
369370
chatMessage.getBooleans().write(0, false);
370371
bundle.add(chatMessage);
371372
bundlePacket.getPacketBundles().write(0, bundle);

0 commit comments

Comments
 (0)