diff --git a/cli/build.gradle.kts b/cli/build.gradle.kts index f41fc8e..fa4d7cc 100644 --- a/cli/build.gradle.kts +++ b/cli/build.gradle.kts @@ -11,6 +11,7 @@ val lwjglNatives = "natives-windows" dependencies { implementation(project(":api")) implementation(project(":core")) + implementation("com.google.code.gson:gson:2.11.0") implementation("io.github.spair:imgui-java-app:$imguiVersion") runtimeOnly("io.github.spair:imgui-java-natives-windows:$imguiVersion") runtimeOnly("org.lwjgl:lwjgl:$lwjglVersion:$lwjglNatives") diff --git a/cli/src/main/java/com/botwithus/bot/cli/CliContext.java b/cli/src/main/java/com/botwithus/bot/cli/CliContext.java index 5d59219..96da7c0 100644 --- a/cli/src/main/java/com/botwithus/bot/cli/CliContext.java +++ b/cli/src/main/java/com/botwithus/bot/cli/CliContext.java @@ -21,6 +21,10 @@ import com.botwithus.bot.core.runtime.ScriptRunner; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + import java.awt.image.BufferedImage; import java.io.PrintStream; import java.nio.file.Files; @@ -297,14 +301,69 @@ public void openConfigPanel(ScriptRunner runner) { if (configPanelOpener != null) configPanelOpener.accept(runner); } - // --- Connection Group management --- + // --- Connection Group management & persistence --- + + private static final Path GROUPS_FILE = Path.of(System.getProperty("user.home"), ".botwithus", "groups.json"); + + /** Simple DTO for JSON serialization of a group. */ + private static class GroupData { + String description; + List members; + GroupData() {} + GroupData(String description, List members) { + this.description = description; + this.members = members; + } + } + + /** Loads persisted groups from ~/.botwithus/groups.json. */ + public void loadGroups() { + if (!Files.exists(GROUPS_FILE)) return; + try { + String json = Files.readString(GROUPS_FILE); + Gson gson = new Gson(); + Map data = gson.fromJson(json, + new TypeToken>() {}.getType()); + if (data != null) { + groups.clear(); + for (var entry : data.entrySet()) { + ConnectionGroup group = new ConnectionGroup(entry.getKey()); + GroupData gd = entry.getValue(); + if (gd.description != null) group.setDescription(gd.description); + if (gd.members != null) gd.members.forEach(group::add); + groups.put(entry.getKey(), group); + } + } + } catch (Exception e) { + System.err.println("[CliContext] Failed to load groups: " + e.getMessage()); + } + } + + /** Persists current groups to ~/.botwithus/groups.json. */ + void saveGroups() { + try { + Files.createDirectories(GROUPS_FILE.getParent()); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Map data = new LinkedHashMap<>(); + for (var entry : groups.entrySet()) { + ConnectionGroup g = entry.getValue(); + data.put(entry.getKey(), new GroupData(g.getDescription(), new ArrayList<>(g.getConnectionNames()))); + } + Files.writeString(GROUPS_FILE, gson.toJson(data)); + } catch (Exception e) { + System.err.println("[CliContext] Failed to save groups: " + e.getMessage()); + } + } public void createGroup(String name) { groups.put(name, new ConnectionGroup(name)); + saveGroups(); } public boolean deleteGroup(String name) { - return groups.remove(name) != null; + boolean removed = groups.remove(name) != null; + if (removed) saveGroups(); + return removed; } public ConnectionGroup getGroup(String name) { @@ -315,6 +374,22 @@ public Map getGroups() { return Collections.unmodifiableMap(groups); } + public void addToGroup(String groupName, String connectionName) { + ConnectionGroup group = groups.get(groupName); + if (group != null) { + group.add(connectionName); + saveGroups(); + } + } + + public void removeFromGroup(String groupName, String connectionName) { + ConnectionGroup group = groups.get(groupName); + if (group != null) { + group.remove(connectionName); + saveGroups(); + } + } + /** * Returns the list of active (connected) Connection objects for a group. * Connections that are in the group but not currently connected are skipped. diff --git a/cli/src/main/java/com/botwithus/bot/cli/ClientManager.java b/cli/src/main/java/com/botwithus/bot/cli/ClientManager.java index 74c166a..a9ccceb 100644 --- a/cli/src/main/java/com/botwithus/bot/cli/ClientManager.java +++ b/cli/src/main/java/com/botwithus/bot/cli/ClientManager.java @@ -113,6 +113,7 @@ public void setGroupDescription(String groupName, String description) { ConnectionGroup group = ctx.getGroup(groupName); if (group != null) { group.setDescription(description); + ctx.saveGroups(); } } @@ -124,17 +125,15 @@ public Set getGroupMembers(String groupName) { @Override public boolean addToGroup(String groupName, String clientName) { - ConnectionGroup group = ctx.getGroup(groupName); - if (group == null) return false; - group.add(clientName); + if (ctx.getGroup(groupName) == null) return false; + ctx.addToGroup(groupName, clientName); return true; } @Override public boolean removeFromGroup(String groupName, String clientName) { - ConnectionGroup group = ctx.getGroup(groupName); - if (group == null) return false; - group.remove(clientName); + if (ctx.getGroup(groupName) == null) return false; + ctx.removeFromGroup(groupName, clientName); return true; } diff --git a/cli/src/main/java/com/botwithus/bot/cli/JBotCli.java b/cli/src/main/java/com/botwithus/bot/cli/JBotCli.java index eda1a8e..46d8bdf 100644 --- a/cli/src/main/java/com/botwithus/bot/cli/JBotCli.java +++ b/cli/src/main/java/com/botwithus/bot/cli/JBotCli.java @@ -40,6 +40,7 @@ public static void main(String[] args) { PrintStream out = logCapture.getOriginalOut(); CliContext ctx = new CliContext(logBuffer, logCapture); + ctx.loadGroups(); CommandRegistry registry = new CommandRegistry(); // Register commands diff --git a/cli/src/main/java/com/botwithus/bot/cli/command/impl/GroupCommand.java b/cli/src/main/java/com/botwithus/bot/cli/command/impl/GroupCommand.java index 1b33338..ae2dd96 100644 --- a/cli/src/main/java/com/botwithus/bot/cli/command/impl/GroupCommand.java +++ b/cli/src/main/java/com/botwithus/bot/cli/command/impl/GroupCommand.java @@ -75,7 +75,7 @@ private void addToGroup(String groupName, String connName, CliContext ctx) { ctx.out().println("'" + connName + "' is already in group '" + groupName + "'."); return; } - group.add(connName); + ctx.addToGroup(groupName, connName); ctx.out().println("Added '" + connName + "' to group '" + groupName + "'."); } @@ -93,7 +93,7 @@ private void removeFromGroup(String groupName, String connName, CliContext ctx) ctx.out().println("'" + connName + "' is not in group '" + groupName + "'."); return; } - group.remove(connName); + ctx.removeFromGroup(groupName, connName); ctx.out().println("Removed '" + connName + "' from group '" + groupName + "'."); } diff --git a/cli/src/main/java/com/botwithus/bot/cli/gui/GroupsPanel.java b/cli/src/main/java/com/botwithus/bot/cli/gui/GroupsPanel.java index b5abf40..ac3dd03 100644 --- a/cli/src/main/java/com/botwithus/bot/cli/gui/GroupsPanel.java +++ b/cli/src/main/java/com/botwithus/bot/cli/gui/GroupsPanel.java @@ -135,7 +135,7 @@ public void render(CliContext ctx) { ImGui.sameLine(0, 12); ImGui.pushID("member_rm_" + grpIdx + "_" + memberIdx); if (ImGui.smallButton("Remove")) { - group.remove(memberName); + ctx.removeFromGroup(groupName, memberName); } ImGui.popID(); memberIdx++; @@ -167,7 +167,7 @@ private void renderAddConnectionDropdown(CliContext ctx, String groupName, Conne ImGui.popItemWidth(); ImGui.sameLine(); if (ImGui.smallButton("Add")) { - group.add(names[selected.get()]); + ctx.addToGroup(groupName, names[selected.get()]); } ImGui.popID(); } diff --git a/cli/src/main/java/com/botwithus/bot/cli/gui/ImGuiApp.java b/cli/src/main/java/com/botwithus/bot/cli/gui/ImGuiApp.java index cd1d229..0f7a65d 100644 --- a/cli/src/main/java/com/botwithus/bot/cli/gui/ImGuiApp.java +++ b/cli/src/main/java/com/botwithus/bot/cli/gui/ImGuiApp.java @@ -120,6 +120,7 @@ protected void initImGui(Configuration config) { logCapture.install(); ctx = new CliContext(logBuffer, logCapture); + ctx.loadGroups(); ctx.setStreamManager(new StreamManager(outputBuffer, textureManager, guiOut)); ScriptProfileStore profileStore = new ScriptProfileStore(); diff --git a/cli/src/main/java/module-info.java b/cli/src/main/java/module-info.java index 45eab44..9c6c2f4 100644 --- a/cli/src/main/java/module-info.java +++ b/cli/src/main/java/module-info.java @@ -1,6 +1,7 @@ module com.botwithus.bot.cli { requires com.botwithus.bot.api; requires com.botwithus.bot.core; + requires com.google.gson; requires imgui.binding; requires imgui.app; requires org.lwjgl;