aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1042-Add-experimental-improved-give-command.patch
blob: b7a7ef41c0ff0f2185760e57cbec6487512aea05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 26 Apr 2024 23:15:27 -0700
Subject: [PATCH] Add experimental improved give command

Supports removing data components from itemstacks

diff --git a/src/main/java/net/minecraft/commands/arguments/item/ItemArgument.java b/src/main/java/net/minecraft/commands/arguments/item/ItemArgument.java
index d76296c6d53065aecb010d8ea682c9acd7365f17..9314a94764786982eff0974411f8341bb0353ecf 100644
--- a/src/main/java/net/minecraft/commands/arguments/item/ItemArgument.java
+++ b/src/main/java/net/minecraft/commands/arguments/item/ItemArgument.java
@@ -16,7 +16,12 @@ public class ItemArgument implements ArgumentType<ItemInput> {
     private final ItemParser parser;
 
     public ItemArgument(CommandBuildContext commandRegistryAccess) {
-        this.parser = new ItemParser(commandRegistryAccess);
+        // Paper start - support component removals
+        this(commandRegistryAccess, false);
+    }
+    public ItemArgument(CommandBuildContext commandRegistryAccess, boolean allowRemovals) {
+        this.parser = new ItemParser(commandRegistryAccess, allowRemovals);
+        // Paper end - support component removals
     }
 
     public static ItemArgument item(CommandBuildContext commandRegistryAccess) {
@@ -25,7 +30,7 @@ public class ItemArgument implements ArgumentType<ItemInput> {
 
     public ItemInput parse(StringReader stringReader) throws CommandSyntaxException {
         ItemParser.ItemResult itemResult = this.parser.parse(stringReader);
-        return new ItemInput(itemResult.item(), itemResult.components());
+        return new ItemInput(itemResult.item(), itemResult.components(), itemResult.patch()); // Paper - support component removals
     }
 
     public static <S> ItemInput getItem(CommandContext<S> context, String name) {
diff --git a/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java b/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java
index 3d24fbca90bc7d8bdbac1be2176555c15ae75039..94ea5f0b1913ffa03794d231a6768dd786dc9697 100644
--- a/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java
+++ b/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java
@@ -25,8 +25,15 @@ public class ItemInput {
     );
     private final Holder<Item> item;
     private final DataComponentMap components;
+    @javax.annotation.Nullable private final net.minecraft.core.component.DataComponentPatch patch; // Paper
 
     public ItemInput(Holder<Item> item, DataComponentMap components) {
+        // Paper start
+        this(item, components, null);
+    }
+    public ItemInput(Holder<Item> item, DataComponentMap components, @javax.annotation.Nullable final net.minecraft.core.component.DataComponentPatch patch) {
+        this.patch = patch;
+        // Paper end
         this.item = item;
         this.components = components;
     }
@@ -37,7 +44,13 @@ public class ItemInput {
 
     public ItemStack createItemStack(int amount, boolean checkOverstack) throws CommandSyntaxException {
         ItemStack itemStack = new ItemStack(this.item, amount);
-        itemStack.applyComponents(this.components);
+        // Paper start - support component removals
+        if (this.patch != null) {
+            itemStack.applyComponents(this.patch);
+        } else {
+            itemStack.applyComponents(this.components);
+        }
+        // Paper end - support component removals
         if (checkOverstack && amount > itemStack.getMaxStackSize()) {
             throw ERROR_STACK_TOO_BIG.create(this.getItemName(), itemStack.getMaxStackSize());
         } else {
diff --git a/src/main/java/net/minecraft/commands/arguments/item/ItemParser.java b/src/main/java/net/minecraft/commands/arguments/item/ItemParser.java
index 5347a96be3bfbbd2963747ba4b5f222215d80371..fa431de18de902c580855e9c4419125519b6176b 100644
--- a/src/main/java/net/minecraft/commands/arguments/item/ItemParser.java
+++ b/src/main/java/net/minecraft/commands/arguments/item/ItemParser.java
@@ -59,8 +59,15 @@ public class ItemParser {
     static final Function<SuggestionsBuilder, CompletableFuture<Suggestions>> SUGGEST_NOTHING = SuggestionsBuilder::buildFuture;
     final HolderLookup.RegistryLookup<Item> items;
     final DynamicOps<Tag> registryOps;
+    final boolean allowRemoves; // Paper - support component removals
 
     public ItemParser(HolderLookup.Provider registriesLookup) {
+        // Paper start - support component removals
+        this(registriesLookup, false);
+    }
+    public ItemParser(HolderLookup.Provider registriesLookup, boolean allowRemoves) {
+        this.allowRemoves = allowRemoves;
+        // Paper end - support component removals
         this.items = registriesLookup.lookupOrThrow(Registries.ITEM);
         this.registryOps = registriesLookup.createSerializationContext(NbtOps.INSTANCE);
     }
@@ -68,6 +75,7 @@ public class ItemParser {
     public ItemParser.ItemResult parse(StringReader reader) throws CommandSyntaxException {
         final MutableObject<Holder<Item>> mutableObject = new MutableObject<>();
         final DataComponentMap.Builder builder = DataComponentMap.builder();
+        final net.minecraft.core.component.DataComponentPatch.Builder patchBuilder = net.minecraft.core.component.DataComponentPatch.builder(); // Paper - support component removals
         this.parse(reader, new ItemParser.Visitor() {
             @Override
             public void visitItem(Holder<Item> item) {
@@ -77,12 +85,19 @@ public class ItemParser {
             @Override
             public <T> void visitComponent(DataComponentType<T> type, T value) {
                 builder.set(type, value);
+                // Paper start - support component removals
+                patchBuilder.set(type, value);
+            }
+            @Override
+            public <T> void visitComponentRemove(final DataComponentType<T> type) {
+                patchBuilder.remove(type);
+                // Paper end - support component removals
             }
         });
         Holder<Item> holder = Objects.requireNonNull(mutableObject.getValue(), "Parser gave no item");
         DataComponentMap dataComponentMap = builder.build();
         validateComponents(reader, holder, dataComponentMap);
-        return new ItemParser.ItemResult(holder, dataComponentMap);
+        return new ItemParser.ItemResult(holder, dataComponentMap, this.allowRemoves ? patchBuilder.build() : null); // Paper - support component removals
     }
 
     private static void validateComponents(StringReader reader, Holder<Item> item, DataComponentMap components) throws CommandSyntaxException {
@@ -116,7 +131,7 @@ public class ItemParser {
         return suggestionsVisitor.resolveSuggestions(builder, stringReader);
     }
 
-    public static record ItemResult(Holder<Item> item, DataComponentMap components) {
+    public static record ItemResult(Holder<Item> item, DataComponentMap components, @javax.annotation.Nullable net.minecraft.core.component.DataComponentPatch patch) { // Paper
     }
 
     class State {
@@ -154,17 +169,28 @@ public class ItemParser {
 
             while (this.reader.canRead() && this.reader.peek() != ']') {
                 this.reader.skipWhitespace();
+                boolean removing = ItemParser.this.allowRemoves && this.reader.canRead() && this.reader.peek() == '!';
+                if (removing) {
+                    this.reader.skip();
+                    this.visitor.visitSuggestions(builder -> this.suggestComponentAssignment(builder, false));
+                }
                 DataComponentType<?> dataComponentType = readComponentType(this.reader);
                 if (!set.add(dataComponentType)) {
                     throw ItemParser.ERROR_REPEATED_COMPONENT.create(dataComponentType);
                 }
 
+                // Paper start - support component removals
+                if (removing) {
+                    this.visitor.visitComponentRemove(dataComponentType);
+                } else {
+                // Paper end - support component removals
                 this.visitor.visitSuggestions(this::suggestAssignment);
                 this.reader.skipWhitespace();
                 this.reader.expect('=');
                 this.visitor.visitSuggestions(ItemParser.SUGGEST_NOTHING);
                 this.reader.skipWhitespace();
                 this.readComponent(dataComponentType);
+                } // Paper - support component removals
                 this.reader.skipWhitespace();
                 this.visitor.visitSuggestions(this::suggestNextOrEndComponents);
                 if (!this.reader.canRead() || this.reader.peek() != ',') {
@@ -239,12 +265,18 @@ public class ItemParser {
         }
 
         private CompletableFuture<Suggestions> suggestComponentAssignment(SuggestionsBuilder builder) {
+            // Paper start - support component removals
+            return this.suggestComponentAssignment(builder, true);
+        }
+        private CompletableFuture<Suggestions> suggestComponentAssignment(SuggestionsBuilder builder, boolean suggestRemove) {
             String string = builder.getRemaining().toLowerCase(Locale.ROOT);
+            if (suggestRemove && string.isBlank()) builder.suggest("!", Component.literal("Remove a data component"));
+            // Paper end - support component removals
             SharedSuggestionProvider.filterResources(BuiltInRegistries.DATA_COMPONENT_TYPE.entrySet(), string, entry -> entry.getKey().location(), entry -> {
                 DataComponentType<?> dataComponentType = entry.getValue();
                 if (dataComponentType.codec() != null) {
                     ResourceLocation resourceLocation = entry.getKey().location();
-                    builder.suggest(resourceLocation.toString() + "=");
+                    builder.suggest(resourceLocation.toString() + (suggestRemove ? "=" : "")); // Paper - support component removals
                 }
             });
             return builder.buildFuture();
@@ -270,6 +302,7 @@ public class ItemParser {
 
         default <T> void visitComponent(DataComponentType<T> type, T value) {
         }
+        default <T> void visitComponentRemove(DataComponentType<T> type) {} // Paper
 
         default void visitSuggestions(Function<SuggestionsBuilder, CompletableFuture<Suggestions>> suggestor) {
         }
diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java
index 0d9de4c61c7b26a6ff37c12fde629161fd0c3d5a..c738bbfa73888a0caed507e02f5c113f681e5cc2 100644
--- a/src/main/java/net/minecraft/server/commands/GiveCommand.java
+++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java
@@ -34,6 +34,38 @@ public class GiveCommand {
         })).then(net.minecraft.commands.Commands.argument("count", IntegerArgumentType.integer(1)).executes((commandcontext) -> {
             return GiveCommand.giveItem((CommandSourceStack) commandcontext.getSource(), ItemArgument.getItem(commandcontext, "item"), EntityArgument.getPlayers(commandcontext, "targets"), IntegerArgumentType.getInteger(commandcontext, "count"));
         })))));
+        // Paper start - support component removals with a custom pgive command
+        final com.mojang.brigadier.tree.CommandNode<net.minecraft.commands.CommandSourceStack> node = net.minecraft.commands.Commands
+            .literal("pgive").requires((commandlistenerwrapper) ->  commandlistenerwrapper.hasPermission(2))
+            .then(net.minecraft.commands.Commands.argument("targets", EntityArgument.players())
+                .then(net.minecraft.commands.Commands.argument("item", new ItemArgument(commandRegistryAccess, true)).executes((commandcontext) -> {
+                    return GiveCommand.giveItem((CommandSourceStack) commandcontext.getSource(), ItemArgument.getItem(commandcontext, "item"), EntityArgument.getPlayers(commandcontext, "targets"), 1);
+                })
+                    .then(net.minecraft.commands.Commands.argument("count", IntegerArgumentType.integer(1)).executes((commandcontext) -> {
+                        return GiveCommand.giveItem((CommandSourceStack) commandcontext.getSource(), ItemArgument.getItem(commandcontext, "item"), EntityArgument.getPlayers(commandcontext, "targets"), IntegerArgumentType.getInteger(commandcontext, "count"));
+                    }))
+                )
+            ).build();
+        setClientNodes(node);
+        dispatcher.getRoot().addChild(node);
+    }
+    static void setClientNodes(com.mojang.brigadier.tree.CommandNode<net.minecraft.commands.CommandSourceStack> node) {
+        if (node instanceof com.mojang.brigadier.tree.ArgumentCommandNode<net.minecraft.commands.CommandSourceStack,?> argumentNode) {
+            if (argumentNode.getType() instanceof ItemArgument) {
+                node.clientNode = new com.mojang.brigadier.tree.ArgumentCommandNode<>(
+                    argumentNode.getName(),
+                    com.mojang.brigadier.arguments.StringArgumentType.greedyString(),
+                    argumentNode.getCommand(),
+                    argumentNode.getRequirement(),
+                    argumentNode.getRedirect(),
+                    argumentNode.getRedirectModifier(),
+                    argumentNode.isFork(),
+                    (ctx, builder) -> builder.buildFuture()
+                );
+            }
+        }
+        node.getChildren().forEach(GiveCommand::setClientNodes);
+        // Paper end - support component removals with a custom pgive command
     }
 
     private static int giveItem(CommandSourceStack source, ItemInput item, Collection<ServerPlayer> targets, int count) throws CommandSyntaxException {