Update CraftBukkit reflection for 1.18
This commit is contained in:
parent
9dc4e87fa8
commit
66c803852c
6 changed files with 162 additions and 59 deletions
|
|
@ -32,7 +32,9 @@ import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for doing reflection on CraftBukkit, used by the cloud implementation.
|
* Utilities for doing reflection on CraftBukkit, used by the cloud implementation.
|
||||||
|
|
@ -65,8 +67,7 @@ public final class CraftBukkitReflection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
public static <T> @NonNull T firstNonNullOrThrow(
|
public static <T> @Nullable T firstNonNullOrNull(
|
||||||
final @NonNull Supplier<@NonNull String> errorMessage,
|
|
||||||
final @Nullable T @NonNull... elements
|
final @Nullable T @NonNull... elements
|
||||||
) {
|
) {
|
||||||
for (final T element : elements) {
|
for (final T element : elements) {
|
||||||
|
|
@ -74,8 +75,21 @@ public final class CraftBukkitReflection {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
@SuppressWarnings("varargs")
|
||||||
|
public static <T> @NonNull T firstNonNullOrThrow(
|
||||||
|
final @NonNull Supplier<@NonNull String> errorMessage,
|
||||||
|
final @Nullable T @NonNull... elements
|
||||||
|
) {
|
||||||
|
final @Nullable T t = firstNonNullOrNull(elements);
|
||||||
|
if (t == null) {
|
||||||
throw new IllegalArgumentException(errorMessage.get());
|
throw new IllegalArgumentException(errorMessage.get());
|
||||||
}
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
public static @NonNull Class<?> needNMSClassOrElse(
|
public static @NonNull Class<?> needNMSClassOrElse(
|
||||||
final @NonNull String nms,
|
final @NonNull String nms,
|
||||||
|
|
@ -191,6 +205,13 @@ public final class CraftBukkitReflection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T streamMethods(
|
||||||
|
final @NonNull Class<?> clazz,
|
||||||
|
final @NonNull Function<Stream<Method>, T> function
|
||||||
|
) {
|
||||||
|
return function.apply(Arrays.stream(clazz.getDeclaredMethods()));
|
||||||
|
}
|
||||||
|
|
||||||
private CraftBukkitReflection() {
|
private CraftBukkitReflection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -193,19 +193,32 @@ public final class BlockPredicateArgument<C> extends CommandArgument<C, BlockPre
|
||||||
CraftBukkitReflection.findMCClass("core.BlockPosition"),
|
CraftBukkitReflection.findMCClass("core.BlockPosition"),
|
||||||
CraftBukkitReflection.findMCClass("core.BlockPos")
|
CraftBukkitReflection.findMCClass("core.BlockPos")
|
||||||
);
|
);
|
||||||
|
private static final @Nullable Class<?> TAG_CONTAINER_CLASS = CraftBukkitReflection.firstNonNullOrNull(
|
||||||
|
CraftBukkitReflection.findClass("net.minecraft.tags.TagContainer"),
|
||||||
|
CraftBukkitReflection.findClass("net.minecraft.tags.ITagRegistry")
|
||||||
|
);
|
||||||
private static final Constructor<?> BLOCK_POSITION_CTR =
|
private static final Constructor<?> BLOCK_POSITION_CTR =
|
||||||
CraftBukkitReflection.needConstructor(BLOCK_POSITION_CLASS, int.class, int.class, int.class);
|
CraftBukkitReflection.needConstructor(BLOCK_POSITION_CLASS, int.class, int.class, int.class);
|
||||||
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 =
|
private static final Method CREATE_PREDICATE_METHOD = CraftBukkitReflection.firstNonNullOrThrow(
|
||||||
CraftBukkitReflection.needMethod(ARGUMENT_BLOCK_PREDICATE_RESULT_CLASS, "create", TAG_REGISTRY_CLASS);
|
() -> "create on BlockPredicateArgument$Result",
|
||||||
private static final Method GET_SERVER_METHOD =
|
CraftBukkitReflection.findMethod(ARGUMENT_BLOCK_PREDICATE_RESULT_CLASS, "create", TAG_REGISTRY_CLASS),
|
||||||
CraftBukkitReflection.needMethod(COMMAND_LISTENER_WRAPPER_CLASS, "getServer");
|
CraftBukkitReflection.findMethod(ARGUMENT_BLOCK_PREDICATE_RESULT_CLASS, "a", TAG_REGISTRY_CLASS)
|
||||||
|
);
|
||||||
|
private static final Method GET_SERVER_METHOD = CraftBukkitReflection.streamMethods(
|
||||||
|
COMMAND_LISTENER_WRAPPER_CLASS,
|
||||||
|
stream -> stream.filter(it -> it.getReturnType().equals(MINECRAFT_SERVER_CLASS) && it.getParameterCount() == 0)
|
||||||
|
.findFirst().orElseThrow(() -> new IllegalStateException("Could not find CommandSourceStack#getServer."))
|
||||||
|
);
|
||||||
private static final Method GET_TAG_REGISTRY_METHOD = CraftBukkitReflection.firstNonNullOrThrow(
|
private static final Method GET_TAG_REGISTRY_METHOD = CraftBukkitReflection.firstNonNullOrThrow(
|
||||||
() -> "getTags method on MinecraftServer",
|
() -> "getTags method on MinecraftServer",
|
||||||
CraftBukkitReflection.findMethod(MINECRAFT_SERVER_CLASS, "getTagRegistry"),
|
CraftBukkitReflection.findMethod(MINECRAFT_SERVER_CLASS, "getTagRegistry"),
|
||||||
CraftBukkitReflection.findMethod(MINECRAFT_SERVER_CLASS, "getTags")
|
CraftBukkitReflection.findMethod(MINECRAFT_SERVER_CLASS, "getTags"),
|
||||||
|
TAG_CONTAINER_CLASS == null ? null : CraftBukkitReflection.streamMethods(MINECRAFT_SERVER_CLASS, stream ->
|
||||||
|
stream.filter(it -> it.getReturnType().equals(TAG_CONTAINER_CLASS) && it.getParameterCount() == 0)
|
||||||
|
.findFirst().orElse(null))
|
||||||
);
|
);
|
||||||
|
|
||||||
private final ArgumentParser<C, BlockPredicate> parser;
|
private final ArgumentParser<C, BlockPredicate> parser;
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,18 @@ 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.needMethod(
|
private static final Method CREATE_PREDICATE_METHOD = CraftBukkitReflection.firstNonNullOrThrow(
|
||||||
|
() -> "ItemPredicateArgument$Result#create",
|
||||||
|
CraftBukkitReflection.findMethod(
|
||||||
ARGUMENT_ITEM_PREDICATE_RESULT_CLASS,
|
ARGUMENT_ITEM_PREDICATE_RESULT_CLASS,
|
||||||
"create",
|
"create",
|
||||||
com.mojang.brigadier.context.CommandContext.class
|
com.mojang.brigadier.context.CommandContext.class
|
||||||
|
),
|
||||||
|
CraftBukkitReflection.findMethod(
|
||||||
|
ARGUMENT_ITEM_PREDICATE_RESULT_CLASS,
|
||||||
|
"a",
|
||||||
|
com.mojang.brigadier.context.CommandContext.class
|
||||||
|
)
|
||||||
);
|
);
|
||||||
private static final Method AS_NMS_COPY_METHOD =
|
private static final Method AS_NMS_COPY_METHOD =
|
||||||
CraftBukkitReflection.needMethod(CRAFT_ITEM_STACK_CLASS, "asNMSCopy", ItemStack.class);
|
CraftBukkitReflection.needMethod(CRAFT_ITEM_STACK_CLASS, "asNMSCopy", ItemStack.class);
|
||||||
|
|
|
||||||
|
|
@ -33,15 +33,14 @@ tasks {
|
||||||
minecraftVersion("1.17.1")
|
minecraftVersion("1.17.1")
|
||||||
runDirectory(file("run/latest"))
|
runDirectory(file("run/latest"))
|
||||||
javaLauncher.set(project.javaToolchains.launcherFor {
|
javaLauncher.set(project.javaToolchains.launcherFor {
|
||||||
languageVersion.set(JavaLanguageVersion.of(16))
|
languageVersion.set(JavaLanguageVersion.of(17))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup a run task for each supported version
|
// Setup a run task for each supported version
|
||||||
mapOf(
|
mapOf(
|
||||||
setOf("1.8.8", "1.9.4", "1.10.2", "1.11.2", "1.12.2") to 8,
|
setOf("1.8.8", "1.9.4", "1.10.2", "1.11.2") to 11,
|
||||||
setOf("1.13.2", "1.14.4", "1.15.2") to 11,
|
setOf("1.12.2", "1.13.2", "1.14.4", "1.15.2", "1.16.5", "1.17.1") to 17,
|
||||||
setOf("1.16.5", "1.17.1") to 16
|
|
||||||
).forEach { (minecraftVersions, javaVersion) ->
|
).forEach { (minecraftVersions, javaVersion) ->
|
||||||
for (version in minecraftVersions) {
|
for (version in minecraftVersions) {
|
||||||
createVersionedRun(version, javaVersion)
|
createVersionedRun(version, javaVersion)
|
||||||
|
|
@ -57,6 +56,7 @@ fun TaskContainerScope.createVersionedRun(
|
||||||
pluginJars.from(shadowJar.flatMap { it.archiveFile })
|
pluginJars.from(shadowJar.flatMap { it.archiveFile })
|
||||||
minecraftVersion(version)
|
minecraftVersion(version)
|
||||||
runDirectory(file("run/$version"))
|
runDirectory(file("run/$version"))
|
||||||
|
systemProperty("Paper.IgnoreJavaVersion", true)
|
||||||
javaLauncher.set(project.javaToolchains.launcherFor {
|
javaLauncher.set(project.javaToolchains.launcherFor {
|
||||||
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,8 @@ import cloud.commandframework.arguments.standard.StringArrayArgument;
|
||||||
import cloud.commandframework.bukkit.BukkitCommandManager;
|
import cloud.commandframework.bukkit.BukkitCommandManager;
|
||||||
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
|
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
|
||||||
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
|
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
|
||||||
import cloud.commandframework.bukkit.data.ItemStackPredicate;
|
|
||||||
import cloud.commandframework.bukkit.data.ProtoItemStack;
|
import cloud.commandframework.bukkit.data.ProtoItemStack;
|
||||||
import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
|
import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
|
||||||
import cloud.commandframework.bukkit.parsers.ItemStackArgument;
|
|
||||||
import cloud.commandframework.bukkit.parsers.ItemStackPredicateArgument;
|
|
||||||
import cloud.commandframework.bukkit.parsers.MaterialArgument;
|
import cloud.commandframework.bukkit.parsers.MaterialArgument;
|
||||||
import cloud.commandframework.bukkit.parsers.WorldArgument;
|
import cloud.commandframework.bukkit.parsers.WorldArgument;
|
||||||
import cloud.commandframework.bukkit.parsers.selector.SingleEntitySelectorArgument;
|
import cloud.commandframework.bukkit.parsers.selector.SingleEntitySelectorArgument;
|
||||||
|
|
@ -383,47 +380,9 @@ public final class ExamplePlugin extends JavaPlugin {
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
|
|
||||||
// MC 1.13+ commands todo: move to separate class
|
// Commands using MC 1.13+ argument types
|
||||||
if (this.manager.queryCapability(CloudBukkitCapabilities.BRIGADIER)) {
|
if (this.manager.queryCapability(CloudBukkitCapabilities.BRIGADIER)) {
|
||||||
/*
|
new Mc113(this.manager).registerCommands();
|
||||||
this.manager.command(builder.literal("replace")
|
|
||||||
.senderType(Player.class)
|
|
||||||
.argument(BlockPredicateArgument.of("predicate"))
|
|
||||||
.literal("with")
|
|
||||||
.argument(MaterialArgument.of("block")) // todo: use BlockDataArgument
|
|
||||||
.argument(IntegerArgument.<CommandSender>newBuilder("radius").withMin(1))
|
|
||||||
.handler(ctx -> {
|
|
||||||
final BlockData block = ctx.<Material>get("block").createBlockData();
|
|
||||||
final BlockPredicate predicate = ctx.get("predicate");
|
|
||||||
final int radius = ctx.get("radius");
|
|
||||||
|
|
||||||
final Player player = (Player) ctx.getSender();
|
|
||||||
final Location loc = player.getLocation();
|
|
||||||
|
|
||||||
this.manager.taskRecipe().begin(ctx).synchronous(context -> {
|
|
||||||
for (double x = loc.getX() - radius; x < loc.getX() + radius; x++) {
|
|
||||||
for (double y = loc.getY() - radius; y < loc.getY() + radius; y++) {
|
|
||||||
for (double z = loc.getZ() - radius; z < loc.getZ() + radius; z++) {
|
|
||||||
final Block blockAt = player.getWorld().getBlockAt((int) x, (int) y, (int) z);
|
|
||||||
if (predicate.test(blockAt)) {
|
|
||||||
blockAt.setBlockData(block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).execute();
|
|
||||||
}));
|
|
||||||
*/
|
|
||||||
this.manager.command(builder.literal("test_item")
|
|
||||||
.argument(ItemStackArgument.of("item"))
|
|
||||||
.literal("is")
|
|
||||||
.argument(ItemStackPredicateArgument.of("predicate"))
|
|
||||||
.handler(ctx -> {
|
|
||||||
final ProtoItemStack protoItemStack = ctx.get("item");
|
|
||||||
final ItemStackPredicate predicate = ctx.get("predicate");
|
|
||||||
ctx.getSender().sendMessage("result: " + predicate.test(
|
|
||||||
protoItemStack.createItemStack(1, true)));
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
//
|
||||||
|
// 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.examples.bukkit;
|
||||||
|
|
||||||
|
import cloud.commandframework.Command;
|
||||||
|
import cloud.commandframework.arguments.standard.IntegerArgument;
|
||||||
|
import cloud.commandframework.bukkit.BukkitCommandManager;
|
||||||
|
import cloud.commandframework.bukkit.data.BlockPredicate;
|
||||||
|
import cloud.commandframework.bukkit.data.ItemStackPredicate;
|
||||||
|
import cloud.commandframework.bukkit.data.ProtoItemStack;
|
||||||
|
import cloud.commandframework.bukkit.parsers.BlockPredicateArgument;
|
||||||
|
import cloud.commandframework.bukkit.parsers.ItemStackArgument;
|
||||||
|
import cloud.commandframework.bukkit.parsers.ItemStackPredicateArgument;
|
||||||
|
import cloud.commandframework.bukkit.parsers.MaterialArgument;
|
||||||
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||||
|
|
||||||
|
@DefaultQualifier(NonNull.class)
|
||||||
|
final class Mc113 {
|
||||||
|
private final BukkitCommandManager<CommandSender> manager;
|
||||||
|
|
||||||
|
Mc113(final BukkitCommandManager<CommandSender> manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerCommands() {
|
||||||
|
final Command.Builder<CommandSender> builder = this.manager.commandBuilder("example")
|
||||||
|
.literal("mc113");
|
||||||
|
|
||||||
|
this.manager.command(builder.literal("replace")
|
||||||
|
.senderType(Player.class)
|
||||||
|
.argument(BlockPredicateArgument.of("predicate"))
|
||||||
|
.literal("with")
|
||||||
|
.argument(MaterialArgument.of("block")) // todo: use BlockDataArgument
|
||||||
|
.argument(IntegerArgument.<CommandSender>newBuilder("radius").withMin(1))
|
||||||
|
.handler(this::executeReplace));
|
||||||
|
|
||||||
|
this.manager.command(builder.literal("test_item")
|
||||||
|
.argument(ItemStackArgument.of("item"))
|
||||||
|
.literal("is")
|
||||||
|
.argument(ItemStackPredicateArgument.of("predicate"))
|
||||||
|
.handler(Mc113::executeTestItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeReplace(final CommandContext<CommandSender> ctx) {
|
||||||
|
final BlockData block = ctx.<Material>get("block").createBlockData();
|
||||||
|
final BlockPredicate predicate = ctx.get("predicate");
|
||||||
|
final int radius = ctx.get("radius");
|
||||||
|
|
||||||
|
final Player player = (Player) ctx.getSender();
|
||||||
|
final Location loc = player.getLocation();
|
||||||
|
|
||||||
|
this.manager.taskRecipe().begin(ctx).synchronous(context -> {
|
||||||
|
for (double x = loc.getX() - radius; x < loc.getX() + radius; x++) {
|
||||||
|
for (double y = loc.getY() - radius; y < loc.getY() + radius; y++) {
|
||||||
|
for (double z = loc.getZ() - radius; z < loc.getZ() + radius; z++) {
|
||||||
|
final Block blockAt = player.getWorld().getBlockAt((int) x, (int) y, (int) z);
|
||||||
|
if (predicate.test(blockAt)) {
|
||||||
|
blockAt.setBlockData(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void executeTestItem(final CommandContext<CommandSender> ctx) {
|
||||||
|
final ProtoItemStack protoItemStack = ctx.get("item");
|
||||||
|
final ItemStackPredicate predicate = ctx.get("predicate");
|
||||||
|
ctx.getSender().sendMessage("result: " + predicate.test(
|
||||||
|
protoItemStack.createItemStack(1, true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue