diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java index defb3e02..6cc0b87b 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java @@ -365,10 +365,10 @@ public class MMOCore extends JavaPlugin { dropTableManager.initialize(clearBefore); statManager.initialize(clearBefore); professionManager.initialize(clearBefore); - classManager.initialize(clearBefore); InventoryManager.load(); skillTreeManager.initialize(clearBefore); + classManager.initialize(clearBefore); questManager.initialize(clearBefore); lootChests.initialize(clearBefore); restrictionManager.initialize(clearBefore); 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 12dc09b4..24e1a492 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 @@ -4,6 +4,8 @@ import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.player.MMOPlayerData; import io.lumine.mythic.lib.player.cooldown.CooldownMap; import io.lumine.mythic.lib.player.skill.PassiveSkill; +import net.Indyuce.mmocore.party.provided.MMOCorePartyModule; +import net.Indyuce.mmocore.party.provided.Party; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.SoundEvent; @@ -79,7 +81,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc private double mana, stamina, stellium; private Guild guild; private SkillCastingHandler skillCasting; - private SkillTree cachedSkillTree; private final PlayerQuests questData; private final PlayerStats playerStats; private final List friends = new ArrayList<>(); @@ -209,6 +210,10 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc return nodeLevelsString.entrySet(); } + public Map getNodeLevels() { + return nodeLevels; + } + public boolean canIncrementNodeLevel(SkillTreeNode node) { NodeState nodeState = nodeStates.get(node); //Check the State of the node @@ -292,6 +297,38 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc nodeLevels.put(node, nodeLevel); } + public void resetSkillTree(SkillTree skillTree) { + for (SkillTreeNode node : skillTree.getNodes()) { + node.getExperienceTable().reset(this,node); + setNodeLevel(node, 0); + } + skillTree.setupNodeState(this); + } + + public Map getNodeStates() { + return nodeStates; + } + + public Map getNodeTimesClaimed() { + Map result = new HashMap<>(); + tableItemClaims.forEach((str, val) -> { + if (str.startsWith(SkillTreeNode.getPrefix())) + result.put(str, val); + }); + return result; + } + + public void resetNodeTimesClaimed() { + Map newTableItemClaims = new HashMap<>(); + tableItemClaims.forEach((str, val) -> { + if (!str.startsWith(SkillTreeNode.getPrefix())) + newTableItemClaims.put(str, val); + }); + tableItemClaims.clear(); + tableItemClaims.putAll(newTableItemClaims); + } + + public void addNodeLevel(SkillTreeNode node) { nodeLevels.put(node, nodeLevels.get(node) + 1); } @@ -299,10 +336,12 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc @Override public void close() { - // Remove from party - AbstractParty party = getParty(); - if (party != null && party instanceof Party) - ((Party) party).removeMember(this); + // Remove from party if it is MMO Party Module + if(MMOCore.plugin.partyModule instanceof MMOCorePartyModule) { + AbstractParty party = getParty(); + if (party != null && party instanceof Party) + ((Party) party).removeMember(this); + } // Close quest data questData.close(); @@ -354,19 +393,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc return Math.max(1, level); } - public void setCachedSkillTree(SkillTree cachedSkillTree) { - this.cachedSkillTree = cachedSkillTree; - } - - @NotNull - public SkillTree getOpenedSkillTree() { - if (cachedSkillTree == null) { - Optional optionnal = MMOCore.plugin.skillTreeManager.getAll().stream().findFirst(); - return optionnal.isPresent() ? optionnal.get() : null; - } - return cachedSkillTree; - } - @Nullable public AbstractParty getParty() { return MMOCore.plugin.partyModule.getParty(this); @@ -415,13 +441,19 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc @Override public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) { - String key = object.getKey() + "." + table.getId() + "." + item.getId(); + return getClaims(object.getKey() + "." + table.getId() + "." + item.getId()); + } + + public int getClaims(String key) { return tableItemClaims.getOrDefault(key, 0); } @Override public void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int times) { - String key = object.getKey() + "." + table.getId() + "." + item.getId(); + setClaims(object.getKey() + "." + table.getId() + "." + item.getId(), times); + } + + public void setClaims(String key, int times) { tableItemClaims.put(key, times); } 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 2aa09e97..86d11d13 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 @@ -25,14 +25,16 @@ import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.experience.EXPSource; import net.Indyuce.mmocore.experience.ExpCurve; -import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.loot.chest.particle.CastingParticle; import net.Indyuce.mmocore.player.stats.StatInfo; import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.RegisteredSkill; -import net.Indyuce.mmocore.skill.cast.ComboMap; +import net.Indyuce.mmocore.skill.cast.KeyCombo; +import net.Indyuce.mmocore.skill.cast.PlayerKey; +import net.Indyuce.mmocore.experience.ExperienceObject; import net.md_5.bungee.api.ChatColor; +import org.apache.commons.lang.Validate; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Particle; @@ -67,6 +69,8 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { private final CastingParticle castParticle; private final int maxBoundActiveSkills, maxBoundPassiveSkills; + + private final List skillTrees = new ArrayList<>(); private final List classScripts = new LinkedList(); private final Map stats = new HashMap<>(); private final Map skills = new LinkedHashMap<>(); @@ -97,7 +101,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { profileField.set(meta, gp); icon.setItemMeta(meta); } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException - | SecurityException exception) { + | SecurityException exception) { throw new IllegalArgumentException("Could not apply playerhead texture: " + exception.getMessage()); } @@ -125,6 +129,13 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table from class '" + id + "': " + exception.getMessage()); } this.expTable = expTable; + if (config.contains("skill-trees")) + for (String str : config.getStringList("skill-trees")) + try { + skillTrees.add(MMOCore.plugin.skillTreeManager.get(str)); + } catch (Exception e) { + MMOCore.log(Level.WARNING, "Could not find skill tree with ID: " + str); + } if (config.contains("scripts")) for (String key : config.getConfigurationSection("scripts").getKeys(false)) @@ -243,7 +254,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { setOption(ClassOption.DISPLAY, false); setOption(ClassOption.DEFAULT, false); maxBoundActiveSkills = 6; - maxBoundPassiveSkills=3; + maxBoundPassiveSkills = 3; for (PlayerResource resource : PlayerResource.values()) resourceHandlers.put(resource, new ResourceRegeneration(resource)); } @@ -302,6 +313,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { public int getMaxBoundActiveSkills() { return maxBoundActiveSkills; } + public int getMaxBoundPassiveSkills() { return maxBoundPassiveSkills; } @@ -413,6 +425,10 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { return skills.containsKey(id); } + public List getSkillTrees() { + return skillTrees; + } + public ClassSkill getSkill(RegisteredSkill skill) { return getSkill(skill.getHandler().getId()); } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java index c3f7b031..197492aa 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java @@ -1,182 +1,264 @@ package net.Indyuce.mmocore.api.player.profess; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute; +import net.Indyuce.mmocore.manager.data.PlayerDataManager; +import net.Indyuce.mmocore.skill.RegisteredSkill; +import net.Indyuce.mmocore.tree.SkillTreeNode; +import net.Indyuce.mmocore.tree.skilltree.SkillTree; +import org.bukkit.configuration.ConfigurationSection; + import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute; -import net.Indyuce.mmocore.manager.data.PlayerDataManager; -import net.Indyuce.mmocore.skill.RegisteredSkill; -import org.bukkit.configuration.ConfigurationSection; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - public class SavedClassInformation { - private final int level, skillPoints, attributePoints, attributeReallocationPoints; - private final double experience; - private final Map attributes; - private final Map skills; + private final int level, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints; + private final double experience; + private final Map attributes; + private final Map skills; + private final Map skillTreePoints; + private final Map nodeLevels; + /** + * Stores the tableItemsClaims values but only for skill tree node as it is class based. + */ + private final Map nodeTimesClaimed; - public SavedClassInformation(ConfigurationSection config) { - level = config.getInt("level"); - experience = config.getDouble("experience"); - skillPoints = config.getInt("skill-points"); - attributePoints = config.getInt("attribute-points"); - attributeReallocationPoints = config.getInt("attribute-realloc-points"); + public SavedClassInformation(ConfigurationSection config) { + level = config.getInt("level"); + experience = config.getDouble("experience"); + skillPoints = config.getInt("skill-points"); + attributePoints = config.getInt("attribute-points"); + attributeReallocationPoints = config.getInt("attribute-realloc-points"); + skillReallocationPoints = config.getInt("skill-reallocation-points"); + skillTreeReallocationPoints = config.getInt("skill-tree-reallocation-points"); + attributes = new HashMap<>(); + if (config.contains("attribute")) + config.getConfigurationSection("attribute").getKeys(false).forEach(key -> attributes.put(key, config.getInt("attribute." + key))); + skills = new HashMap<>(); + if (config.contains("skill")) + config.getConfigurationSection("skill").getKeys(false).forEach(key -> skills.put(key, config.getInt("skill." + key))); + skillTreePoints = new HashMap<>(); + if (config.contains("skill-tree-points")) + config.getConfigurationSection("skill-tree-points").getKeys(false).forEach(key -> skillTreePoints.put(key, config.getInt("skill-tree-points." + key))); + nodeLevels = new HashMap<>(); + if (config.contains("node-levels")) + config.getConfigurationSection("node-levels").getKeys(false).forEach(key -> nodeLevels.put(MMOCore.plugin.skillTreeManager.getNode(key), config.getInt("node-levels." + key))); + nodeTimesClaimed = new HashMap<>(); + if (config.contains("node-times-claimed")) + config.getConfigurationSection("node-times-claimed").getKeys(false).forEach(key -> nodeTimesClaimed.put(key, config.getInt("node-times-claimed." + key))); - attributes = new HashMap<>(); - if (config.contains("attribute")) - config.getConfigurationSection("attribute").getKeys(false).forEach(key -> attributes.put(key, config.getInt("attribute." + key))); - skills = new HashMap<>(); - if (config.contains("skill")) - config.getConfigurationSection("skill").getKeys(false).forEach(key -> skills.put(key, config.getInt("skill." + key))); - } + } - public SavedClassInformation(JsonObject json) { - level = json.get("level").getAsInt(); - experience = json.get("experience").getAsDouble(); - skillPoints = json.get("skill-points").getAsInt(); - attributePoints = json.get("attribute-points").getAsInt(); - attributeReallocationPoints = json.get("attribute-realloc-points").getAsInt(); + public SavedClassInformation(JsonObject json) { + level = json.get("level").getAsInt(); + experience = json.get("experience").getAsDouble(); + skillPoints = json.get("skill-points").getAsInt(); + attributePoints = json.get("attribute-points").getAsInt(); + attributeReallocationPoints = json.get("attribute-realloc-points").getAsInt(); + skillReallocationPoints = json.get("skill-reallocation-points").getAsInt(); + skillTreeReallocationPoints = json.get("skill-tree-reallocation-points").getAsInt(); + attributes = new HashMap<>(); + if (json.has("attribute")) + for (Entry entry : json.getAsJsonObject("attribute").entrySet()) + attributes.put(entry.getKey(), entry.getValue().getAsInt()); + skills = new HashMap<>(); + if (json.has("skill")) + for (Entry entry : json.getAsJsonObject("skill").entrySet()) + skills.put(entry.getKey(), entry.getValue().getAsInt()); + skillTreePoints = new HashMap<>(); + if (json.has("skill-tree-points")) + for (Entry entry : json.getAsJsonObject("skill-tree-points").entrySet()) + skillTreePoints.put(entry.getKey(), entry.getValue().getAsInt()); + nodeLevels = new HashMap<>(); + if (json.has("node-levels")) + for (Entry entry : json.getAsJsonObject("node-levels").entrySet()) + nodeLevels.put(MMOCore.plugin.skillTreeManager.getNode(entry.getKey()), entry.getValue().getAsInt()); + nodeTimesClaimed=new HashMap<>(); + if (json.has("node-times-claimed")) + for (Entry entry : json.getAsJsonObject("node-times-claimed").entrySet()) + nodeTimesClaimed.put(entry.getKey(), entry.getValue().getAsInt()); - attributes = new HashMap<>(); - if (json.has("attribute")) - for (Entry entry : json.getAsJsonObject("attribute").entrySet()) - attributes.put(entry.getKey(), entry.getValue().getAsInt()); - skills = new HashMap<>(); - if (json.has("skill")) - for (Entry entry : json.getAsJsonObject("skill").entrySet()) - skills.put(entry.getKey(), entry.getValue().getAsInt()); - } + } - public SavedClassInformation(PlayerData player) { - this(player.getLevel(), player.getExperience(), player.getSkillPoints(), player.getAttributePoints(), player.getAttributeReallocationPoints(), - player.getAttributes().mapPoints(), player.mapSkillLevels()); - } + public SavedClassInformation(PlayerData player) { + this(player.getLevel(), player.getExperience(), player.getSkillPoints(), player.getAttributePoints(), player.getAttributeReallocationPoints() + , player.getSkillTreeReallocationPoints(), player.getSkillReallocationPoints(), + player.getAttributes().mapPoints(), player.mapSkillLevels(), player.getSkillTreePoints(), player.getNodeLevels(),player.getNodeTimesClaimed()); + } - public SavedClassInformation(PlayerDataManager.DefaultPlayerData data) { - this(data.getLevel(), 0, data.getSkillPoints(), data.getAttributePoints(), data.getAttrReallocPoints()); - } + public SavedClassInformation(PlayerDataManager.DefaultPlayerData data) { + this(data.getLevel(), 0, data.getSkillPoints(), data.getAttributePoints(), data.getAttrReallocPoints(), data.getSkillTreeReallocPoints(), data.getSkillReallocPoints()); + } - public SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints) { - this(level, experience, skillPoints, attributePoints, attributeReallocationPoints, new HashMap<>(), new HashMap<>()); - } + public SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints, int skillTreeReallocationPoints, int skillReallocationPoints) { + this(level, experience, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints, new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(),new HashMap<>()); + } - private SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints, - Map attributes, Map skills) { - this.level = level; - this.experience = experience; - this.skillPoints = skillPoints; - this.attributePoints = attributePoints; - this.attributeReallocationPoints = attributeReallocationPoints; - this.attributes = attributes; - this.skills = skills; - } + public SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints, int skillTreeReallocationPoints, int skillReallocationPoints, + Map attributes, Map skills, Map skillTreePoints, Map nodeLevels,Map nodeTimesClaimed) { + this.level = level; + this.skillPoints = skillPoints; + this.attributePoints = attributePoints; + this.attributeReallocationPoints = attributeReallocationPoints; + this.skillTreeReallocationPoints = skillTreeReallocationPoints; + this.skillReallocationPoints = skillReallocationPoints; + this.experience = experience; + this.attributes = attributes; + this.skills = skills; + this.skillTreePoints = skillTreePoints; + this.nodeLevels = nodeLevels; + this.nodeTimesClaimed=nodeTimesClaimed; + } - public int getLevel() { - return level; - } + public int getLevel() { + return level; + } - public double getExperience() { - return experience; - } + public double getExperience() { + return experience; + } - public int getSkillPoints() { - return skillPoints; - } + public int getSkillPoints() { + return skillPoints; + } - public int getAttributePoints() { - return attributePoints; - } + public int getAttributePoints() { + return attributePoints; + } - public int getAttributeReallocationPoints() { - return attributeReallocationPoints; - } + public int getAttributeReallocationPoints() { + return attributeReallocationPoints; + } - public Set getSkillKeys() { - return skills.keySet(); - } + public Set getSkillKeys() { + return skills.keySet(); + } - public int getSkillLevel(RegisteredSkill skill) { - return getSkillLevel(skill.getHandler().getId()); - } + public int getSkillLevel(RegisteredSkill skill) { + return getSkillLevel(skill.getHandler().getId()); + } - public int getSkillLevel(String id) { - return skills.get(id); - } + public int getSkillLevel(String id) { + return skills.get(id); + } - public void registerSkillLevel(RegisteredSkill skill, int level) { - registerSkillLevel(skill.getHandler().getId(), level); - } + public void registerSkillLevel(RegisteredSkill skill, int level) { + registerSkillLevel(skill.getHandler().getId(), level); + } - public void registerSkillLevel(String attribute, int level) { - skills.put(attribute, level); - } + public int getSkillTreeReallocationPoints() { + return skillTreeReallocationPoints; + } - public Set getAttributeKeys() { - return attributes.keySet(); - } + public int getSkillReallocationPoints() { + return skillReallocationPoints; + } - public int getAttributeLevel(PlayerAttribute attribute) { - return getAttributeLevel(attribute.getId()); - } + public void registerSkillLevel(String attribute, int level) { + skills.put(attribute, level); + } - public int getAttributeLevel(String id) { - return attributes.get(id); - } - public void registerAttributeLevel(PlayerAttribute attribute, int level) { - registerAttributeLevel(attribute.getId(), level); - } + public Set getNodeKeys() { + return nodeLevels.keySet(); + } - public void registerAttributeLevel(String attribute, int level) { - attributes.put(attribute, level); - } + public int getNodeLevel(SkillTreeNode node) { + return nodeLevels.get(node); + } - public void load(PlayerClass profess, PlayerData player) { + public Set getSkillTreePointsKeys() { + return skillTreePoints.keySet(); + } - /* - * saves current class info inside a SavedClassInformation, only if the - * class is a real class and not the default one. - */ - if (!player.getProfess().hasOption(ClassOption.DEFAULT) || MMOCore.plugin.configManager.saveDefaultClassInfo) - player.applyClassInfo(player.getProfess(), new SavedClassInformation(player)); + public int getSkillTreePoints(String skillTreeId) { + return skillTreePoints.get(skillTreeId); + } - /* - * resets information which much be reset after everything is saved. - */ - player.mapSkillLevels().forEach((skill, level) -> player.resetSkillLevel(skill)); - player.getAttributes().getInstances().forEach(ins -> ins.setBase(0)); - while (player.hasSkillBound(0)) - player.unbindSkill(0); + public Set getAttributeKeys() { + return attributes.keySet(); + } - /* - * reads this class info, applies it to the player. set class after - * changing level so the player stats can be calculated based on new - * level. - */ - player.setLevel(level); - player.setExperience(experience); - player.setSkillPoints(skillPoints); - player.setAttributePoints(attributePoints); - player.setAttributeReallocationPoints(attributeReallocationPoints); + public int getAttributeLevel(String id) { + return attributes.getOrDefault(id,0); + } - skills.forEach(player::setSkillLevel); - attributes.forEach((id, pts) -> player.getAttributes().setBaseAttribute(id, pts)); + public void registerAttributeLevel(PlayerAttribute attribute, int level) { + registerAttributeLevel(attribute.getId(), level); + } - /* - * unload current class information and set the new profess once - * everything is changed - */ - player.setClass(profess); - player.unloadClassInfo(profess); + public void registerAttributeLevel(String attribute, int level) { + attributes.put(attribute, level); + } - // Updates level on exp bar - player.refreshVanillaExp(); - } + public void load(PlayerClass profess, PlayerData player) { + + /* + * saves current class info inside a SavedClassInformation, only if the + * class is a real class and not the default one. + */ + if (!player.getProfess().hasOption(ClassOption.DEFAULT) || MMOCore.plugin.configManager.saveDefaultClassInfo) + player.applyClassInfo(player.getProfess(), new SavedClassInformation(player)); + + /* + * resets information which much be reset after everything is saved. + */ + + player.mapSkillLevels().forEach((skill, level) -> player.resetSkillLevel(skill)); + player.getAttributes().getInstances().forEach(ins -> ins.setBase(0)); + + // We reset the experience table for each skill tree node to remove the perm stat. + for (SkillTree skillTree : player.getProfess().getSkillTrees()) + for (SkillTreeNode node : skillTree.getNodes()) + node.getExperienceTable().reset(player, node); + player.getNodeLevels().clear(); + player.getNodeStates().clear(); + + while (player.hasSkillBound(0)) + player.unbindSkill(0); + + /* + * reads this class info, applies it to the player. set class after + * changing level so the player stats can be calculated based on new + * level. + */ + player.setLevel(level); + player.setExperience(experience); + player.setSkillPoints(skillPoints); + player.setAttributePoints(attributePoints); + player.setAttributeReallocationPoints(attributeReallocationPoints); + player.setSkillTreeReallocationPoints(skillTreeReallocationPoints); + player.setSkillReallocationPoints(skillReallocationPoints); + + (skills).forEach(player::setSkillLevel); + attributes.forEach((id, pts) -> player.getAttributes().setBaseAttribute(id, pts)); + skillTreePoints.forEach((skillTree, point) -> player.setSkillTreePoints(skillTree, point)); + //Setup node levels and node state. + nodeLevels.forEach((node, level) -> player.setNodeLevel(node, level)); + for(SkillTree skillTree: profess.getSkillTrees()) + skillTree.setupNodeState(player); + + //Add the values to the times claimed table and claims the corresponding stat triggers. + nodeTimesClaimed.forEach((str,val)->player.setClaims(str,val)); + //We claim back the stats triggers for all the skill tree nodes of the new class. + for(SkillTree skillTree:profess.getSkillTrees()) + for(SkillTreeNode node:skillTree.getNodes()) + node.getExperienceTable().claimStatTriggers(player,node); + + /* + * unload current class information and set the new profess once + * everything is changed + */ + player.setClass(profess); + player.unloadClassInfo(profess); + + // Updates level on exp bar + player.refreshVanillaExp(); + } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/StatTrigger.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/StatTrigger.java index 421c75b6..2ddb2142 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/StatTrigger.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/StatTrigger.java @@ -11,12 +11,14 @@ import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import java.util.Collection; +import java.util.UUID; public class StatTrigger extends Trigger { private final String stat; private final double amount; private final ModifierType type; private double totalAmount; + private final UUID uuid =UUID.randomUUID(); public StatTrigger(MMOLineConfig config) { super(config); @@ -35,7 +37,7 @@ public class StatTrigger extends Trigger { @Override public void apply(PlayerData player) { totalAmount+=amount; - new StatModifier("trigger",stat,totalAmount,type).register(player.getMMOPlayerData()); + new StatModifier("trigger."+uuid.toString(),stat,totalAmount,type).register(player.getMMOPlayerData()); } @@ -46,6 +48,6 @@ public class StatTrigger extends Trigger { */ public void remove(PlayerData playerData) { totalAmount-=amount; - new StatModifier("trigger", stat, totalAmount, type).register(playerData.getMMOPlayerData()); + new StatModifier("trigger."+uuid.toString(), stat, totalAmount, type).register(playerData.getMMOPlayerData()); } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/SkillTreeCommand.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/SkillTreeCommand.java index 817650d0..2fd40c25 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/SkillTreeCommand.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/SkillTreeCommand.java @@ -1,6 +1,7 @@ package net.Indyuce.mmocore.command; import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.event.MMOCommandEvent; import net.Indyuce.mmocore.manager.InventoryManager; @@ -21,18 +22,22 @@ public class SkillTreeCommand extends BukkitCommand { @Override public boolean execute(@NotNull CommandSender sender, String s, String[] args) { - if (!(sender instanceof Player)) + if (!(sender instanceof Player player)) return false; - PlayerData data = PlayerData.get((Player) sender); + PlayerData data = PlayerData.get(player); MMOCommandEvent event = new MMOCommandEvent(data, "skilltree"); Bukkit.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) return true; - if (MMOCore.plugin.skillTreeManager.getAll().size() != 0) { + if (data.getProfess().getSkillTrees().size() != 0) { InventoryManager.TREE_VIEW.newInventory(data).open(); return false; } - return true; + else { + MMOCore.plugin.configManager.getSimpleMessage("no-skill-tree").send(player); + return true; + } + } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java index f041466d..4a565c00 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java @@ -76,9 +76,6 @@ public class ExperienceTable { public void claimStatTriggers(PlayerData data, ExperienceObject object) { for (ExperienceItem item : items) { int timesClaimed = data.getClaims(object, this, item); - //MMOCore.log(object.getKey() + "." + getId() + "." + item.getId()); - //data.getItemClaims().keySet().forEach(str->MMOCore.log(str)); - //MMOCore.log(timesClaimed+""); for (int i = 0; i < timesClaimed; i++) item.applyStatTriggers(data); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillTreeViewer.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillTreeViewer.java index f75948a3..022af806 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillTreeViewer.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillTreeViewer.java @@ -59,9 +59,9 @@ public class SkillTreeViewer extends EditableInventory { holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoint(inv.getSkillTree().getId())); holders.register("global-points", inv.getPlayerData().getSkillTreePoint("global")); holders.register("realloc-points", inv.getPlayerData().getSkillTreeReallocationPoints()); - int maxPointSpent=inv.getSkillTree().getMaxPointSpent(); - holders.register("max-point-spent",maxPointSpent==Integer.MAX_VALUE?"∞":maxPointSpent); - holders.register("point-spent",inv.getPlayerData().getPointSpent(inv.getSkillTree())); + int maxPointSpent = inv.getSkillTree().getMaxPointSpent(); + holders.register("max-point-spent", maxPointSpent == Integer.MAX_VALUE ? "∞" : maxPointSpent); + holders.register("point-spent", inv.getPlayerData().getPointSpent(inv.getSkillTree())); return holders; } @@ -101,10 +101,10 @@ public class SkillTreeViewer extends EditableInventory { @Override public ItemStack display(SkillTreeInventory inv, int n) { int index = inv.getEditable().getByFunction("skill-tree").getSlots().size() * inv.treeListPage + n; - if (!MMOCore.plugin.skillTreeManager.has(index)) { + if (inv.skillTrees.size() <= index) { return new ItemStack(Material.AIR); } - SkillTree skillTree = MMOCore.plugin.skillTreeManager.get(index); + SkillTree skillTree = inv.skillTrees.get(index); //We display with the material corresponding to the skillTree ItemStack item = super.display(inv, n, skillTree.getItem()); @@ -129,13 +129,13 @@ public class SkillTreeViewer extends EditableInventory { @Override public Placeholders getPlaceholders(SkillTreeInventory inv, int n) { int index = inv.getEditable().getByFunction("skill-tree").getSlots().size() * inv.treeListPage + n; - SkillTree skillTree = MMOCore.plugin.skillTreeManager.get(index); + SkillTree skillTree = inv.skillTrees.get(index); Placeholders holders = new Placeholders(); holders.register("name", skillTree.getName()); holders.register("id", skillTree.getId()); - int maxPointSpent=inv.getSkillTree().getMaxPointSpent(); - holders.register("max-point-spent",maxPointSpent==Integer.MAX_VALUE?"∞":maxPointSpent); - holders.register("point-spent",inv.getPlayerData().getPointSpent(inv.getSkillTree())); + int maxPointSpent = inv.getSkillTree().getMaxPointSpent(); + holders.register("max-point-spent", maxPointSpent == Integer.MAX_VALUE ? "∞" : maxPointSpent); + holders.register("point-spent", inv.getPlayerData().getPointSpent(inv.getSkillTree())); holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoint(inv.getSkillTree().getId())); holders.register("global-points", inv.getPlayerData().getSkillTreePoint("global")); return holders; @@ -249,9 +249,9 @@ public class SkillTreeViewer extends EditableInventory { holders.register("max-children", node.getMaxChildren()); holders.register("size", node.getSize()); } - int maxPointSpent=inv.getSkillTree().getMaxPointSpent(); - holders.register("max-point-spent",maxPointSpent==Integer.MAX_VALUE?"∞":maxPointSpent); - holders.register("point-spent",inv.getPlayerData().getPointSpent(inv.getSkillTree())); + int maxPointSpent = inv.getSkillTree().getMaxPointSpent(); + holders.register("max-point-spent", maxPointSpent == Integer.MAX_VALUE ? "∞" : maxPointSpent); + holders.register("point-spent", inv.getPlayerData().getPointSpent(inv.getSkillTree())); holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoint(inv.getSkillTree().getId())); holders.register("global-points", inv.getPlayerData().getSkillTreePoint("global")); return holders; @@ -266,14 +266,16 @@ public class SkillTreeViewer extends EditableInventory { private final int width, height; private int treeListPage; private final int maxTreeListPage; - private final SkillTree skillTree; + private final List skillTrees; + private SkillTree skillTree; private final List slots; public SkillTreeInventory(PlayerData playerData, EditableInventory editable) { super(playerData, editable); - skillTree = playerData.getOpenedSkillTree(); - maxTreeListPage = (MMOCore.plugin.skillTreeManager.getAll().size() - 1) / editable.getByFunction("skill-tree").getSlots().size(); + skillTrees = playerData.getProfess().getSkillTrees(); + skillTree = skillTrees.get(0); + maxTreeListPage = (skillTrees.size() - 1) / editable.getByFunction("skill-tree").getSlots().size(); //We get the width and height of the GUI(corresponding to the slots given) slots = editable.getByFunction("skill-tree-node").getSlots(); minSlot = 64; @@ -381,12 +383,7 @@ public class SkillTreeViewer extends EditableInventory { //We remove all the nodeStates progress playerData.giveSkillTreePoints(skillTree.getId(), reallocated); playerData.giveSkillTreeReallocationPoints(-1); - for (SkillTreeNode node : skillTree.getNodes()) { - node.getExperienceTable().reset(playerData,node); - playerData.setNodeLevel(node, 0); - playerData.setNodeState(node, NodeState.LOCKED); - - } + playerData.resetSkillTree(skillTree); skillTree.setupNodeState(playerData); MMOCore.plugin.configManager.getSimpleMessage("reallocated-points", "points", "" + playerData.getSkillTreePoint(skillTree.getId()), "skill-tree", skillTree.getName()).send(player); MMOCore.plugin.soundManager.getSound(SoundEvent.RESET_SKILL_TREE).playTo(player); @@ -400,10 +397,9 @@ public class SkillTreeViewer extends EditableInventory { if (item.getFunction().equals("skill-tree")) { String id = event.getClickedItem().getItemMeta().getPersistentDataContainer().get( new NamespacedKey(MMOCore.plugin, "skill-tree-id"), PersistentDataType.STRING); - playerData.setCachedSkillTree(MMOCore.plugin.skillTreeManager.get(id)); MMOCore.plugin.soundManager.getSound(SoundEvent.CHANGE_SKILL_TREE).playTo(player); - - newInventory(playerData).open(); + skillTree=MMOCore.plugin.skillTreeManager.get(id); + open(); event.setCancelled(true); return; } @@ -418,7 +414,7 @@ public class SkillTreeViewer extends EditableInventory { return; } SkillTreeNode node = skillTree.getNode(new IntegerCoordinates(x, y)); - if(playerData.getPointSpent(skillTree)>= skillTree.getMaxPointSpent()) { + if (playerData.getPointSpent(skillTree) >= skillTree.getMaxPointSpent()) { MMOCore.plugin.configManager.getSimpleMessage("max-points-reached").send(player); MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer()); event.setCancelled(true); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java index 5f8183bf..f36568a8 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java @@ -231,6 +231,9 @@ public class MySQLPlayerDataManager extends PlayerDataManager { classinfo.addProperty("skill-points", info.getSkillPoints()); classinfo.addProperty("attribute-points", info.getAttributePoints()); classinfo.addProperty("attribute-realloc-points", info.getAttributeReallocationPoints()); + classinfo.addProperty("skill-reallocation-points",info.getSkillReallocationPoints()); + classinfo.addProperty("skill-tree-reallocation-points",info.getSkillTreeReallocationPoints()); + JsonObject skillinfo = new JsonObject(); for (String skill : info.getSkillKeys()) skillinfo.addProperty(skill, info.getSkillLevel(skill)); @@ -240,6 +243,16 @@ public class MySQLPlayerDataManager extends PlayerDataManager { attributeinfo.addProperty(attribute, info.getAttributeLevel(attribute)); classinfo.add("attribute", attributeinfo); + JsonObject nodeLevelsInfo = new JsonObject(); + for (SkillTreeNode node : info.getNodeKeys()) + attributeinfo.addProperty(node.getFullId(), info.getNodeLevel(node)); + classinfo.add("node-levels", nodeLevelsInfo); + + JsonObject skillTreePointsInfo = new JsonObject(); + for (String skillTreeId : info.getSkillTreePointsKeys()) + attributeinfo.addProperty(skillTreeId, info.getSkillTreePoints(skillTreeId)); + classinfo.add("skill-tree-points", skillTreePointsInfo); + json.add(c, classinfo); } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java index 3a449c60..6be5aec7 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java @@ -174,11 +174,15 @@ public class YAMLPlayerDataManager extends PlayerDataManager { config.set("class-info." + key + ".skill-points", info.getSkillPoints()); config.set("class-info." + key + ".attribute-points", info.getAttributePoints()); config.set("class-info." + key + ".attribute-realloc-points", info.getAttributeReallocationPoints()); + config.set("class-info." + key + ".skill-tree-reallocation-points", info.getSkillTreeReallocationPoints()); + config.set("class-info." + key + ".skill-reallocation-points", info.getSkillReallocationPoints()); info.getSkillKeys().forEach(skill -> config.set("class-info." + key + ".skill." + skill, info.getSkillLevel(skill))); - info.getAttributeKeys() - .forEach(attribute -> config.set("class-info." + key + ".attribute." + attribute, info.getAttributeLevel(attribute))); + info.getAttributeKeys().forEach(attribute -> config.set("class-info." + key + ".attribute." + attribute, info.getAttributeLevel(attribute))); + info.getNodeKeys().forEach(node -> config.set("class-info." + key + ".node-levels." + node.getFullId(), info.getNodeLevel(node))); + info.getSkillTreePointsKeys().forEach(skillTreeId -> config.set("class-info." + key + ".skill-tree-points." + skillTreeId, info.getAttributeLevel(skillTreeId))); } + file.save(); } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/party/compat/PartiesPartyModule.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/party/compat/PartiesPartyModule.java index be63fb4b..480d5fbd 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/party/compat/PartiesPartyModule.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/party/compat/PartiesPartyModule.java @@ -7,6 +7,7 @@ import com.alessiodp.parties.api.interfaces.PartyPlayer; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.party.AbstractParty; import net.Indyuce.mmocore.party.PartyModule; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.jetbrains.annotations.Nullable; @@ -14,12 +15,13 @@ import java.util.ArrayList; import java.util.List; public class PartiesPartyModule implements PartyModule { - private final PartiesAPI api = Parties.getApi(); @Nullable @Override public AbstractParty getParty(PlayerData playerData) { - Party party = api.getParty(playerData.getUniqueId()); + PartiesAPI api= Parties.getApi(); + PartyPlayer partyPlayer = api.getPartyPlayer(playerData.getUniqueId()); + Party party = api.getParty(partyPlayer.getPartyId()); return party == null ? null : new CustomParty(party); } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java index 56224924..d72b1034 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java @@ -9,7 +9,6 @@ import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.player.Unlockable; -import net.Indyuce.mmocore.tree.skilltree.AutomaticSkillTree; import net.Indyuce.mmocore.tree.skilltree.SkillTree; import org.apache.commons.lang.Validate; import org.bukkit.Location; @@ -29,7 +28,7 @@ public class SkillTreeNode implements Unlockable, ExperienceObject { /** * The lore corresponding to each level */ - private final Map> lores = new HashMap<>(); + private final Map> lores = new HashMap<>(); private final ExperienceTable experienceTable; @@ -53,11 +52,11 @@ public class SkillTreeNode implements Unlockable, ExperienceObject { name = Objects.requireNonNull(config.getString("name"), "Could not find node name"); size = Objects.requireNonNull(config.getInt("size")); isRoot = config.getBoolean("is-root", false); - if(config.contains("lores")) { - for(String key: config.getConfigurationSection("lores").getKeys(false)) { + if (config.contains("lores")) { + for (String key : config.getConfigurationSection("lores").getKeys(false)) { try { - lores.put(Integer.parseInt(key),config.getStringList("lores."+key)); - }catch (NumberFormatException e) { + lores.put(Integer.parseInt(key), config.getStringList("lores." + key)); + } catch (NumberFormatException e) { throw new RuntimeException("You must only specifiy integers in lores."); } } @@ -69,11 +68,19 @@ public class SkillTreeNode implements Unlockable, ExperienceObject { maxLevel = config.contains("max-level") ? config.getInt("max-level") : 1; maxChildren = config.contains("max-children") ? config.getInt("max-children") : 1; - //If coordinates are precised adn we are not with an automaticTree we set them up - if ((!(tree instanceof AutomaticSkillTree))) { - Validate.isTrue(config.contains("coordinates.x") && config.contains("coordinates.y"), "No coordinates specified"); - coordinates = new IntegerCoordinates(config.getInt("coordinates.x"), config.getInt("coordinates.y")); - } + //If coordinates are precised and we are not with an automaticTree we set them up + Validate.isTrue(config.contains("coordinates.x") && config.contains("coordinates.y"), "No coordinates specified"); + coordinates = new IntegerCoordinates(config.getInt("coordinates.x"), config.getInt("coordinates.y")); + + } + + /** + * Prefix used in the key + * + * @return + */ + public static String getPrefix() { + return "node"; } @@ -158,7 +165,7 @@ public class SkillTreeNode implements Unlockable, ExperienceObject { @Override public String getKey() { - return "node_" + getFullId().replace("-", "_"); + return getPrefix() + ":" + getFullId().replace("-", "_"); } @Nullable @@ -210,9 +217,9 @@ public class SkillTreeNode implements Unlockable, ExperienceObject { public List getLore(PlayerData playerData) { Placeholders holders = getPlaceholders(playerData); List parsedLore = new ArrayList<>(); - if(!lores.containsKey(playerData.getNodeLevel(this))) + if (!lores.containsKey(playerData.getNodeLevel(this))) return parsedLore; - List lore= lores.get(playerData.getNodeLevel(this)); + List lore = lores.get(playerData.getNodeLevel(this)); lore.forEach(string -> parsedLore.add( MythicLib.plugin.parseColors(holders.apply(playerData.getPlayer(), string)))); return parsedLore; diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/AutomaticSkillTree.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/AutomaticSkillTree.java deleted file mode 100644 index 17374ba6..00000000 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/AutomaticSkillTree.java +++ /dev/null @@ -1,212 +0,0 @@ -package net.Indyuce.mmocore.tree.skilltree; - -import net.Indyuce.mmocore.tree.IntegerCoordinates; -import net.Indyuce.mmocore.tree.ParentType; -import net.Indyuce.mmocore.tree.SkillTreeNode; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.configuration.ConfigurationSection; - -import java.util.HashMap; -import java.util.Objects; - -/** - * Skill Trees where you only need to fill the strong and soft - */ -public class AutomaticSkillTree extends SkillTree { - - //Hash map to store the number of left and right branches of each node - private final HashMap nodeBranches = new HashMap<>(); - - public AutomaticSkillTree(ConfigurationSection config) { - super(config); - } - - @Override - public void whenPostLoaded(ConfigurationSection config) { - - - //We setup the children and parents for each node. - for (SkillTreeNode node : nodes.values()) { - ConfigurationSection section = config.getConfigurationSection("nodes." + node.getId() + ".parents.soft"); - if (section != null) { - for (String parent : section.getKeys(false)) { - node.addParent(getNode(parent),section.getInt(parent),ParentType.SOFT); - getNode(parent).addChild(node); - } - } - section = config.getConfigurationSection("nodes." + node.getId() + ".parents.strong"); - - if (section != null) { - for (String parent : section.getKeys(false)) { - node.addParent(getNode(parent),section.getInt(parent),ParentType.STRONG); - getNode(parent).addChild(node); - } - } - - } - //We find the root of the tree which is - for (SkillTreeNode node : nodes.values()) { - if (node.getSoftParents().size() == 0 && node.getStrongParents().size() == 0) { - Validate.isTrue(roots.size() == 0, "You can't have 2 roots on one automatic skill tree. You have " + (roots.size() != 0 ? roots.get(0).getName() : "") + " and " + node.getName() + "."); - //We mark the node as a root also - roots.add(node); - node.setIsRoot(); - } - } - - //We setup the width of all the nodes recursively - setupTreeWidth(roots.get(0)); - //We recursively setup all the coordinates of the tree nodes - roots.get(0).setCoordinates(new IntegerCoordinates(0, 0)); - setupCoordinates(roots.get(0)); - - //We get and cache the values of minX,minY,maxX and maxY - minX = nodeBranches.get(roots.get(0)).getLeftBranches(); - minY = 0; - maxX = nodeBranches.get(roots.get(0)).getRightBranches(); - - for (SkillTreeNode node : nodes.values()) { - if (node.getCoordinates().getY() > maxY) - maxY = node.getCoordinates().getY(); - } - - //Eventually we setup the skill tree info related to coordinates - super.coordinatesSetup(); - - } - - /** - * Recursive algorithm to automatically calculate the integercoordinates each node should have to have a good display. - * It also fills the list pathToParents representing all the coordinates corresponding to a path between 2 nodes (for the GUI) - * - * @param node the root - */ - private void setupCoordinates(SkillTreeNode node) { - if (node.isRoot()) { - node.setCoordinates(new IntegerCoordinates(0, 2)); - } - int childrenSize = node.getChildren().size(); - - int x = node.getCoordinates().getX(); - int y = node.getCoordinates().getY(); - - int leftOffset = 0; - int rightOffset = 0; - - - - for (int i = 0; i < childrenSize; i++) { - SkillTreeNode child = node.getChildren().get(i); - int yOffset = childrenSize == 1 || child.getChildren().size()== 1 ? 1 : 2; - - if (childrenSize % 2 == 1 && i == 0) { - child.setCoordinates(new IntegerCoordinates(x, y - yOffset)); - leftOffset += 2 + nodeBranches.get(child).getLeftBranches(); - rightOffset += 2 + nodeBranches.get(child).getRightBranches(); - } else if (i % 2 == 0) { - child.setCoordinates(new IntegerCoordinates(x - leftOffset - 2 - nodeBranches.get(child).getWidth(), y - yOffset)); - leftOffset += 2 + nodeBranches.get(child).getWidth(); - } else { - child.setCoordinates(new IntegerCoordinates(x + rightOffset + 2 + nodeBranches.get(child).getWidth(), y - yOffset)); - rightOffset += 2 + nodeBranches.get(child).getWidth(); - } - - //We setup the path to parent variable (Used for the GUI) - int childX = child.getCoordinates().getX(); - int childY = child.getCoordinates().getY(); - - int parentX = node.getCoordinates().getX(); - int parentY = node.getCoordinates().getY(); - int offset = childX > parentX ? -1 : 1; - while (childY + 1 != parentY) { - paths.add(new IntegerCoordinates(childX, childY + 1)); - childY++; - - } - while (childX != parentX) { - paths.add(new IntegerCoordinates(childX, childY + 1)); - childX += offset; - } - - - //We setup the coordinates for the associated child - setupCoordinates(child); - } - - } - - public Branches getBranches(SkillTreeNode node) { - return nodeBranches.get(node); - } - - /** - * Recursively sed to setup all the right and left branches of the node to later determine its coordinates for GUI display - */ - public void setupTreeWidth(SkillTreeNode node) { - - int childrenSize = node.getChildren().size(); - int leftBranches = 0; - int rightBranches = 0; - for (int i = 0; i < childrenSize; i++) { - SkillTreeNode child = node.getChildren().get(i); - setupTreeWidth(child); - //If there is an odd number ob branches the first one will be at the center so we add to the left and to the right - if (childrenSize % 2 == 1 && i == 0) { - - leftBranches += nodeBranches.get(child).getLeftBranches(); - rightBranches += nodeBranches.get(child).getRightBranches(); - } else if (i % 2 == 0) { - leftBranches += nodeBranches.get(child).getWidth(); - } else { - rightBranches += nodeBranches.get(child).getWidth(); - } - } - - nodeBranches.put(node, new Branches(leftBranches, rightBranches)); - } - - private class Branches { - private final int leftBranches, rightBranches; - - public Branches(int leftBranches, int rightBranches) { - this.leftBranches = leftBranches; - this.rightBranches = rightBranches; - } - - public int getLeftBranches() { - return leftBranches; - } - - public int getRightBranches() { - return rightBranches; - } - - public int getWidth() { - return leftBranches + rightBranches; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Branches branches = (Branches) o; - return leftBranches == branches.leftBranches && rightBranches == branches.rightBranches; - } - - - @Override - public String toString() { - return "Branches{" + - "leftBranches=" + leftBranches + - ", rightBranches=" + rightBranches + - '}'; - } - - @Override - public int hashCode() { - return Objects.hash(leftBranches, rightBranches); - } - } -} - diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/LinkedSkillTree.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/LinkedSkillTree.java index 124e53cc..6c700b29 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/LinkedSkillTree.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/LinkedSkillTree.java @@ -1,11 +1,13 @@ package net.Indyuce.mmocore.tree.skilltree; +import io.lumine.mythic.lib.skill.Skill; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.tree.NodeState; import net.Indyuce.mmocore.tree.IntegerCoordinates; import net.Indyuce.mmocore.tree.ParentType; import net.Indyuce.mmocore.tree.SkillTreeNode; import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.jetbrains.annotations.NotNull; @@ -56,56 +58,75 @@ public class LinkedSkillTree extends SkillTree { Validate.notNull(root, "Their must be a node(the root of the tree) at the coordinates (0,0) "); } - @Override - public void setupNodeStateFrom(SkillTreeNode node, PlayerData playerData) { + public void setupNodeState(PlayerData playerData) { + //Values are labelled as unlockable + for (SkillTreeNode root : roots) + playerData.setNodeState(root, NodeState.UNLOCKABLE); - int x = node.getCoordinates().getX(); - int y = node.getCoordinates().getY(); - List checkCoordinates = Arrays.asList(new IntegerCoordinates(x + 1, y), - new IntegerCoordinates(x - 1, y), new IntegerCoordinates(x, y + 1), new IntegerCoordinates(x, y - 1)); - if (playerData.getNodeLevel(node) > 0) { - playerData.setNodeState(node, NodeState.UNLOCKED); - } else if (playerData.getNodeLevel(node) == 0 && node.isRoot()) { - playerData.setNodeState(node, NodeState.UNLOCKABLE); - } else { - boolean isUnlockable = false; - for (IntegerCoordinates coordinates : checkCoordinates) { - if (isNode(coordinates)) - if (isNode(coordinates) && playerData.getNodeState(getNode(coordinates)) == NodeState.UNLOCKED && numberNeighbours(coordinates, playerData) <= getNode(coordinates).getMaxChildren()) - isUnlockable = true; - } - if (isUnlockable) + //All the nodes with level >0 are unlocked + for (SkillTreeNode node : nodes.values()) { + if (playerData.getNodeLevel(node) > 0) + playerData.setNodeState(node, NodeState.UNLOCKED); + } + //Setup unlockable nodes + for (SkillTreeNode node : nodes.values()) { + if (isUnlockable(node, playerData) && !playerData.hasNodeState(node)) playerData.setNodeState(node, NodeState.UNLOCKABLE); - else { - List parents = new ArrayList<>(); - parents.add(node); - boolean isFullyLocked = isFullyLockedFrom(node, parents, playerData); - - if (isFullyLocked) - playerData.setNodeState(node, NodeState.FULLY_LOCKED); - else - playerData.setNodeState(node, NodeState.LOCKED); - } - } - //We call the recursive algorithm on the rest of the points. Doesn't call the algorithm if already loaded. - for (IntegerCoordinates coordinates : checkCoordinates) { - if (isNode(coordinates) && !playerData.hasNodeState(getNode(coordinates))) - setupNodeStateFrom(getNode(coordinates), playerData); + labelLockedNodes(playerData); + + //We label all the remaining nodes to FULLY LOCKED + for (SkillTreeNode node : nodes.values()) { + if (!playerData.hasNodeState(node)) + playerData.setNodeState(node, NodeState.FULLY_LOCKED); + } + + } + + /** + * We recursively label all the locked nodes who are connected to an unlockable node. + **/ + private void labelLockedNodes(PlayerData playerData) { + List unlockableNodes = nodes.values().stream().filter(node -> playerData.getNodeState(node) == NodeState.UNLOCKABLE).toList(); + for (SkillTreeNode node : unlockableNodes) { + labelLockedNodesFrom(playerData, node); } } + private void labelLockedNodesFrom(PlayerData data, SkillTreeNode node) { + for (IntegerCoordinates coor : getCheckCoordinates(node.getCoordinates())) { + if (isNode(coor) && !data.hasNodeState(getNode(coor))) { + data.setNodeState(getNode(coor), NodeState.LOCKED); + labelLockedNodesFrom(data, getNode(coor)); + } + } + } - //Counts the number of Unlocked Nieghbourgs of a node for a certain playerData - private int numberNeighbours(IntegerCoordinates coor, PlayerData playerData) { + private List getCheckCoordinates(IntegerCoordinates coor) { + return Arrays.asList(new IntegerCoordinates(coor.getX() + 1, coor.getY()), + new IntegerCoordinates(coor.getX() - 1, coor.getY()), new IntegerCoordinates(coor.getX(), coor.getY() + 1), new IntegerCoordinates(coor.getX(), coor.getY() - 1)); + } + + + private boolean isUnlockable(SkillTreeNode node, PlayerData playerData) { + + boolean isUnlockable = false; + for (IntegerCoordinates coordinates : getCheckCoordinates(node.getCoordinates())) { + if (isNode(coordinates)) + if (isNode(coordinates) && playerData.getNodeState(getNode(coordinates)) == NodeState.UNLOCKED && countUnlockedNeighbours(coordinates, playerData) <= getNode(coordinates).getMaxChildren()) + isUnlockable = true; + } + return isUnlockable; + } + + /** + * Counts the number of unlocked neighbours of a node for a certain playerData + **/ + private int countUnlockedNeighbours(IntegerCoordinates coor, PlayerData playerData) { int number = 0; - int x = coor.getX(); - int y = coor.getY(); - List checkCoordinates = Arrays.asList(new IntegerCoordinates(x + 1, y), - new IntegerCoordinates(x - 1, y), new IntegerCoordinates(x, y + 1), new IntegerCoordinates(x, y - 1)); - for (IntegerCoordinates coordinates : checkCoordinates) { + for (IntegerCoordinates coordinates : getCheckCoordinates(coor)) { if (isNode(coordinates) && playerData.getNodeLevel(getNode(coordinates)) > 0) number++; } @@ -113,40 +134,4 @@ public class LinkedSkillTree extends SkillTree { } - /** - * A recursive algorithm to see if a node is fully locked or not in a linked skill tree - */ - public boolean isFullyLockedFrom(SkillTreeNode current, List parents, PlayerData playerData) { - if (!parents.contains(current) && (playerData.getNodeState(current) == NodeState.UNLOCKABLE || playerData.getNodeState(current) == NodeState.UNLOCKED)) { - //If the node is unlocked either we say it is not fully locked if a path can be found either wer return true is not path can be found down this way - if (numberNeighbours(current.getCoordinates(), playerData) <= getNode(current.getCoordinates()).getMaxChildren()) { - return false; - } else - return true; - } - //We verify that the node is unlocked or unlockable and can have links the first node - - int x = current.getCoordinates().getX(); - int y = current.getCoordinates().getY(); - List checkCoordinates = Arrays.asList(new IntegerCoordinates(x + 1, y), - new IntegerCoordinates(x - 1, y), new IntegerCoordinates(x, y + 1), new IntegerCoordinates(x, y - 1)); - //We filter coordinates with only nodes that are not parents and not fully locked - //We also need to have the number of neighbour <=max-child(max-child=1 -> can have 1 neighbour but if it has 2 it will make the other branches fully blocked - checkCoordinates = checkCoordinates.stream().filter(coor -> isNode(coor) - && playerData.getNodeState(getNode(coor)) != NodeState.FULLY_LOCKED - && !parents.contains(getNode(coor)) - ).collect(Collectors.toList()); - - boolean isFullyLocked = true; - - parents.add(current); - for (IntegerCoordinates coordinates : checkCoordinates) { - if (!isFullyLockedFrom(getNode(coordinates), parents, playerData)) { - isFullyLocked = false; - //Very important to break to stop the recursion algorithm once one unlockable point has been found - break; - } - } - return isFullyLocked; - } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/SkillTree.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/SkillTree.java index b31f6032..d344a557 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/SkillTree.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/tree/skilltree/SkillTree.java @@ -157,12 +157,9 @@ public abstract class SkillTree extends PostLoadObject implements RegisteredObje try { String string = config.getString("type"); Validate.notNull(string, "You must precise a type for the skill tree."); - Validate.isTrue(string.equals("automatic") || string.equals("linked") || string.equals("custom"), "You must precise the type of the skill tree in the yml!" + - "\nAllowed values: 'automatic','linked','custom'"); - if (string.equals("automatic")) { - skillTree = new AutomaticSkillTree(config); - skillTree.postLoad(); - } + Validate.isTrue(string.equals("linked") || string.equals("custom"), "You must precise the type of the skill tree in the yml!" + + "\nAllowed values: 'linked','custom'"); + if (string.equals("linked")) { skillTree = new LinkedSkillTree(config); skillTree.postLoad(); diff --git a/MMOCore-Dist/src/main/resources/default/gui/skill-tree.yml b/MMOCore-Dist/src/main/resources/default/gui/skill-tree.yml index 49136ea6..230034df 100644 --- a/MMOCore-Dist/src/main/resources/default/gui/skill-tree.yml +++ b/MMOCore-Dist/src/main/resources/default/gui/skill-tree.yml @@ -12,25 +12,25 @@ items: item: PLAYER_HEAD name: "Up" texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTk5YWFmMjQ1NmE2MTIyZGU4ZjZiNjI2ODNmMmJjMmVlZDlhYmI4MWZkNWJlYTFiNGMyM2E1ODE1NmI2NjkifX19 - slots: [ 52 ] + slots: [ 50 ] down: function: down item: PLAYER_HEAD name: "Down" texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzkxMmQ0NWIxYzc4Y2MyMjQ1MjcyM2VlNjZiYTJkMTU3NzdjYzI4ODU2OGQ2YzFiNjJhNTQ1YjI5YzcxODcifX19 - slots: [ 51 ] + slots: [ 49 ] right: function: right item: PLAYER_HEAD name: "Right" texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTNmYzUyMjY0ZDhhZDllNjU0ZjQxNWJlZjAxYTIzOTQ3ZWRiY2NjY2Y2NDkzNzMyODliZWE0ZDE0OTU0MWY3MCJ9fX0= - slots: [ 50 ] + slots: [ 51 ] left: function: left item: PLAYER_HEAD name: "Left" texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzNlOTE5MTlkYjBhY2VmZGMyNzJkNjdmZDg3YjRiZTg4ZGM0NGE5NTg5NTg4MjQ0NzRlMjFlMDZkNTNlNiJ9fX0= - slots: [ 49 ] + slots: [ 48 ] skill-tree: name: '{skill-tree-node}' @@ -49,14 +49,14 @@ items: next-tree-list-page: function: 'next-tree-list-page' - item: ARROW - name: "Next Page" + item: PLAYER_HEAD + texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTk5YWFmMjQ1NmE2MTIyZGU4ZjZiNjI2ODNmMmJjMmVlZDlhYmI4MWZkNWJlYTFiNGMyM2E1ODE1NmI2NjkifX19 slots: [ 36 ] previous-tree-list-page: function: 'previous-tree-list-page' - item: 'ARROW' - name: "Previous Page" + item: PLAYER_HEAD + texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzkxMmQ0NWIxYzc4Y2MyMjQ1MjcyM2VlNjZiYTJkMTU3NzdjYzI4ODU2OGQ2YzFiNjJhNTQ1YjI5YzcxODcifX19 slots: [ 0 ] reallocation: @@ -76,7 +76,7 @@ items: skill-tree-node: function: 'skill-tree-node' - slots: [2,3,4,5,6,7,8,11,12,13,14,15,16,17,20,21,22,23,24,25,26,29,30,31,32,33,34,35,38,39,40,41,42,43,44] + slots: [1,2,3,4,5,6,7,8,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,28,29,30,31,32,33,34,35,37,38,39,40,41,42,43,44] #The lore that will be displayed after the lore of the node lore: - '&7Current State: &6{current-state}' diff --git a/MMOCore-Dist/src/main/resources/default/messages.yml b/MMOCore-Dist/src/main/resources/default/messages.yml index c90ece7f..bb41193d 100644 --- a/MMOCore-Dist/src/main/resources/default/messages.yml +++ b/MMOCore-Dist/src/main/resources/default/messages.yml @@ -185,4 +185,5 @@ upgrade-skill-node: '&eYour skill node &6{skill-node} &eis now Level &6{level}&e skill-node-max-level-hit: '&cYou already hit the max level for that skill node.' not-enough-skill-tree-points: '&cYou need one skill tree point.' reallocated-points: '&eYou successfully reset the skill tree {skill-tree}. &eYou now have &6{points} &eskill tree points.' -not-skill-tree-reallocation-point: '&cYou do not have 1 skill tree reallocation point.' \ No newline at end of file +not-skill-tree-reallocation-point: '&cYou do not have 1 skill tree reallocation point.' +no-skill-tree: '&cYour class doesn''t have any skill tree.' \ No newline at end of file