Skip to content

Commit 66788a9

Browse files
committed
implements fabric commands api
1 parent 18840ad commit 66788a9

8 files changed

Lines changed: 340 additions & 0 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--- a/net/minecraft/commands/Commands.java
2+
+++ b/net/minecraft/commands/Commands.java
3+
@@ -25,6 +_,8 @@
4+
import java.util.stream.Collectors;
5+
import java.util.stream.Stream;
6+
import javax.annotation.Nullable;
7+
+
8+
+import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
9+
import net.minecraft.ChatFormatting;
10+
import net.minecraft.SharedConstants;
11+
import net.minecraft.Util;
12+
@@ -329,6 +_,7 @@
13+
.redirect(flattenedAliasTarget));
14+
}
15+
// Paper end - Brigadier Command API
16+
+ CommandRegistrationCallback.EVENT.invoker().register(this.dispatcher, context, selection);
17+
this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer());
18+
}
19+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--- a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
2+
+++ b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
3+
@@ -9,7 +_,9 @@
4+
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
5+
import java.util.ArrayList;
6+
import java.util.Collections;
7+
+import java.util.HashSet;
8+
import java.util.List;
9+
+import java.util.Set;
10+
import java.util.UUID;
11+
import java.util.concurrent.CompletableFuture;
12+
import java.util.function.BiConsumer;
13+
@@ -18,10 +_,13 @@
14+
import java.util.function.Function;
15+
import java.util.function.Predicate;
16+
import javax.annotation.Nullable;
17+
+
18+
+import net.fabricmc.fabric.api.command.v2.FabricEntitySelectorParser;
19+
import net.minecraft.advancements.critereon.MinMaxBounds;
20+
import net.minecraft.commands.PermissionSource;
21+
import net.minecraft.commands.arguments.selector.options.EntitySelectorOptions;
22+
import net.minecraft.network.chat.Component;
23+
+import net.minecraft.resources.ResourceLocation;
24+
import net.minecraft.server.level.ServerPlayer;
25+
import net.minecraft.util.Mth;
26+
import net.minecraft.util.ToFloatFunction;
27+
@@ -30,7 +_,7 @@
28+
import net.minecraft.world.phys.AABB;
29+
import net.minecraft.world.phys.Vec3;
30+
31+
-public class EntitySelectorParser {
32+
+public class EntitySelectorParser implements FabricEntitySelectorParser {
33+
public static final char SYNTAX_SELECTOR_START = '@';
34+
private static final char SYNTAX_OPTIONS_START = '[';
35+
private static final char SYNTAX_OPTIONS_END = ']';
36+
@@ -118,6 +_,21 @@
37+
private boolean hasScores;
38+
private boolean hasAdvancements;
39+
private boolean usesSelectors;
40+
+ private final Set<ResourceLocation> flags = new HashSet<>();
41+
+
42+
+ @Override
43+
+ public void setCustomFlag(ResourceLocation key, boolean value) {
44+
+ if (value) {
45+
+ this.flags.add(key);
46+
+ } else {
47+
+ this.flags.remove(key);
48+
+ }
49+
+ }
50+
+
51+
+ @Override
52+
+ public boolean getCustomFlag(ResourceLocation key) {
53+
+ return this.flags.contains(key);
54+
+ }
55+
56+
public EntitySelectorParser(StringReader reader, boolean allowSelectors) {
57+
this.reader = reader;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--- a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
2+
+++ b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
3+
@@ -83,6 +_,10 @@
4+
OPTIONS.put(id, new EntitySelectorOptions.Option(handler, predicate, tooltip));
5+
}
6+
7+
+ public static void callPutOption(String id, EntitySelectorOptions.Modifier modifier, Predicate<EntitySelectorParser> condition, Component description) {
8+
+ register(id, modifier, condition, description);
9+
+ }
10+
+
11+
public static void bootStrap() {
12+
if (OPTIONS.isEmpty()) {
13+
register("name", parser -> {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--- a/net/minecraft/commands/synchronization/ArgumentTypeInfos.java
2+
+++ b/net/minecraft/commands/synchronization/ArgumentTypeInfos.java
3+
@@ -65,13 +_,17 @@
4+
import net.minecraft.core.Registry;
5+
6+
public class ArgumentTypeInfos {
7+
- private static final Map<Class<?>, ArgumentTypeInfo<?, ?>> BY_CLASS = Maps.newHashMap();
8+
+ private static Map<Class<?>, ArgumentTypeInfo<?, ?>> BY_CLASS = Maps.newHashMap();
9+
10+
private static <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>> ArgumentTypeInfo<A, T> register(
11+
Registry<ArgumentTypeInfo<?, ?>> registry, String id, Class<? extends A> argumentClass, ArgumentTypeInfo<A, T> info
12+
) {
13+
BY_CLASS.put(argumentClass, info);
14+
return Registry.register(registry, id, info);
15+
+ }
16+
+
17+
+ public static Map<Class<?>, ArgumentTypeInfo<?, ?>> fabric_getClassMap() {
18+
+ return BY_CLASS;
19+
}
20+
21+
public static ArgumentTypeInfo<?, ?> bootstrap(Registry<ArgumentTypeInfo<?, ?>> registry) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.api.command.v2;
18+
19+
import com.mojang.brigadier.arguments.ArgumentType;
20+
21+
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
22+
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
23+
import net.minecraft.core.Registry;
24+
import net.minecraft.core.registries.BuiltInRegistries;
25+
26+
import net.minecraft.resources.ResourceLocation;
27+
28+
public final class ArgumentTypeRegistry {
29+
/**
30+
* Register a new argument type.
31+
*
32+
* @param id the identifier of the argument type
33+
* @param clazz the class of the argument type
34+
* @param serializer the serializer for the argument type
35+
* @param <A> the argument type
36+
* @param <T> the argument type properties
37+
*/
38+
public static <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>> void registerArgumentType(
39+
ResourceLocation id, Class<? extends A> clazz, ArgumentTypeInfo<A, T> serializer) {
40+
ArgumentTypeInfos.fabric_getClassMap().put(clazz, serializer);
41+
Registry.register(BuiltInRegistries.COMMAND_ARGUMENT_TYPE, id, serializer);
42+
}
43+
44+
private ArgumentTypeRegistry() {
45+
}
46+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.api.command.v2;
18+
19+
import com.mojang.brigadier.CommandDispatcher;
20+
21+
import net.minecraft.commands.CommandBuildContext;
22+
import net.minecraft.commands.CommandSourceStack;
23+
import net.minecraft.commands.Commands;
24+
25+
import net.fabricmc.fabric.api.event.Event;
26+
import net.fabricmc.fabric.api.event.EventFactory;
27+
28+
/**
29+
* Callback for when a server registers all commands.
30+
*
31+
* <p>To register some commands, you would register an event listener and implement the callback.
32+
*
33+
* <pre>{@code
34+
* CommandRegistrationCallback.EVENT.register((dispatcher, buildContext, selection) -> {
35+
* // For example, this command is only registered on an integrated server like the vanilla publish command
36+
* if (selection.includeIntegrated) dispatcher.register(Commands.literal("integrated_command").executes(context -> {...}));
37+
* })};
38+
* }</pre>
39+
*/
40+
public interface CommandRegistrationCallback {
41+
Event<CommandRegistrationCallback> EVENT = EventFactory.createArrayBacked(CommandRegistrationCallback.class, (callbacks) -> (dispatcher, buildContext, selection) -> {
42+
for (CommandRegistrationCallback callback : callbacks) {
43+
callback.register(dispatcher, buildContext, selection);
44+
}
45+
});
46+
47+
/**
48+
* Called when the server is registering commands.
49+
*
50+
* @param dispatcher the command dispatcher to register commands to
51+
* @param buildContext object exposing access to the game's holders
52+
* @param selection environment selection the registrations should be done for, used for commands that are dedicated or integrated server only
53+
*/
54+
void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext buildContext, Commands.CommandSelection selection);
55+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.api.command.v2;
18+
19+
import java.util.function.Predicate;
20+
21+
import net.minecraft.commands.arguments.selector.EntitySelectorParser;
22+
import net.minecraft.commands.arguments.selector.options.EntitySelectorOptions;
23+
import net.minecraft.network.chat.Component;
24+
25+
import net.minecraft.resources.ResourceLocation;
26+
27+
/**
28+
* Contains a function to register an entity selector option.
29+
*/
30+
public final class EntitySelectorOptionRegistry {
31+
private EntitySelectorOptionRegistry() {
32+
}
33+
34+
/**
35+
* Registers an entity selector option. The added option is available under the underscore
36+
* separated ID.
37+
*
38+
* <p>Here's an example of a custom entity selector option. The option is registered under
39+
* {@code example_min_health} and can be used like {@code @e[example_min_health=5]}.
40+
* <pre>{@code
41+
* EntitySelectorOptionRegistry.register(
42+
* Identifier.fromNamespaceAndPath("modid", "min_health"),
43+
* Component.literal("Minimum entity health"),
44+
* (parser) -> {
45+
* final float minHealth = parser.getReader().readFloat();
46+
*
47+
* if (minHealth > 0) {
48+
* parser.addPredicate((entity) -> entity instanceof LivingEntity livingEntity && livingEntity.getHealth() >= minHealth);
49+
* }
50+
* },
51+
* (parser) -> true
52+
* );
53+
* }</pre>
54+
*
55+
* <p>By default, a selector option can be used multiple times. To make a non-repeatable
56+
* option, either use {@link FabricEntitySelectorParser} to flag the existence of an option
57+
* and check it inside {@code canUse}, or use {@link #registerNonRepeatable} instead of this
58+
* method.
59+
*
60+
* @param id the ID of the option
61+
* @param description the description of the option
62+
* @param modifier the modifier for the entity option that reads and sets the predicate
63+
* @param canUse the predicate that checks whether the option is syntactically valid
64+
*/
65+
public static void register(ResourceLocation id, Component description, EntitySelectorOptions.Modifier modifier, Predicate<EntitySelectorParser> canUse) {
66+
EntitySelectorOptions.callPutOption(id.toDebugFileName(), modifier, canUse, description);
67+
}
68+
69+
/**
70+
* Registers an entity selector option. The added option is available under the underscore
71+
* separated ID. The added option cannot be used multiple times within a single selector.
72+
*
73+
* @param id the ID of the option
74+
* @param description the description of the option
75+
* @param modifier the modifier for the entity option that reads and sets the predicate
76+
*/
77+
public static void registerNonRepeatable(ResourceLocation id, Component description, EntitySelectorOptions.Modifier modifier) {
78+
register(id, description, (parser) -> {
79+
modifier.handle(parser);
80+
parser.setCustomFlag(id, true);
81+
}, (parser) -> !parser.getCustomFlag(id)); // has a flag = used before
82+
}
83+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.fabricmc.fabric.api.command.v2;
18+
19+
import net.minecraft.resources.ResourceLocation;
20+
import net.minecraft.resources.ResourceLocation;
21+
22+
/**
23+
* Fabric extension to {@link net.minecraft.commands.arguments.selector.EntitySelectorParser}, implemented
24+
* using interface injection. This allows custom entity selectors to
25+
* set a custom flag to a parser. This can be used to implement mutually-exclusive
26+
* or non-repeatable entity selector option.
27+
*/
28+
public interface FabricEntitySelectorParser {
29+
/**
30+
* Sets a flag.
31+
* @param key the key of the flag
32+
* @param value the value of the flag
33+
*/
34+
default void setCustomFlag(ResourceLocation key, boolean value) {
35+
throw new UnsupportedOperationException("Implemented via mixin");
36+
}
37+
38+
/**
39+
* Gets the value of the flag.
40+
* @param key the key of the flag
41+
* @return the value, or {@code false} if the flag is not set
42+
*/
43+
default boolean getCustomFlag(ResourceLocation key) {
44+
throw new UnsupportedOperationException("Implemented via mixin");
45+
}
46+
}

0 commit comments

Comments
 (0)