bukkit/paper: Update reflection for Minecraft 1.19 (#374)
This commit is contained in:
parent
2572b73c4b
commit
1fe1b4a0d3
8 changed files with 387 additions and 137 deletions
|
|
@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Annotations: `@CommandMethod` annotation processing for compile-time validation ([#365](https://github.com/Incendo/cloud/pull/365))
|
- Annotations: `@CommandMethod` annotation processing for compile-time validation ([#365](https://github.com/Incendo/cloud/pull/365))
|
||||||
- Add root command deletion support (core/pircbotx/javacord/jda/bukkit/paper) ([#369](https://github.com/Incendo/cloud/pull/369),
|
- Add root command deletion support (core/pircbotx/javacord/jda/bukkit/paper) ([#369](https://github.com/Incendo/cloud/pull/369),
|
||||||
[#371](https://github.com/Incendo/cloud/pull/371))
|
[#371](https://github.com/Incendo/cloud/pull/371))
|
||||||
|
- Bukkit/Paper: Full support for Minecraft 1.19
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Core: Fix missing caption registration for the regex caption ([#351](https://github.com/Incendo/cloud/pull/351))
|
- Core: Fix missing caption registration for the regex caption ([#351](https://github.com/Incendo/cloud/pull/351))
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework.bukkit;
|
||||||
import cloud.commandframework.arguments.parser.ArgumentParser;
|
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
import cloud.commandframework.arguments.standard.UUIDArgument;
|
import cloud.commandframework.arguments.standard.UUIDArgument;
|
||||||
import cloud.commandframework.brigadier.CloudBrigadierManager;
|
import cloud.commandframework.brigadier.CloudBrigadierManager;
|
||||||
|
import cloud.commandframework.bukkit.internal.CommandBuildContextSupplier;
|
||||||
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
||||||
import cloud.commandframework.bukkit.parsers.BlockPredicateArgument;
|
import cloud.commandframework.bukkit.parsers.BlockPredicateArgument;
|
||||||
import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
|
import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
|
||||||
|
|
@ -88,12 +89,12 @@ public final class BukkitBrigadierMapper<C> {
|
||||||
this.mapSimpleNMS(new TypeToken<EnchantmentArgument.EnchantmentParser<C>>() {
|
this.mapSimpleNMS(new TypeToken<EnchantmentArgument.EnchantmentParser<C>>() {
|
||||||
}, "item_enchantment");
|
}, "item_enchantment");
|
||||||
/* Map Item arguments */
|
/* Map Item arguments */
|
||||||
this.mapSimpleNMS(new TypeToken<ItemStackArgument.Parser<C>>() {
|
this.mapSimpleContextNMS(new TypeToken<ItemStackArgument.Parser<C>>() {
|
||||||
}, "item_stack");
|
}, "item_stack");
|
||||||
this.mapSimpleNMS(new TypeToken<ItemStackPredicateArgument.Parser<C>>() {
|
this.mapSimpleContextNMS(new TypeToken<ItemStackPredicateArgument.Parser<C>>() {
|
||||||
}, "item_predicate");
|
}, "item_predicate");
|
||||||
/* Map Block arguments */
|
/* Map Block arguments */
|
||||||
this.mapSimpleNMS(new TypeToken<BlockPredicateArgument.Parser<C>>() {
|
this.mapSimpleContextNMS(new TypeToken<BlockPredicateArgument.Parser<C>>() {
|
||||||
}, "block_predicate");
|
}, "block_predicate");
|
||||||
/* Map Entity Selectors */
|
/* Map Entity Selectors */
|
||||||
this.mapNMS(new TypeToken<SingleEntitySelectorArgument.SingleEntitySelectorParser<C>>() {
|
this.mapNMS(new TypeToken<SingleEntitySelectorArgument.SingleEntitySelectorParser<C>>() {
|
||||||
|
|
@ -156,13 +157,37 @@ public final class BukkitBrigadierMapper<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to register a mapping between a cloud argument parser type and an NMS brigadier argument type which
|
||||||
|
* has a single-arg constructor taking CommandBuildContext.
|
||||||
|
*
|
||||||
|
* @param type Type to map
|
||||||
|
* @param <T> argument parser type
|
||||||
|
* @param argumentId registry id of argument type
|
||||||
|
* @since 1.7.0
|
||||||
|
*/
|
||||||
|
public <T extends ArgumentParser<C, ?>> void mapSimpleContextNMS(
|
||||||
|
final @NonNull TypeToken<T> type,
|
||||||
|
final @NonNull String argumentId
|
||||||
|
) {
|
||||||
|
this.mapNMS(type, () -> {
|
||||||
|
try {
|
||||||
|
return (ArgumentType<?>) MinecraftArgumentTypes.getClassByKey(NamespacedKey.minecraft(argumentId))
|
||||||
|
.getDeclaredConstructors()[0]
|
||||||
|
.newInstance(CommandBuildContextSupplier.commandBuildContext());
|
||||||
|
} catch (final ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to register a mapping between a cloud argument parser type and an NMS brigadier argument type which
|
* Attempt to register a mapping between a cloud argument parser type and an NMS brigadier argument type which
|
||||||
* has a no-args constructor.
|
* has a no-args constructor.
|
||||||
*
|
*
|
||||||
* @param type Type to map
|
* @param type Type to map
|
||||||
* @param <T> argument parser type
|
* @param <T> argument parser type
|
||||||
* @param argumentId network id of argument type
|
* @param argumentId registry id of argument type
|
||||||
* @since 1.5.0
|
* @since 1.5.0
|
||||||
*/
|
*/
|
||||||
public <T extends ArgumentParser<C, ?>> void mapSimpleNMS(
|
public <T extends ArgumentParser<C, ?>> void mapSimpleNMS(
|
||||||
|
|
@ -178,7 +203,7 @@ public final class BukkitBrigadierMapper<C> {
|
||||||
*
|
*
|
||||||
* @param type Type to map
|
* @param type Type to map
|
||||||
* @param <T> argument parser type
|
* @param <T> argument parser type
|
||||||
* @param argumentId network id of argument type
|
* @param argumentId registry id of argument type
|
||||||
* @param useCloudSuggestions whether to use cloud suggestions
|
* @param useCloudSuggestions whether to use cloud suggestions
|
||||||
* @since 1.6.0
|
* @since 1.6.0
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Alexander Söderberg & Contributors
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
package cloud.commandframework.bukkit.internal;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not API, and as such, may break, change, or be removed without any notice.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
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 Class<?> MC_SERVER_CLASS = CraftBukkitReflection.needNMSClassOrElse(
|
||||||
|
"MinecraftServer", "net.minecraft.server.MinecraftServer"
|
||||||
|
);
|
||||||
|
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()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new IllegalStateException("Cannot find MinecraftServer#registryAccess"));
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
GET_SERVER_METHOD = MC_SERVER_CLASS.getDeclaredMethod("getServer");
|
||||||
|
} catch (final NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandBuildContextSupplier() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object commandBuildContext() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -62,8 +62,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A registry of the {@link ArgumentType}s provided by Minecraft.
|
* A registry of the {@link ArgumentType}s provided by Minecraft.
|
||||||
* <p>
|
|
||||||
* This file is taken from MIT licensed code in commodore (https://github.com/lucko/commodore).
|
|
||||||
*
|
*
|
||||||
* <p>This is not API, and as such, may break, change, or be removed without any notice.</p>
|
* <p>This is not API, and as such, may break, change, or be removed without any notice.</p>
|
||||||
*/
|
*/
|
||||||
|
|
@ -73,6 +71,64 @@ public final class MinecraftArgumentTypes {
|
||||||
private MinecraftArgumentTypes() {
|
private MinecraftArgumentTypes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final ArgumentTypeGetter ARGUMENT_TYPE_GETTER;
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (CraftBukkitReflection.classExists("org.bukkit.entity.Warden")) {
|
||||||
|
ARGUMENT_TYPE_GETTER = new ArgumentTypeGetterImpl(); // 1.19+
|
||||||
|
} else {
|
||||||
|
ARGUMENT_TYPE_GETTER = new LegacyArgumentTypeGetter(); // 1.13-1.18.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a registered argument type class by key.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @return the returned argument type class
|
||||||
|
* @throws IllegalArgumentException if no such argument is registered
|
||||||
|
*/
|
||||||
|
public static Class<? extends ArgumentType<?>> getClassByKey(
|
||||||
|
final @NonNull NamespacedKey key
|
||||||
|
) throws IllegalArgumentException {
|
||||||
|
return ARGUMENT_TYPE_GETTER.getClassByKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface ArgumentTypeGetter {
|
||||||
|
Class<? extends ArgumentType<?>> getClassByKey(@NonNull NamespacedKey key) throws IllegalArgumentException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static final class ArgumentTypeGetterImpl implements MinecraftArgumentTypes.ArgumentTypeGetter {
|
||||||
|
private final Object argumentRegistry;
|
||||||
|
private final Map<?, ?> byClassMap;
|
||||||
|
|
||||||
|
private ArgumentTypeGetterImpl() {
|
||||||
|
this.argumentRegistry = RegistryReflection.registryByName("command_argument_type");
|
||||||
|
try {
|
||||||
|
final Field declaredField = CraftBukkitReflection.needMCClass("commands.synchronization.ArgumentTypeInfos")
|
||||||
|
.getDeclaredFields()[0];
|
||||||
|
declaredField.setAccessible(true);
|
||||||
|
this.byClassMap = (Map<?, ?>) declaredField.get(null);
|
||||||
|
} catch (final ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ArgumentType<?>> getClassByKey(final @NonNull NamespacedKey key) throws IllegalArgumentException {
|
||||||
|
final Object argTypeInfo = RegistryReflection.get(this.argumentRegistry, key.getNamespace() + ":" + key.getKey());
|
||||||
|
for (final Map.Entry<?, ?> entry : this.byClassMap.entrySet()) {
|
||||||
|
if (entry.getValue() == argTypeInfo) {
|
||||||
|
return (Class<? extends ArgumentType<?>>) entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(key.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static final class LegacyArgumentTypeGetter implements ArgumentTypeGetter {
|
||||||
private static final Constructor<?> MINECRAFT_KEY_CONSTRUCTOR;
|
private static final Constructor<?> MINECRAFT_KEY_CONSTRUCTOR;
|
||||||
private static final Method ARGUMENT_REGISTRY_GET_BY_KEY_METHOD;
|
private static final Method ARGUMENT_REGISTRY_GET_BY_KEY_METHOD;
|
||||||
private static final Field BY_CLASS_MAP_FIELD;
|
private static final Field BY_CLASS_MAP_FIELD;
|
||||||
|
|
@ -119,22 +175,13 @@ public final class MinecraftArgumentTypes {
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(NoSuchFieldException::new);
|
.orElseThrow(NoSuchFieldException::new);
|
||||||
BY_CLASS_MAP_FIELD.setAccessible(true);
|
BY_CLASS_MAP_FIELD.setAccessible(true);
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (final ReflectiveOperationException e) {
|
||||||
throw new ExceptionInInitializerError(e);
|
throw new ExceptionInInitializerError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets a registered argument type class by key.
|
public Class<? extends ArgumentType<?>> getClassByKey(final @NonNull NamespacedKey key) throws IllegalArgumentException {
|
||||||
*
|
|
||||||
* @param key the key
|
|
||||||
* @return the returned argument type class
|
|
||||||
* @throws IllegalArgumentException if no such argument is registered
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static Class<? extends ArgumentType<?>> getClassByKey(
|
|
||||||
final @NonNull NamespacedKey key
|
|
||||||
) throws IllegalArgumentException {
|
|
||||||
try {
|
try {
|
||||||
Object minecraftKey = MINECRAFT_KEY_CONSTRUCTOR.newInstance(key.getNamespace(), key.getKey());
|
Object minecraftKey = MINECRAFT_KEY_CONSTRUCTOR.newInstance(key.getNamespace(), key.getKey());
|
||||||
Object entry = ARGUMENT_REGISTRY_GET_BY_KEY_METHOD.invoke(null, minecraftKey);
|
Object entry = ARGUMENT_REGISTRY_GET_BY_KEY_METHOD.invoke(null, minecraftKey);
|
||||||
|
|
@ -153,5 +200,6 @@ public final class MinecraftArgumentTypes {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Alexander Söderberg & Contributors
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
package cloud.commandframework.bukkit.internal;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not API, and as such, may break, change, or be removed without any notice.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
public final class RegistryReflection {
|
||||||
|
public static final @Nullable Field REGISTRY_REGISTRY;
|
||||||
|
public static final @Nullable Method REGISTRY_GET;
|
||||||
|
|
||||||
|
private static final Class<?> RESOURCE_LOCATION_CLASS = CraftBukkitReflection.needNMSClassOrElse(
|
||||||
|
"MinecraftKey",
|
||||||
|
"net.minecraft.resources.MinecraftKey",
|
||||||
|
"net.minecraft.resources.ResourceLocation"
|
||||||
|
);
|
||||||
|
private static final Constructor<?> RESOURCE_LOCATION_CTR = CraftBukkitReflection.needConstructor(
|
||||||
|
RESOURCE_LOCATION_CLASS,
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
|
||||||
|
private RegistryReflection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
Class<?> registryClass;
|
||||||
|
if (CraftBukkitReflection.MAJOR_REVISION < 17) {
|
||||||
|
REGISTRY_REGISTRY = null;
|
||||||
|
REGISTRY_GET = 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.setAccessible(true);
|
||||||
|
final Class<?> resourceLocationClass = CraftBukkitReflection.firstNonNullOrThrow(
|
||||||
|
() -> "ResourceLocation class",
|
||||||
|
CraftBukkitReflection.findMCClass("resources.ResourceLocation"),
|
||||||
|
CraftBukkitReflection.findMCClass("resources.MinecraftKey")
|
||||||
|
);
|
||||||
|
REGISTRY_GET = Arrays.stream(registryClass.getDeclaredMethods())
|
||||||
|
.filter(it -> it.getParameterCount() == 1
|
||||||
|
&& it.getParameterTypes()[0].equals(resourceLocationClass)
|
||||||
|
&& it.getReturnType().equals(Object.class))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new IllegalStateException("Could not find Registry#get(ResourceLocation)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object get(final Object registry, final String resourceLocation) {
|
||||||
|
Objects.requireNonNull(REGISTRY_GET, "REGISTRY_GET");
|
||||||
|
try {
|
||||||
|
return REGISTRY_GET.invoke(registry, RegistryReflection.createResourceLocation(resourceLocation));
|
||||||
|
} catch (final ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object registryByName(final String name) {
|
||||||
|
Objects.requireNonNull(REGISTRY_REGISTRY, "REGISTRY_REGISTRY");
|
||||||
|
try {
|
||||||
|
return get(REGISTRY_REGISTRY.get(null), name);
|
||||||
|
} catch (final ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object createResourceLocation(final String str) {
|
||||||
|
try {
|
||||||
|
return RESOURCE_LOCATION_CTR.newInstance(str);
|
||||||
|
} catch (final ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,15 +30,15 @@ import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
||||||
import cloud.commandframework.bukkit.BukkitCommandManager;
|
import cloud.commandframework.bukkit.BukkitCommandManager;
|
||||||
import cloud.commandframework.bukkit.data.BlockPredicate;
|
import cloud.commandframework.bukkit.data.BlockPredicate;
|
||||||
|
import cloud.commandframework.bukkit.internal.CommandBuildContextSupplier;
|
||||||
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
|
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
|
||||||
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
||||||
|
import cloud.commandframework.bukkit.internal.RegistryReflection;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
import io.leangen.geantyref.TypeToken;
|
import io.leangen.geantyref.TypeToken;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
@ -144,60 +144,19 @@ public final class BlockPredicateArgument<C> extends CommandArgument<C, BlockPre
|
||||||
public static final class Parser<C> implements ArgumentParser<C, BlockPredicate> {
|
public static final class Parser<C> implements ArgumentParser<C, BlockPredicate> {
|
||||||
|
|
||||||
private static final Class<?> TAG_CONTAINER_CLASS;
|
private static final Class<?> TAG_CONTAINER_CLASS;
|
||||||
private static final @Nullable Field REGISTRY_REGISTRY;
|
|
||||||
private static final @Nullable Method REGISTRY_GET;
|
|
||||||
private static final @Nullable Object BLOCK_REGISTRY_RESOURCE_LOCATION;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Class<?> tagContainerClass;
|
Class<?> tagContainerClass;
|
||||||
if (CraftBukkitReflection.MAJOR_REVISION > 12 && CraftBukkitReflection.MAJOR_REVISION < 16) {
|
if (CraftBukkitReflection.MAJOR_REVISION > 12 && CraftBukkitReflection.MAJOR_REVISION < 16) {
|
||||||
tagContainerClass = CraftBukkitReflection.needNMSClass("TagRegistry");
|
tagContainerClass = CraftBukkitReflection.needNMSClass("TagRegistry");
|
||||||
REGISTRY_REGISTRY = null;
|
|
||||||
REGISTRY_GET = null;
|
|
||||||
BLOCK_REGISTRY_RESOURCE_LOCATION = null;
|
|
||||||
} else {
|
} else {
|
||||||
tagContainerClass = CraftBukkitReflection.firstNonNullOrNull(
|
tagContainerClass = CraftBukkitReflection.firstNonNullOrThrow(
|
||||||
|
() -> "tagContainerClass",
|
||||||
CraftBukkitReflection.findNMSClass("ITagRegistry"),
|
CraftBukkitReflection.findNMSClass("ITagRegistry"),
|
||||||
CraftBukkitReflection.findMCClass("tags.ITagRegistry"),
|
CraftBukkitReflection.findMCClass("tags.ITagRegistry"),
|
||||||
CraftBukkitReflection.findMCClass("tags.TagContainer")
|
CraftBukkitReflection.findMCClass("tags.TagContainer"),
|
||||||
|
String.class // fail
|
||||||
);
|
);
|
||||||
if (tagContainerClass == null) {
|
|
||||||
tagContainerClass = CraftBukkitReflection.firstNonNullOrThrow(
|
|
||||||
() -> "Registry",
|
|
||||||
CraftBukkitReflection.findMCClass("core.IRegistry"),
|
|
||||||
CraftBukkitReflection.findMCClass("core.Registry")
|
|
||||||
);
|
|
||||||
final Class<?> tagContainerClassFinal = tagContainerClass;
|
|
||||||
REGISTRY_REGISTRY = Arrays.stream(tagContainerClass.getDeclaredFields())
|
|
||||||
.filter(it -> it.getType().equals(tagContainerClassFinal))
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> new IllegalStateException("Could not find Registry Registry field"));
|
|
||||||
REGISTRY_REGISTRY.setAccessible(true);
|
|
||||||
final Class<?> resourceLocationClass = CraftBukkitReflection.firstNonNullOrThrow(
|
|
||||||
() -> "ResourceLocation class",
|
|
||||||
CraftBukkitReflection.findMCClass("resources.ResourceLocation"),
|
|
||||||
CraftBukkitReflection.findMCClass("resources.MinecraftKey")
|
|
||||||
);
|
|
||||||
REGISTRY_GET = Arrays.stream(tagContainerClass.getDeclaredMethods())
|
|
||||||
.filter(it -> it.getParameterCount() == 1
|
|
||||||
&& it.getParameterTypes()[0].equals(resourceLocationClass)
|
|
||||||
&& it.getReturnType().equals(Object.class))
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> new IllegalStateException("Could not find Registry#get(ResourceLocation)"));
|
|
||||||
final Constructor<?> resourceLocationCtr = CraftBukkitReflection.needConstructor(
|
|
||||||
resourceLocationClass,
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
BLOCK_REGISTRY_RESOURCE_LOCATION = resourceLocationCtr.newInstance("block");
|
|
||||||
} catch (final ReflectiveOperationException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
REGISTRY_REGISTRY = null;
|
|
||||||
REGISTRY_GET = null;
|
|
||||||
BLOCK_REGISTRY_RESOURCE_LOCATION = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TAG_CONTAINER_CLASS = tagContainerClass;
|
TAG_CONTAINER_CLASS = tagContainerClass;
|
||||||
}
|
}
|
||||||
|
|
@ -244,8 +203,7 @@ public final class BlockPredicateArgument<C> extends CommandArgument<C, BlockPre
|
||||||
private static final Constructor<?> SHAPE_DETECTOR_BLOCK_CTR = CraftBukkitReflection
|
private static final Constructor<?> SHAPE_DETECTOR_BLOCK_CTR = CraftBukkitReflection
|
||||||
.needConstructor(SHAPE_DETECTOR_BLOCK_CLASS, LEVEL_READER_CLASS, BLOCK_POSITION_CLASS, boolean.class);
|
.needConstructor(SHAPE_DETECTOR_BLOCK_CLASS, LEVEL_READER_CLASS, BLOCK_POSITION_CLASS, boolean.class);
|
||||||
private static final Method GET_HANDLE_METHOD = CraftBukkitReflection.needMethod(CRAFT_WORLD_CLASS, "getHandle");
|
private static final Method GET_HANDLE_METHOD = CraftBukkitReflection.needMethod(CRAFT_WORLD_CLASS, "getHandle");
|
||||||
private static final Method CREATE_PREDICATE_METHOD = CraftBukkitReflection.firstNonNullOrThrow(
|
private static final @Nullable Method CREATE_PREDICATE_METHOD = CraftBukkitReflection.firstNonNullOrNull(
|
||||||
() -> "create on BlockPredicateArgument$Result",
|
|
||||||
CraftBukkitReflection.findMethod(ARGUMENT_BLOCK_PREDICATE_RESULT_CLASS, "create", TAG_CONTAINER_CLASS),
|
CraftBukkitReflection.findMethod(ARGUMENT_BLOCK_PREDICATE_RESULT_CLASS, "create", TAG_CONTAINER_CLASS),
|
||||||
CraftBukkitReflection.findMethod(ARGUMENT_BLOCK_PREDICATE_RESULT_CLASS, "a", TAG_CONTAINER_CLASS)
|
CraftBukkitReflection.findMethod(ARGUMENT_BLOCK_PREDICATE_RESULT_CLASS, "a", TAG_CONTAINER_CLASS)
|
||||||
);
|
);
|
||||||
|
|
@ -279,22 +237,30 @@ public final class BlockPredicateArgument<C> extends CommandArgument<C, BlockPre
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private ArgumentParser<C, BlockPredicate> createParser() throws ReflectiveOperationException {
|
private ArgumentParser<C, BlockPredicate> createParser() throws ReflectiveOperationException {
|
||||||
return new WrappedBrigadierParser<C, Object>(
|
final Constructor<?> ctr = ARGUMENT_BLOCK_PREDICATE_CLASS.getDeclaredConstructors()[0];
|
||||||
(ArgumentType<Object>) ARGUMENT_BLOCK_PREDICATE_CLASS.getConstructor().newInstance()
|
final ArgumentType<Object> inst;
|
||||||
).map((ctx, result) -> {
|
if (ctr.getParameterCount() == 0) {
|
||||||
|
inst = (ArgumentType<Object>) ctr.newInstance();
|
||||||
|
} else {
|
||||||
|
// 1.19+
|
||||||
|
inst = (ArgumentType<Object>) ctr.newInstance(CommandBuildContextSupplier.commandBuildContext());
|
||||||
|
}
|
||||||
|
return new WrappedBrigadierParser<C, Object>(inst).map((ctx, result) -> {
|
||||||
|
if (result instanceof Predicate) {
|
||||||
|
// 1.19+
|
||||||
|
return ArgumentParseResult.success(new BlockPredicateImpl((Predicate<Object>) result));
|
||||||
|
}
|
||||||
final Object commandSourceStack = ctx.get(WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER);
|
final Object commandSourceStack = ctx.get(WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER);
|
||||||
try {
|
try {
|
||||||
final Object server = GET_SERVER_METHOD.invoke(commandSourceStack);
|
final Object server = GET_SERVER_METHOD.invoke(commandSourceStack);
|
||||||
final Object tagRegistry;
|
final Object obj;
|
||||||
if (GET_TAG_REGISTRY_METHOD != null) {
|
if (GET_TAG_REGISTRY_METHOD != null) {
|
||||||
tagRegistry = GET_TAG_REGISTRY_METHOD.invoke(server);
|
obj = GET_TAG_REGISTRY_METHOD.invoke(server);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(REGISTRY_GET, "REGISTRY_GET");
|
obj = RegistryReflection.registryByName("block");
|
||||||
Objects.requireNonNull(REGISTRY_REGISTRY, "REGISTRY_REGISTRY");
|
|
||||||
final Object registryRegistry = REGISTRY_REGISTRY.get(null);
|
|
||||||
tagRegistry = REGISTRY_GET.invoke(registryRegistry, BLOCK_REGISTRY_RESOURCE_LOCATION);
|
|
||||||
}
|
}
|
||||||
final Predicate<Object> predicate = (Predicate<Object>) CREATE_PREDICATE_METHOD.invoke(result, tagRegistry);
|
Objects.requireNonNull(CREATE_PREDICATE_METHOD, "create on BlockPredicateArgument$Result");
|
||||||
|
final Predicate<Object> predicate = (Predicate<Object>) CREATE_PREDICATE_METHOD.invoke(result, obj);
|
||||||
return ArgumentParseResult.success(new BlockPredicateImpl(predicate));
|
return ArgumentParseResult.success(new BlockPredicateImpl(predicate));
|
||||||
} catch (final ReflectiveOperationException ex) {
|
} catch (final ReflectiveOperationException ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,13 @@ import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
||||||
import cloud.commandframework.bukkit.BukkitCommandManager;
|
import cloud.commandframework.bukkit.BukkitCommandManager;
|
||||||
import cloud.commandframework.bukkit.data.ProtoItemStack;
|
import cloud.commandframework.bukkit.data.ProtoItemStack;
|
||||||
|
import cloud.commandframework.bukkit.internal.CommandBuildContextSupplier;
|
||||||
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
|
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
|
||||||
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
@ -228,6 +230,10 @@ public final class ItemStackArgument<C> extends CommandArgument<C, ProtoItemStac
|
||||||
CraftBukkitReflection.findField(ITEM_INPUT_CLASS, "c"),
|
CraftBukkitReflection.findField(ITEM_INPUT_CLASS, "c"),
|
||||||
CraftBukkitReflection.findField(ITEM_INPUT_CLASS, "tag")
|
CraftBukkitReflection.findField(ITEM_INPUT_CLASS, "tag")
|
||||||
);
|
);
|
||||||
|
private static final Class<?> HOLDER_CLASS = CraftBukkitReflection.findMCClass("core.Holder");
|
||||||
|
private static final @Nullable Method VALUE_METHOD = HOLDER_CLASS == null
|
||||||
|
? null
|
||||||
|
: CraftBukkitReflection.needMethod(HOLDER_CLASS, "value");
|
||||||
|
|
||||||
private final ArgumentParser<C, ProtoItemStack> parser;
|
private final ArgumentParser<C, ProtoItemStack> parser;
|
||||||
|
|
||||||
|
|
@ -241,9 +247,16 @@ public final class ItemStackArgument<C> extends CommandArgument<C, ProtoItemStac
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private ArgumentParser<C, ProtoItemStack> createParser() throws ReflectiveOperationException {
|
private ArgumentParser<C, ProtoItemStack> createParser() throws ReflectiveOperationException {
|
||||||
return new WrappedBrigadierParser<C, Object>(
|
final Constructor<?> ctr = ARGUMENT_ITEM_STACK_CLASS.getDeclaredConstructors()[0];
|
||||||
(ArgumentType<Object>) ARGUMENT_ITEM_STACK_CLASS.getConstructor().newInstance()
|
final ArgumentType<Object> inst;
|
||||||
).map((ctx, itemInput) -> ArgumentParseResult.success(new ModernProtoItemStack(itemInput)));
|
if (ctr.getParameterCount() == 0) {
|
||||||
|
inst = (ArgumentType<Object>) ctr.newInstance();
|
||||||
|
} else {
|
||||||
|
// 1.19+
|
||||||
|
inst = (ArgumentType<Object>) ctr.newInstance(CommandBuildContextSupplier.commandBuildContext());
|
||||||
|
}
|
||||||
|
return new WrappedBrigadierParser<C, Object>(inst)
|
||||||
|
.map((ctx, itemInput) -> ArgumentParseResult.success(new ModernProtoItemStack(itemInput)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -272,7 +285,11 @@ public final class ItemStackArgument<C> extends CommandArgument<C, ProtoItemStac
|
||||||
ModernProtoItemStack(final @NonNull Object itemInput) {
|
ModernProtoItemStack(final @NonNull Object itemInput) {
|
||||||
this.itemInput = itemInput;
|
this.itemInput = itemInput;
|
||||||
try {
|
try {
|
||||||
this.material = (Material) GET_MATERIAL_METHOD.invoke(null, ITEM_FIELD.get(itemInput));
|
Object item = ITEM_FIELD.get(itemInput);
|
||||||
|
if (HOLDER_CLASS != null && HOLDER_CLASS.isInstance(item)) {
|
||||||
|
item = VALUE_METHOD.invoke(item);
|
||||||
|
}
|
||||||
|
this.material = (Material) GET_MATERIAL_METHOD.invoke(null, item);
|
||||||
final Object compoundTag = COMPOUND_TAG_FIELD.get(itemInput);
|
final Object compoundTag = COMPOUND_TAG_FIELD.get(itemInput);
|
||||||
if (compoundTag != null) {
|
if (compoundTag != null) {
|
||||||
this.snbt = compoundTag.toString();
|
this.snbt = compoundTag.toString();
|
||||||
|
|
|
||||||
|
|
@ -30,15 +30,18 @@ import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
||||||
import cloud.commandframework.bukkit.BukkitCommandManager;
|
import cloud.commandframework.bukkit.BukkitCommandManager;
|
||||||
import cloud.commandframework.bukkit.data.ItemStackPredicate;
|
import cloud.commandframework.bukkit.data.ItemStackPredicate;
|
||||||
|
import cloud.commandframework.bukkit.internal.CommandBuildContextSupplier;
|
||||||
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
|
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
|
||||||
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
import cloud.commandframework.bukkit.internal.MinecraftArgumentTypes;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
import com.mojang.brigadier.context.StringRange;
|
import com.mojang.brigadier.context.StringRange;
|
||||||
import io.leangen.geantyref.TypeToken;
|
import io.leangen.geantyref.TypeToken;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
@ -151,8 +154,7 @@ public final class ItemStackPredicateArgument<C> extends CommandArgument<C, Item
|
||||||
CraftBukkitReflection.findMCClass("commands.arguments.item.ArgumentItemPredicate$b"),
|
CraftBukkitReflection.findMCClass("commands.arguments.item.ArgumentItemPredicate$b"),
|
||||||
CraftBukkitReflection.findMCClass("commands.arguments.item.ItemPredicateArgument$Result")
|
CraftBukkitReflection.findMCClass("commands.arguments.item.ItemPredicateArgument$Result")
|
||||||
);
|
);
|
||||||
private static final Method CREATE_PREDICATE_METHOD = CraftBukkitReflection.firstNonNullOrThrow(
|
private static final @Nullable Method CREATE_PREDICATE_METHOD = CraftBukkitReflection.firstNonNullOrNull(
|
||||||
() -> "ItemPredicateArgument$Result#create",
|
|
||||||
CraftBukkitReflection.findMethod(
|
CraftBukkitReflection.findMethod(
|
||||||
ARGUMENT_ITEM_PREDICATE_RESULT_CLASS,
|
ARGUMENT_ITEM_PREDICATE_RESULT_CLASS,
|
||||||
"create",
|
"create",
|
||||||
|
|
@ -184,11 +186,22 @@ public final class ItemStackPredicateArgument<C> extends CommandArgument<C, Item
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private ArgumentParser<C, ItemStackPredicate> createParser() throws ReflectiveOperationException {
|
private ArgumentParser<C, ItemStackPredicate> createParser() throws ReflectiveOperationException {
|
||||||
return new WrappedBrigadierParser<C, Object>(
|
final Constructor<?> ctr = ARGUMENT_ITEM_PREDICATE_CLASS.getDeclaredConstructors()[0];
|
||||||
(ArgumentType<Object>) ARGUMENT_ITEM_PREDICATE_CLASS.getConstructor().newInstance()
|
final ArgumentType<Object> inst;
|
||||||
).map((ctx, result) -> {
|
if (ctr.getParameterCount() == 0) {
|
||||||
|
inst = (ArgumentType<Object>) ctr.newInstance();
|
||||||
|
} else {
|
||||||
|
// 1.19+
|
||||||
|
inst = (ArgumentType<Object>) ctr.newInstance(CommandBuildContextSupplier.commandBuildContext());
|
||||||
|
}
|
||||||
|
return new WrappedBrigadierParser<C, Object>(inst).map((ctx, result) -> {
|
||||||
|
if (result instanceof Predicate) {
|
||||||
|
// 1.19+
|
||||||
|
return ArgumentParseResult.success(new ItemStackPredicateImpl((Predicate<Object>) result));
|
||||||
|
}
|
||||||
final Object commandSourceStack = ctx.get(WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER);
|
final Object commandSourceStack = ctx.get(WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER);
|
||||||
final com.mojang.brigadier.context.CommandContext<Object> dummy = createDummyContext(ctx, commandSourceStack);
|
final com.mojang.brigadier.context.CommandContext<Object> dummy = createDummyContext(ctx, commandSourceStack);
|
||||||
|
Objects.requireNonNull(CREATE_PREDICATE_METHOD, "ItemPredicateArgument$Result#create");
|
||||||
try {
|
try {
|
||||||
final Predicate<Object> predicate = (Predicate<Object>) CREATE_PREDICATE_METHOD.invoke(result, dummy);
|
final Predicate<Object> predicate = (Predicate<Object>) CREATE_PREDICATE_METHOD.invoke(result, dummy);
|
||||||
return ArgumentParseResult.success(new ItemStackPredicateImpl(predicate));
|
return ArgumentParseResult.success(new ItemStackPredicateImpl(predicate));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue