Skip to content

Commit

Permalink
Commands helper (#269)
Browse files Browse the repository at this point in the history
* reloadable commands & helper

* rename class

* fix commands not being removed

* fix OreDictIngredient mutating ores list

* prevent overwriting existing commands
  • Loading branch information
brachy84 authored Dec 6, 2024
1 parent c2bfd4b commit 0cdf700
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 17 deletions.
4 changes: 4 additions & 0 deletions examples/postInit/custom/vanilla.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,7 @@ item('minecraft:golden_apple').setRarity(textformat('-1'))
eventManager.listen(EnderTeleportEvent) { event ->
event.setAttackDamage 19.5f
}

command.registerCommand('groovy_test') { server, sender, args ->
sender.sendMessage('Hello from GroovyScript')
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ public void onPostInit(FMLPostInitializationEvent event) {
@Mod.EventHandler
public void onServerLoad(FMLServerStartingEvent event) {
event.registerServerCommand(new GSCommand());
VanillaModule.command.onStartServer(event.getServer());
}

@SubscribeEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public String getName() {
@Override
@NotNull
public List<String> getAliases() {
return Arrays.asList("grs", "GroovyScript", "gs");
return Arrays.asList("grs", "gs");
}

@Override
Expand Down
115 changes: 115 additions & 0 deletions src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.cleanroommc.groovyscript.compat.vanilla;

import com.cleanroommc.groovyscript.GroovyScript;
import com.cleanroommc.groovyscript.api.GroovyBlacklist;
import com.cleanroommc.groovyscript.api.GroovyLog;
import com.cleanroommc.groovyscript.api.IScriptReloadable;
import com.cleanroommc.groovyscript.command.SimpleCommand;
import com.cleanroommc.groovyscript.core.mixin.CommandHandlerAccessor;
import com.cleanroommc.groovyscript.registry.AbstractReloadableStorage;
import com.cleanroommc.groovyscript.registry.NamedRegistry;
import net.minecraft.command.CommandHandler;
import net.minecraft.command.ICommand;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.fml.common.FMLCommonHandler;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;

public class Command extends NamedRegistry implements IScriptReloadable {

private final List<ICommand> serverCommands = new ArrayList<>();
private final AbstractReloadableStorage<ICommand> serverReloadableCommands = new AbstractReloadableStorage<>();
private final AbstractReloadableStorage<ICommand> clientReloadableCommands = new AbstractReloadableStorage<>();
private boolean serverStarted = false;

public void registerCommand(ICommand command) {
if (GroovyScript.getSandbox().isRunning() && GroovyScript.getSandbox().getCurrentLoader().isReloadable()) {
this.serverReloadableCommands.addScripted(command);
} else {
this.serverCommands.add(command);
}
if (this.serverStarted) {
forServer(commandHandler -> registerCommand(commandHandler, command));
}
}

public void registerClientCommand(ICommand command) {
if (FMLCommonHandler.instance().getSide().isServer()) return;

if (registerCommand(ClientCommandHandler.instance, command) && GroovyScript.getSandbox().isRunning() && GroovyScript.getSandbox().getCurrentLoader().isReloadable()) {
this.clientReloadableCommands.addScripted(command);
}
}

public void registerCommand(String name, String usage, SimpleCommand.ICommand command) {
registerCommand(new SimpleCommand(name, usage, command));
}

public void registerCommand(String name, SimpleCommand.ICommand command) {
registerCommand(new SimpleCommand(name, "/" + name, command));
}

public void registerClientCommand(String name, String usage, SimpleCommand.ICommand command) {
registerClientCommand(new SimpleCommand(name, usage, command));
}

public void registerClientCommand(String name, SimpleCommand.ICommand command) {
registerClientCommand(new SimpleCommand(name, "/" + name, command));
}

public boolean registerCommand(CommandHandler handler, ICommand command) {
if (handler.getCommands().containsKey(command.getName())) {
GroovyLog.get().error("Error registering command '/{}', because a command with that name already exists", command.getName());
return false;
}
for (String alias : command.getAliases()) {
if (handler.getCommands().containsKey(alias)) {
GroovyLog.get().error("Error registering command '/{}', because a command for the alias '/{}' already exists", command.getName(), alias);
return false;
}
}
handler.registerCommand(command);
return true;
}

@GroovyBlacklist
public void removeCommand(CommandHandler commandHandler, ICommand command) {
Set<ICommand> commands = ((CommandHandlerAccessor) commandHandler).getCommandSet();
if (commands.remove(command)) {
commandHandler.getCommands().entrySet().removeIf(entry -> Objects.equals(command, entry.getValue()));
}
}

@GroovyBlacklist
public void onStartServer(MinecraftServer server) {
this.serverStarted = true;
CommandHandler commandHandler = (CommandHandler) server.getCommandManager();
for (ICommand command : this.serverCommands) {
registerCommand(commandHandler, command);
}
for (ICommand command : this.serverReloadableCommands.getScriptedRecipes()) {
registerCommand(commandHandler, command);
}
}

@GroovyBlacklist
public void onReload() {
this.clientReloadableCommands.removeScripted().forEach(c -> removeCommand(ClientCommandHandler.instance, c));
forServer(commandHandler -> this.serverReloadableCommands.removeScripted().forEach(c -> removeCommand(commandHandler, c)));
}

@Override
public void afterScriptLoad() {}

private void forServer(Consumer<CommandHandler> consumer) {
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
if (server != null) {
consumer.accept((CommandHandler) server.getCommandManager());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.cleanroommc.groovyscript.compat.vanilla;

import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.text.TextComponentString;

public class CommandSenderExpansion {

public static boolean isPlayer(ICommandSender commandSender) {
return commandSender instanceof EntityPlayer;
}

public static void sendMessage(ICommandSender commandSender, String msg) {
commandSender.sendMessage(new TextComponentString(msg));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.cleanroommc.groovyscript.compat.loot.Loot;
import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer;
import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;

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

public static void initializeBinding() {
GroovyScript.getSandbox().registerBinding(crafting);
Expand All @@ -35,8 +37,10 @@ public static void initializeBinding() {
GroovyScript.getSandbox().registerBinding(content);
GroovyScript.getSandbox().registerBinding(rarity);
GroovyScript.getSandbox().registerBinding(inWorldCrafting);
GroovyScript.getSandbox().registerBinding(command);

ExpansionHelper.mixinClass(ItemStack.class, ItemStackExpansion.class);
ExpansionHelper.mixinClass(ICommandSender.class, CommandSenderExpansion.class);
}

@Override
Expand All @@ -49,6 +53,7 @@ public void onReload() {
rarity.onReload();
player.onReload();
inWorldCrafting.onReload();
command.onReload();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.cleanroommc.groovyscript.core.mixin;

import net.minecraft.command.CommandHandler;
import net.minecraft.command.ICommand;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

import java.util.Set;

@Mixin(CommandHandler.class)
public interface CommandHandlerAccessor {

@Accessor
Set<ICommand> getCommandSet();
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ public Ingredient toMcIngredient() {

@Override
public ItemStack[] getMatchingStacks() {
ItemStack[] stacks = itemStacks.toArray(new ItemStack[0]);
ItemStack[] stacks = new ItemStack[itemStacks.size()];
for (int i = 0; i < stacks.length; i++) {
ItemStack stack = stacks[i].copy();
ItemStack stack = itemStacks.get(i).copy();
stack.setCount(getAmount());
stacks[i] = stack;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.cleanroommc.groovyscript.helper.ingredient;

import com.cleanroommc.groovyscript.api.GroovyBlacklist;
import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule;
import com.google.common.collect.Iterators;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraftforge.oredict.OreDictionary;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

Expand Down Expand Up @@ -61,28 +60,24 @@ public Ingredient toMcIngredient() {
return Ingredient.fromStacks(getMatchingStacks());
}

@GroovyBlacklist
private List<ItemStack> prepareItemStacks() {
@Override
public ItemStack[] getMatchingStacks() {
List<ItemStack> stacks = OreDictionary.getOres(this.oreDict);
ItemStack[] copies = new ItemStack[stacks.size()];
for (int i = 0; i < stacks.size(); i++) {
ItemStack stack = stacks.get(i).copy();
stack.setCount(getAmount());
stacks.set(i, stack);
copies[i] = stack;
}
return stacks;
}

@Override
public ItemStack[] getMatchingStacks() {
return prepareItemStacks().toArray(new ItemStack[0]);
return copies;
}

public ItemStack getFirst() {
return prepareItemStacks().get(0);
return getMatchingStacks()[0];
}

public ItemStack getAt(int index) {
return prepareItemStacks().get(index);
return getMatchingStacks()[index];
}

@Override
Expand Down Expand Up @@ -129,6 +124,6 @@ public void remove(Iterable<ItemStack> itemStacks) {
@NotNull
@Override
public Iterator<ItemStack> iterator() {
return Iterators.unmodifiableIterator(prepareItemStacks().listIterator());
return Arrays.asList(getMatchingStacks()).listIterator();
}
}
1 change: 1 addition & 0 deletions src/main/resources/mixin.groovyscript.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"minVersion": "0.8",
"compatibilityLevel": "JAVA_8",
"mixins": [
"CommandHandlerAccessor",
"CreativeTabsAccessor",
"EntityAccessor",
"EntityItemMixin",
Expand Down

0 comments on commit 0cdf700

Please sign in to comment.