From 4dd9bae1811775fe75168a2facfdb7e0119f0f24 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Fri, 1 Oct 2021 16:14:23 -0700 Subject: [PATCH] Expose minecraft brigadier argument types --- .../brigadier/MinecraftArgumentType.java | 71 +++++ .../brigadier/arguments/SimpleArgument.java | 60 ++++ .../brigadier/types/GameProfileResult.java | 14 + .../paper/brigadier/types/Position.java | 23 ++ build-data/paper.at | 5 + ...e-minecraft-brigadier-argument-types.patch | 276 ++++++++++++++++++ 6 files changed, 449 insertions(+) create mode 100644 Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/MinecraftArgumentType.java create mode 100644 Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/arguments/SimpleArgument.java create mode 100644 Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/GameProfileResult.java create mode 100644 Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/Position.java create mode 100644 patches/server/0814-Expose-minecraft-brigadier-argument-types.patch diff --git a/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/MinecraftArgumentType.java b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/MinecraftArgumentType.java new file mode 100644 index 000000000000..4555f7de4a73 --- /dev/null +++ b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/MinecraftArgumentType.java @@ -0,0 +1,71 @@ +package io.papermc.paper.brigadier; + +import com.mojang.brigadier.arguments.ArgumentType; +import io.papermc.paper.brigadier.arguments.SimpleArgument; +import io.papermc.paper.brigadier.types.GameProfileResult; +import io.papermc.paper.brigadier.types.Position; +import net.kyori.adventure.nbt.api.BinaryTagHolder; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.EntityType; +import org.bukkit.potion.PotionEffectType; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +public abstract class MinecraftArgumentType implements Keyed { + + protected static final Map ARGUMENT_TYPE_MAP = new HashMap<>(); + + public static final SimpleArgument GAME_PROFILES = SimpleArgument.wrapper("game_profile", GameProfileResult.class); + + public static final SimpleArgument BLOCK_POSITION = SimpleArgument.wrapper("block_pos", Position.class); + + public static final SimpleArgument VEC3 = SimpleArgument.wrapper("vec3", Position.class); + + public static final SimpleArgument VEC2 = SimpleArgument.wrapper("vec2", Position.class); + + + + public static final SimpleArgument COLOR = SimpleArgument.wrapper("color", TextColor.class); + + + + public static final SimpleArgument COMPONENT = SimpleArgument.wrapper("component", Component.class); + + public static final SimpleArgument NBT_COMPOUND_TAG = SimpleArgument.wrapper("nbt_compound_tag", BinaryTagHolder.class); + + + + public static final SimpleArgument INVENTORY_SLOT = SimpleArgument.wrapper("item_slot", Integer.class); + + public static final SimpleArgument RESOURCE_LOCATION = SimpleArgument.wrapper("resource_location", NamespacedKey.class); + + public static final SimpleArgument MOB_EFFECT = SimpleArgument.wrapper("mob_effect", PotionEffectType.class); + + + + public static final SimpleArgument ENCHANTMENT = SimpleArgument.wrapper("item_enchantment", Enchantment.class); + + public static final SimpleArgument ENTITY_TYPE = SimpleArgument.wrapper("entity_summon", EntityType.class); + + + + public static final SimpleArgument ROTATION = SimpleArgument.wrapper("rotation", Position.class); + + + private final NamespacedKey key; + + protected MinecraftArgumentType(@NotNull String id) { + this.key = NamespacedKey.minecraft(id); + } + + @Override + public @NotNull NamespacedKey getKey() { + return this.key; + } +} diff --git a/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/arguments/SimpleArgument.java b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/arguments/SimpleArgument.java new file mode 100644 index 000000000000..f70b4d67a7ae --- /dev/null +++ b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/arguments/SimpleArgument.java @@ -0,0 +1,60 @@ +package io.papermc.paper.brigadier.arguments; + +import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.brigadier.MinecraftArgumentType; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.NotNull; + +public abstract class SimpleArgument

