mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-27 05:05:24 +01:00
Start 1.20.4 update
This commit is contained in:
parent
80a097953f
commit
8ba1dc1284
@ -34,8 +34,8 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'net.bytebuddy:byte-buddy:1.14.9'
|
implementation 'net.bytebuddy:byte-buddy:1.14.9'
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.20.4-R0.1-SNAPSHOT'
|
||||||
compileOnly 'org.spigotmc:spigot:1.20.2-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT'
|
||||||
compileOnly 'io.netty:netty-all:4.0.23.Final'
|
compileOnly 'io.netty:netty-all:4.0.23.Final'
|
||||||
compileOnly 'net.kyori:adventure-text-serializer-gson:4.13.0'
|
compileOnly 'net.kyori:adventure-text-serializer-gson:4.13.0'
|
||||||
compileOnly 'com.googlecode.json-simple:json-simple:1.1.1'
|
compileOnly 'com.googlecode.json-simple:json-simple:1.1.1'
|
||||||
@ -46,7 +46,7 @@ dependencies {
|
|||||||
testImplementation 'org.mockito:mockito-core:5.6.0'
|
testImplementation 'org.mockito:mockito-core:5.6.0'
|
||||||
testImplementation 'io.netty:netty-common:4.1.97.Final'
|
testImplementation 'io.netty:netty-common:4.1.97.Final'
|
||||||
testImplementation 'io.netty:netty-transport:4.1.97.Final'
|
testImplementation 'io.netty:netty-transport:4.1.97.Final'
|
||||||
testImplementation 'org.spigotmc:spigot:1.20.2-R0.1-SNAPSHOT'
|
testImplementation 'org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT'
|
||||||
testImplementation 'net.kyori:adventure-text-serializer-gson:4.13.0'
|
testImplementation 'net.kyori:adventure-text-serializer-gson:4.13.0'
|
||||||
testImplementation 'net.kyori:adventure-text-serializer-plain:4.13.1'
|
testImplementation 'net.kyori:adventure-text-serializer-plain:4.13.1'
|
||||||
}
|
}
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
@ -37,12 +37,12 @@ public class ProtocolLibrary {
|
|||||||
/**
|
/**
|
||||||
* The maximum version ProtocolLib has been tested with.
|
* The maximum version ProtocolLib has been tested with.
|
||||||
*/
|
*/
|
||||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.20.2";
|
public static final String MAXIMUM_MINECRAFT_VERSION = "1.20.24";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.20.2) was released.
|
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.20.4) was released.
|
||||||
*/
|
*/
|
||||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2023-09-21";
|
public static final String MINECRAFT_LAST_RELEASE_DATE = "2023-12-07";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugins that are currently incompatible with ProtocolLib.
|
* Plugins that are currently incompatible with ProtocolLib.
|
||||||
|
@ -159,6 +159,37 @@ public class StructureCache {
|
|||||||
return TRICKED_DATA_SERIALIZER_BASE.invoke(new ZeroBuffer());
|
return TRICKED_DATA_SERIALIZER_BASE.invoke(new ZeroBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initTrickDataSerializer() {
|
||||||
|
// create an empty instance of a nbt tag compound / text compound that we can re-use when needed
|
||||||
|
Object textCompound = WrappedChatComponent.fromText("").getHandle();
|
||||||
|
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
|
||||||
|
// base builder which intercepts a few methods
|
||||||
|
DynamicType.Builder<?> baseBuilder = ByteBuddyFactory.getInstance()
|
||||||
|
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
|
||||||
|
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerBase")
|
||||||
|
.method(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())
|
||||||
|
.and(ElementMatchers.returns(ElementMatchers.isSubTypeOf(MinecraftReflection.getNBTBaseClass()))))
|
||||||
|
.intercept(FixedValue.value(compound))
|
||||||
|
.method(ElementMatchers.returns(MinecraftReflection.getIChatBaseComponentClass()))
|
||||||
|
.intercept(FixedValue.value(textCompound))
|
||||||
|
.method(ElementMatchers.returns(PublicKey.class).and(ElementMatchers.takesNoArguments()))
|
||||||
|
.intercept(FixedValue.nullValue());
|
||||||
|
Class<?> serializerBase = baseBuilder.make()
|
||||||
|
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
||||||
|
.getLoaded();
|
||||||
|
TRICKED_DATA_SERIALIZER_BASE = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
|
||||||
|
|
||||||
|
// extended builder which intercepts the read string method as well
|
||||||
|
Class<?> withStringIntercept = baseBuilder
|
||||||
|
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerJson")
|
||||||
|
.method(ElementMatchers.returns(String.class).and(ElementMatchers.takesArguments(int.class)))
|
||||||
|
.intercept(FixedValue.value("{}"))
|
||||||
|
.make()
|
||||||
|
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
||||||
|
.getLoaded();
|
||||||
|
TRICKED_DATA_SERIALIZER_JSON = Accessors.getConstructorAccessor(withStringIntercept, ByteBuf.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a packet data serializer sub-class if needed to allow the fixed read of a NbtTagCompound because of a
|
* Creates a packet data serializer sub-class if needed to allow the fixed read of a NbtTagCompound because of a
|
||||||
* null check in the MapChunk packet constructor.
|
* null check in the MapChunk packet constructor.
|
||||||
@ -174,43 +205,13 @@ public class StructureCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// create an empty instance of a nbt tag compound / text compound that we can re-use when needed
|
initTrickDataSerializer();
|
||||||
Object textCompound = WrappedChatComponent.fromText("").getHandle();
|
|
||||||
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
|
|
||||||
// base builder which intercepts a few methods
|
|
||||||
DynamicType.Builder<?> baseBuilder = ByteBuddyFactory.getInstance()
|
|
||||||
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
|
|
||||||
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerBase")
|
|
||||||
.method(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())
|
|
||||||
.and(ElementMatchers.returns(ElementMatchers.isSubTypeOf(MinecraftReflection.getNBTBaseClass()))))
|
|
||||||
.intercept(FixedValue.value(compound))
|
|
||||||
.method(ElementMatchers.returns(MinecraftReflection.getIChatBaseComponentClass()))
|
|
||||||
.intercept(FixedValue.value(textCompound))
|
|
||||||
.method(ElementMatchers.returns(PublicKey.class).and(ElementMatchers.takesNoArguments()))
|
|
||||||
.intercept(FixedValue.nullValue());
|
|
||||||
Class<?> serializerBase = baseBuilder.make()
|
|
||||||
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
|
||||||
.getLoaded();
|
|
||||||
TRICKED_DATA_SERIALIZER_BASE = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
|
|
||||||
|
|
||||||
// extended builder which intercepts the read string method as well
|
|
||||||
Class<?> withStringIntercept = baseBuilder
|
|
||||||
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerJson")
|
|
||||||
.method(ElementMatchers.returns(String.class).and(ElementMatchers.takesArguments(int.class)))
|
|
||||||
.intercept(FixedValue.value("{}"))
|
|
||||||
.make()
|
|
||||||
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
|
||||||
.getLoaded();
|
|
||||||
TRICKED_DATA_SERIALIZER_JSON = Accessors.getConstructorAccessor(withStringIntercept, ByteBuf.class);
|
|
||||||
|
|
||||||
// worked
|
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
} finally {
|
} finally {
|
||||||
TRICK_TRIED = true;
|
TRICK_TRIED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// didn't work
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,12 @@ public class PacketRegistry {
|
|||||||
// Whether or not the registry has been initialized
|
// Whether or not the registry has been initialized
|
||||||
private static volatile boolean INITIALIZED = false;
|
private static volatile boolean INITIALIZED = false;
|
||||||
|
|
||||||
|
static void reset() {
|
||||||
|
synchronized (registryLock) {
|
||||||
|
INITIALIZED = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a register we are currently building.
|
* Represents a register we are currently building.
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
@ -314,7 +320,7 @@ public class PacketRegistry {
|
|||||||
/**
|
/**
|
||||||
* Initializes the packet registry.
|
* Initializes the packet registry.
|
||||||
*/
|
*/
|
||||||
private static void initialize() {
|
static void initialize() {
|
||||||
if (INITIALIZED) {
|
if (INITIALIZED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1390,7 +1390,7 @@ public final class MinecraftReflection {
|
|||||||
* @param aliases Potential aliases
|
* @param aliases Potential aliases
|
||||||
* @return Optional that may contain the class
|
* @return Optional that may contain the class
|
||||||
*/
|
*/
|
||||||
private static Optional<Class<?>> getOptionalNMS(String className, String... aliases) {
|
public static Optional<Class<?>> getOptionalNMS(String className, String... aliases) {
|
||||||
if (minecraftPackage == null) {
|
if (minecraftPackage == null) {
|
||||||
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
|
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,10 @@ import org.bukkit.Server;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
|
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
|
||||||
|
/**
|
||||||
|
* Version 1.20.4 - the decorated pot update
|
||||||
|
*/
|
||||||
|
public static final MinecraftVersion v1_20_4 = new MinecraftVersion("1.20.4");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version 1.20.2 - the update that added the configuration protocol phase.
|
* Version 1.20.2 - the update that added the configuration protocol phase.
|
||||||
@ -135,7 +139,7 @@ public final class MinecraftVersion implements Comparable<MinecraftVersion>, Ser
|
|||||||
/**
|
/**
|
||||||
* The latest release version of minecraft.
|
* The latest release version of minecraft.
|
||||||
*/
|
*/
|
||||||
public static final MinecraftVersion LATEST = CONFIG_PHASE_PROTOCOL_UPDATE;
|
public static final MinecraftVersion LATEST = v1_20_4;
|
||||||
|
|
||||||
// used when serializing
|
// used when serializing
|
||||||
private static final long serialVersionUID = -8695133558996459770L;
|
private static final long serialVersionUID = -8695133558996459770L;
|
||||||
|
@ -2,6 +2,7 @@ package com.comphenix.protocol.wrappers;
|
|||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
@ -10,7 +11,10 @@ import com.comphenix.protocol.reflect.accessors.Accessors;
|
|||||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import net.minecraft.network.chat.IChatBaseComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a chat component added in Minecraft 1.7.2
|
* Represents a chat component added in Minecraft 1.7.2
|
||||||
@ -20,6 +24,8 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
|||||||
private static final Class<?> SERIALIZER = MinecraftReflection.getChatSerializerClass();
|
private static final Class<?> SERIALIZER = MinecraftReflection.getChatSerializerClass();
|
||||||
private static final Class<?> COMPONENT = MinecraftReflection.getIChatBaseComponentClass();
|
private static final Class<?> COMPONENT = MinecraftReflection.getIChatBaseComponentClass();
|
||||||
private static final Class<?> GSON_CLASS = MinecraftReflection.getMinecraftGsonClass();
|
private static final Class<?> GSON_CLASS = MinecraftReflection.getMinecraftGsonClass();
|
||||||
|
private static final Optional<Class<?>> MUTABLE_COMPONENT_CLASS
|
||||||
|
= MinecraftReflection.getOptionalNMS("network.chat.IChatMutableComponent");
|
||||||
|
|
||||||
private static Object GSON = null;
|
private static Object GSON = null;
|
||||||
private static MethodAccessor DESERIALIZE = null;
|
private static MethodAccessor DESERIALIZE = null;
|
||||||
@ -38,13 +44,18 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
|||||||
|
|
||||||
GSON = Accessors.getFieldAccessor(fuzzy.getFieldByType("gson", GSON_CLASS)).get(null);
|
GSON = Accessors.getFieldAccessor(fuzzy.getFieldByType("gson", GSON_CLASS)).get(null);
|
||||||
|
|
||||||
try {
|
if (MinecraftVersion.v1_20_4.atOrAbove()) {
|
||||||
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getChatDeserializer(), true)
|
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(SERIALIZER, false)
|
||||||
.getMethodByReturnTypeAndParameters("deserialize", Object.class, new Class<?>[] { GSON_CLASS, String.class, Class.class, boolean.class }));
|
.getMethodByReturnTypeAndParameters("fromJsonLenient", MUTABLE_COMPONENT_CLASS.get(), String.class));
|
||||||
} catch (IllegalArgumentException ex) {
|
} else {
|
||||||
// We'll handle it in the ComponentParser
|
try {
|
||||||
DESERIALIZE = null;
|
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getChatDeserializer(), true)
|
||||||
}
|
.getMethodByReturnTypeAndParameters("deserialize", Object.class, new Class<?>[] { GSON_CLASS, String.class, Class.class, boolean.class }));
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// We'll handle it in the ComponentParser
|
||||||
|
DESERIALIZE = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get a component from a standard Minecraft message
|
// Get a component from a standard Minecraft message
|
||||||
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class, boolean.class);
|
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class, boolean.class);
|
||||||
@ -58,6 +69,10 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Object deserialize(String json) {
|
private static Object deserialize(String json) {
|
||||||
|
if (MinecraftVersion.v1_20_4.atOrAbove()) {
|
||||||
|
return DESERIALIZE.invoke(null, json);
|
||||||
|
}
|
||||||
|
|
||||||
// Should be non-null on 1.9 and up
|
// Should be non-null on 1.9 and up
|
||||||
if (DESERIALIZE != null) {
|
if (DESERIALIZE != null) {
|
||||||
return DESERIALIZE.invoke(null, GSON, json, COMPONENT, true);
|
return DESERIALIZE.invoke(null, GSON, json, COMPONENT, true);
|
||||||
|
@ -7,6 +7,7 @@ import java.util.stream.Collectors;
|
|||||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
|
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import net.minecraft.SharedConstants;
|
import net.minecraft.SharedConstants;
|
||||||
import net.minecraft.commands.CommandDispatcher;
|
import net.minecraft.commands.CommandDispatcher;
|
||||||
@ -28,16 +29,19 @@ import net.minecraft.world.flag.FeatureFlagSet;
|
|||||||
import net.minecraft.world.flag.FeatureFlags;
|
import net.minecraft.world.flag.FeatureFlags;
|
||||||
import net.minecraft.world.item.enchantment.Enchantments;
|
import net.minecraft.world.item.enchantment.Enchantments;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.bukkit.*;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftLootTable;
|
import org.bukkit.Keyed;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftRegistry;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemFactory;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftLootTable;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftRegistry;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.util.Versioning;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemFactory;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R3.util.Versioning;
|
||||||
import org.spigotmc.SpigotWorldConfig;
|
import org.spigotmc.SpigotWorldConfig;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@ -102,12 +106,13 @@ public class BukkitInitialization {
|
|||||||
resourcePackRepository.c() /* getAvailablePacks() */ .stream().map(ResourcePackLoader::e /* openFull() */).collect(Collectors.toList()));
|
resourcePackRepository.c() /* getAvailablePacks() */ .stream().map(ResourcePackLoader::e /* openFull() */).collect(Collectors.toList()));
|
||||||
LayeredRegistryAccess<RegistryLayer> layeredRegistryAccess = RegistryLayer.a(); // .createRegistryAccess()
|
LayeredRegistryAccess<RegistryLayer> layeredRegistryAccess = RegistryLayer.a(); // .createRegistryAccess()
|
||||||
layeredRegistryAccess = WorldLoader.b(resourceManager, layeredRegistryAccess, RegistryLayer.b /* WORLDGEN */, RegistryDataLoader.a /* WORLDGEN_REGISTRIES */); // .loadAndReplaceLayer()
|
layeredRegistryAccess = WorldLoader.b(resourceManager, layeredRegistryAccess, RegistryLayer.b /* WORLDGEN */, RegistryDataLoader.a /* WORLDGEN_REGISTRIES */); // .loadAndReplaceLayer()
|
||||||
IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().c(); // .compositeAccess().freeze()
|
IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().d(); // .compositeAccess().freeze()
|
||||||
|
// IRegistryCustom.Dimension registryCustom = layeredRegistryAccess.a().c(); // .compositeAccess().freeze()
|
||||||
|
|
||||||
DataPackResources dataPackResources = DataPackResources.a(
|
DataPackResources dataPackResources = DataPackResources.a(
|
||||||
resourceManager,
|
resourceManager,
|
||||||
registryCustom,
|
registryCustom,
|
||||||
FeatureFlags.d.a() /* REGISTRY.allFlags() */,
|
FeatureFlagSet.a() /* REGISTRY.allFlags() */,
|
||||||
CommandDispatcher.ServerType.b /* DEDICATED */,
|
CommandDispatcher.ServerType.b /* DEDICATED */,
|
||||||
0,
|
0,
|
||||||
MoreExecutors.directExecutor(),
|
MoreExecutors.directExecutor(),
|
||||||
@ -166,7 +171,7 @@ public class BukkitInitialization {
|
|||||||
|
|
||||||
// Init Enchantments
|
// Init Enchantments
|
||||||
Enchantments.A.getClass();
|
Enchantments.A.getClass();
|
||||||
Enchantment.stopAcceptingRegistrations();
|
// Enchantment.stopAcceptingRegistrations();
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
@ -45,9 +45,9 @@ public class PacketTypeTest {
|
|||||||
BukkitInitialization.initializeAll();
|
BukkitInitialization.initializeAll();
|
||||||
|
|
||||||
// I'm well aware this is jank, but it does in fact work correctly and give the desired result
|
// I'm well aware this is jank, but it does in fact work correctly and give the desired result
|
||||||
/*PacketType.onDynamicCreate = className -> {
|
/* PacketType.onDynamicCreate = className -> {
|
||||||
throw new RuntimeException("Dynamically generated packet " + className);
|
throw new RuntimeException("Dynamically generated packet " + className);
|
||||||
};*/
|
}; */
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
@ -342,21 +342,22 @@ public class PacketTypeTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPacketCreation() {
|
public void testPacketCreation() {
|
||||||
boolean fail = false;
|
List<PacketType> failed = new ArrayList<>();
|
||||||
for (PacketType type : PacketType.values()) {
|
for (PacketType type : PacketType.values()) {
|
||||||
if (type.isSupported()) {
|
if (!type.isSupported()) {
|
||||||
try {
|
continue;
|
||||||
new PacketContainer(type);
|
}
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
try {
|
||||||
fail = true;
|
new PacketContainer(type);
|
||||||
}
|
} catch (Exception ex) {
|
||||||
}
|
failed.add(type);
|
||||||
}
|
}
|
||||||
assertFalse(fail, "Packet type(s) failed to instantiate");
|
}
|
||||||
}
|
assertTrue(failed.isEmpty(), "Failed to create: " + failed);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPacketBundleWriting() {
|
public void testPacketBundleWriting() {
|
||||||
@ -365,7 +366,7 @@ public class PacketTypeTest {
|
|||||||
List<PacketContainer> bundle = new ArrayList<>();
|
List<PacketContainer> bundle = new ArrayList<>();
|
||||||
|
|
||||||
PacketContainer chatMessage = new PacketContainer(PacketType.Play.Server.SYSTEM_CHAT);
|
PacketContainer chatMessage = new PacketContainer(PacketType.Play.Server.SYSTEM_CHAT);
|
||||||
chatMessage.getStrings().write(0, WrappedChatComponent.fromText("Test").getJson());
|
chatMessage.getChatComponents().write(0, WrappedChatComponent.fromText("Test"));
|
||||||
chatMessage.getBooleans().write(0, false);
|
chatMessage.getBooleans().write(0, false);
|
||||||
bundle.add(chatMessage);
|
bundle.add(chatMessage);
|
||||||
bundlePacket.getPacketBundles().write(0, bundle);
|
bundlePacket.getPacketBundles().write(0, bundle);
|
||||||
|
@ -58,6 +58,7 @@ import net.md_5.bungee.api.chat.ClickEvent;
|
|||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||||
|
import net.minecraft.core.IRegistry;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.network.PacketDataSerializer;
|
import net.minecraft.network.PacketDataSerializer;
|
||||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||||
@ -500,7 +501,8 @@ public class PacketContainerTest {
|
|||||||
// are inner classes (which is ultimately pointless because AttributeSnapshots don't access any
|
// are inner classes (which is ultimately pointless because AttributeSnapshots don't access any
|
||||||
// members of the packet itself)
|
// members of the packet itself)
|
||||||
PacketPlayOutUpdateAttributes packet = (PacketPlayOutUpdateAttributes) attribute.getHandle();
|
PacketPlayOutUpdateAttributes packet = (PacketPlayOutUpdateAttributes) attribute.getHandle();
|
||||||
AttributeBase base = BuiltInRegistries.v.a(MinecraftKey.a("generic.max_health"));
|
IRegistry<AttributeBase> registry = BuiltInRegistries.u;
|
||||||
|
AttributeBase base = registry.a(MinecraftKey.a("generic.max_health"));
|
||||||
AttributeSnapshot snapshot = new AttributeSnapshot(base, 20.0D, modifiers);
|
AttributeSnapshot snapshot = new AttributeSnapshot(base, 20.0D, modifiers);
|
||||||
attribute.getSpecificModifier(List.class).write(0, Lists.newArrayList(snapshot));
|
attribute.getSpecificModifier(List.class).write(0, Lists.newArrayList(snapshot));
|
||||||
|
|
||||||
@ -882,6 +884,7 @@ public class PacketContainerTest {
|
|||||||
|
|
||||||
// Make sure watchable collections can be cloned
|
// Make sure watchable collections can be cloned
|
||||||
if (type == PacketType.Play.Server.ENTITY_METADATA) {
|
if (type == PacketType.Play.Server.ENTITY_METADATA) {
|
||||||
|
IRegistry<CatVariant> catVariantRegistry = BuiltInRegistries.ak;
|
||||||
constructed.getDataValueCollectionModifier().write(0, Lists.newArrayList(
|
constructed.getDataValueCollectionModifier().write(0, Lists.newArrayList(
|
||||||
new WrappedDataValue(0, Registry.get(Byte.class), (byte) 1),
|
new WrappedDataValue(0, Registry.get(Byte.class), (byte) 1),
|
||||||
new WrappedDataValue(0, Registry.get(Float.class), 5F),
|
new WrappedDataValue(0, Registry.get(Float.class), 5F),
|
||||||
@ -895,7 +898,7 @@ public class PacketContainerTest {
|
|||||||
0,
|
0,
|
||||||
Registry.getItemStackSerializer(false),
|
Registry.getItemStackSerializer(false),
|
||||||
BukkitConverters.getItemStackConverter().getGeneric(new ItemStack(Material.WOODEN_AXE))),
|
BukkitConverters.getItemStackConverter().getGeneric(new ItemStack(Material.WOODEN_AXE))),
|
||||||
new WrappedDataValue(0, Registry.get(CatVariant.class), BuiltInRegistries.aj.e(CatVariant.e)),
|
new WrappedDataValue(0, Registry.get(CatVariant.class), catVariantRegistry.e(CatVariant.e)),
|
||||||
new WrappedDataValue(0, Registry.get(FrogVariant.class), FrogVariant.a)
|
new WrappedDataValue(0, Registry.get(FrogVariant.class), FrogVariant.a)
|
||||||
));
|
));
|
||||||
} else if (type == PacketType.Play.Server.CHAT) {
|
} else if (type == PacketType.Play.Server.CHAT) {
|
||||||
|
@ -12,8 +12,8 @@ import net.minecraft.server.level.PlayerChunkMap;
|
|||||||
import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
|
import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
|
||||||
import net.minecraft.server.level.WorldServer;
|
import net.minecraft.server.level.WorldServer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity;
|
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ public class EntityUtilitiesTest {
|
|||||||
when(bukkit.getHandle()).thenReturn(world);
|
when(bukkit.getHandle()).thenReturn(world);
|
||||||
|
|
||||||
ChunkProviderServer provider = mock(ChunkProviderServer.class);
|
ChunkProviderServer provider = mock(ChunkProviderServer.class);
|
||||||
when(world.k()).thenReturn(provider);
|
when(world.l()).thenReturn(provider);
|
||||||
|
|
||||||
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
|
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
|
||||||
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
|
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.comphenix.protocol.injector;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.BukkitInitialization;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class StructureCacheTests {
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void beforeAll() {
|
||||||
|
BukkitInitialization.initializeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitTrickSerializer() {
|
||||||
|
try {
|
||||||
|
StructureCache.initTrickDataSerializer();
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
// no exception or an already injected exception means it succeeded
|
||||||
|
assertTrue(ex.getMessage().contains("Cannot inject already loaded type"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.comphenix.protocol.injector.packet;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.BukkitInitialization;
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class PacketRegistryTests {
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void beforeAll() {
|
||||||
|
BukkitInitialization.initializeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegistryInit() {
|
||||||
|
PacketRegistry.reset();
|
||||||
|
// completing without exception
|
||||||
|
PacketRegistry.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllPacketsRegistered() {
|
||||||
|
List<PacketType> missing = new ArrayList<>();
|
||||||
|
for (PacketType type : PacketType.values()) {
|
||||||
|
if (type.isDeprecated()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!PacketRegistry.tryGetPacketClass(type).isPresent()) {
|
||||||
|
missing.add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(missing.isEmpty(), "Missing packets: " + missing);
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,7 @@ public class AggregateClonerTest {
|
|||||||
|
|
||||||
// @Test
|
// @Test
|
||||||
// Usages of NonNullList were removed in 1.17.1
|
// Usages of NonNullList were removed in 1.17.1
|
||||||
public void testNonNullList() {
|
/* public void testNonNullList() {
|
||||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
||||||
|
|
||||||
NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.b);
|
NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.b);
|
||||||
@ -41,5 +41,5 @@ public class AggregateClonerTest {
|
|||||||
|
|
||||||
assertEquals(list.size(), list1.size());
|
assertEquals(list.size(), list1.size());
|
||||||
Assertions.assertArrayEquals(list.toArray(), list1.toArray());
|
Assertions.assertArrayEquals(list.toArray(), list1.toArray());
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import net.minecraft.world.level.ChunkCoordIntPair;
|
|||||||
import net.minecraft.world.level.block.state.IBlockData;
|
import net.minecraft.world.level.block.state.IBlockData;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack;
|
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
@ -2,8 +2,8 @@ package com.comphenix.protocol.utility;
|
|||||||
|
|
||||||
public class MinecraftReflectionTestUtil {
|
public class MinecraftReflectionTestUtil {
|
||||||
|
|
||||||
public static final String RELEASE_TARGET = "1.20.2";
|
public static final String RELEASE_TARGET = "1.20.4";
|
||||||
public static final String PACKAGE_VERSION = "v1_20_R2";
|
public static final String PACKAGE_VERSION = "v1_20_R3";
|
||||||
public static final String NMS = "net.minecraft";
|
public static final String NMS = "net.minecraft";
|
||||||
public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION;
|
public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION;
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class MinecraftVersionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCurrent() {
|
void testCurrent() {
|
||||||
assertEquals(MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE, MinecraftVersion.getCurrentVersion());
|
assertEquals(MinecraftVersion.v1_20_4, MinecraftVersion.getCurrentVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static com.comphenix.protocol.utility.MinecraftReflection.getMinecraftClass;
|
import static com.comphenix.protocol.utility.MinecraftReflection.getMinecraftClass;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
@ -46,7 +48,8 @@ public class AutoWrapperTest {
|
|||||||
assertTrue(nms.h());
|
assertTrue(nms.h());
|
||||||
assertTrue(nms.j());
|
assertTrue(nms.j());
|
||||||
assertFalse(nms.i());
|
assertFalse(nms.i());
|
||||||
assertEquals("test", nms.d().a());
|
assertTrue(nms.d().isPresent());
|
||||||
|
assertEquals("test", nms.d().get().a());
|
||||||
validateRawText(nms.a(), "Test123");
|
validateRawText(nms.a(), "Test123");
|
||||||
validateRawText(nms.b(), "Test567");
|
validateRawText(nms.b(), "Test567");
|
||||||
assertSame(AdvancementFrameType.b, nms.e());
|
assertSame(AdvancementFrameType.b, nms.e());
|
||||||
@ -61,7 +64,7 @@ public class AutoWrapperTest {
|
|||||||
(net.minecraft.world.item.ItemStack)MinecraftReflection.getMinecraftItemStack(new ItemStack(Material.ENDER_EYE)),
|
(net.minecraft.world.item.ItemStack)MinecraftReflection.getMinecraftItemStack(new ItemStack(Material.ENDER_EYE)),
|
||||||
IChatBaseComponent.b("Test123"),
|
IChatBaseComponent.b("Test123"),
|
||||||
IChatBaseComponent.b("Test567"),
|
IChatBaseComponent.b("Test567"),
|
||||||
new net.minecraft.resources.MinecraftKey("minecraft", "test"),
|
Optional.of(new net.minecraft.resources.MinecraftKey("minecraft", "test")),
|
||||||
AdvancementFrameType.b,
|
AdvancementFrameType.b,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -8,6 +8,7 @@ import com.comphenix.protocol.PacketType;
|
|||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation;
|
import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import net.minecraft.core.IRegistry;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||||
import net.minecraft.resources.MinecraftKey;
|
import net.minecraft.resources.MinecraftKey;
|
||||||
@ -93,7 +94,8 @@ public class WrappedAttributeTest {
|
|||||||
modifiers.add((AttributeModifier) wrapper.getHandle());
|
modifiers.add((AttributeModifier) wrapper.getHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeBase base = BuiltInRegistries.v.a(MinecraftKey.a(attribute.getAttributeKey()));
|
IRegistry<AttributeBase> registry = BuiltInRegistries.u;
|
||||||
|
AttributeBase base = registry.a(MinecraftKey.a(attribute.getAttributeKey()));
|
||||||
return new AttributeSnapshot(base, attribute.getBaseValue(), modifiers);
|
return new AttributeSnapshot(base, attribute.getBaseValue(), modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,9 +19,9 @@ import net.minecraft.world.level.block.state.IBlockData;
|
|||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
import org.bukkit.block.data.type.GlassPane;
|
import org.bukkit.block.data.type.GlassPane;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.block.impl.CraftStainedGlassPane;
|
import org.bukkit.craftbukkit.v1_20_R3.block.impl.CraftStainedGlassPane;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers;
|
import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ public class WrappedBlockDataTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDataCreation() {
|
public void testDataCreation() {
|
||||||
IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).n();
|
IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).o();
|
||||||
GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData);
|
GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData);
|
||||||
data.setFace(BlockFace.EAST, true);
|
data.setFace(BlockFace.EAST, true);
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
|||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||||
import net.minecraft.world.entity.projectile.EntityEgg;
|
import net.minecraft.world.entity.projectile.EntityEgg;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEgg;
|
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEgg;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity;
|
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user