diff --git a/src/main/java/com/playmonumenta/libraryofsouls/LibraryOfSoulsAPI.java b/src/main/java/com/playmonumenta/libraryofsouls/LibraryOfSoulsAPI.java index fc5f581..02b9851 100644 --- a/src/main/java/com/playmonumenta/libraryofsouls/LibraryOfSoulsAPI.java +++ b/src/main/java/com/playmonumenta/libraryofsouls/LibraryOfSoulsAPI.java @@ -1,9 +1,11 @@ package com.playmonumenta.libraryofsouls; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import net.kyori.adventure.text.Component; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.jetbrains.annotations.Nullable; @@ -55,4 +57,13 @@ public static Set getSoulLocations() { SoulsDatabase db = SoulsDatabase.getInstance(); return db.listMobLocations(); } + + public static List getDescription(String soulName) { + SoulsDatabase db = SoulsDatabase.getInstance(); + SoulEntry soul = db.getSoul(soulName); + if (soul == null) { + return null; + } + return soul.getDescription(); + } } diff --git a/src/main/java/com/playmonumenta/libraryofsouls/SoulEntry.java b/src/main/java/com/playmonumenta/libraryofsouls/SoulEntry.java index 5c5d621..fff06e1 100644 --- a/src/main/java/com/playmonumenta/libraryofsouls/SoulEntry.java +++ b/src/main/java/com/playmonumenta/libraryofsouls/SoulEntry.java @@ -44,9 +44,10 @@ public class SoulEntry implements Soul, BestiaryEntryInterface { private final Set mLocs; private final List mHistory; private List mLore; + private List mDescription; /* Create a SoulEntry object with existing history */ - public SoulEntry(List history, Set locationNames, List lore) throws Exception { + public SoulEntry(List history, Set locationNames, List lore, List description) throws Exception { mHistory = history; if (locationNames == null) { @@ -56,11 +57,17 @@ public SoulEntry(List history, Set locationNames, List } if (lore == null) { - mLore = new ArrayList(); + mLore = new ArrayList<>(); } else { mLore = lore; } + if (description == null) { + mDescription = new ArrayList<>(); + } else { + mDescription = description; + } + String refLabel = history.get(0).getLabel(); Component refName = history.get(0).getName(); @@ -79,6 +86,7 @@ public SoulEntry(Player player, NBTTagCompound nbt) throws Exception { mHistory = new ArrayList(1); mHistory.add(newHist); mLore = new ArrayList<>(); + mDescription = new ArrayList<>(); } /* Update this SoulEntry so new soul is now current; preserve history */ @@ -219,6 +227,15 @@ public List getLore() { return mLore; } + public void setDescription(List description, Player player) { + mDescription = description; + SoulsDatabase.getInstance().updateLore(this, player); + } + + public List getDescription() { + return mDescription; + } + /* * Soul Interface *--------------------------------------------------------------------------------*/ @@ -250,8 +267,11 @@ public ItemStack getBestiaryItem(Player player) { lore.add(Component.text(BestiarySoulInventory.formatWell(getId().getKey()), NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, false)); lore.add(Component.text("Kills: " + BestiaryManager.getKillsForMob(player, this), NamedTextColor.DARK_RED).decoration(TextDecoration.ITALIC, false)); + if (!mDescription.isEmpty()) { + lore.addAll(getDescription()); + } if (info.allowsAccessTo(InfoTier.STATS)) { - lore.add(Component.text("Click for mob info", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); + lore.add(Component.text("Click for more info!", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC, false)); } meta.lore(lore); @@ -421,6 +441,27 @@ public static SoulEntry fromJson(JsonObject obj, boolean loadHistory) throws Exc lore.add(Component.text(elem.getAsString())); } + List description = new ArrayList<>(); + elem = obj.get("description"); + if (elem != null && elem.isJsonArray()) { + JsonArray array = elem.getAsJsonArray(); + if (array == null) { + throw new Exception("Failed to parse description as JSON array"); + } + + Iterator iter = array.iterator(); + while (iter.hasNext()) { + JsonElement descriptionElement = iter.next(); + if (!descriptionElement.isJsonPrimitive()) { + throw new Exception("description entry for '" + elem + "' is not a string!"); + } + Component comp = GSON_SERIALIZER.deserialize(descriptionElement.getAsString()); + description.add(comp); + } + } else if (elem != null && elem.isJsonPrimitive()) { + description.add(Component.text(elem.getAsString())); + } + List history = new ArrayList(); elem = obj.get("history"); if (elem != null) { @@ -435,7 +476,7 @@ public static SoulEntry fromJson(JsonObject obj, boolean loadHistory) throws Exc throw new Exception("history entry for '" + elem.toString() + "' is not a string!"); } - history.add(SoulHistoryEntry.fromJson(historyElement.getAsJsonObject(), locs, lore)); + history.add(SoulHistoryEntry.fromJson(historyElement.getAsJsonObject(), locs, lore, description)); } } else { if (array.size() >= 1) { @@ -444,12 +485,12 @@ public static SoulEntry fromJson(JsonObject obj, boolean loadHistory) throws Exc throw new Exception("history entry for '" + elem.toString() + "' is not a string!"); } - history.add(SoulHistoryEntry.fromJson(historyElement.getAsJsonObject(), locs, lore)); + history.add(SoulHistoryEntry.fromJson(historyElement.getAsJsonObject(), locs, lore, description)); } } } - return new SoulEntry(history, locs, lore); + return new SoulEntry(history, locs, lore, description); } public JsonObject toJson() { @@ -462,13 +503,17 @@ public JsonObject toJson() { obj.add("history", histArray); JsonArray loreArray = new JsonArray(); - for (Component comp : mLore) { loreArray.add(GSON_SERIALIZER.serialize(comp)); } - obj.add("lore", loreArray); + JsonArray descriptionArray = new JsonArray(); + for (Component comp : mDescription) { + descriptionArray.add(GSON_SERIALIZER.serialize(comp)); + } + obj.add("description", descriptionArray); + JsonArray locsArray = new JsonArray(); for (String location : mLocs) { locsArray.add(location); diff --git a/src/main/java/com/playmonumenta/libraryofsouls/SoulHistoryEntry.java b/src/main/java/com/playmonumenta/libraryofsouls/SoulHistoryEntry.java index 19f975d..8af6a49 100644 --- a/src/main/java/com/playmonumenta/libraryofsouls/SoulHistoryEntry.java +++ b/src/main/java/com/playmonumenta/libraryofsouls/SoulHistoryEntry.java @@ -81,19 +81,21 @@ public double height() { private final Set mLocs; private final NamespacedKey mId; private final List mLore; + private final List mDescription; private final @Nullable Double mWidth; private final @Nullable Double mHeight; private @Nullable ItemStack mPlaceholder = null; private @Nullable ItemStack mBoS = null; /* Create a SoulHistoryEntry object with existing history */ - public SoulHistoryEntry(NBTTagCompound nbt, long modifiedOn, String modifiedBy, Set locations, List lore, @Nullable Double width, @Nullable Double height) throws Exception { + public SoulHistoryEntry(NBTTagCompound nbt, long modifiedOn, String modifiedBy, Set locations, List lore, List description, @Nullable Double width, @Nullable Double height) throws Exception { mNBT = nbt; mModifiedOn = modifiedOn; mModifiedBy = modifiedBy; mLocs = locations; mId = EntityNBT.fromEntityData(mNBT).getEntityType().getKey(); mLore = lore; + mDescription = description; mWidth = width; mHeight = height; @@ -116,6 +118,7 @@ public SoulHistoryEntry(Player player, NBTTagCompound nbt) throws Exception { mLocs = new HashSet(); mId = EntityNBT.fromEntityData(mNBT).getEntityType().getKey(); mLore = new ArrayList<>(); + mDescription = new ArrayList<>(); mWidth = hitboxSize.width(); mHeight = hitboxSize.height(); @@ -133,12 +136,13 @@ public boolean requiresAutoUpdate() { public SoulHistoryEntry getAutoUpdate(Location loc) throws Exception { HitboxSize hitboxSize = new HitboxSize(loc, mNBT); return new SoulHistoryEntry(mNBT, - Instant.now().getEpochSecond(), - "AutoUpdate", - mLocs, - mLore, - hitboxSize.width(), - hitboxSize.height()); + Instant.now().getEpochSecond(), + "AutoUpdate", + mLocs, + mLore, + mDescription, + hitboxSize.width(), + hitboxSize.height()); } @@ -660,6 +664,13 @@ private void regenerateItems() { ((ListVariable)placeholderWrap.getVariable("Lore")).add("It exists.", null); } + if (mDescription != null && !mDescription.isEmpty()) { + ((ListVariable)placeholderWrap.getVariable("Lore")).add(ChatColor.WHITE + "Description:", null); + ((ListVariable)bosWrap.getVariable("Lore")).add(ChatColor.WHITE + "Description:", null); + // Rather than a giant block of text, two words suffice. + ((ListVariable)placeholderWrap.getVariable("Lore")).add("It exists.", null); + } + /* If the item has been modified, list when */ if (mModifiedBy != null && !mModifiedBy.isEmpty()) { /* Relative time on the placeholder item */ @@ -722,7 +733,7 @@ public JsonObject toJson() { return obj; } - public static SoulHistoryEntry fromJson(JsonObject obj, Set locations, List lore) throws Exception { + public static SoulHistoryEntry fromJson(JsonObject obj, Set locations, List lore, List description) throws Exception { JsonElement elem = obj.get("mojangson"); NBTTagCompound nbt = NBTTagCompound.fromString(elem.getAsString()); @@ -738,6 +749,6 @@ public static SoulHistoryEntry fromJson(JsonObject obj, Set locations, L height = obj.get("height").getAsDouble(); } - return new SoulHistoryEntry(nbt, modifiedOn, modifiedBy, locations, lore, width, height); + return new SoulHistoryEntry(nbt, modifiedOn, modifiedBy, locations, lore, description, width, height); } } diff --git a/src/main/java/com/playmonumenta/libraryofsouls/SoulsDatabase.java b/src/main/java/com/playmonumenta/libraryofsouls/SoulsDatabase.java index f800eef..47b7a34 100644 --- a/src/main/java/com/playmonumenta/libraryofsouls/SoulsDatabase.java +++ b/src/main/java/com/playmonumenta/libraryofsouls/SoulsDatabase.java @@ -267,7 +267,7 @@ public void updateLore(SoulEntry soul, Player sender) { try { soul.update(sender, soul.getNBT()); } catch (Exception ex) { - sender.sendMessage("Exception when updating lore: " + ex + " for " + soul.getDisplayName()); + sender.sendMessage("Exception when updating lore or description: " + ex + " for " + soul.getDisplayName()); } save(); } diff --git a/src/main/java/com/playmonumenta/libraryofsouls/bestiary/BestiaryCommand.java b/src/main/java/com/playmonumenta/libraryofsouls/bestiary/BestiaryCommand.java index 3deca25..7ba7cfb 100644 --- a/src/main/java/com/playmonumenta/libraryofsouls/bestiary/BestiaryCommand.java +++ b/src/main/java/com/playmonumenta/libraryofsouls/bestiary/BestiaryCommand.java @@ -186,6 +186,66 @@ public static void registerWriteAccessCommands() { } soul.setLore(lore, sender); }))) + .withSubcommand(new CommandAPICommand("description") + .withPermission(CommandPermission.fromString("los.bestiary.description")) + .withArguments(new StringArgument("mobLabel").replaceSuggestions(LibraryOfSoulsCommand.LIST_MOBS_FUNCTION)) + .withArguments(new TextArgument("description")) + .executesPlayer((sender, args) -> { + String name = (String)args[0]; + SoulEntry soul = SoulsDatabase.getInstance().getSoul(name); + if (soul == null) { + throw CommandAPI.failWithString("Mob '" + name + "' not found"); + } else { + Component component = Component.text((String)args[1]); + List compList = new ArrayList<>(); + compList.add(component); + soul.setDescription(compList, sender); + } + }) + .executesProxy((sender, args) -> { + if (sender.getCallee() instanceof Player player) { + String name = (String)args[0]; + SoulEntry soul = SoulsDatabase.getInstance().getSoul(name); + if (soul == null) { + throw CommandAPI.failWithString("Mob '" + name + "' not found"); + } + Component component = Component.text((String)args[1]); + List compList = new ArrayList<>(); + compList.add(component); + soul.setDescription(compList, player); + } else { + throw CommandAPI.failWithString("Callee must be instance of Player"); + } + })) + .withSubcommand(new CommandAPICommand("description") + .withSubcommand(new CommandAPICommand("clear") + .withPermission(CommandPermission.fromString("los.bestiary.description")) + .withArguments(new StringArgument("mobLabel").replaceSuggestions(LibraryOfSoulsCommand.LIST_MOBS_FUNCTION)) + .executesPlayer((sender, args) -> { + String name = (String)args[0]; + SoulEntry soul = SoulsDatabase.getInstance().getSoul(name); + if (soul == null) { + throw CommandAPI.failWithString("Mob '" + name + "' not found"); + } + soul.setDescription(new ArrayList<>(), sender); + }))) + .withSubcommand(new CommandAPICommand("description") + .withSubcommand(new CommandAPICommand("frommainhand") + .withArguments(new StringArgument("mobLabel").replaceSuggestions(LibraryOfSoulsCommand.LIST_MOBS_FUNCTION)) + .withPermission(CommandPermission.fromString("los.bestiary.description")) + .executesPlayer((sender, args) -> { + ItemStack item = sender.getInventory().getItemInMainHand(); + if (item == null || !item.getItemMeta().hasLore()) { + throw CommandAPI.failWithString("You need a valid item with lore text!"); + } + List lore = item.lore(); + String name = (String)args[0]; + SoulEntry soul = SoulsDatabase.getInstance().getSoul(name); + if (soul == null) { + throw CommandAPI.failWithString("Mob '" + name + "' not found"); + } + soul.setDescription(lore, sender); + }))) .register(); }