Update cloud-bukkit & cloud-paper for Minecraft 1.19.3 (#412)
This commit is contained in:
parent
7777a85d41
commit
0bb6625de6
4 changed files with 163 additions and 15 deletions
|
|
@ -29,6 +29,7 @@ import cloud.commandframework.brigadier.CloudBrigadierManager;
|
|||
import cloud.commandframework.bukkit.argument.NamespacedKeyArgument;
|
||||
import cloud.commandframework.bukkit.internal.CommandBuildContextSupplier;
|
||||
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
||||
import cloud.commandframework.bukkit.internal.RegistryReflection;
|
||||
import cloud.commandframework.bukkit.parsers.BlockPredicateArgument;
|
||||
import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
|
||||
import cloud.commandframework.bukkit.parsers.ItemStackArgument;
|
||||
|
|
@ -90,8 +91,17 @@ public final class BukkitBrigadierMapper<C> {
|
|||
this.mapSimpleNMS(new TypeToken<NamespacedKeyArgument.Parser<C>>() {
|
||||
}, "resource_location", true);
|
||||
/* Map Enchantment */
|
||||
try {
|
||||
// Pre-1.19.3
|
||||
final Class<? extends ArgumentType<?>> ench = MinecraftArgumentTypes.getClassByKey(NamespacedKey.minecraft(
|
||||
"item_enchantment"));
|
||||
this.mapSimpleNMS(new TypeToken<EnchantmentArgument.EnchantmentParser<C>>() {
|
||||
}, "item_enchantment");
|
||||
} catch (final IllegalArgumentException ignore) {
|
||||
// 1.19.3+
|
||||
this.mapNMS(new TypeToken<EnchantmentArgument.EnchantmentParser<C>>() {
|
||||
}, this::modernEnchantment);
|
||||
}
|
||||
/* Map Item arguments */
|
||||
this.mapSimpleContextNMS(new TypeToken<ItemStackArgument.Parser<C>>() {
|
||||
}, "item_stack");
|
||||
|
|
@ -117,6 +127,17 @@ public final class BukkitBrigadierMapper<C> {
|
|||
}, this::argumentVec2);
|
||||
}
|
||||
|
||||
private ArgumentType<?> modernEnchantment() {
|
||||
try {
|
||||
return (ArgumentType<?>) MinecraftArgumentTypes.getClassByKey(NamespacedKey.minecraft("resource_key"))
|
||||
.getDeclaredConstructors()[0]
|
||||
.newInstance(RegistryReflection.registryKey(RegistryReflection.registryByName("enchantment")));
|
||||
} catch (final Exception e) {
|
||||
this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve enchantment argument", e);
|
||||
return fallbackType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param single Whether the selector is for a single entity only (true), or for multiple entities (false)
|
||||
* @param playersOnly Whether the selector is for players only (true), or for all entities (false)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ package cloud.commandframework.bukkit.internal;
|
|||
import com.google.common.annotations.Beta;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* This is not API, and as such, may break, change, or be removed without any notice.
|
||||
|
|
@ -35,11 +37,61 @@ import java.util.Arrays;
|
|||
public final class CommandBuildContextSupplier {
|
||||
|
||||
private static final Class<?> COMMAND_BUILD_CONTEXT_CLASS = CraftBukkitReflection.needMCClass("commands.CommandBuildContext");
|
||||
private static final Constructor<?> COMMAND_BUILD_CONTEXT_CTR = COMMAND_BUILD_CONTEXT_CLASS.getDeclaredConstructors()[0];
|
||||
private static final Class<?> REG_ACC_CLASS = COMMAND_BUILD_CONTEXT_CTR.getParameterTypes()[0];
|
||||
private static final @Nullable Constructor<?> COMMAND_BUILD_CONTEXT_CTR;
|
||||
private static final @Nullable Method CREATE_CONTEXT_METHOD;
|
||||
private static final @Nullable Method GET_WORLD_DATA_METHOD;
|
||||
private static final @Nullable Method GET_FEATURE_FLAGS_METHOD;
|
||||
private static final Class<?> REG_ACC_CLASS;
|
||||
private static final Class<?> MC_SERVER_CLASS = CraftBukkitReflection.needNMSClassOrElse(
|
||||
"MinecraftServer", "net.minecraft.server.MinecraftServer"
|
||||
);
|
||||
|
||||
static {
|
||||
@Nullable Constructor<?> ctr;
|
||||
try {
|
||||
ctr = COMMAND_BUILD_CONTEXT_CLASS.getDeclaredConstructors()[0];
|
||||
} catch (final Exception ex) {
|
||||
ctr = null;
|
||||
}
|
||||
COMMAND_BUILD_CONTEXT_CTR = ctr;
|
||||
|
||||
if (COMMAND_BUILD_CONTEXT_CTR == null) {
|
||||
CREATE_CONTEXT_METHOD = Arrays.stream(COMMAND_BUILD_CONTEXT_CLASS.getDeclaredMethods())
|
||||
.filter(it -> it.getParameterCount() == 2 && COMMAND_BUILD_CONTEXT_CLASS.isAssignableFrom(it
|
||||
.getReturnType()) && Modifier.isStatic(it.getModifiers()))
|
||||
.skip(1)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find CommandBuildContext.configurable"));
|
||||
|
||||
final Class<?> worldDataCls = CraftBukkitReflection.firstNonNullOrThrow(
|
||||
() -> "Could not find WorldData class",
|
||||
CraftBukkitReflection.findMCClass("world.level.storage.SaveData"),
|
||||
CraftBukkitReflection.findMCClass("world.level.storage.WorldData")
|
||||
);
|
||||
GET_WORLD_DATA_METHOD = Arrays.stream(MC_SERVER_CLASS.getDeclaredMethods())
|
||||
.filter(it -> it.getParameterCount() == 0 && !Modifier.isStatic(it.getModifiers()) && it
|
||||
.getReturnType()
|
||||
.equals(worldDataCls))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find MinecraftServer#getWorldData method"));
|
||||
final Class<?> featureFlagSetCls = CraftBukkitReflection.needMCClass("world.flag.FeatureFlagSet");
|
||||
GET_FEATURE_FLAGS_METHOD = Arrays.stream(worldDataCls.getDeclaredMethods())
|
||||
.filter(it -> it.getParameterCount() == 0 && it
|
||||
.getReturnType()
|
||||
.equals(featureFlagSetCls) && !Modifier.isStatic(it.getModifiers()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find enabledFeatures method"));
|
||||
} else {
|
||||
CREATE_CONTEXT_METHOD = null;
|
||||
GET_WORLD_DATA_METHOD = null;
|
||||
GET_FEATURE_FLAGS_METHOD = null;
|
||||
}
|
||||
|
||||
REG_ACC_CLASS = COMMAND_BUILD_CONTEXT_CTR != null
|
||||
? COMMAND_BUILD_CONTEXT_CTR.getParameterTypes()[0]
|
||||
: CREATE_CONTEXT_METHOD.getParameterTypes()[0];
|
||||
}
|
||||
|
||||
private static final Method GET_SERVER_METHOD;
|
||||
private static final Method REGISTRY_ACCESS = Arrays.stream(MC_SERVER_CLASS.getDeclaredMethods())
|
||||
.filter(m -> REG_ACC_CLASS.isAssignableFrom(m.getReturnType()))
|
||||
|
|
@ -58,11 +110,24 @@ public final class CommandBuildContextSupplier {
|
|||
}
|
||||
|
||||
public static Object commandBuildContext() {
|
||||
if (COMMAND_BUILD_CONTEXT_CTR != null) {
|
||||
try {
|
||||
final Object server = GET_SERVER_METHOD.invoke(null);
|
||||
return COMMAND_BUILD_CONTEXT_CTR.newInstance(REGISTRY_ACCESS.invoke(server));
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else if (CREATE_CONTEXT_METHOD != null && GET_WORLD_DATA_METHOD != null && GET_FEATURE_FLAGS_METHOD != null) {
|
||||
try {
|
||||
final Object server = GET_SERVER_METHOD.invoke(null);
|
||||
final Object worldData = GET_WORLD_DATA_METHOD.invoke(server);
|
||||
final Object flags = GET_FEATURE_FLAGS_METHOD.invoke(worldData);
|
||||
return CREATE_CONTEXT_METHOD.invoke(null, REGISTRY_ACCESS.invoke(server), flags);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,14 @@
|
|||
package cloud.commandframework.bukkit.internal;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
|
@ -39,6 +44,7 @@ public final class RegistryReflection {
|
|||
|
||||
public static final @Nullable Field REGISTRY_REGISTRY;
|
||||
public static final @Nullable Method REGISTRY_GET;
|
||||
public static final @Nullable Method REGISTRY_KEY;
|
||||
|
||||
private static final Class<?> RESOURCE_LOCATION_CLASS = CraftBukkitReflection.needNMSClassOrElse(
|
||||
"MinecraftKey",
|
||||
|
|
@ -58,17 +64,14 @@ public final class RegistryReflection {
|
|||
if (CraftBukkitReflection.MAJOR_REVISION < 17) {
|
||||
REGISTRY_REGISTRY = null;
|
||||
REGISTRY_GET = null;
|
||||
REGISTRY_KEY = null;
|
||||
} else {
|
||||
registryClass = CraftBukkitReflection.firstNonNullOrThrow(
|
||||
() -> "Registry",
|
||||
CraftBukkitReflection.findMCClass("core.IRegistry"),
|
||||
CraftBukkitReflection.findMCClass("core.Registry")
|
||||
);
|
||||
final Class<?> registryClassFinal = registryClass;
|
||||
REGISTRY_REGISTRY = Arrays.stream(registryClass.getDeclaredFields())
|
||||
.filter(it -> it.getType().equals(registryClassFinal))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find Registry Registry field"));
|
||||
REGISTRY_REGISTRY = registryRegistryField(registryClass);
|
||||
REGISTRY_REGISTRY.setAccessible(true);
|
||||
final Class<?> resourceLocationClass = CraftBukkitReflection.firstNonNullOrThrow(
|
||||
() -> "ResourceLocation class",
|
||||
|
|
@ -81,6 +84,21 @@ public final class RegistryReflection {
|
|||
&& it.getReturnType().equals(Object.class))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find Registry#get(ResourceLocation)"));
|
||||
|
||||
final Class<?> resourceKeyClass = CraftBukkitReflection.needMCClass("resources.ResourceKey");
|
||||
REGISTRY_KEY = Arrays.stream(registryClass.getDeclaredMethods())
|
||||
.filter(m -> m.getParameterCount() == 0 && m.getReturnType().equals(resourceKeyClass))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object registryKey(final Object registry) {
|
||||
Objects.requireNonNull(REGISTRY_KEY, "REGISTRY_KEY");
|
||||
try {
|
||||
return REGISTRY_KEY.invoke(registry);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,4 +127,36 @@ public final class RegistryReflection {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Field registryRegistryField(final Class<?> registryClass) {
|
||||
// Pre-1.19.3 we want the first Registry type field in Registry
|
||||
// 1.19.3+ we want the only static final Registry<? extends Registry<?>> from BuiltInRegistries
|
||||
// In 1.19.3+ there are no Registry type fields in Registry
|
||||
return Arrays.stream(registryClass.getDeclaredFields())
|
||||
.filter(it -> it.getType().equals(registryClass))
|
||||
.findFirst()
|
||||
.orElseGet(() -> registryRegistryFieldFromBuiltInRegistries(registryClass));
|
||||
}
|
||||
|
||||
private static Field registryRegistryFieldFromBuiltInRegistries(final Class<?> registryClass) {
|
||||
final Class<?> builtInRegistriesClass =
|
||||
CraftBukkitReflection.needMCClass("core.registries.BuiltInRegistries");
|
||||
return Arrays.stream(builtInRegistriesClass.getDeclaredFields())
|
||||
.filter(it -> {
|
||||
if (!it.getType().equals(registryClass) || !Modifier.isStatic(it.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
final Type genericType = it.getGenericType();
|
||||
if (!(genericType instanceof ParameterizedType)) {
|
||||
return false;
|
||||
}
|
||||
Type valueType = ((ParameterizedType) genericType).getActualTypeArguments()[0];
|
||||
while (valueType instanceof WildcardType) {
|
||||
valueType = ((WildcardType) valueType).getUpperBounds()[0];
|
||||
}
|
||||
return GenericTypeReflector.erase(valueType).equals(registryClass);
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find Registry Registry field"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ final class SelectorUtils {
|
|||
}
|
||||
|
||||
private static final class EntityArgumentParseFunction implements WrappedBrigadierParser.ParseFunction<Object> {
|
||||
|
||||
static final EntityArgumentParseFunction INSTANCE = new EntityArgumentParseFunction();
|
||||
|
||||
@Override
|
||||
|
|
@ -132,6 +133,7 @@ final class SelectorUtils {
|
|||
}
|
||||
|
||||
private abstract static class SelectorParser<C, T> implements ArgumentParser<C, T>, SelectorMapper<T> {
|
||||
|
||||
protected static final Supplier<Object> NO_PLAYERS_EXCEPTION_TYPE =
|
||||
Suppliers.memoize(() -> findExceptionType("argument.entity.notfound.player"));
|
||||
protected static final Supplier<Object> NO_ENTITIES_EXCEPTION_TYPE =
|
||||
|
|
@ -141,6 +143,7 @@ final class SelectorUtils {
|
|||
|
||||
// Hide brigadier references in inner class
|
||||
protected static final class Thrower {
|
||||
|
||||
private final Object type;
|
||||
|
||||
Thrower(final Object simpleCommandExceptionType) {
|
||||
|
|
@ -228,12 +231,14 @@ final class SelectorUtils {
|
|||
}
|
||||
|
||||
abstract static class EntitySelectorParser<C, T> extends SelectorParser<C, T> {
|
||||
|
||||
protected EntitySelectorParser(final boolean single) {
|
||||
super(single, false);
|
||||
}
|
||||
}
|
||||
|
||||
abstract static class PlayerSelectorParser<C, T> extends SelectorParser<C, T> {
|
||||
|
||||
protected PlayerSelectorParser(final boolean single) {
|
||||
super(single, true);
|
||||
}
|
||||
|
|
@ -258,6 +263,7 @@ final class SelectorUtils {
|
|||
}
|
||||
|
||||
private static class ModernSelectorParser<C, T> implements ArgumentParser<C, T> {
|
||||
|
||||
private final ArgumentParser<C, Object> wrappedBrigadierParser;
|
||||
private final SelectorMapper<T> mapper;
|
||||
|
||||
|
|
@ -326,12 +332,14 @@ final class SelectorUtils {
|
|||
}
|
||||
|
||||
static final class EntitySelectorWrapper {
|
||||
|
||||
private static volatile @MonotonicNonNull Methods methods;
|
||||
|
||||
private final CommandContext<?> commandContext;
|
||||
private final Object selector;
|
||||
|
||||
private static final class Methods {
|
||||
|
||||
private @MonotonicNonNull Method getBukkitEntity;
|
||||
private @MonotonicNonNull Method entity;
|
||||
private @MonotonicNonNull Method player;
|
||||
|
|
@ -342,7 +350,9 @@ final class SelectorUtils {
|
|||
final Object nativeSender = commandContext.get(WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER);
|
||||
final Class<?> nativeSenderClass = nativeSender.getClass();
|
||||
for (final Method method : selector.getClass().getDeclaredMethods()) {
|
||||
if (method.getParameterCount() != 1 || !method.getParameterTypes()[0].equals(nativeSenderClass)) {
|
||||
if (method.getParameterCount() != 1
|
||||
|| !method.getParameterTypes()[0].equals(nativeSenderClass)
|
||||
|| !Modifier.isPublic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -475,6 +485,7 @@ final class SelectorUtils {
|
|||
|
||||
@FunctionalInterface
|
||||
interface ReflectiveOperation<T> {
|
||||
|
||||
T run() throws ReflectiveOperationException;
|
||||
}
|
||||
|
||||
|
|
@ -494,6 +505,7 @@ final class SelectorUtils {
|
|||
|
||||
@FunctionalInterface
|
||||
interface SelectorMapper<T> {
|
||||
|
||||
T mapResult(String input, EntitySelectorWrapper wrapper) throws Exception; // throws CommandSyntaxException
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue