From 2ec66e92ef047e996d515d2abf16673b70746586 Mon Sep 17 00:00:00 2001 From: Ka0rX Date: Sun, 19 Mar 2023 10:53:40 +0100 Subject: [PATCH] Skill Slots Update --- .../mmocore/api/player/PlayerData.java | 49 ++++++++++---- .../api/player/profess/PlayerClass.java | 2 +- .../profess/skillbinding/BoundSkillInfo.java | 67 +++++++++++++++++++ .../SkillSlot.java | 24 +++++-- .../net/Indyuce/mmocore/gui/SkillList.java | 53 ++++++++++----- .../src/main/resources/default/messages.yml | 1 + 6 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/BoundSkillInfo.java rename MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/{skillslot => skillbinding}/SkillSlot.java (65%) diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java index 1a99c77c..bf5f062d 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -5,6 +5,7 @@ import io.lumine.mythic.lib.api.player.MMOPlayerData; import io.lumine.mythic.lib.api.stat.StatInstance; import io.lumine.mythic.lib.api.stat.modifier.StatModifier; import io.lumine.mythic.lib.player.cooldown.CooldownMap; +import io.lumine.mythic.lib.player.skill.PassiveSkill; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.SoundEvent; @@ -17,6 +18,7 @@ import net.Indyuce.mmocore.api.player.profess.PlayerClass; import net.Indyuce.mmocore.api.player.profess.SavedClassInformation; import net.Indyuce.mmocore.api.player.profess.Subclass; import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource; +import net.Indyuce.mmocore.api.player.profess.skillbinding.BoundSkillInfo; import net.Indyuce.mmocore.api.player.social.FriendRequest; import net.Indyuce.mmocore.api.player.stats.PlayerStats; import net.Indyuce.mmocore.api.quest.PlayerQuests; @@ -91,7 +93,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc private final List friends = new ArrayList<>(); private final Set waypoints = new HashSet<>(); private final Map skills = new HashMap<>(); - private final List boundSkills = new ArrayList<>(); + private final Map boundSkills = new HashMap<>(); private final PlayerProfessions collectSkills = new PlayerProfessions(this); private final PlayerAttributes attributes = new PlayerAttributes(this); private final Map classSlots = new HashMap<>(); @@ -164,13 +166,13 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc MMOCore.log(Level.SEVERE, "[Userdata] Could not find class " + getProfess().getId() + " while refreshing player data."); } - int j = 0; - while (j < boundSkills.size()) + Iterator ite=boundSkills.keySet().iterator(); + while (ite.hasNext()) try { - boundSkills.set(j, Objects.requireNonNull(getProfess().getSkill(boundSkills.get(j).getSkill()))); + int slot=ite.next(); + BoundSkillInfo boundSkillInfo=new BoundSkillInfo(boundSkills.get(slot)); + boundSkills.put(slot, boundSkillInfo); } catch (Exception ignored) { - } finally { - j++; } for (SkillTree skillTree : getProfess().getSkillTrees()) @@ -1047,10 +1049,23 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc public void setSkillLevel(String skill, int level) { skills.put(skill, level); + refreshBoundedSkill(skill); } public void resetSkillLevel(String skill) { skills.remove(skill); + refreshBoundedSkill(skill); + } + + public void refreshBoundedSkill(String skill) { + boundSkills.values() + .stream() + .filter(skillInfo->skillInfo.getClassSkill().getSkill().getHandler().getId().equals(skill)) + .forEach(BoundSkillInfo::refresh); + //TODO Remove test: + Bukkit.broadcastMessage("match"+boundSkills.values() + .stream() + .filter(skillInfo->skillInfo.getClassSkill().getSkill().getHandler().getId().equals(skill)).toList().size()); } @Deprecated @@ -1108,8 +1123,8 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc this.profess = profess; // Clear old skills - for (Iterator iterator = boundSkills.iterator(); iterator.hasNext(); ) - if (!getProfess().hasSkill(iterator.next().getSkill())) + for (Iterator iterator = boundSkills.values().iterator(); iterator.hasNext(); ) + if (!getProfess().hasSkill(iterator.next().getClassSkill().getSkill())) iterator.remove(); // Update stats @@ -1122,7 +1137,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc } public ClassSkill getBoundSkill(int slot) { - return slot >= boundSkills.size() ? null : boundSkills.get(slot); + return slot >= boundSkills.size() ? null : boundSkills.get(slot).getClassSkill(); } @@ -1140,8 +1155,18 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc */ public void bindSkill(int slot, ClassSkill skill) { Validate.notNull(skill, "Skill cannot be null"); - if (slot >= 0) - boundSkills.set(slot, skill); + //Unbinds the previous skill (Important for passive skills. + if (boundSkills.containsKey(slot)) + boundSkills.get(slot).unbind(); + if (slot >= 0) { + if (skill.getSkill().getTrigger().isPassive()) { + PassiveSkill passiveSkill = skill.toPassive(this); + passiveSkill.register(mmoData); + boundSkills.put(slot, new BoundSkillInfo(skill, this, passiveSkill.getUniqueId())); + } else { + boundSkills.put(slot, new BoundSkillInfo(skill, this)); + } + } } public void unbindSkill(int slot) { @@ -1150,7 +1175,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc public List getBoundSkills() { - return boundSkills; + return boundSkills.values().stream().map(BoundSkillInfo::getClassSkill).collect(Collectors.toList()); } @NotNull diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java index 02092c48..0a3b1255 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java @@ -21,7 +21,7 @@ import net.Indyuce.mmocore.api.player.profess.event.EventTrigger; import net.Indyuce.mmocore.api.player.profess.resource.ManaDisplayOptions; import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource; import net.Indyuce.mmocore.api.player.profess.resource.ResourceRegeneration; -import net.Indyuce.mmocore.api.player.profess.skillslot.SkillSlot; +import net.Indyuce.mmocore.api.player.profess.skillbinding.SkillSlot; import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.experience.EXPSource; diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/BoundSkillInfo.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/BoundSkillInfo.java new file mode 100644 index 00000000..d2b948df --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/BoundSkillInfo.java @@ -0,0 +1,67 @@ +package net.Indyuce.mmocore.api.player.profess.skillbinding; + +import io.lumine.mythic.lib.player.skill.PassiveSkill; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.skill.ClassSkill; + +import java.util.Objects; +import java.util.UUID; + +public class BoundSkillInfo { + private final PlayerData playerData; + private final ClassSkill classSkill; + private UUID passiveSkillUUID; + + public BoundSkillInfo(ClassSkill classSkill, PlayerData playerData) { + this.classSkill = classSkill; + this.playerData = playerData; + } + + public BoundSkillInfo(ClassSkill classSkill, PlayerData playerData, UUID passiveSkillUUID) { + this.classSkill = classSkill; + this.playerData = playerData; + this.passiveSkillUUID = passiveSkillUUID; + } + + /** + * Used on update to refresh the classSkill & all references to old data. + */ + public BoundSkillInfo(BoundSkillInfo info) { + this.playerData=info.getPlayerData(); + this.classSkill= Objects.requireNonNull(playerData.getProfess().getSkill(info.getClassSkill().getSkill())); + info.unbind(); + PassiveSkill passiveSkill = classSkill.toPassive(playerData); + passiveSkill.register(playerData.getMMOPlayerData()); + this.passiveSkillUUID=passiveSkill.getUniqueId(); + } + + public ClassSkill getClassSkill() { + return classSkill; + } + + public PlayerData getPlayerData() { + return playerData; + } + + public UUID getPassiveSkillUUID() { + return passiveSkillUUID; + } + + /** + * This is used to refresh the PassiveSkill playerModifier so it is always associated to the + */ + public void refresh() { + if (classSkill.getSkill().getTrigger().isPassive()) { + playerData.getMMOPlayerData().getPassiveSkillMap().removeModifier(passiveSkillUUID); + PassiveSkill passiveSkill = classSkill.toPassive(playerData); + passiveSkill.register(playerData.getMMOPlayerData()); + this.passiveSkillUUID=passiveSkill.getUniqueId(); + } + } + + public void unbind() { + if (classSkill.getSkill().getTrigger().isPassive()) { + playerData.getMMOPlayerData().getPassiveSkillMap().removeModifier(passiveSkillUUID); + } + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillslot/SkillSlot.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/SkillSlot.java similarity index 65% rename from MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillslot/SkillSlot.java rename to MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/SkillSlot.java index 0759798e..b3dc33c5 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillslot/SkillSlot.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/SkillSlot.java @@ -1,11 +1,12 @@ -package net.Indyuce.mmocore.api.player.profess.skillslot; +package net.Indyuce.mmocore.api.player.profess.skillbinding; -import io.lumine.mythic.lib.api.math.BooleanExpressionParser; +import io.lumine.mythic.lib.MythicLib; +import net.Indyuce.mmocore.comp.mythicmobs.MythicHook; import net.Indyuce.mmocore.skill.ClassSkill; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.inventory.ItemStack; +import javax.script.ScriptException; import java.util.List; public class SkillSlot { @@ -49,8 +50,9 @@ public class SkillSlot { public Material getItem() { return item; } - public boolean hasItem(){ - return item!=null; + + public boolean hasItem() { + return item != null; } public int getModelData() { @@ -58,6 +60,16 @@ public class SkillSlot { } public boolean canPlaceSkill(ClassSkill classSkill) { - return new BooleanExpressionParser(expression).parse(classSkill.getSkill().getCategories()); + + String parsedExpression = expression; + for (String category : classSkill.getSkill().getCategories()) + parsedExpression = parsedExpression.replace("<" + category + ">", "true"); + parsedExpression = parsedExpression.replaceAll("<.*>", "false"); + try { + boolean res = (boolean) MythicLib.plugin.getScriptEngine().eval(parsedExpression); + return res; + } catch (ScriptException e) { + throw new RuntimeException(e); + } } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java index 4b17b883..3061afb9 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java @@ -5,6 +5,7 @@ import io.lumine.mythic.lib.api.item.ItemTag; import io.lumine.mythic.lib.api.item.NBTItem; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.api.player.profess.skillbinding.SkillSlot; import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.gui.api.EditableInventory; import net.Indyuce.mmocore.gui.api.GeneratedInventory; @@ -28,8 +29,9 @@ import org.bukkit.inventory.meta.ItemMeta; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import java.util.stream.Collectors; -public class SkillList extends EditableInventory { +public class SkillList extends EditableInventory { public SkillList() { super("skill-list"); } @@ -65,25 +67,39 @@ public class SkillList extends EditableInventory { return new SlotItem(config) { @Override public ItemStack display(SkillViewerInventory inv, int n) { - if (n >= inv.getPlayerData().getSkillSlotLimit()) { + if (!inv.getPlayerData().getProfess().hasSlot(n)) { return new ItemStack(Material.AIR); } + SkillSlot skillSlot = inv.getPlayerData().getProfess().getSkillSlot(n); ItemStack item = super.display(inv, n); if (!inv.getPlayerData().hasSkillBound(n)) { - item.setType(super.emptyMaterial); - + //If there is an item filled in the slot config it shows it, else shows the default item. + Material material = skillSlot.hasItem() ? skillSlot.getItem() : super.emptyMaterial; + int customModelData = skillSlot.hasItem() ? skillSlot.getModelData() : super.emptyCMD; + item.setType(material); + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(),skillSlot.getName())); + List lore=skillSlot.getLore() + .stream() + .map(str->MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(),str)) + .collect(Collectors.toList()); + meta.setLore(lore); if (MythicLib.plugin.getVersion().isStrictlyHigher(1, 13)) { - ItemMeta meta = item.getItemMeta(); - meta.setCustomModelData(super.emptyCMD); - item.setItemMeta(meta); + meta.setCustomModelData(customModelData); } + item.setItemMeta(meta); + } + return item; } + /** + * This should only be called when there is a skill bound. + */ @Override public Placeholders getPlaceholders(SkillViewerInventory inv, int n) { - Placeholders holders= super.getPlaceholders(inv, n); + Placeholders holders = super.getPlaceholders(inv, n); String none = MythicLib.plugin.parseColors(config.getString("no-skill")); RegisteredSkill skill = inv.getPlayerData().hasSkillBound(n) ? inv.getPlayerData().getBoundSkill(n).getSkill() : null; holders.register("skill", skill == null ? none : skill.getName()); @@ -297,8 +313,7 @@ public class SkillList extends EditableInventory { // Cached information private final List skills; private final List skillSlots; - private final List activeSlotSlots; - private final List passiveSlotSlots; + private final List slotSlots; //The skill the player Selected private ClassSkill selected; @@ -309,9 +324,8 @@ public class SkillList extends EditableInventory { skills = new ArrayList<>(playerData.getProfess().getSkills()); skillSlots = getEditable().getByFunction("skill").getSlots(); - Validate.notNull(getEditable().getByFunction("active-slot"), "Your skill GUI config file is out-of-date, please regenerate it."); - activeSlotSlots = getEditable().getByFunction("active-slot").getSlots(); - passiveSlotSlots = getEditable().getByFunction("passive-slot").getSlots(); + Validate.notNull(getEditable().getByFunction("slot"), "Your skill GUI config file is out-of-date, please regenerate it."); + slotSlots = getEditable().getByFunction("slot").getSlots(); selected = skills.get(page * skillSlots.size()); } @@ -379,9 +393,9 @@ public class SkillList extends EditableInventory { /* * binding or unbinding skills. */ - if (item.getFunction().equals("active-slot")) { - int index = activeSlotSlots.indexOf(context.getSlot()); - + if (item.getFunction().equals("slot")) { + int index = slotSlots.indexOf(context.getSlot()); + SkillSlot skillSlot=playerData.getProfess().getSkillSlot(index); // unbind if there is a current spell. if (context.getClickType() == ClickType.RIGHT) { if (!playerData.hasSkillBound(index)) { @@ -404,6 +418,13 @@ public class SkillList extends EditableInventory { return; } + if(!skillSlot.canPlaceSkill(selected)){ + MMOCore.plugin.configManager.getSimpleMessage("not-compatible-skill").send(player); + player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2); + return; + } + + player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 2); playerData.bindSkill(index, selected); open(); diff --git a/MMOCore-Dist/src/main/resources/default/messages.yml b/MMOCore-Dist/src/main/resources/default/messages.yml index 078e44e3..74292831 100644 --- a/MMOCore-Dist/src/main/resources/default/messages.yml +++ b/MMOCore-Dist/src/main/resources/default/messages.yml @@ -199,6 +199,7 @@ not-enough-skill-points-shift: '&cYou need {shift_points} skill points.' upgrade-skill: '&eYour &6{skill} &eis now Level &6{level}&e!' not-unlocked-skill: '&cYou have not unlocked that skill yet.' no-skill-bound: '&cYou don''t have any skill bound to this slot.' +not-compatible-skill: '&cThe selected skill is not compatible with this slot.' skill-max-level-hit: '&cYou already hit the max level for that skill.' no-skill-placeholder: 'No Skill Bound' not-skill-reallocation-point: '&cYou do not have 1 skill reallocation point.'