diff --git a/src/main/java/land/chipmunk/chipmunkbot/ChipmunkBot.java b/src/main/java/land/chipmunk/chipmunkbot/ChipmunkBot.java index 33d4f15..6e4bdf4 100644 --- a/src/main/java/land/chipmunk/chipmunkbot/ChipmunkBot.java +++ b/src/main/java/land/chipmunk/chipmunkbot/ChipmunkBot.java @@ -18,8 +18,9 @@ public class ChipmunkBot extends Client { @Getter private final TabCompletePlugin tabComplete; @Getter private final QueryPlugin query; @Getter private final PlayerListPlugin playerList; + @Getter private final CommandSpyPlugin commandSpy; @Getter private final CommandManager commandManager; - @Getter private final ChatCommandHandler chatCommandHandler; + @Getter private final PlayerCommandHandler playerCommandHandler; @Getter private final PositionManager position; @Getter private final CommandCore core; @Getter private final SelfCarePlugin selfCare; @@ -33,8 +34,9 @@ public class ChipmunkBot extends Client { this.tabComplete = new TabCompletePlugin(this); this.query = new QueryPlugin(this); this.playerList = new PlayerListPlugin(this); + this.commandSpy = new CommandSpyPlugin(this); this.commandManager = new CommandManager(this); - this.chatCommandHandler = new ChatCommandHandler(this, options); + this.playerCommandHandler = new PlayerCommandHandler(this, options); this.position = new PositionManager(this); this.core = new CommandCore(this, options); this.selfCare = new SelfCarePlugin(this); diff --git a/src/main/java/land/chipmunk/chipmunkbot/Options.java b/src/main/java/land/chipmunk/chipmunkbot/Options.java index e356482..bca2ffc 100644 --- a/src/main/java/land/chipmunk/chipmunkbot/Options.java +++ b/src/main/java/land/chipmunk/chipmunkbot/Options.java @@ -13,6 +13,7 @@ public class Options { public class Commands { public String prefix = "default."; + public String cspyPrefix = "default."; } public class Core { diff --git a/src/main/java/land/chipmunk/chipmunkbot/commands/MusicCommand.java b/src/main/java/land/chipmunk/chipmunkbot/commands/MusicCommand.java index 67b1121..92dbe54 100644 --- a/src/main/java/land/chipmunk/chipmunkbot/commands/MusicCommand.java +++ b/src/main/java/land/chipmunk/chipmunkbot/commands/MusicCommand.java @@ -139,7 +139,7 @@ public class MusicCommand { public int list (CommandContext context, Path path) throws CommandSyntaxException { final CommandSource source = context.getSource(); final ChipmunkBot client = source.client(); - final String prefix = client.chatCommandHandler().prefix(); + final String prefix = client.playerCommandHandler().prefix(); final File directory = path.toFile(); final String[] filenames = directory.list(); diff --git a/src/main/java/land/chipmunk/chipmunkbot/plugins/ChatQueueManager.java b/src/main/java/land/chipmunk/chipmunkbot/plugins/ChatQueueManager.java deleted file mode 100644 index a32a1fb..0000000 --- a/src/main/java/land/chipmunk/chipmunkbot/plugins/ChatQueueManager.java +++ /dev/null @@ -1,55 +0,0 @@ -package land.chipmunk.chipmunkbot.plugins; - -import land.chipmunk.chipmunkbot.ChipmunkBot; -import land.chipmunk.chipmunkbot.Options; -import com.github.steveice10.packetlib.event.session.SessionListener; -import com.github.steveice10.packetlib.event.session.SessionAdapter; -import com.github.steveice10.packetlib.event.session.DisconnectedEvent; -import com.github.steveice10.mc.protocol.MinecraftProtocol; -import com.github.steveice10.mc.protocol.data.ProtocolState; -import lombok.Getter; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -public class TickLoop extends SessionAdapter { - private Client client; - private Timer timer; - @Getter private List listeners = new ArrayList<>(); - - public TickLoop (ChipmunkBot client, Options options) { - this.client = client; - client.session().addListener((SessionListener) this); - - final TimerTask task = new TimerTask() { - public void run () { - if (((MinecraftProtocol) client.session().getPacketProtocol()).getState() != ProtocolState.GAME) return; - - int cancel = false; - for (Listener listener : listeners) { - if (!listener.onTick()) cancel = true; - } - - if (!c) - } - }; - - timer = new Timer(); - timer.schedule(task, options.chat.queue.interval, options.chat.queue.interval); - } - - public void disconnected (DisconnectedEvent event) { - if (client.reconnectDelay() < 0 && timer != null) { - timer.cancel(); - timer.purge(); - } - } - - public static class Listener { - public void onTick () {} - } - - public void addListener (Listener listener) { listeners.add(listener); } - public void removeListener (Listener listener) { listeners.remove(listener); } -} diff --git a/src/main/java/land/chipmunk/chipmunkbot/plugins/CommandSpyPlugin.java b/src/main/java/land/chipmunk/chipmunkbot/plugins/CommandSpyPlugin.java new file mode 100644 index 0000000..8da3db0 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkbot/plugins/CommandSpyPlugin.java @@ -0,0 +1,80 @@ +package land.chipmunk.chipmunkbot.plugins; + +import land.chipmunk.chipmunkbot.ChipmunkBot; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.NamedTextColor; +import land.chipmunk.chipmunkbot.data.MutablePlayerListEntry; +import lombok.Getter; +import java.util.List; +import java.util.ArrayList; + +public class CommandSpyPlugin extends ChatPlugin.Listener { + private final ChipmunkBot client; + @Getter private List listeners = new ArrayList<>(); + + private static final Style ENABLED_STYLE = Style.style(NamedTextColor.YELLOW); + private static final Style DISABLED_STYLE = Style.style(NamedTextColor.AQUA); + + private static final Component COMMAND_SEPARATOR_COMPONENT = Component.text(": "); + private static final Component SIGN_CREATED_TEXT_COMPONENT = Component.text(" created a sign with contents:"); + private static final Component SIGN_LINE_SEPARATOR_COMPONENT = Component.text("\n "); + + public CommandSpyPlugin (ChipmunkBot client) { + this.client = client; + client.chat().addListener((ChatPlugin.Listener) this); + } + + @Override + public void systemMessageReceived (Component component, boolean overlay) { + if (overlay || !(component instanceof final TextComponent t_component)) return; + final boolean enabled = component.style().equals(ENABLED_STYLE); + if (!enabled && !component.style().equals(DISABLED_STYLE)) return; + + final String username = t_component.content(); + final MutablePlayerListEntry sender = client.playerList().getEntry(username); + if (sender == null) return; + + final List children = component.children(); + + if (children.size() == 2) { + // Command + final Component separator = children.get(0); + final Component prefixedCommand = children.get(1); + if ( + !(separator instanceof final TextComponent t_separator) || + !(prefixedCommand instanceof final TextComponent t_prefixedCommand) || + !separator.equals(COMMAND_SEPARATOR_COMPONENT) || + !prefixedCommand.style().isEmpty() + ) return; + + final String command = t_prefixedCommand.content(); + if (command.length() < 1 || command.charAt(0) != '/') return; + final String rawCommand = command.substring(1); + + for (Listener listener : listeners) listener.commandReceived(sender, rawCommand, enabled); + } else if (children.size() == 9) { + // Sign created + final Component[] lines = new Component[4]; + + if (!children.get(0).equals(SIGN_CREATED_TEXT_COMPONENT)) return; + + for (int i = 0; i < lines.length; i++) { + int separatorChildIndex = (i * 2) + 1; + if (!children.get(separatorChildIndex).equals(SIGN_LINE_SEPARATOR_COMPONENT)) return; + lines[i] = children.get(separatorChildIndex + 1); + } + + for (Listener listener : listeners) listener.signCreated(sender, lines, enabled); + } + } + + public static class Listener { + public void commandReceived (MutablePlayerListEntry sender, String command, boolean senderHasCommandSpy) {} + public void signCreated (MutablePlayerListEntry sender, Component[] lines, boolean senderHasCommandSpy) {} + } + + public void addListener (Listener listener) { listeners.add(listener); } + public void removeListener (Listener listener) { listeners.remove(listener); } +} diff --git a/src/main/java/land/chipmunk/chipmunkbot/plugins/ChatCommandHandler.java b/src/main/java/land/chipmunk/chipmunkbot/plugins/PlayerCommandHandler.java similarity index 56% rename from src/main/java/land/chipmunk/chipmunkbot/plugins/ChatCommandHandler.java rename to src/main/java/land/chipmunk/chipmunkbot/plugins/PlayerCommandHandler.java index f2057c6..0370f3b 100644 --- a/src/main/java/land/chipmunk/chipmunkbot/plugins/ChatCommandHandler.java +++ b/src/main/java/land/chipmunk/chipmunkbot/plugins/PlayerCommandHandler.java @@ -9,6 +9,7 @@ import land.chipmunk.chipmunkbot.plugins.ChatPlugin; import land.chipmunk.chipmunkbot.data.chat.PlayerMessage; import land.chipmunk.chipmunkbot.util.ComponentUtilities; import land.chipmunk.chipmunkbot.plugins.CommandManager; +import land.chipmunk.chipmunkbot.data.MutablePlayerListEntry; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import com.mojang.brigadier.CommandDispatcher; @@ -17,18 +18,22 @@ import com.mojang.brigadier.Message; import lombok.Getter; import lombok.Setter; -public class ChatCommandHandler extends ChatPlugin.Listener { +public class PlayerCommandHandler { private ChipmunkBot client; @Getter @Setter private String prefix; + @Getter @Setter private String cspyPrefix; - public ChatCommandHandler (ChipmunkBot client, Options options) { + public PlayerCommandHandler (ChipmunkBot client, Options options) { this.client = client; this.prefix = options.commands.prefix; - client.chat().addListener((ChatPlugin.Listener) this); + this.cspyPrefix = options.commands.cspyPrefix != null ? options.commands.cspyPrefix : this.prefix; + + // TODO: Make this less messy (I might just rewrite how I do events eventually) + client.chat().addListener(new ChatPlugin.Listener() { @Override public void playerMessageReceived (PlayerMessage message) { handleMessage(message); } }); + client.commandSpy().addListener(new CommandSpyPlugin.Listener() { @Override public void commandReceived (MutablePlayerListEntry sender, String command, boolean senderHasCommandSpy) { handleCommand(sender, command); } }); } - @Override - public void playerMessageReceived (PlayerMessage message) { + public void handleMessage (PlayerMessage message) { final Component contents = message.contents(); if (contents == null) return; final String contentsString = ComponentUtilities.stringify(contents); @@ -36,10 +41,21 @@ public class ChatCommandHandler extends ChatPlugin.Listener { final String commandString = contentsString.substring(prefix.length()); final PlayerCommandSource source = new PlayerCommandSource(client, message.sender()); + this.tryExecuteCommand(source, commandString); + } + public void handleCommand (MutablePlayerListEntry sender, String command) { + if (!command.startsWith(cspyPrefix)) return; + final String commandString = command.substring(cspyPrefix.length()); + + final PlayerCommandSource source = new PlayerCommandSource(client, sender); + this.tryExecuteCommand(source, commandString); + } + + private void tryExecuteCommand (CommandSource source, String command) { try { CommandDispatcher dispatcher = client.commandManager().dispatcher(); - dispatcher.execute(commandString, source); + dispatcher.execute(command, source); } catch (CommandSyntaxException exception) { CommandManager.sendException(source, exception); } catch (Exception exception) { diff --git a/src/main/resources/default_config.json b/src/main/resources/default_config.json index a2a850f..6051c7c 100644 --- a/src/main/resources/default_config.json +++ b/src/main/resources/default_config.json @@ -7,7 +7,8 @@ "reconnectDelay": 1000, "commands": { - "prefix": "default." + "prefix": "default.", + "cspyPrefix": "default." }, "core": {