Skip to content

Commit 0cdf700

Browse files
authored
Commands helper (#269)
* reloadable commands & helper * rename class * fix commands not being removed * fix OreDictIngredient mutating ores list * prevent overwriting existing commands
1 parent c2bfd4b commit 0cdf700

File tree

10 files changed

+169
-17
lines changed

10 files changed

+169
-17
lines changed

examples/postInit/custom/vanilla.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,7 @@ item('minecraft:golden_apple').setRarity(textformat('-1'))
256256
eventManager.listen(EnderTeleportEvent) { event ->
257257
event.setAttackDamage 19.5f
258258
}
259+
260+
command.registerCommand('groovy_test') { server, sender, args ->
261+
sender.sendMessage('Hello from GroovyScript')
262+
}

src/main/java/com/cleanroommc/groovyscript/GroovyScript.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ public void onPostInit(FMLPostInitializationEvent event) {
192192
@Mod.EventHandler
193193
public void onServerLoad(FMLServerStartingEvent event) {
194194
event.registerServerCommand(new GSCommand());
195+
VanillaModule.command.onStartServer(event.getServer());
195196
}
196197

197198
@SubscribeEvent

src/main/java/com/cleanroommc/groovyscript/command/GSCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public String getName() {
169169
@Override
170170
@NotNull
171171
public List<String> getAliases() {
172-
return Arrays.asList("grs", "GroovyScript", "gs");
172+
return Arrays.asList("grs", "gs");
173173
}
174174

175175
@Override
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package com.cleanroommc.groovyscript.compat.vanilla;
2+
3+
import com.cleanroommc.groovyscript.GroovyScript;
4+
import com.cleanroommc.groovyscript.api.GroovyBlacklist;
5+
import com.cleanroommc.groovyscript.api.GroovyLog;
6+
import com.cleanroommc.groovyscript.api.IScriptReloadable;
7+
import com.cleanroommc.groovyscript.command.SimpleCommand;
8+
import com.cleanroommc.groovyscript.core.mixin.CommandHandlerAccessor;
9+
import com.cleanroommc.groovyscript.registry.AbstractReloadableStorage;
10+
import com.cleanroommc.groovyscript.registry.NamedRegistry;
11+
import net.minecraft.command.CommandHandler;
12+
import net.minecraft.command.ICommand;
13+
import net.minecraft.server.MinecraftServer;
14+
import net.minecraftforge.client.ClientCommandHandler;
15+
import net.minecraftforge.fml.common.FMLCommonHandler;
16+
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
import java.util.Objects;
20+
import java.util.Set;
21+
import java.util.function.Consumer;
22+
23+
public class Command extends NamedRegistry implements IScriptReloadable {
24+
25+
private final List<ICommand> serverCommands = new ArrayList<>();
26+
private final AbstractReloadableStorage<ICommand> serverReloadableCommands = new AbstractReloadableStorage<>();
27+
private final AbstractReloadableStorage<ICommand> clientReloadableCommands = new AbstractReloadableStorage<>();
28+
private boolean serverStarted = false;
29+
30+
public void registerCommand(ICommand command) {
31+
if (GroovyScript.getSandbox().isRunning() && GroovyScript.getSandbox().getCurrentLoader().isReloadable()) {
32+
this.serverReloadableCommands.addScripted(command);
33+
} else {
34+
this.serverCommands.add(command);
35+
}
36+
if (this.serverStarted) {
37+
forServer(commandHandler -> registerCommand(commandHandler, command));
38+
}
39+
}
40+
41+
public void registerClientCommand(ICommand command) {
42+
if (FMLCommonHandler.instance().getSide().isServer()) return;
43+
44+
if (registerCommand(ClientCommandHandler.instance, command) && GroovyScript.getSandbox().isRunning() && GroovyScript.getSandbox().getCurrentLoader().isReloadable()) {
45+
this.clientReloadableCommands.addScripted(command);
46+
}
47+
}
48+
49+
public void registerCommand(String name, String usage, SimpleCommand.ICommand command) {
50+
registerCommand(new SimpleCommand(name, usage, command));
51+
}
52+
53+
public void registerCommand(String name, SimpleCommand.ICommand command) {
54+
registerCommand(new SimpleCommand(name, "/" + name, command));
55+
}
56+
57+
public void registerClientCommand(String name, String usage, SimpleCommand.ICommand command) {
58+
registerClientCommand(new SimpleCommand(name, usage, command));
59+
}
60+
61+
public void registerClientCommand(String name, SimpleCommand.ICommand command) {
62+
registerClientCommand(new SimpleCommand(name, "/" + name, command));
63+
}
64+
65+
public boolean registerCommand(CommandHandler handler, ICommand command) {
66+
if (handler.getCommands().containsKey(command.getName())) {
67+
GroovyLog.get().error("Error registering command '/{}', because a command with that name already exists", command.getName());
68+
return false;
69+
}
70+
for (String alias : command.getAliases()) {
71+
if (handler.getCommands().containsKey(alias)) {
72+
GroovyLog.get().error("Error registering command '/{}', because a command for the alias '/{}' already exists", command.getName(), alias);
73+
return false;
74+
}
75+
}
76+
handler.registerCommand(command);
77+
return true;
78+
}
79+
80+
@GroovyBlacklist
81+
public void removeCommand(CommandHandler commandHandler, ICommand command) {
82+
Set<ICommand> commands = ((CommandHandlerAccessor) commandHandler).getCommandSet();
83+
if (commands.remove(command)) {
84+
commandHandler.getCommands().entrySet().removeIf(entry -> Objects.equals(command, entry.getValue()));
85+
}
86+
}
87+
88+
@GroovyBlacklist
89+
public void onStartServer(MinecraftServer server) {
90+
this.serverStarted = true;
91+
CommandHandler commandHandler = (CommandHandler) server.getCommandManager();
92+
for (ICommand command : this.serverCommands) {
93+
registerCommand(commandHandler, command);
94+
}
95+
for (ICommand command : this.serverReloadableCommands.getScriptedRecipes()) {
96+
registerCommand(commandHandler, command);
97+
}
98+
}
99+
100+
@GroovyBlacklist
101+
public void onReload() {
102+
this.clientReloadableCommands.removeScripted().forEach(c -> removeCommand(ClientCommandHandler.instance, c));
103+
forServer(commandHandler -> this.serverReloadableCommands.removeScripted().forEach(c -> removeCommand(commandHandler, c)));
104+
}
105+
106+
@Override
107+
public void afterScriptLoad() {}
108+
109+
private void forServer(Consumer<CommandHandler> consumer) {
110+
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
111+
if (server != null) {
112+
consumer.accept((CommandHandler) server.getCommandManager());
113+
}
114+
}
115+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.cleanroommc.groovyscript.compat.vanilla;
2+
3+
import net.minecraft.command.ICommandSender;
4+
import net.minecraft.entity.player.EntityPlayer;
5+
import net.minecraft.util.text.TextComponentString;
6+
7+
public class CommandSenderExpansion {
8+
9+
public static boolean isPlayer(ICommandSender commandSender) {
10+
return commandSender instanceof EntityPlayer;
11+
}
12+
13+
public static void sendMessage(ICommandSender commandSender, String msg) {
14+
commandSender.sendMessage(new TextComponentString(msg));
15+
}
16+
}

src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.cleanroommc.groovyscript.compat.loot.Loot;
99
import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer;
1010
import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper;
11+
import net.minecraft.command.ICommandSender;
1112
import net.minecraft.item.ItemStack;
1213

1314
import java.util.Collection;
@@ -25,6 +26,7 @@ public class VanillaModule extends GroovyPropertyContainer implements IScriptRel
2526
public static final Content content = new Content();
2627
public static final Rarity rarity = new Rarity();
2728
public static final InWorldCrafting inWorldCrafting = new InWorldCrafting();
29+
public static final Command command = new Command();
2830

2931
public static void initializeBinding() {
3032
GroovyScript.getSandbox().registerBinding(crafting);
@@ -35,8 +37,10 @@ public static void initializeBinding() {
3537
GroovyScript.getSandbox().registerBinding(content);
3638
GroovyScript.getSandbox().registerBinding(rarity);
3739
GroovyScript.getSandbox().registerBinding(inWorldCrafting);
40+
GroovyScript.getSandbox().registerBinding(command);
3841

3942
ExpansionHelper.mixinClass(ItemStack.class, ItemStackExpansion.class);
43+
ExpansionHelper.mixinClass(ICommandSender.class, CommandSenderExpansion.class);
4044
}
4145

4246
@Override
@@ -49,6 +53,7 @@ public void onReload() {
4953
rarity.onReload();
5054
player.onReload();
5155
inWorldCrafting.onReload();
56+
command.onReload();
5257
}
5358

5459
@Override
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.cleanroommc.groovyscript.core.mixin;
2+
3+
import net.minecraft.command.CommandHandler;
4+
import net.minecraft.command.ICommand;
5+
import org.spongepowered.asm.mixin.Mixin;
6+
import org.spongepowered.asm.mixin.gen.Accessor;
7+
8+
import java.util.Set;
9+
10+
@Mixin(CommandHandler.class)
11+
public interface CommandHandlerAccessor {
12+
13+
@Accessor
14+
Set<ICommand> getCommandSet();
15+
}

src/main/java/com/cleanroommc/groovyscript/helper/ingredient/ItemsIngredient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public Ingredient toMcIngredient() {
4545

4646
@Override
4747
public ItemStack[] getMatchingStacks() {
48-
ItemStack[] stacks = itemStacks.toArray(new ItemStack[0]);
48+
ItemStack[] stacks = new ItemStack[itemStacks.size()];
4949
for (int i = 0; i < stacks.length; i++) {
50-
ItemStack stack = stacks[i].copy();
50+
ItemStack stack = itemStacks.get(i).copy();
5151
stack.setCount(getAmount());
5252
stacks[i] = stack;
5353
}

src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package com.cleanroommc.groovyscript.helper.ingredient;
22

3-
import com.cleanroommc.groovyscript.api.GroovyBlacklist;
43
import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule;
5-
import com.google.common.collect.Iterators;
64
import net.minecraft.item.ItemStack;
75
import net.minecraft.item.crafting.Ingredient;
86
import net.minecraftforge.oredict.OreDictionary;
97
import org.jetbrains.annotations.NotNull;
108

9+
import java.util.Arrays;
1110
import java.util.Iterator;
1211
import java.util.List;
1312

@@ -61,28 +60,24 @@ public Ingredient toMcIngredient() {
6160
return Ingredient.fromStacks(getMatchingStacks());
6261
}
6362

64-
@GroovyBlacklist
65-
private List<ItemStack> prepareItemStacks() {
63+
@Override
64+
public ItemStack[] getMatchingStacks() {
6665
List<ItemStack> stacks = OreDictionary.getOres(this.oreDict);
66+
ItemStack[] copies = new ItemStack[stacks.size()];
6767
for (int i = 0; i < stacks.size(); i++) {
6868
ItemStack stack = stacks.get(i).copy();
6969
stack.setCount(getAmount());
70-
stacks.set(i, stack);
70+
copies[i] = stack;
7171
}
72-
return stacks;
73-
}
74-
75-
@Override
76-
public ItemStack[] getMatchingStacks() {
77-
return prepareItemStacks().toArray(new ItemStack[0]);
72+
return copies;
7873
}
7974

8075
public ItemStack getFirst() {
81-
return prepareItemStacks().get(0);
76+
return getMatchingStacks()[0];
8277
}
8378

8479
public ItemStack getAt(int index) {
85-
return prepareItemStacks().get(index);
80+
return getMatchingStacks()[index];
8681
}
8782

8883
@Override
@@ -129,6 +124,6 @@ public void remove(Iterable<ItemStack> itemStacks) {
129124
@NotNull
130125
@Override
131126
public Iterator<ItemStack> iterator() {
132-
return Iterators.unmodifiableIterator(prepareItemStacks().listIterator());
127+
return Arrays.asList(getMatchingStacks()).listIterator();
133128
}
134129
}

src/main/resources/mixin.groovyscript.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"minVersion": "0.8",
66
"compatibilityLevel": "JAVA_8",
77
"mixins": [
8+
"CommandHandlerAccessor",
89
"CreativeTabsAccessor",
910
"EntityAccessor",
1011
"EntityItemMixin",

0 commit comments

Comments
 (0)