From 2b62b9406d7be25b5e2a599deabd8eb3d221d120 Mon Sep 17 00:00:00 2001 From: Kam Date: Wed, 4 Feb 2026 12:55:06 -0500 Subject: [PATCH] Folder Saving for Cloner Add --- .../npcs/client/gui/GuiNpcMobSpawnerAdd.java | 133 +++++++++++++----- .../gui/GuiNpcMobSpawnerFullscreen.java | 32 +++-- .../npcs/client/gui/SubGuiFolderSelect.java | 74 ++++++++++ 3 files changed, 185 insertions(+), 54 deletions(-) create mode 100644 src/main/java/noppes/npcs/client/gui/SubGuiFolderSelect.java diff --git a/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerAdd.java b/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerAdd.java index be816eb38..5cea7fe28 100644 --- a/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerAdd.java +++ b/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerAdd.java @@ -2,6 +2,7 @@ package noppes.npcs.client.gui; import kamkeel.npcs.network.PacketClient; import kamkeel.npcs.network.packets.request.clone.CloneAllTagsShortPacket; +import kamkeel.npcs.network.packets.request.clone.CloneFolderListPacket; import kamkeel.npcs.network.packets.request.clone.ClonePreSavePacket; import kamkeel.npcs.network.packets.request.clone.CloneSavePacket; import net.minecraft.client.Minecraft; @@ -29,6 +30,7 @@ import noppes.npcs.entity.EntityNPCInterface; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.UUID; public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCallback, IGuiData, ISubGuiListener { @@ -41,8 +43,10 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall private static String folder = null; public boolean isNPC = false; - // Folder names cache for the selector - private String[] folderLabels = new String[0]; + // Client-side folder names + private ArrayList clientFolderNames = new ArrayList<>(); + // Server-side folder names (populated via CloneFolderListPacket) + private static ArrayList serverFolderNames = new ArrayList<>(); // Selected Tags to Add public static NBTTagList tagsCompound; @@ -75,17 +79,36 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall PacketClient.sendClient(new CloneAllTagsShortPacket()); } - buildFolderLabels(); + buildClientFolderNames(); + + // Request server folders if in server mode + if (serverSide) { + PacketClient.sendClient(new CloneFolderListPacket()); + } + + // Validate saved folder selection + validateFolder(); } - private void buildFolderLabels() { - ArrayList names = new ArrayList<>(); + private void buildClientFolderNames() { + clientFolderNames.clear(); if (ClientCloneController.Instance != null) { for (CloneFolder f : ClientCloneController.Instance.getFolderList()) { - names.add(f.name); + clientFolderNames.add(f.name); + } + } + } + + private List getActiveFolderList() { + return serverSide ? serverFolderNames : clientFolderNames; + } + + private void validateFolder() { + if (saveMode == 1 && folder != null) { + if (!getActiveFolderList().contains(folder)) { + folder = null; } } - folderLabels = names.toArray(new String[0]); } @Override @@ -107,26 +130,20 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall int selectedTab = (tab >= 1 && tab <= 15) ? tab - 1 : 0; addButton(new GuiButtonBiDirectional(2, guiLeft + 56, guiTop + 45, 90, 20, tabLabels, selectedTab)); } else { - // Folder selector - if (folderLabels.length > 0) { - int selectedFolder = 0; - if (folder != null) { - for (int i = 0; i < folderLabels.length; i++) { - if (folder.equals(folderLabels[i])) { - selectedFolder = i; - break; - } - } - } - addButton(new GuiButtonBiDirectional(2, guiLeft + 56, guiTop + 45, 90, 20, folderLabels, selectedFolder)); - } else { - addLabel(new GuiNpcLabel(7, "No folders", guiLeft + 60, guiTop + 51)); - } + // Folder selector button — opens SubGuiFolderSelect + String btnText = folder != null ? folder : "Select a Folder"; + addButton(new GuiNpcButton(2, guiLeft + 56, guiTop + 45, 148, 20, btnText)); } - addButton(new GuiNpcButton(0, guiLeft + 4, guiTop + 70, 80, 20, "gui.save")); + // Save / Cancel + GuiNpcButton saveBtn = new GuiNpcButton(0, guiLeft + 4, guiTop + 70, 80, 20, "gui.save"); + if (saveMode == 1 && folder == null) { + saveBtn.enabled = false; + } + addButton(saveBtn); addButton(new GuiNpcButton(1, guiLeft + 86, guiTop + 70, 80, 20, "gui.cancel")); + // Client / Server toggle addButton(new GuiNpcButton(3, guiLeft + 4, guiTop + 95, new String[]{"Client side", "Server side"}, serverSide ? 1 : 0)); if (isNPC) { @@ -139,32 +156,26 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall } private void updateDestinationFromSelector() { - GuiNpcButton selector = getButton(2); - if (selector == null) return; - - int index = selector.getValue(); if (saveMode == 0) { - // Tab mode - tab = index + 1; + GuiNpcButton selector = getButton(2); + if (selector == null) return; + tab = selector.getValue() + 1; folder = null; - } else { - // Folder mode - if (index >= 0 && index < folderLabels.length) { - folder = folderLabels[index]; - tab = -1; - } } + // In folder mode, folder is already set via SubGuiFolderSelect } public void buttonEvent(GuiButton guibutton) { int id = guibutton.id; + + // Save if (id == 0) { updateDestinationFromSelector(); String name = getTextField(0).getText(); if (name.isEmpty()) return; - if (saveMode == 1 && folderLabels.length == 0) + if (saveMode == 1 && folder == null) return; if (!serverSide) { @@ -186,32 +197,60 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall } } } + + // Cancel if (id == 1) { close(); } + + // Destination selector if (id == 2) { - updateDestinationFromSelector(); + if (saveMode == 0) { + // Tab mode — update from BiDirectional + updateDestinationFromSelector(); + } else { + // Folder mode — open folder selector Sub GUI + List folders = getActiveFolderList(); + setSubGui(new SubGuiFolderSelect(folders, folder)); + } } + + // Client / Server toggle if (id == 3) { + boolean wasServerSide = serverSide; serverSide = ((GuiNpcButton) guibutton).getValue() == 1; + + if (serverSide && !wasServerSide) { + // Switching to server mode — request fresh folder list + PacketClient.sendClient(new CloneFolderListPacket()); + } + + // Validate folder exists on the new side + validateFolder(); + initGui(); } + + // Wand Tags if (id == 4) { if (isNPC) { this.setSubGui(new SubGuiClonerQuickTags(this)); } } + + // NPC Tags if (id == 5) { if (isNPC) { this.setSubGui(new SubGuiClonerNPCTags((EntityNPCInterface) toClone, this)); } } + + // Tab/Folder mode toggle if (id == 6) { saveMode = ((GuiNpcButton) guibutton).getValue(); initGui(); } } - @Override public void confirmClicked(boolean confirm, int id) { if (confirm) { @@ -246,7 +285,6 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall displayGuiScreen(this); } - @Override public void save() { } @@ -258,6 +296,17 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall displayGuiScreen(new GuiYesNo(this, "Warning", "You are about to overwrite a clone", 1)); else confirmClicked(true, 0); + } else if (compound.hasKey("CloneFolders")) { + // Server folder list arrived + NBTTagList folderList = compound.getTagList("CloneFolders", 10); + serverFolderNames.clear(); + for (int i = 0; i < folderList.tagCount(); i++) { + CloneFolder f = new CloneFolder(); + f.readNBT(folderList.getCompoundTagAt(i)); + serverFolderNames.add(f.name); + } + validateFolder(); + initGui(); } else if (compound.hasKey("ShortTags")) { NBTTagList validTags = compound.getTagList("ShortTags", 10); tagMap.clear(); @@ -280,6 +329,12 @@ public class GuiNpcMobSpawnerAdd extends GuiNPCInterface implements GuiYesNoCall @Override public void subGuiClosed(SubGuiInterface subgui) { + if (subgui instanceof SubGuiFolderSelect) { + SubGuiFolderSelect sel = (SubGuiFolderSelect) subgui; + if (sel.selectedFolder != null) { + folder = sel.selectedFolder; + } + } initGui(); } diff --git a/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerFullscreen.java b/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerFullscreen.java index 4ee6a8ff0..4919ccbae 100644 --- a/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerFullscreen.java +++ b/src/main/java/noppes/npcs/client/gui/GuiNpcMobSpawnerFullscreen.java @@ -291,36 +291,38 @@ public class GuiNpcMobSpawnerFullscreen extends GuiDirectory implements IGuiData protected void initRightPanel(int startY) { if (GuiNpcMobSpawner.showingClones >= 3) return; - int btnY = startY; int btnGap = 4; + int panelH = contentH - 4; + int midY = startY + (panelH / 2); + int bottomY = contentY + contentH - btnH; - GuiNpcButton spawnBtn = new GuiNpcButton(1, rightX, btnY, rightPanelW, btnH, "item.monsterPlacer.name"); + // Spawn — top + GuiNpcButton spawnBtn = new GuiNpcButton(1, rightX, startY, rightPanelW, btnH, "item.monsterPlacer.name"); if (movePhase > 0) spawnBtn.enabled = false; addButton(spawnBtn); - btnY += btnH + btnGap; - GuiNpcButton spawnerBtn = new GuiNpcButton(2, rightX, btnY, rightPanelW, btnH, "spawner.mobspawner"); + // Spawner — below midpoint + GuiNpcButton spawnerBtn = new GuiNpcButton(2, rightX, midY + btnGap / 2, rightPanelW, btnH, "spawner.mobspawner"); if (movePhase > 0) spawnerBtn.enabled = false; addButton(spawnerBtn); - btnY += btnH + btnGap; if (GuiNpcMobSpawner.showingClones == 0 || GuiNpcMobSpawner.showingClones == 2) { - GuiNpcButton removeBtn = new GuiNpcButton(6, rightX, btnY, rightPanelW, btnH, "gui.remove"); - if (movePhase > 0) removeBtn.enabled = false; - addButton(removeBtn); - btnY += btnH + btnGap; - - // Move button + // Move — above midpoint String moveLabel = movePhase > 0 ? "Moving" : "Move"; - addButton(new GuiNpcButton(50, rightX, btnY, rightPanelW, btnH, moveLabel)); - btnY += btnH + btnGap; + GuiNpcButton moveBtn = new GuiNpcButton(50, rightX, midY - btnH - btnGap / 2, rightPanelW, btnH, moveLabel); + addButton(moveBtn); - // Confirm button (only visible during phase 1) + // Confirm — below Move (only visible during phase 1) if (movePhase == 1) { - GuiNpcButton confirmBtn = new GuiNpcButton(51, rightX, btnY, rightPanelW, btnH, "Confirm"); + GuiNpcButton confirmBtn = new GuiNpcButton(51, rightX, midY - btnH - btnGap / 2 + btnH + btnGap, rightPanelW, btnH, "Confirm"); confirmBtn.enabled = !moveSelection.isEmpty(); addButton(confirmBtn); } + + // Remove — bottom + GuiNpcButton removeBtn = new GuiNpcButton(6, rightX, bottomY, rightPanelW, btnH, "gui.remove"); + if (movePhase > 0) removeBtn.enabled = false; + addButton(removeBtn); } } diff --git a/src/main/java/noppes/npcs/client/gui/SubGuiFolderSelect.java b/src/main/java/noppes/npcs/client/gui/SubGuiFolderSelect.java new file mode 100644 index 000000000..3ec727543 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/SubGuiFolderSelect.java @@ -0,0 +1,74 @@ +package noppes.npcs.client.gui; + +import net.minecraft.client.gui.GuiButton; +import noppes.npcs.client.gui.util.GuiCustomScroll; +import noppes.npcs.client.gui.util.GuiNpcButton; +import noppes.npcs.client.gui.util.ICustomScrollListener; +import noppes.npcs.client.gui.util.SubGuiInterface; + +import java.util.ArrayList; +import java.util.List; + +public class SubGuiFolderSelect extends SubGuiInterface implements ICustomScrollListener { + + public String selectedFolder; + private final List folderList; + private GuiCustomScroll folderScroll; + + public SubGuiFolderSelect(List folders, String currentSelection) { + this.folderList = new ArrayList<>(folders); + this.selectedFolder = currentSelection; + setBackground("menubg.png"); + xSize = 200; + ySize = 220; + closeOnEsc = true; + } + + @Override + public void initGui() { + super.initGui(); + + folderScroll = new GuiCustomScroll(this, 0); + folderScroll.setSize(xSize - 8, ySize - 50); + folderScroll.guiLeft = guiLeft + 4; + folderScroll.guiTop = guiTop + 4; + folderScroll.setList(new ArrayList<>(folderList)); + if (selectedFolder != null) { + folderScroll.setSelected(selectedFolder); + } + addScroll(folderScroll); + + int btnW = (xSize - 12) / 2; + addButton(new GuiNpcButton(0, guiLeft + 4, guiTop + ySize - 44, btnW, 20, "gui.done")); + addButton(new GuiNpcButton(1, guiLeft + 4 + btnW + 4, guiTop + ySize - 44, btnW, 20, "gui.cancel")); + + getButton(0).enabled = folderScroll.hasSelected(); + } + + @Override + public void customScrollClicked(int i, int j, int k, GuiCustomScroll guiCustomScroll) { + getButton(0).enabled = folderScroll.hasSelected(); + } + + @Override + public void customScrollDoubleClicked(String selection, GuiCustomScroll guiCustomScroll) { + selectedFolder = selection; + close(); + } + + @Override + protected void actionPerformed(GuiButton guibutton) { + if (guibutton.id == 0) { + selectedFolder = folderScroll.getSelected(); + close(); + } + if (guibutton.id == 1) { + selectedFolder = null; + close(); + } + } + + @Override + public void save() { + } +}