diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/CloopCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/CloopCommand.java index f111546..6ba5aac 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/CloopCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/CloopCommand.java @@ -3,127 +3,102 @@ package land.chipmunk.chipmunkmod.commands; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; -import land.chipmunk.chipmunkmod.data.CommandLoop; -import land.chipmunk.chipmunkmod.modules.CommandLooper; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import static land.chipmunk.chipmunkmod.command.CommandManager.literal; +import static land.chipmunk.chipmunkmod.command.CommandManager.argument; +import static com.mojang.brigadier.arguments.LongArgumentType.longArg; +import static com.mojang.brigadier.arguments.LongArgumentType.getLong; +import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; +import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - +import land.chipmunk.chipmunkmod.modules.CommandLoopManager; import java.util.List; -import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger; -import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; -import static land.chipmunk.chipmunkmod.command.CommandManager.argument; -import static land.chipmunk.chipmunkmod.command.CommandManager.literal; - public class CloopCommand { + private static final DynamicCommandExceptionType INVALID_CLOOP_ID_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("Invalid cloop id: %s", Text.literal(String.valueOf(id)))); + public static void register (CommandDispatcher dispatcher) { dispatcher.register( literal("cloop") .then( literal("add") .then( - argument("interval", integer()) + argument("interval", longArg()) .then( argument("command", greedyString()) - .executes(c -> add(c)) + .executes(c -> addCloop(c)) ) ) ) .then( literal("remove") .then( - argument("index", integer()) - .executes(c -> remove(c)) + argument("id", integer()) + .executes(c -> removeCloop(c)) ) ) .then( literal("clear") - .executes(c -> clear(c)) + .executes(c -> clearCloops(c)) ) .then( literal("list") - .executes(c -> list(c)) + .executes(c -> listCloops(c)) ) ); } - public static int add (CommandContext context) { + public static int addCloop (CommandContext context) { final FabricClientCommandSource source = context.getSource(); - + final long interval = getLong(context, "interval"); final String command = getString(context, "command"); - final int interval = getInteger(context, "interval"); - CommandLooper.INSTANCE.addLoop(command, interval); - - source.sendFeedback( - Text.translatable( - "Added command %s with interval %s to the command loops", - Text.literal(command).formatted(Formatting.AQUA), - Text.literal(String.valueOf(interval)).formatted(Formatting.GOLD) - ) - ); + int id = CommandLoopManager.INSTANCE.loopCommand(command, interval); + source.sendFeedback(Text.translatable("Successfully created a loop for command '%s' with id %s", Text.literal(command), Text.literal(String.valueOf(id)))); return Command.SINGLE_SUCCESS; } - public static int remove (CommandContext context) { + public static int removeCloop (CommandContext context) throws CommandSyntaxException { final FabricClientCommandSource source = context.getSource(); + final CommandLoopManager manager = CommandLoopManager.INSTANCE; + final int id = getInteger(context, "id"); - final int index = getInteger(context, "index"); + if (id < 0 || id >= manager.commandLoops().size()) throw INVALID_CLOOP_ID_EXCEPTION.create(id); - CommandLooper.INSTANCE.removeLoop(index); - - source.sendFeedback( - Text.translatable( - "Removed command loop %s", - Text.literal(String.valueOf(index)).formatted(Formatting.GOLD) - ) - ); + manager.removeAndStop(id); + source.sendFeedback(Text.translatable("Successfully removed loop with id %s", Text.literal(String.valueOf(id)))); return Command.SINGLE_SUCCESS; } - public static int list (CommandContext context) { + public static int clearCloops (CommandContext context) { final FabricClientCommandSource source = context.getSource(); + final CommandLoopManager manager = CommandLoopManager.INSTANCE; - final List cloops = CommandLooper.INSTANCE.loops(); + manager.clearLoops(); - MutableText text = Text.empty(); - text.append(Text.literal("Command Loops:").formatted(Formatting.GREEN)); - text.append("\n"); // should i use Text.literal("\n")? + source.sendFeedback(Text.translatable("Successfully cleared all command loops")); + return Command.SINGLE_SUCCESS; + } - for (int i = 0; i < cloops.size(); i++) { - final CommandLoop cloop = cloops.get(i); - text.append( - Text.translatable( - "%s > %s - %s", // should i use \u203a? - Text.literal(String.valueOf(i)).formatted(Formatting.GREEN), - Text.literal(cloop.command()).formatted(Formatting.AQUA), - Text.literal(String.valueOf(cloop.interval())).formatted(Formatting.GOLD) - ).formatted(Formatting.GRAY) - ); + public static int listCloops (CommandContext context) { + final FabricClientCommandSource source = context.getSource(); + final List loops = CommandLoopManager.INSTANCE.commandLoops(); - // PLS TELL ME HOW TO REMOVE THE LAST ONE OF MutableText SPLSPLpLSLPsSSPLPSPLSPSL - // btw is this the best way to do it lol - final int lastIndex = cloops.size() - 1; - if (i < lastIndex) { text.append("\n"); } + int id = 0; + for (CommandLoopManager.CommandLoop loop : loops) { + source.sendFeedback(Text.translatable("%s: %s (%s)", Text.literal(String.valueOf(id)), Text.literal(loop.command()), Text.literal(String.valueOf(loop.interval())))); + id++; } - source.sendFeedback(text); - - return Command.SINGLE_SUCCESS; - } - - public static int clear (CommandContext context) { - final FabricClientCommandSource source = context.getSource(); - - CommandLooper.INSTANCE.clearLoops(); - - source.sendFeedback(Text.literal("Cleared all command loops")); + if (id == 0) { + source.sendFeedback(Text.translatable("No command loops are currently running")); + } return Command.SINGLE_SUCCESS; } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java index 36393e6..910d4e1 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java @@ -1,28 +1,36 @@ package land.chipmunk.chipmunkmod.mixin; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.suggestion.Suggestions; +import land.chipmunk.chipmunkmod.command.CommandManager; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.TextFieldWidget; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + import java.util.concurrent.CompletableFuture; -import com.mojang.brigadier.suggestion.Suggestions; -import net.minecraft.client.gui.widget.TextFieldWidget; -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.client.MinecraftClient; -import land.chipmunk.chipmunkmod.command.CommandManager; @Mixin(net.minecraft.client.gui.screen.ChatInputSuggestor.class) public class ChatInputSuggestorMixin { @Shadow - CompletableFuture pendingSuggestions; + private CompletableFuture pendingSuggestions; + + @Final + @Shadow + private boolean slashOptional; @Shadow public void show (boolean narrateFirstSuggestion) {} + @Mutable + @Final @Shadow final TextFieldWidget textField; @@ -31,7 +39,9 @@ public class ChatInputSuggestorMixin { } @Inject(at = @At("TAIL"), method = "refresh()V") - public void onRefresh (CallbackInfo ci) { + public void refresh (CallbackInfo ci) { + if (slashOptional) return; + final String text = this.textField.getText(); final int cursor = this.textField.getCursor(); diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java index fd09b0b..462c627 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java @@ -12,7 +12,6 @@ public class ClientPlayNetworkHandlerMixin { @Inject(method = "onGameJoin", at = @At("TAIL")) private void onGameJoin (GameJoinS2CPacket packet, CallbackInfo ci) { SelfCare.INSTANCE.init(); - CommandLooper.INSTANCE.init(); SongPlayer.INSTANCE.coreReady(); RainbowName.INSTANCE.init(); } diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/CommandLoopManager.java b/src/main/java/land/chipmunk/chipmunkmod/modules/CommandLoopManager.java new file mode 100644 index 0000000..9917f05 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/CommandLoopManager.java @@ -0,0 +1,83 @@ +package land.chipmunk.chipmunkmod.modules; + +import lombok.Getter; +import lombok.Setter; +import java.util.List; +import java.util.ArrayList; +import java.util.Timer; +import java.util.TimerTask; + +public class CommandLoopManager { + private final CommandCore core; + @Getter @Setter private List commandLoops = new ArrayList<>(); + + public CommandLoopManager (CommandCore core) { + this.core = core; + } + + public static final CommandLoopManager INSTANCE = new CommandLoopManager(CommandCore.INSTANCE); + + public int loopCommand (String command, long interval) { + final CommandLoop loop = new CommandLoop(this.core, command, interval); + if (!commandLoops.add(loop)) return -1; + return commandLoops.size() - 1; + } + + public boolean removeAndStop (CommandLoop loop) { + loop.stop(); + return commandLoops.remove(loop); + } + + public boolean removeAndStop (int id) { + return removeAndStop(commandLoops.get(id)); + } + + public void clearLoops () { + for (CommandLoop loop : this.commandLoops) loop.stop(); + commandLoops.clear(); + } + + public void cleanup () { this.clearLoops(); } + + public static class CommandLoop { + @Getter @Setter private CommandCore core; + @Getter @Setter private String command; + @Getter private long interval; + private Timer timer; + + public CommandLoop (CommandCore core, String command, long interval) { + this.core = core; + this.command = command; + this.interval = interval; + this.timer = new Timer(); + timer.schedule(this.createTimerTask(), interval, interval); + } + + private long interval (long interval) { + if (timer == null) throw new IllegalStateException("Attempted to set the interval of a stopped command loop"); + + timer.cancel(); + timer.purge(); + + this.interval = interval; + this.timer = new Timer(); + timer.schedule(this.createTimerTask(), interval, interval); + + return interval; + } + + private void stop () { + timer.cancel(); + timer.purge(); + } + + public TimerTask createTimerTask () { + return new TimerTask() { + @Override + public void run () { + core.run(command); + } + }; + } + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/CommandLooper.java b/src/main/java/land/chipmunk/chipmunkmod/modules/CommandLooper.java deleted file mode 100644 index e494879..0000000 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/CommandLooper.java +++ /dev/null @@ -1,78 +0,0 @@ -package land.chipmunk.chipmunkmod.modules; - -import land.chipmunk.chipmunkmod.data.CommandLoop; -import lombok.Getter; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; - -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -public class CommandLooper { - private final MinecraftClient client; - - // sus - private final List loopTasks = new ArrayList<>(); - @Getter private final List loops = new ArrayList<>(); - - private Timer timer = null; - - public static CommandLooper INSTANCE = new CommandLooper(MinecraftClient.getInstance()); - - public CommandLooper (MinecraftClient client) { - this.client = client; - } - - public void init () { - TimerTask task = new TimerTask() { - @Override - public void run () { - final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler(); - - if (networkHandler == null) { cleanup(); } - } - }; - - if (timer != null) cleanup(); - - timer = new Timer(); - timer.schedule(task, 0, 50); - } - - public void cleanup() { - if (timer == null) return; - clearLoops(); - } - - public void addLoop(String command, long interval) { - TimerTask loopTask = new TimerTask() { - public void run() { - CommandCore.INSTANCE.run(command); - } - }; - loopTasks.add(loopTask); - loops.add(new CommandLoop(command, interval)); // mabe,.,.. - // should i use 50 or 0? - timer.scheduleAtFixedRate(loopTask, 0, interval); - } - - public void removeLoop(int index) { - TimerTask loopTask = loopTasks.remove(index); - if (loopTask != null) { - loopTask.cancel(); - } - - loops.remove(index); - } - - public void clearLoops() { - for (TimerTask loopTask : loopTasks) { - loopTask.cancel(); - } - loopTasks.clear(); - - loops.clear(); - } -}