mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 08:27:45 +00:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
90e146e7b0
12 files changed
+171
-185
No files matched your search
@@ -33,20 +33,19 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
desc = "List all custom abilities"
|
||||
)
|
||||
public void list(ICommandSender sender, String[] args) {
|
||||
Set<String> uuids = AbilityController.Instance.getCustomAbilityIds();
|
||||
if (uuids.isEmpty()) {
|
||||
Set<String> names = AbilityController.Instance.getCustomAbilityNames();
|
||||
if (names.isEmpty()) {
|
||||
sendResult(sender, "No custom abilities found.");
|
||||
return;
|
||||
}
|
||||
|
||||
sendResult(sender, "Custom Abilities (" + uuids.size() + "):");
|
||||
for (String uuid : uuids) {
|
||||
Ability ability = AbilityController.Instance.getCustomAbility(uuid);
|
||||
sendResult(sender, "Custom Abilities (" + names.size() + "):");
|
||||
for (String name : names) {
|
||||
Ability ability = AbilityController.Instance.getCustomAbility(name);
|
||||
if (ability != null) {
|
||||
String name = ability.getName() != null ? ability.getName() : uuid;
|
||||
sendResult(sender, " - \u00A7b" + name + "\u00A77 (" + ability.getTypeId() + ") [" + uuid + "]");
|
||||
sendResult(sender, " - \u00A7b" + name + "\u00A77 (" + ability.getTypeId() + ")");
|
||||
} else {
|
||||
sendResult(sender, " - \u00A7b" + uuid);
|
||||
sendResult(sender, " - \u00A7b" + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,23 +81,23 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
desc = "Delete a custom ability by UUID",
|
||||
usage = "<uuid>"
|
||||
desc = "Delete a custom ability by name",
|
||||
usage = "<name>"
|
||||
)
|
||||
public void delete(ICommandSender sender, String[] args) {
|
||||
if (args.length < 1) {
|
||||
sendError(sender, "Usage: /kam ability delete <uuid>");
|
||||
sendError(sender, "Usage: /kam ability delete <name>");
|
||||
return;
|
||||
}
|
||||
|
||||
String uuid = args[0];
|
||||
if (!AbilityController.Instance.hasCustomAbility(uuid)) {
|
||||
sendError(sender, "No custom ability with UUID: " + uuid);
|
||||
String name = joinArgs(args, 0);
|
||||
if (!AbilityController.Instance.hasCustomAbilityName(name)) {
|
||||
sendError(sender, "No custom ability with name: " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
AbilityController.Instance.deleteCustomAbility(uuid);
|
||||
sendResult(sender, "Deleted ability: \u00A7b" + uuid);
|
||||
AbilityController.Instance.deleteCustomAbility(name);
|
||||
sendResult(sender, "Deleted ability: \u00A7b" + name);
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
@@ -189,7 +188,7 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the ability's canonical ID for storage (registry key for built-in, UUID for custom)
|
||||
// Use the ability's canonical ID for storage (registry key for built-in, name for custom)
|
||||
String canonicalKey = ability.getId();
|
||||
if (canonicalKey == null || canonicalKey.isEmpty()) {
|
||||
canonicalKey = abilityKey; // Fallback to user-provided key
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class AbilityController implements IAbilityHandler {
|
||||
|
||||
@@ -40,6 +41,11 @@ public class AbilityController implements IAbilityHandler {
|
||||
private final List<IAbilityExtender> extenders = new ArrayList<>();
|
||||
private final List<Predicate<EntityPlayer>> flightCheckers = new ArrayList<>();
|
||||
|
||||
// ── Legacy Migration ─────────────────────────────────────────────────────
|
||||
private static final Pattern UUID_PATTERN =
|
||||
Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
// ── Derived State ────────────────────────────────────────────────────────
|
||||
private final Set<String> builtInTypeIds = new HashSet<>();
|
||||
|
||||
@@ -156,6 +162,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
|
||||
public void load() {
|
||||
customAbilities.clear();
|
||||
int migrated = 0;
|
||||
|
||||
File dir = getDir();
|
||||
File[] files = dir.exists() ? dir.listFiles() : null;
|
||||
@@ -164,14 +171,39 @@ public class AbilityController implements IAbilityHandler {
|
||||
if (!file.isFile() || !file.getName().endsWith(".json")) continue;
|
||||
try {
|
||||
String filename = file.getName();
|
||||
String uuid = filename.substring(0, filename.length() - 5);
|
||||
String key = filename.substring(0, filename.length() - 5);
|
||||
|
||||
NBTTagCompound nbt = NBTJsonUtil.LoadFile(file);
|
||||
Ability ability = fromNBT(nbt);
|
||||
if (ability != null) {
|
||||
ability.setId(uuid);
|
||||
customAbilities.put(uuid, ability);
|
||||
if (ability == null) continue;
|
||||
|
||||
// Legacy migration: UUID-named files get renamed to name-based
|
||||
if (UUID_PATTERN.matcher(key).matches()) {
|
||||
String name = ability.getName();
|
||||
if (name == null || name.isEmpty()) {
|
||||
name = key; // Fallback to UUID if no name stored
|
||||
}
|
||||
|
||||
// Ensure unique name
|
||||
while (hasCustomAbilityName(name) || nameFileExists(dir, name)) {
|
||||
name = name + "_";
|
||||
}
|
||||
ability.setName(name);
|
||||
|
||||
// Rename file from UUID.json to name.json
|
||||
File newFile = new File(dir, name + ".json");
|
||||
if (file.renameTo(newFile)) {
|
||||
LogWriter.info("Migrated ability file: " + key + ".json -> " + name + ".json");
|
||||
} else {
|
||||
LogWriter.error("Failed to rename ability file: " + key + ".json -> " + name + ".json");
|
||||
}
|
||||
|
||||
key = name;
|
||||
migrated++;
|
||||
}
|
||||
|
||||
ability.setId(key);
|
||||
customAbilities.put(key, ability);
|
||||
} catch (Exception e) {
|
||||
LogWriter.error("Error loading custom ability: " + file.getAbsolutePath(), e);
|
||||
}
|
||||
@@ -179,21 +211,57 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
|
||||
customAbilityRevision++;
|
||||
if (migrated > 0) {
|
||||
LogWriter.info("Migrated " + migrated + " UUID-named abilities to name-based files");
|
||||
}
|
||||
LogWriter.info("Loaded " + customAbilities.size() + " custom abilities");
|
||||
}
|
||||
|
||||
private boolean nameFileExists(File dir, String name) {
|
||||
return new File(dir, name + ".json").exists();
|
||||
}
|
||||
|
||||
public boolean saveCustomAbility(Ability ability) {
|
||||
if (ability == null) return false;
|
||||
|
||||
String uuid = ability.getId();
|
||||
if (uuid == null || uuid.isEmpty()) {
|
||||
uuid = UUID.randomUUID().toString();
|
||||
ability.setId(uuid);
|
||||
String name = ability.getName();
|
||||
if (name == null || name.isEmpty()) return false;
|
||||
|
||||
// Ensure unique name for new abilities (no existing id)
|
||||
String oldName = ability.getId();
|
||||
boolean isNew = oldName == null || oldName.isEmpty();
|
||||
if (isNew) {
|
||||
while (hasCustomAbilityName(name)) {
|
||||
name = name + "_";
|
||||
}
|
||||
ability.setName(name);
|
||||
}
|
||||
|
||||
// Handle rename: old id (previous name) differs from current name
|
||||
if (!isNew && !oldName.equals(name)) {
|
||||
// Check uniqueness of new name (excluding the entry being renamed)
|
||||
String testName = name;
|
||||
while (customAbilities.containsKey(testName) && !testName.equals(oldName)) {
|
||||
testName = testName + "_";
|
||||
}
|
||||
if (!testName.equals(name)) {
|
||||
name = testName;
|
||||
ability.setName(name);
|
||||
}
|
||||
|
||||
// Delete old file and remove old map entry
|
||||
File oldFile = new File(getDir(), oldName + ".json");
|
||||
if (oldFile.exists()) {
|
||||
oldFile.delete();
|
||||
}
|
||||
customAbilities.remove(oldName);
|
||||
}
|
||||
|
||||
ability.setId(name);
|
||||
|
||||
File dir = getDir();
|
||||
File fileNew = new File(dir, uuid + ".json_new");
|
||||
File fileCurrent = new File(dir, uuid + ".json");
|
||||
File fileNew = new File(dir, name + ".json_new");
|
||||
File fileCurrent = new File(dir, name + ".json");
|
||||
|
||||
try {
|
||||
NBTTagCompound nbt = ability.writeNBT();
|
||||
@@ -207,52 +275,43 @@ public class AbilityController implements IAbilityHandler {
|
||||
fileNew.delete();
|
||||
}
|
||||
|
||||
customAbilities.put(uuid, ability);
|
||||
customAbilities.put(name, ability);
|
||||
customAbilityRevision++;
|
||||
LogWriter.info("Saved custom ability: " + ability.getName() + " [" + uuid + "]");
|
||||
LogWriter.info("Saved custom ability: " + name);
|
||||
SyncController.syncAllCustomAbilities();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogWriter.error("Error saving custom ability: " + uuid, e);
|
||||
LogWriter.error("Error saving custom ability: " + name, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deleteCustomAbility(String uuid) {
|
||||
if (uuid == null || uuid.isEmpty()) return false;
|
||||
public boolean deleteCustomAbility(String name) {
|
||||
if (name == null || name.isEmpty()) return false;
|
||||
|
||||
Ability removed = customAbilities.remove(uuid);
|
||||
Ability removed = customAbilities.remove(name);
|
||||
if (removed == null) return false;
|
||||
|
||||
File dir = getDir();
|
||||
File file = new File(dir, uuid + ".json");
|
||||
File file = new File(dir, name + ".json");
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
|
||||
customAbilityRevision++;
|
||||
LogWriter.info("Deleted custom ability: " + uuid);
|
||||
LogWriter.info("Deleted custom ability: " + name);
|
||||
SyncController.syncAllCustomAbilities();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Ability getCustomAbility(String uuid) {
|
||||
return customAbilities.get(uuid);
|
||||
public Ability getCustomAbility(String name) {
|
||||
return customAbilities.get(name);
|
||||
}
|
||||
|
||||
public boolean hasCustomAbility(String uuid) {
|
||||
return customAbilities.containsKey(uuid);
|
||||
}
|
||||
|
||||
public Set<String> getCustomAbilityIds() {
|
||||
public Set<String> getCustomAbilityNames() {
|
||||
return new LinkedHashSet<>(customAbilities.keySet());
|
||||
}
|
||||
|
||||
public String getCustomAbilityName(String uuid) {
|
||||
Ability a = customAbilities.get(uuid);
|
||||
return a != null ? a.getName() : null;
|
||||
}
|
||||
|
||||
public Map<String, Ability> getCustomAbilities() {
|
||||
return customAbilities;
|
||||
}
|
||||
@@ -300,7 +359,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Custom: exact UUID
|
||||
// Custom: exact name
|
||||
Ability custom = customAbilities.get(key);
|
||||
if (custom != null) return custom.deepCopy();
|
||||
|
||||
@@ -322,7 +381,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
keys.add(id);
|
||||
}
|
||||
}
|
||||
// Use ability names for custom abilities (instead of UUIDs) for readable tab completion
|
||||
// Custom abilities keyed by name
|
||||
for (Ability ability : customAbilities.values()) {
|
||||
String name = ability.getName();
|
||||
if (name != null && !name.isEmpty()) {
|
||||
@@ -342,7 +401,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Use ability names for custom abilities (instead of UUIDs) for readable tab completion
|
||||
// Custom abilities keyed by name
|
||||
for (Ability ability : customAbilities.values()) {
|
||||
if (ability.getAllowedBy().allowsPlayer()) {
|
||||
String name = ability.getName();
|
||||
@@ -378,7 +437,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
if (ability.getId() != null && ability.getId().equalsIgnoreCase(key)) return true;
|
||||
}
|
||||
|
||||
// Custom: exact UUID
|
||||
// Custom: exact name
|
||||
if (customAbilities.containsKey(key)) return true;
|
||||
|
||||
// Custom: case-insensitive name
|
||||
@@ -549,17 +608,17 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getCustomAbilityIdArray() {
|
||||
public String[] getCustomAbilityNameArray() {
|
||||
return customAbilities.keySet().toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomAbilityId(String uuid) {
|
||||
return customAbilities.containsKey(uuid);
|
||||
public boolean hasCustomAbilityName(String name) {
|
||||
return customAbilities.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteCustomAbilityById(String uuid) {
|
||||
return deleteCustomAbility(uuid);
|
||||
public boolean deleteCustomAbilityByName(String name) {
|
||||
return deleteCustomAbility(name);
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class AbilitySlot {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a slot that references a built-in ability (by name) or custom ability (by UUID).
|
||||
* Create a slot that references a built-in ability (by name) or custom ability (by name).
|
||||
*/
|
||||
public static AbilitySlot reference(String referenceId) {
|
||||
AbilitySlot slot = new AbilitySlot();
|
||||
|
||||
+7
-9
@@ -20,18 +20,18 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Request packet to get a specific custom ability by UUID.
|
||||
* Request packet to get a specific custom ability by name.
|
||||
*/
|
||||
public final class CustomAbilityGetPacket extends AbstractPacket {
|
||||
public static String packetName = "Request|CustomAbilityGet";
|
||||
|
||||
private String uuid;
|
||||
private String name;
|
||||
|
||||
public CustomAbilityGetPacket() {
|
||||
}
|
||||
|
||||
public CustomAbilityGetPacket(String uuid) {
|
||||
this.uuid = uuid;
|
||||
public CustomAbilityGetPacket(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +47,7 @@ public final class CustomAbilityGetPacket extends AbstractPacket {
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
ByteBufUtils.writeString(out, uuid);
|
||||
ByteBufUtils.writeString(out, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,12 +58,10 @@ public final class CustomAbilityGetPacket extends AbstractPacket {
|
||||
if (!PacketUtil.verifyItemPacket(packetName, EnumItemPacketType.WAND, player))
|
||||
return;
|
||||
|
||||
String id = ByteBufUtils.readString(in);
|
||||
Ability ability = AbilityController.Instance.getCustomAbility(id);
|
||||
String abilityName = ByteBufUtils.readString(in);
|
||||
Ability ability = AbilityController.Instance.getCustomAbility(abilityName);
|
||||
if (ability != null) {
|
||||
NBTTagCompound compound = ability.writeNBT();
|
||||
// Include the UUID so the client can track it
|
||||
compound.setString("_uuid", id);
|
||||
GuiDataPacket.sendGuiData((EntityPlayerMP) player, compound);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -19,18 +19,18 @@ import noppes.npcs.NoppesUtilServer;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Request packet to remove a custom ability by UUID.
|
||||
* Request packet to remove a custom ability by name.
|
||||
*/
|
||||
public final class CustomAbilityRemovePacket extends AbstractPacket {
|
||||
public static String packetName = "Request|CustomAbilityRemove";
|
||||
|
||||
private String uuid;
|
||||
private String name;
|
||||
|
||||
public CustomAbilityRemovePacket() {
|
||||
}
|
||||
|
||||
public CustomAbilityRemovePacket(String uuid) {
|
||||
this.uuid = uuid;
|
||||
public CustomAbilityRemovePacket(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +51,7 @@ public final class CustomAbilityRemovePacket extends AbstractPacket {
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
ByteBufUtils.writeString(out, uuid);
|
||||
ByteBufUtils.writeString(out, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-1
@@ -71,7 +71,6 @@ public final class CustomAbilitySavePacket extends AbstractPacket {
|
||||
AbilityController.Instance.saveCustomAbility(ability);
|
||||
NoppesUtilServer.sendCustomAbilitiesData((EntityPlayerMP) player);
|
||||
NBTTagCompound responseNbt = ability.writeNBT();
|
||||
responseNbt.setString("_uuid", ability.getId());
|
||||
GuiDataPacket.sendGuiData((EntityPlayerMP) player, responseNbt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -950,7 +950,7 @@ public class DataAbilities {
|
||||
abilitySlots.add(AbilitySlot.inline(ability));
|
||||
}
|
||||
|
||||
/** Add a reference ability by key (built-in name or custom UUID). */
|
||||
/** Add a reference ability by key (built-in name or custom ability name). */
|
||||
public void addAbilityReference(String key) {
|
||||
abilitySlots.add(AbilitySlot.reference(key));
|
||||
}
|
||||
|
||||
@@ -810,13 +810,10 @@ public class NoppesUtilServer {
|
||||
kamkeel.npcs.controllers.data.ability.AbilityController controller = kamkeel.npcs.controllers.data.ability.AbilityController.Instance;
|
||||
if (controller != null) {
|
||||
int index = 0;
|
||||
for (String uuid : controller.getCustomAbilityIds()) {
|
||||
Ability ability = controller.getCustomAbility(uuid);
|
||||
for (String name : controller.getCustomAbilityNames()) {
|
||||
Ability ability = controller.getCustomAbility(name);
|
||||
if (ability == null || !ability.getAllowedBy().allowsNpc()) continue;
|
||||
|
||||
String name = controller.getCustomAbilityName(uuid);
|
||||
if (name == null || name.isEmpty()) name = uuid;
|
||||
map.put(name + "\t" + uuid, index++);
|
||||
map.put(name, index++);
|
||||
}
|
||||
}
|
||||
sendScrollData(player, map, EnumScrollData.CUSTOM_ABILITIES);
|
||||
|
||||
@@ -21,7 +21,6 @@ import noppes.npcs.constants.EnumScrollData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
@@ -33,10 +32,8 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
private final SubGuiAbilityConfig parentConfig;
|
||||
private final GuiNPCAbilities parentAbilities;
|
||||
private String selectedDisplayName = null;
|
||||
private String selectedUuid = null;
|
||||
private String selectedName = null;
|
||||
|
||||
/** Maps display name -> UUID for custom abilities. */
|
||||
private final HashMap<String, String> displayToUuid = new HashMap<>();
|
||||
private HashMap<String, Integer> rawData = new HashMap<>();
|
||||
private GuiCustomScroll scroll;
|
||||
|
||||
@@ -97,15 +94,15 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
addButton(new GuiNpcButton(0, guiLeft + 10, y, 95, 20, "gui.load"));
|
||||
addButton(new GuiNpcButton(2, guiLeft + 115, y, 95, 20, "gui.cancel"));
|
||||
|
||||
getButton(0).setEnabled(selectedUuid != null);
|
||||
getButton(0).setEnabled(selectedName != null);
|
||||
}
|
||||
|
||||
private List<String> getFilteredList() {
|
||||
if (search.isEmpty()) {
|
||||
return new ArrayList<>(displayToUuid.keySet());
|
||||
return new ArrayList<>(rawData.keySet());
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String name : displayToUuid.keySet()) {
|
||||
for (String name : rawData.keySet()) {
|
||||
if (name.toLowerCase().contains(search.toLowerCase())) {
|
||||
list.add(name);
|
||||
}
|
||||
@@ -117,7 +114,7 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
public void buttonEvent(GuiButton guibutton) {
|
||||
int id = guibutton.id;
|
||||
|
||||
if (id == 0 && selectedUuid != null) {
|
||||
if (id == 0 && selectedName != null) {
|
||||
if (parentAbilities != null) {
|
||||
// From NPC abilities GUI - ask clone/reference
|
||||
setSubGui(new SubGuiAbilityLoadMode());
|
||||
@@ -125,7 +122,7 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
// From config GUI - always clone
|
||||
waitingForLoad = true;
|
||||
pendingLoadMode = SubGuiAbilityLoadMode.MODE_CLONE;
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selectedUuid));
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selectedName));
|
||||
}
|
||||
} else if (id == 2) {
|
||||
close();
|
||||
@@ -152,16 +149,16 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
if (mode < 0) return; // cancelled
|
||||
|
||||
if (mode == SubGuiAbilityLoadMode.MODE_REFERENCE) {
|
||||
// Reference mode - just pass the reference ID
|
||||
if (parentAbilities != null && selectedUuid != null) {
|
||||
parentAbilities.loadAbilityReference(selectedUuid);
|
||||
// Reference mode - just pass the reference name
|
||||
if (parentAbilities != null && selectedName != null) {
|
||||
parentAbilities.loadAbilityReference(selectedName);
|
||||
}
|
||||
close();
|
||||
} else {
|
||||
// Clone mode - request full data
|
||||
waitingForLoad = true;
|
||||
pendingLoadMode = SubGuiAbilityLoadMode.MODE_CLONE;
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selectedUuid));
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selectedName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,9 +167,7 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) {
|
||||
if (scroll.id == 0) {
|
||||
selectedDisplayName = scroll.getSelected();
|
||||
if (selectedDisplayName != null) {
|
||||
selectedUuid = displayToUuid.get(selectedDisplayName);
|
||||
}
|
||||
selectedName = selectedDisplayName;
|
||||
initGui();
|
||||
}
|
||||
}
|
||||
@@ -181,15 +176,13 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
public void customScrollDoubleClicked(String selection, GuiCustomScroll scroll) {
|
||||
if (scroll.id == 0 && selection != null && !selection.isEmpty()) {
|
||||
selectedDisplayName = selection;
|
||||
selectedUuid = displayToUuid.get(selectedDisplayName);
|
||||
if (selectedUuid != null) {
|
||||
if (parentAbilities != null) {
|
||||
setSubGui(new SubGuiAbilityLoadMode());
|
||||
} else {
|
||||
waitingForLoad = true;
|
||||
pendingLoadMode = SubGuiAbilityLoadMode.MODE_CLONE;
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selectedUuid));
|
||||
}
|
||||
selectedName = selection;
|
||||
if (parentAbilities != null) {
|
||||
setSubGui(new SubGuiAbilityLoadMode());
|
||||
} else {
|
||||
waitingForLoad = true;
|
||||
pendingLoadMode = SubGuiAbilityLoadMode.MODE_CLONE;
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selectedName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,22 +190,10 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
@Override
|
||||
public void setData(Vector<String> list, HashMap<String, Integer> data, EnumScrollData type) {
|
||||
if (type == EnumScrollData.CUSTOM_ABILITIES) {
|
||||
displayToUuid.clear();
|
||||
rawData = data;
|
||||
for (String key : data.keySet()) {
|
||||
// key format: "displayName\tUUID"
|
||||
int tabIndex = key.indexOf('\t');
|
||||
if (tabIndex > 0) {
|
||||
String displayName = key.substring(0, tabIndex);
|
||||
String uuid = key.substring(tabIndex + 1);
|
||||
displayToUuid.put(displayName, uuid);
|
||||
} else {
|
||||
displayToUuid.put(key, key);
|
||||
}
|
||||
}
|
||||
if (scroll != null) {
|
||||
scroll.setList(getFilteredList());
|
||||
if (selectedDisplayName != null && displayToUuid.containsKey(selectedDisplayName)) {
|
||||
if (selectedDisplayName != null && rawData.containsKey(selectedDisplayName)) {
|
||||
scroll.setSelected(selectedDisplayName);
|
||||
}
|
||||
}
|
||||
@@ -226,11 +207,6 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
waitingForLoad = false;
|
||||
Ability loaded = AbilityController.Instance.fromNBT(compound);
|
||||
if (loaded != null) {
|
||||
if (pendingLoadMode == SubGuiAbilityLoadMode.MODE_CLONE) {
|
||||
// Give it a new UUID so it's a unique inline copy
|
||||
loaded.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
if (parentConfig != null) {
|
||||
parentConfig.loadAbility(loaded);
|
||||
} else if (parentAbilities != null) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package noppes.npcs.client.gui.global;
|
||||
import kamkeel.npcs.client.renderer.TelegraphRenderer;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import java.util.UUID;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.network.PacketClient;
|
||||
import kamkeel.npcs.network.packets.request.ability.BuiltInAbilityGetPacket;
|
||||
@@ -62,10 +61,7 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
private GuiCustomScroll scroll;
|
||||
private HashMap<String, Integer> customData = new HashMap<>();
|
||||
private HashMap<String, Integer> builtInData = new HashMap<>();
|
||||
/** Maps display name -> UUID for custom abilities */
|
||||
private final HashMap<String, String> displayToUuid = new HashMap<>();
|
||||
private String selected = null;
|
||||
private String selectedUuid = null;
|
||||
private String search = "";
|
||||
private Ability selectedAbility = null;
|
||||
|
||||
@@ -117,7 +113,7 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
|
||||
// Remove button — only for custom view
|
||||
addButton(new GuiNpcButton(1, guiLeft + 368, guiTop + 30, 45, 20, "gui.remove"));
|
||||
getButton(1).setEnabled(selected != null && !selected.isEmpty() && displayToUuid.containsKey(selected));
|
||||
getButton(1).setEnabled(selected != null && !selected.isEmpty() && customData.containsKey(selected));
|
||||
}
|
||||
|
||||
// Edit button — hidden when viewing built-in
|
||||
@@ -178,29 +174,17 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
}
|
||||
|
||||
private List<String> getSearchList() {
|
||||
if (showingBuiltIn) {
|
||||
if (search.isEmpty()) {
|
||||
return new ArrayList<>(builtInData.keySet());
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String name : builtInData.keySet()) {
|
||||
if (name.toLowerCase().contains(search.toLowerCase())) {
|
||||
list.add(name);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
} else {
|
||||
if (search.isEmpty()) {
|
||||
return new ArrayList<>(displayToUuid.keySet());
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String name : displayToUuid.keySet()) {
|
||||
if (name.toLowerCase().contains(search.toLowerCase())) {
|
||||
list.add(name);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
HashMap<String, Integer> data = getCurrentData();
|
||||
if (search.isEmpty()) {
|
||||
return new ArrayList<>(data.keySet());
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String name : data.keySet()) {
|
||||
if (name.toLowerCase().contains(search.toLowerCase())) {
|
||||
list.add(name);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -260,7 +244,6 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
if (id == 10) {
|
||||
showingBuiltIn = !showingBuiltIn;
|
||||
selected = null;
|
||||
selectedUuid = null;
|
||||
selectedAbility = null;
|
||||
currentIsBuiltIn = false;
|
||||
search = "";
|
||||
@@ -276,7 +259,7 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
if (id == 2 && !showingBuiltIn) {
|
||||
// Add — open type selection
|
||||
setSubGui(new SubGuiAbilityTypeSelect());
|
||||
} else if (id == 1 && !showingBuiltIn && selected != null && selectedUuid != null) {
|
||||
} else if (id == 1 && !showingBuiltIn && selected != null) {
|
||||
GuiYesNo guiyesno = new GuiYesNo(this, selected, StatCollector.translateToLocal("gui.delete"), 1);
|
||||
displayGuiScreen(guiyesno);
|
||||
} else if (id == 100 && !showingBuiltIn && !currentIsBuiltIn && selectedAbility != null) {
|
||||
@@ -325,17 +308,11 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
selected = newSelection;
|
||||
|
||||
if (showingBuiltIn) {
|
||||
// Fetch built-in ability by display name
|
||||
selectedUuid = null;
|
||||
currentIsBuiltIn = true;
|
||||
PacketClient.sendClient(new BuiltInAbilityGetPacket(selected));
|
||||
} else {
|
||||
// Fetch custom ability by UUID
|
||||
selectedUuid = displayToUuid.get(selected);
|
||||
currentIsBuiltIn = false;
|
||||
if (selectedUuid != null) {
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selectedUuid));
|
||||
}
|
||||
PacketClient.sendClient(new CustomAbilityGetPacket(selected));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,21 +334,9 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
if (type == EnumScrollData.CUSTOM_ABILITIES) {
|
||||
String prevSelected = scroll != null ? scroll.getSelected() : null;
|
||||
this.customData = data;
|
||||
displayToUuid.clear();
|
||||
for (String key : data.keySet()) {
|
||||
// key format: "displayName\tUUID"
|
||||
int tabIndex = key.indexOf('\t');
|
||||
if (tabIndex > 0) {
|
||||
String displayName = key.substring(0, tabIndex);
|
||||
String uuid = key.substring(tabIndex + 1);
|
||||
displayToUuid.put(displayName, uuid);
|
||||
} else {
|
||||
displayToUuid.put(key, key);
|
||||
}
|
||||
}
|
||||
if (!showingBuiltIn && scroll != null) {
|
||||
scroll.setList(getSearchList());
|
||||
if (prevSelected != null && displayToUuid.containsKey(prevSelected)) {
|
||||
if (prevSelected != null && customData.containsKey(prevSelected)) {
|
||||
scroll.setSelected(prevSelected);
|
||||
}
|
||||
}
|
||||
@@ -422,7 +387,6 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
Ability newAbility = AbilityController.Instance.create(pendingTypeId);
|
||||
if (newAbility != null) {
|
||||
variantGui.getVariants().get(idx).apply(newAbility);
|
||||
newAbility.setId(UUID.randomUUID().toString());
|
||||
if (hasDuplicateName(newAbility)) {
|
||||
pendingSaveAbility = newAbility;
|
||||
pendingNewCreation = true;
|
||||
@@ -450,7 +414,6 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
if (variants.size() == 1) {
|
||||
variants.get(0).apply(newAbility);
|
||||
}
|
||||
newAbility.setId(UUID.randomUUID().toString());
|
||||
if (hasDuplicateName(newAbility)) {
|
||||
pendingSaveAbility = newAbility;
|
||||
pendingNewCreation = true;
|
||||
@@ -504,7 +467,6 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
private void openConfig(Ability ability) {
|
||||
selectedAbility = ability;
|
||||
selected = ability.getName();
|
||||
selectedUuid = ability.getId();
|
||||
previewExecutor.stop();
|
||||
setSubGui(ability.createConfigGui(this));
|
||||
}
|
||||
@@ -512,12 +474,9 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
private boolean hasDuplicateName(Ability ability) {
|
||||
String name = ability.getName();
|
||||
if (name == null || name.isEmpty()) return false;
|
||||
for (java.util.Map.Entry<String, String> entry : displayToUuid.entrySet()) {
|
||||
if (entry.getKey().equals(name) && !entry.getValue().equals(ability.getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
String oldName = ability.getId();
|
||||
// A duplicate exists if the name is already in use and it's not the same ability being edited
|
||||
return customData.containsKey(name) && !name.equals(oldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -525,11 +484,10 @@ public class GuiNpcManageAbilities extends GuiAbilityInterface
|
||||
NoppesUtil.openGUI(player, this);
|
||||
if (!result) return;
|
||||
|
||||
if (id == 1 && selected != null && selectedUuid != null) {
|
||||
PacketClient.sendClient(new CustomAbilityRemovePacket(selectedUuid));
|
||||
if (id == 1 && selected != null) {
|
||||
PacketClient.sendClient(new CustomAbilityRemovePacket(selected));
|
||||
scroll.clear();
|
||||
selected = null;
|
||||
selectedUuid = null;
|
||||
selectedAbility = null;
|
||||
initGui();
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ScriptPlayerAbilityData implements IPlayerAbilityData {
|
||||
if (!ability.getAllowedBy().allowsPlayer()) {
|
||||
return; // Ability is NPC-only
|
||||
}
|
||||
// Use canonical key (registry key for built-in, UUID for custom)
|
||||
// Use canonical key (registry key for built-in, name for custom)
|
||||
String canonicalKey = ability.getId() != null ? ability.getId() : key;
|
||||
data.unlockAbility(canonicalKey);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user