extends MinecraftArgumentType { + + private final Class

paperType; + + protected SimpleArgument(String id, Class

paperType) { + super(id); + this.paperType = paperType; + } + + public abstract ArgumentType

create(); + + public abstract P getFromContext(@NotNull CommandContext context, @NotNull String name); + + public @NotNull Class

getPaperType() { + return paperType; + } + + public static

Wrapper

wrapper(@NotNull String id, Class

paperType) { + return new Wrapper<>(id, paperType); + } + + public static class Wrapper

extends SimpleArgument

{ + + private SimpleArgument

delegate; + + private Wrapper(String id, Class

paperType) { + super(id, paperType); + } + + @Override + public ArgumentType

create() { + checkDelegate(); + return this.delegate.create(); + } + + @Override + public P getFromContext(@NotNull CommandContext context, @NotNull String name) { + checkDelegate(); + return this.delegate.getFromContext(context, name); + } + + private void checkDelegate() { + if (this.delegate == null) { + this.delegate = (SimpleArgument

) ARGUMENT_TYPE_MAP.get(this.getKey()); + if (this.delegate == null) { + throw new IllegalStateException("delegate was null for " + this.getKey()); + } + } + } + } +} diff --git a/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/GameProfileResult.java b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/GameProfileResult.java new file mode 100644 index 000000000000..48a13a89f1bc --- /dev/null +++ b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/GameProfileResult.java @@ -0,0 +1,14 @@ +package io.papermc.paper.brigadier.types; + +import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; +import com.destroystokyo.paper.profile.PlayerProfile; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +public interface GameProfileResult { + + @NotNull Collection getProfiles(@NotNull C source) throws CommandSyntaxException; +} + diff --git a/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/Position.java b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/Position.java new file mode 100644 index 000000000000..7c8d9a9fc8aa --- /dev/null +++ b/Paper-MojangAPI/src/main/java/io/papermc/paper/brigadier/types/Position.java @@ -0,0 +1,23 @@ +package io.papermc.paper.brigadier.types; + +import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; +import org.bukkit.Location; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +public interface Position { + + @NotNull Vector getPositionVector(@NotNull C source); + + float getXRot(@NotNull C source); + + float getYRot(@NotNull C source); + + @NotNull Location getLocation(@NotNull C source); + + boolean isXRelative(); + + boolean isYRelative(); + + boolean isZRelative(); +} diff --git a/build-data/paper.at b/build-data/paper.at index e924e5b0fd40..568618cc4d9e 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -241,3 +241,8 @@ public-f com.mojang.brigadier.tree.CommandNode requirement # Block Enderpearl Travel Exploit public net.minecraft.world.entity.projectile.Projectile cachedOwner public net.minecraft.world.entity.projectile.Projectile ownerUUID + +# Expose more conversions +public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations +public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations toBukkitSlot(I)Lorg/bukkit/scoreboard/DisplaySlot; +public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations fromBukkitSlot(Lorg/bukkit/scoreboard/DisplaySlot;)I diff --git a/patches/server/0814-Expose-minecraft-brigadier-argument-types.patch b/patches/server/0814-Expose-minecraft-brigadier-argument-types.patch new file mode 100644 index 000000000000..18b1691ef63a --- /dev/null +++ b/patches/server/0814-Expose-minecraft-brigadier-argument-types.patch @@ -0,0 +1,276 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 1 Oct 2021 16:13:15 -0700 +Subject: [PATCH] Expose minecraft brigadier argument types + + +diff --git a/src/main/java/io/papermc/paper/brigadier/MinecraftArgumentTypes.java b/src/main/java/io/papermc/paper/brigadier/MinecraftArgumentTypes.java +new file mode 100644 +index 0000000000000000000000000000000000000000..299379bc58c885033f4e7413694768687684eacd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/brigadier/MinecraftArgumentTypes.java +@@ -0,0 +1,88 @@ ++package io.papermc.paper.brigadier; ++ ++import com.mojang.brigadier.arguments.ArgumentType; ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.brigadier.arguments.PaperInheritanceArgument; ++import io.papermc.paper.brigadier.arguments.PaperMappedArgument; ++import io.papermc.paper.brigadier.types.GameProfileResult; ++import io.papermc.paper.brigadier.types.Position; ++import net.kyori.adventure.nbt.api.BinaryTagHolder; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.format.TextColor; ++import net.minecraft.commands.arguments.ColorArgument; ++import net.minecraft.commands.arguments.ComponentArgument; ++import net.minecraft.commands.arguments.CompoundTagArgument; ++import net.minecraft.commands.arguments.EntitySummonArgument; ++import net.minecraft.commands.arguments.GameProfileArgument; ++import net.minecraft.commands.arguments.ItemEnchantmentArgument; ++import net.minecraft.commands.arguments.MobEffectArgument; ++import net.minecraft.commands.arguments.ResourceLocationArgument; ++import net.minecraft.commands.arguments.ScoreboardSlotArgument; ++import net.minecraft.commands.arguments.SlotArgument; ++import net.minecraft.commands.arguments.TimeArgument; ++import net.minecraft.commands.arguments.UuidArgument; ++import net.minecraft.commands.arguments.coordinates.BlockPosArgument; ++import net.minecraft.commands.arguments.coordinates.Coordinates; ++import net.minecraft.commands.arguments.coordinates.RotationArgument; ++import net.minecraft.commands.arguments.coordinates.Vec2Argument; ++import net.minecraft.commands.arguments.coordinates.Vec3Argument; ++import net.minecraft.world.effect.MobEffect; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.enchantments.Enchantment; ++import org.bukkit.entity.EntityType; ++import org.bukkit.potion.PotionEffectType; ++import org.bukkit.scoreboard.DisplaySlot; ++ ++import java.util.UUID; ++import java.util.function.Function; ++import java.util.function.Supplier; ++ ++public final class MinecraftArgumentTypes { ++ ++ private MinecraftArgumentTypes() { ++ } ++ ++ public static void bootStrap() { ++ inherited("game_profile", GameProfileArgument::gameProfile, GameProfileResult.class, GameProfileArgument.Result.class); ++ inherited("block_pos", BlockPosArgument::blockPos, Position.class, Coordinates.class); ++ inherited("vec3", Vec3Argument::vec3, Position.class, Coordinates.class); ++ inherited("vec2", Vec2Argument::vec2, Position.class, Coordinates.class); ++ ++ mapped("color", ColorArgument::color, TextColor.class, PaperAdventure::asAdventure); ++ ++ mapped("component", ComponentArgument::textComponent, Component.class, PaperAdventure::asAdventure); ++ mapped("nbt_compound_tag", CompoundTagArgument::compoundTag, BinaryTagHolder.class, PaperAdventure::asBinaryTagHolder); ++ ++ inherited("rotation", RotationArgument::rotation, Position.class, Coordinates.class); ++ mapped("scoreboard_slot", ScoreboardSlotArgument::displaySlot, DisplaySlot.class, CraftScoreboardTranslations::toBukkitSlot); ++ ++ simple("item_slot", SlotArgument::slot, Integer.class); ++ mapped("resource_location", ResourceLocationArgument::id, NamespacedKey.class, CraftNamespacedKey::fromMinecraft); ++ mapped("mob_effect", MobEffectArgument::effect, PotionEffectType.class, mobEffect -> PotionEffectType.getById(MobEffect.getId(mobEffect))); ++ ++ mapped("item_enchantment", ItemEnchantmentArgument::enchantment, Enchantment.class, ench -> Registry.ENCHANTMENT.get(CraftNamespacedKey.fromMinecraft(net.minecraft.core.Registry.ENCHANTMENT.getKey(ench)))); ++ mapped("entity_summon", EntitySummonArgument::id, EntityType.class, location -> Registry.ENTITY_TYPE.get(CraftNamespacedKey.fromMinecraft(location))); ++ ++ simple("time", TimeArgument::time, Integer.class); ++ simple("uuid", UuidArgument::uuid, UUID.class); ++ } ++ ++ private static void simple(String id, Supplier> argumentTypeSupplier, Class type) { ++ inherited(id, argumentTypeSupplier, type, type); ++ } ++ ++ private static void inherited(String id, Supplier> argumentTypeSupplier, Class

paperType, Class minecraftClass) { ++ register(new PaperInheritanceArgument<>(id, paperType, argumentTypeSupplier, minecraftClass)); ++ } ++ ++ private static void mapped(String id, Supplier> argumentTypeSupplier, Class

paperType, Function mapper) { ++ register(new PaperMappedArgument<>(id, paperType, argumentTypeSupplier, mapper)); ++ } ++ ++ private static void register(MinecraftArgumentType argumentType) { ++ MinecraftArgumentType.ARGUMENT_TYPE_MAP.put(argumentType.getKey(), argumentType); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/brigadier/arguments/PaperInheritanceArgument.java b/src/main/java/io/papermc/paper/brigadier/arguments/PaperInheritanceArgument.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dc78affb694405a399e63ee6a98ea122ef826e00 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/brigadier/arguments/PaperInheritanceArgument.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.brigadier.arguments; ++ ++import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; ++import com.mojang.brigadier.arguments.ArgumentType; ++import com.mojang.brigadier.context.CommandContext; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.function.Supplier; ++ ++public class PaperInheritanceArgument extends SimpleArgument

{ ++ ++ private final Supplier> supplier; ++ private final Class minecraftClass; ++ ++ public PaperInheritanceArgument(String id, Class

paperType, Supplier> supplier, Class minecraftClass) { ++ super(id, paperType); ++ this.supplier = supplier; ++ this.minecraftClass = minecraftClass; ++ } ++ ++ @Override ++ public ArgumentType

create() { ++ return (ArgumentType

) this.supplier.get(); ++ } ++ ++ @Override ++ public P getFromContext(@NotNull CommandContext context, @NotNull String name) { ++ return context.getArgument(name, this.minecraftClass); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/brigadier/arguments/PaperMappedArgument.java b/src/main/java/io/papermc/paper/brigadier/arguments/PaperMappedArgument.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9d1558909481a175a0138c1ca802dcb7ca5c67f5 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/brigadier/arguments/PaperMappedArgument.java +@@ -0,0 +1,63 @@ ++package io.papermc.paper.brigadier.arguments; ++ ++import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; ++import com.mojang.brigadier.StringReader; ++import com.mojang.brigadier.arguments.ArgumentType; ++import com.mojang.brigadier.context.CommandContext; ++import com.mojang.brigadier.exceptions.CommandSyntaxException; ++import com.mojang.brigadier.suggestion.Suggestions; ++import com.mojang.brigadier.suggestion.SuggestionsBuilder; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Collection; ++import java.util.concurrent.CompletableFuture; ++import java.util.function.Function; ++import java.util.function.Supplier; ++ ++public class PaperMappedArgument extends SimpleArgument

{ ++ ++ private final Supplier> supplier; ++ private final Function mapper; ++ ++ public PaperMappedArgument(String id, Class

paperType, Supplier> supplier, Function mapper) { ++ super(id, paperType); ++ this.supplier = supplier; ++ this.mapper = mapper; ++ } ++ ++ @Override ++ public ArgumentType

create() { ++ return new MappedArgumentType<>(supplier.get(), this.mapper); ++ } ++ ++ @Override ++ public P getFromContext(@NotNull CommandContext context, @NotNull String name) { ++ return context.getArgument(name, this.getPaperType()); ++ } ++ ++ private static class MappedArgumentType implements ArgumentType

{ ++ ++ private final ArgumentType delegate; ++ private final Function mapper; ++ ++ private MappedArgumentType(ArgumentType delegate, Function mapper) { ++ this.delegate = delegate; ++ this.mapper = mapper; ++ } ++ ++ @Override ++ public P parse(StringReader reader) throws CommandSyntaxException { ++ return this.mapper.apply(this.delegate.parse(reader)); ++ } ++ ++ @Override ++ public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { ++ return this.delegate.listSuggestions(context, builder); ++ } ++ ++ @Override ++ public Collection getExamples() { ++ return this.delegate.getExamples(); ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/commands/arguments/GameProfileArgument.java b/src/main/java/net/minecraft/commands/arguments/GameProfileArgument.java +index 348f25363d26c9ef2c51572edcc67db603f4c647..f3e7a9f0b96b35fba37acd132bdf2c060e309a60 100644 +--- a/src/main/java/net/minecraft/commands/arguments/GameProfileArgument.java ++++ b/src/main/java/net/minecraft/commands/arguments/GameProfileArgument.java +@@ -85,8 +85,14 @@ public class GameProfileArgument implements ArgumentType { // Paper + Collection getNames(CommandSourceStack commandSourceStack) throws CommandSyntaxException; ++ // Paper start ++ @Override ++ default Collection getProfiles(CommandSourceStack source) throws CommandSyntaxException { ++ return Collections.unmodifiableCollection(com.google.common.collect.Collections2.transform(getNames(source), profile -> new com.destroystokyo.paper.profile.CraftPlayerProfile(profile).clone())); ++ } ++ // Paper end + } + + public static class SelectorResult implements GameProfileArgument.Result { +diff --git a/src/main/java/net/minecraft/commands/arguments/coordinates/Coordinates.java b/src/main/java/net/minecraft/commands/arguments/coordinates/Coordinates.java +index 2be1acce27600988c0795ccef629b531dacfedef..92d0840147907ff9d77b1a5b4efdd64e88e2bd10 100644 +--- a/src/main/java/net/minecraft/commands/arguments/coordinates/Coordinates.java ++++ b/src/main/java/net/minecraft/commands/arguments/coordinates/Coordinates.java +@@ -5,7 +5,7 @@ import net.minecraft.core.BlockPos; + import net.minecraft.world.phys.Vec2; + import net.minecraft.world.phys.Vec3; + +-public interface Coordinates { ++public interface Coordinates extends io.papermc.paper.brigadier.types.Position { // Paper + Vec3 getPosition(CommandSourceStack source); + + Vec2 getRotation(CommandSourceStack source); +@@ -19,4 +19,25 @@ public interface Coordinates { + boolean isYRelative(); + + boolean isZRelative(); ++ // Paper start ++ @Override ++ default org.bukkit.util.Vector getPositionVector(CommandSourceStack source) { ++ return org.bukkit.craftbukkit.util.CraftVector.toBukkit(getPosition(source)); ++ } ++ ++ @Override ++ default org.bukkit.Location getLocation(CommandSourceStack source) { ++ return net.minecraft.server.MCUtil.toLocation(((CommandSourceStack) source).getLevel(), getBlockPos((CommandSourceStack) source)); ++ } ++ ++ @Override ++ default float getXRot(CommandSourceStack source) { ++ return getRotation(source).x; ++ } ++ ++ @Override ++ default float getYRot(CommandSourceStack source) { ++ return getRotation(source).y; ++ } ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java +index 64576ddd8363be55755fa50d1c16d95e4e02402d..b8c7367025d08bc5c56f0a6eff0d9cf2322d0a92 100644 +--- a/src/main/java/net/minecraft/server/Bootstrap.java ++++ b/src/main/java/net/minecraft/server/Bootstrap.java +@@ -72,6 +72,7 @@ public class Bootstrap { + DispenseItemBehavior.bootStrap(); + CauldronInteraction.bootStrap(); + ArgumentTypes.bootStrap(); ++ io.papermc.paper.brigadier.MinecraftArgumentTypes.bootStrap(); // Paper + StaticTags.bootStrap(); + Bootstrap.wrapStreams(); + }