Merge remote-tracking branch 'origin/master'

# Conflicts:
#	MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
#	MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
This commit is contained in:
Indyuce 2022-10-18 10:50:33 +02:00
commit 446b68ea31
17 changed files with 450 additions and 523 deletions

View File

@ -365,10 +365,10 @@ public class MMOCore extends JavaPlugin {
dropTableManager.initialize(clearBefore); dropTableManager.initialize(clearBefore);
statManager.initialize(clearBefore); statManager.initialize(clearBefore);
professionManager.initialize(clearBefore); professionManager.initialize(clearBefore);
classManager.initialize(clearBefore);
InventoryManager.load(); InventoryManager.load();
skillTreeManager.initialize(clearBefore); skillTreeManager.initialize(clearBefore);
classManager.initialize(clearBefore);
questManager.initialize(clearBefore); questManager.initialize(clearBefore);
lootChests.initialize(clearBefore); lootChests.initialize(clearBefore);
restrictionManager.initialize(clearBefore); restrictionManager.initialize(clearBefore);

View File

@ -4,6 +4,8 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData; import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.player.cooldown.CooldownMap; import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import io.lumine.mythic.lib.player.skill.PassiveSkill; 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.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
@ -79,7 +81,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
private double mana, stamina, stellium; private double mana, stamina, stellium;
private Guild guild; private Guild guild;
private SkillCastingHandler skillCasting; private SkillCastingHandler skillCasting;
private SkillTree cachedSkillTree;
private final PlayerQuests questData; private final PlayerQuests questData;
private final PlayerStats playerStats; private final PlayerStats playerStats;
private final List<UUID> friends = new ArrayList<>(); private final List<UUID> friends = new ArrayList<>();
@ -209,6 +210,10 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return nodeLevelsString.entrySet(); return nodeLevelsString.entrySet();
} }
public Map<SkillTreeNode, Integer> getNodeLevels() {
return nodeLevels;
}
public boolean canIncrementNodeLevel(SkillTreeNode node) { public boolean canIncrementNodeLevel(SkillTreeNode node) {
NodeState nodeState = nodeStates.get(node); NodeState nodeState = nodeStates.get(node);
//Check the State of the node //Check the State of the node
@ -292,6 +297,38 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
nodeLevels.put(node, nodeLevel); 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<SkillTreeNode, NodeState> getNodeStates() {
return nodeStates;
}
public Map<String, Integer> getNodeTimesClaimed() {
Map<String, Integer> result = new HashMap<>();
tableItemClaims.forEach((str, val) -> {
if (str.startsWith(SkillTreeNode.getPrefix()))
result.put(str, val);
});
return result;
}
public void resetNodeTimesClaimed() {
Map<String, Integer> 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) { public void addNodeLevel(SkillTreeNode node) {
nodeLevels.put(node, nodeLevels.get(node) + 1); nodeLevels.put(node, nodeLevels.get(node) + 1);
} }
@ -299,10 +336,12 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
@Override @Override
public void close() { public void close() {
// Remove from party // Remove from party if it is MMO Party Module
if(MMOCore.plugin.partyModule instanceof MMOCorePartyModule) {
AbstractParty party = getParty(); AbstractParty party = getParty();
if (party != null && party instanceof Party) if (party != null && party instanceof Party)
((Party) party).removeMember(this); ((Party) party).removeMember(this);
}
// Close quest data // Close quest data
questData.close(); questData.close();
@ -354,19 +393,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return Math.max(1, level); return Math.max(1, level);
} }
public void setCachedSkillTree(SkillTree cachedSkillTree) {
this.cachedSkillTree = cachedSkillTree;
}
@NotNull
public SkillTree getOpenedSkillTree() {
if (cachedSkillTree == null) {
Optional<SkillTree> optionnal = MMOCore.plugin.skillTreeManager.getAll().stream().findFirst();
return optionnal.isPresent() ? optionnal.get() : null;
}
return cachedSkillTree;
}
@Nullable @Nullable
public AbstractParty getParty() { public AbstractParty getParty() {
return MMOCore.plugin.partyModule.getParty(this); return MMOCore.plugin.partyModule.getParty(this);
@ -415,13 +441,19 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
@Override @Override
public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) { 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); return tableItemClaims.getOrDefault(key, 0);
} }
@Override @Override
public void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int times) { 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); tableItemClaims.put(key, times);
} }

View File

@ -25,14 +25,16 @@ import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.EXPSource; import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExpCurve; import net.Indyuce.mmocore.experience.ExpCurve;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.loot.chest.particle.CastingParticle; import net.Indyuce.mmocore.loot.chest.particle.CastingParticle;
import net.Indyuce.mmocore.player.stats.StatInfo; import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill; 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 net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.Validate;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Particle; import org.bukkit.Particle;
@ -67,6 +69,8 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
private final CastingParticle castParticle; private final CastingParticle castParticle;
private final int maxBoundActiveSkills, maxBoundPassiveSkills; private final int maxBoundActiveSkills, maxBoundPassiveSkills;
private final List<SkillTree> skillTrees = new ArrayList<>();
private final List<PassiveSkill> classScripts = new LinkedList(); private final List<PassiveSkill> classScripts = new LinkedList();
private final Map<String, LinearValue> stats = new HashMap<>(); private final Map<String, LinearValue> stats = new HashMap<>();
private final Map<String, ClassSkill> skills = new LinkedHashMap<>(); private final Map<String, ClassSkill> skills = new LinkedHashMap<>();
@ -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()); MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table from class '" + id + "': " + exception.getMessage());
} }
this.expTable = expTable; 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")) if (config.contains("scripts"))
for (String key : config.getConfigurationSection("scripts").getKeys(false)) for (String key : config.getConfigurationSection("scripts").getKeys(false))
@ -302,6 +313,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
public int getMaxBoundActiveSkills() { public int getMaxBoundActiveSkills() {
return maxBoundActiveSkills; return maxBoundActiveSkills;
} }
public int getMaxBoundPassiveSkills() { public int getMaxBoundPassiveSkills() {
return maxBoundPassiveSkills; return maxBoundPassiveSkills;
} }
@ -413,6 +425,10 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
return skills.containsKey(id); return skills.containsKey(id);
} }
public List<SkillTree> getSkillTrees() {
return skillTrees;
}
public ClassSkill getSkill(RegisteredSkill skill) { public ClassSkill getSkill(RegisteredSkill skill) {
return getSkill(skill.getHandler().getId()); return getSkill(skill.getHandler().getId());
} }

View File

@ -1,25 +1,32 @@
package net.Indyuce.mmocore.api.player.profess; 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.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; 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 { public class SavedClassInformation {
private final int level, skillPoints, attributePoints, attributeReallocationPoints; private final int level, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints;
private final double experience; private final double experience;
private final Map<String, Integer> attributes; private final Map<String, Integer> attributes;
private final Map<String, Integer> skills; private final Map<String, Integer> skills;
private final Map<String, Integer> skillTreePoints;
private final Map<SkillTreeNode, Integer> nodeLevels;
/**
* Stores the tableItemsClaims values but only for skill tree node as it is class based.
*/
private final Map<String,Integer> nodeTimesClaimed;
public SavedClassInformation(ConfigurationSection config) { public SavedClassInformation(ConfigurationSection config) {
level = config.getInt("level"); level = config.getInt("level");
@ -27,13 +34,24 @@ public class SavedClassInformation {
skillPoints = config.getInt("skill-points"); skillPoints = config.getInt("skill-points");
attributePoints = config.getInt("attribute-points"); attributePoints = config.getInt("attribute-points");
attributeReallocationPoints = config.getInt("attribute-realloc-points"); attributeReallocationPoints = config.getInt("attribute-realloc-points");
skillReallocationPoints = config.getInt("skill-reallocation-points");
skillTreeReallocationPoints = config.getInt("skill-tree-reallocation-points");
attributes = new HashMap<>(); attributes = new HashMap<>();
if (config.contains("attribute")) if (config.contains("attribute"))
config.getConfigurationSection("attribute").getKeys(false).forEach(key -> attributes.put(key, config.getInt("attribute." + key))); config.getConfigurationSection("attribute").getKeys(false).forEach(key -> attributes.put(key, config.getInt("attribute." + key)));
skills = new HashMap<>(); skills = new HashMap<>();
if (config.contains("skill")) if (config.contains("skill"))
config.getConfigurationSection("skill").getKeys(false).forEach(key -> skills.put(key, config.getInt("skill." + key))); 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)));
} }
public SavedClassInformation(JsonObject json) { public SavedClassInformation(JsonObject json) {
@ -42,7 +60,8 @@ public class SavedClassInformation {
skillPoints = json.get("skill-points").getAsInt(); skillPoints = json.get("skill-points").getAsInt();
attributePoints = json.get("attribute-points").getAsInt(); attributePoints = json.get("attribute-points").getAsInt();
attributeReallocationPoints = json.get("attribute-realloc-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<>(); attributes = new HashMap<>();
if (json.has("attribute")) if (json.has("attribute"))
for (Entry<String, JsonElement> entry : json.getAsJsonObject("attribute").entrySet()) for (Entry<String, JsonElement> entry : json.getAsJsonObject("attribute").entrySet())
@ -51,31 +70,50 @@ public class SavedClassInformation {
if (json.has("skill")) if (json.has("skill"))
for (Entry<String, JsonElement> entry : json.getAsJsonObject("skill").entrySet()) for (Entry<String, JsonElement> entry : json.getAsJsonObject("skill").entrySet())
skills.put(entry.getKey(), entry.getValue().getAsInt()); skills.put(entry.getKey(), entry.getValue().getAsInt());
skillTreePoints = new HashMap<>();
if (json.has("skill-tree-points"))
for (Entry<String, JsonElement> entry : json.getAsJsonObject("skill-tree-points").entrySet())
skillTreePoints.put(entry.getKey(), entry.getValue().getAsInt());
nodeLevels = new HashMap<>();
if (json.has("node-levels"))
for (Entry<String, JsonElement> 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<String, JsonElement> entry : json.getAsJsonObject("node-times-claimed").entrySet())
nodeTimesClaimed.put(entry.getKey(), entry.getValue().getAsInt());
} }
public SavedClassInformation(PlayerData player) { public SavedClassInformation(PlayerData player) {
this(player.getLevel(), player.getExperience(), player.getSkillPoints(), player.getAttributePoints(), player.getAttributeReallocationPoints(), this(player.getLevel(), player.getExperience(), player.getSkillPoints(), player.getAttributePoints(), player.getAttributeReallocationPoints()
player.getAttributes().mapPoints(), player.mapSkillLevels()); , player.getSkillTreeReallocationPoints(), player.getSkillReallocationPoints(),
player.getAttributes().mapPoints(), player.mapSkillLevels(), player.getSkillTreePoints(), player.getNodeLevels(),player.getNodeTimesClaimed());
} }
public SavedClassInformation(PlayerDataManager.DefaultPlayerData data) { public SavedClassInformation(PlayerDataManager.DefaultPlayerData data) {
this(data.getLevel(), 0, data.getSkillPoints(), data.getAttributePoints(), data.getAttrReallocPoints()); 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) { public SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints, int skillTreeReallocationPoints, int skillReallocationPoints) {
this(level, experience, skillPoints, attributePoints, attributeReallocationPoints, new HashMap<>(), new HashMap<>()); 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, public SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints, int skillTreeReallocationPoints, int skillReallocationPoints,
Map<String, Integer> attributes, Map<String, Integer> skills) { Map<String, Integer> attributes, Map<String, Integer> skills, Map<String, Integer> skillTreePoints, Map<SkillTreeNode, Integer> nodeLevels,Map<String, Integer> nodeTimesClaimed) {
this.level = level; this.level = level;
this.experience = experience;
this.skillPoints = skillPoints; this.skillPoints = skillPoints;
this.attributePoints = attributePoints; this.attributePoints = attributePoints;
this.attributeReallocationPoints = attributeReallocationPoints; this.attributeReallocationPoints = attributeReallocationPoints;
this.skillTreeReallocationPoints = skillTreeReallocationPoints;
this.skillReallocationPoints = skillReallocationPoints;
this.experience = experience;
this.attributes = attributes; this.attributes = attributes;
this.skills = skills; this.skills = skills;
this.skillTreePoints = skillTreePoints;
this.nodeLevels = nodeLevels;
this.nodeTimesClaimed=nodeTimesClaimed;
} }
public int getLevel() { public int getLevel() {
@ -114,20 +152,41 @@ public class SavedClassInformation {
registerSkillLevel(skill.getHandler().getId(), level); registerSkillLevel(skill.getHandler().getId(), level);
} }
public int getSkillTreeReallocationPoints() {
return skillTreeReallocationPoints;
}
public int getSkillReallocationPoints() {
return skillReallocationPoints;
}
public void registerSkillLevel(String attribute, int level) { public void registerSkillLevel(String attribute, int level) {
skills.put(attribute, level); skills.put(attribute, level);
} }
public Set<SkillTreeNode> getNodeKeys() {
return nodeLevels.keySet();
}
public int getNodeLevel(SkillTreeNode node) {
return nodeLevels.get(node);
}
public Set<String> getSkillTreePointsKeys() {
return skillTreePoints.keySet();
}
public int getSkillTreePoints(String skillTreeId) {
return skillTreePoints.get(skillTreeId);
}
public Set<String> getAttributeKeys() { public Set<String> getAttributeKeys() {
return attributes.keySet(); return attributes.keySet();
} }
public int getAttributeLevel(PlayerAttribute attribute) {
return getAttributeLevel(attribute.getId());
}
public int getAttributeLevel(String id) { public int getAttributeLevel(String id) {
return attributes.get(id); return attributes.getOrDefault(id,0);
} }
public void registerAttributeLevel(PlayerAttribute attribute, int level) { public void registerAttributeLevel(PlayerAttribute attribute, int level) {
@ -150,8 +209,17 @@ public class SavedClassInformation {
/* /*
* resets information which much be reset after everything is saved. * resets information which much be reset after everything is saved.
*/ */
player.mapSkillLevels().forEach((skill, level) -> player.resetSkillLevel(skill)); player.mapSkillLevels().forEach((skill, level) -> player.resetSkillLevel(skill));
player.getAttributes().getInstances().forEach(ins -> ins.setBase(0)); 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)) while (player.hasSkillBound(0))
player.unbindSkill(0); player.unbindSkill(0);
@ -165,9 +233,23 @@ public class SavedClassInformation {
player.setSkillPoints(skillPoints); player.setSkillPoints(skillPoints);
player.setAttributePoints(attributePoints); player.setAttributePoints(attributePoints);
player.setAttributeReallocationPoints(attributeReallocationPoints); player.setAttributeReallocationPoints(attributeReallocationPoints);
player.setSkillTreeReallocationPoints(skillTreeReallocationPoints);
player.setSkillReallocationPoints(skillReallocationPoints);
skills.forEach(player::setSkillLevel); (skills).forEach(player::setSkillLevel);
attributes.forEach((id, pts) -> player.getAttributes().setBaseAttribute(id, pts)); 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 * unload current class information and set the new profess once

View File

@ -11,12 +11,14 @@ import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.Collection; import java.util.Collection;
import java.util.UUID;
public class StatTrigger extends Trigger { public class StatTrigger extends Trigger {
private final String stat; private final String stat;
private final double amount; private final double amount;
private final ModifierType type; private final ModifierType type;
private double totalAmount; private double totalAmount;
private final UUID uuid =UUID.randomUUID();
public StatTrigger(MMOLineConfig config) { public StatTrigger(MMOLineConfig config) {
super(config); super(config);
@ -35,7 +37,7 @@ public class StatTrigger extends Trigger {
@Override @Override
public void apply(PlayerData player) { public void apply(PlayerData player) {
totalAmount+=amount; 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) { public void remove(PlayerData playerData) {
totalAmount-=amount; totalAmount-=amount;
new StatModifier("trigger", stat, totalAmount, type).register(playerData.getMMOPlayerData()); new StatModifier("trigger."+uuid.toString(), stat, totalAmount, type).register(playerData.getMMOPlayerData());
} }
} }

View File

@ -1,6 +1,7 @@
package net.Indyuce.mmocore.command; package net.Indyuce.mmocore.command;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.event.MMOCommandEvent; import net.Indyuce.mmocore.api.event.MMOCommandEvent;
import net.Indyuce.mmocore.manager.InventoryManager; import net.Indyuce.mmocore.manager.InventoryManager;
@ -21,19 +22,23 @@ public class SkillTreeCommand extends BukkitCommand {
@Override @Override
public boolean execute(@NotNull CommandSender sender, String s, String[] args) { public boolean execute(@NotNull CommandSender sender, String s, String[] args) {
if (!(sender instanceof Player)) if (!(sender instanceof Player player))
return false; return false;
PlayerData data = PlayerData.get((Player) sender); PlayerData data = PlayerData.get(player);
MMOCommandEvent event = new MMOCommandEvent(data, "skilltree"); MMOCommandEvent event = new MMOCommandEvent(data, "skilltree");
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) if (event.isCancelled())
return true; return true;
if (MMOCore.plugin.skillTreeManager.getAll().size() != 0) { if (data.getProfess().getSkillTrees().size() != 0) {
InventoryManager.TREE_VIEW.newInventory(data).open(); InventoryManager.TREE_VIEW.newInventory(data).open();
return false; return false;
} }
else {
MMOCore.plugin.configManager.getSimpleMessage("no-skill-tree").send(player);
return true; return true;
} }
}
} }

View File

@ -76,9 +76,6 @@ public class ExperienceTable {
public void claimStatTriggers(PlayerData data, ExperienceObject object) { public void claimStatTriggers(PlayerData data, ExperienceObject object) {
for (ExperienceItem item : items) { for (ExperienceItem item : items) {
int timesClaimed = data.getClaims(object, this, item); 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++) for (int i = 0; i < timesClaimed; i++)
item.applyStatTriggers(data); item.applyStatTriggers(data);

View File

@ -101,10 +101,10 @@ public class SkillTreeViewer extends EditableInventory {
@Override @Override
public ItemStack display(SkillTreeInventory inv, int n) { public ItemStack display(SkillTreeInventory inv, int n) {
int index = inv.getEditable().getByFunction("skill-tree").getSlots().size() * inv.treeListPage + 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); 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 //We display with the material corresponding to the skillTree
ItemStack item = super.display(inv, n, skillTree.getItem()); ItemStack item = super.display(inv, n, skillTree.getItem());
@ -129,7 +129,7 @@ public class SkillTreeViewer extends EditableInventory {
@Override @Override
public Placeholders getPlaceholders(SkillTreeInventory inv, int n) { public Placeholders getPlaceholders(SkillTreeInventory inv, int n) {
int index = inv.getEditable().getByFunction("skill-tree").getSlots().size() * inv.treeListPage + 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(); Placeholders holders = new Placeholders();
holders.register("name", skillTree.getName()); holders.register("name", skillTree.getName());
holders.register("id", skillTree.getId()); holders.register("id", skillTree.getId());
@ -266,14 +266,16 @@ public class SkillTreeViewer extends EditableInventory {
private final int width, height; private final int width, height;
private int treeListPage; private int treeListPage;
private final int maxTreeListPage; private final int maxTreeListPage;
private final SkillTree skillTree; private final List<SkillTree> skillTrees;
private SkillTree skillTree;
private final List<Integer> slots; private final List<Integer> slots;
public SkillTreeInventory(PlayerData playerData, EditableInventory editable) { public SkillTreeInventory(PlayerData playerData, EditableInventory editable) {
super(playerData, editable); super(playerData, editable);
skillTree = playerData.getOpenedSkillTree(); skillTrees = playerData.getProfess().getSkillTrees();
maxTreeListPage = (MMOCore.plugin.skillTreeManager.getAll().size() - 1) / editable.getByFunction("skill-tree").getSlots().size(); 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) //We get the width and height of the GUI(corresponding to the slots given)
slots = editable.getByFunction("skill-tree-node").getSlots(); slots = editable.getByFunction("skill-tree-node").getSlots();
minSlot = 64; minSlot = 64;
@ -381,12 +383,7 @@ public class SkillTreeViewer extends EditableInventory {
//We remove all the nodeStates progress //We remove all the nodeStates progress
playerData.giveSkillTreePoints(skillTree.getId(), reallocated); playerData.giveSkillTreePoints(skillTree.getId(), reallocated);
playerData.giveSkillTreeReallocationPoints(-1); playerData.giveSkillTreeReallocationPoints(-1);
for (SkillTreeNode node : skillTree.getNodes()) { playerData.resetSkillTree(skillTree);
node.getExperienceTable().reset(playerData,node);
playerData.setNodeLevel(node, 0);
playerData.setNodeState(node, NodeState.LOCKED);
}
skillTree.setupNodeState(playerData); skillTree.setupNodeState(playerData);
MMOCore.plugin.configManager.getSimpleMessage("reallocated-points", "points", "" + playerData.getSkillTreePoint(skillTree.getId()), "skill-tree", skillTree.getName()).send(player); 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); 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")) { if (item.getFunction().equals("skill-tree")) {
String id = event.getClickedItem().getItemMeta().getPersistentDataContainer().get( String id = event.getClickedItem().getItemMeta().getPersistentDataContainer().get(
new NamespacedKey(MMOCore.plugin, "skill-tree-id"), PersistentDataType.STRING); 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); MMOCore.plugin.soundManager.getSound(SoundEvent.CHANGE_SKILL_TREE).playTo(player);
skillTree=MMOCore.plugin.skillTreeManager.get(id);
newInventory(playerData).open(); open();
event.setCancelled(true); event.setCancelled(true);
return; return;
} }

View File

@ -231,6 +231,9 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
classinfo.addProperty("skill-points", info.getSkillPoints()); classinfo.addProperty("skill-points", info.getSkillPoints());
classinfo.addProperty("attribute-points", info.getAttributePoints()); classinfo.addProperty("attribute-points", info.getAttributePoints());
classinfo.addProperty("attribute-realloc-points", info.getAttributeReallocationPoints()); 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(); JsonObject skillinfo = new JsonObject();
for (String skill : info.getSkillKeys()) for (String skill : info.getSkillKeys())
skillinfo.addProperty(skill, info.getSkillLevel(skill)); skillinfo.addProperty(skill, info.getSkillLevel(skill));
@ -240,6 +243,16 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
attributeinfo.addProperty(attribute, info.getAttributeLevel(attribute)); attributeinfo.addProperty(attribute, info.getAttributeLevel(attribute));
classinfo.add("attribute", attributeinfo); 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); json.add(c, classinfo);
} }

View File

@ -174,11 +174,15 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
config.set("class-info." + key + ".skill-points", info.getSkillPoints()); config.set("class-info." + key + ".skill-points", info.getSkillPoints());
config.set("class-info." + key + ".attribute-points", info.getAttributePoints()); config.set("class-info." + key + ".attribute-points", info.getAttributePoints());
config.set("class-info." + key + ".attribute-realloc-points", info.getAttributeReallocationPoints()); 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.getSkillKeys().forEach(skill -> config.set("class-info." + key + ".skill." + skill, info.getSkillLevel(skill)));
info.getAttributeKeys() info.getAttributeKeys().forEach(attribute -> config.set("class-info." + key + ".attribute." + attribute, info.getAttributeLevel(attribute)));
.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(); file.save();
} }

View File

@ -7,6 +7,7 @@ import com.alessiodp.parties.api.interfaces.PartyPlayer;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.party.AbstractParty; import net.Indyuce.mmocore.party.AbstractParty;
import net.Indyuce.mmocore.party.PartyModule; import net.Indyuce.mmocore.party.PartyModule;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -14,12 +15,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class PartiesPartyModule implements PartyModule { public class PartiesPartyModule implements PartyModule {
private final PartiesAPI api = Parties.getApi();
@Nullable @Nullable
@Override @Override
public AbstractParty getParty(PlayerData playerData) { 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); return party == null ? null : new CustomParty(party);
} }

View File

@ -9,7 +9,6 @@ import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.Placeholders;
import net.Indyuce.mmocore.player.Unlockable; import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.tree.skilltree.AutomaticSkillTree;
import net.Indyuce.mmocore.tree.skilltree.SkillTree; import net.Indyuce.mmocore.tree.skilltree.SkillTree;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Location; import org.bukkit.Location;
@ -69,11 +68,19 @@ public class SkillTreeNode implements Unlockable, ExperienceObject {
maxLevel = config.contains("max-level") ? config.getInt("max-level") : 1; maxLevel = config.contains("max-level") ? config.getInt("max-level") : 1;
maxChildren = config.contains("max-children") ? config.getInt("max-children") : 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 coordinates are precised and 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"); Validate.isTrue(config.contains("coordinates.x") && config.contains("coordinates.y"), "No coordinates specified");
coordinates = new IntegerCoordinates(config.getInt("coordinates.x"), config.getInt("coordinates.y")); 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 @Override
public String getKey() { public String getKey() {
return "node_" + getFullId().replace("-", "_"); return getPrefix() + ":" + getFullId().replace("-", "_");
} }
@Nullable @Nullable

View File

@ -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<SkillTreeNode, Branches> 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);
}
}
}

View File

@ -1,11 +1,13 @@
package net.Indyuce.mmocore.tree.skilltree; package net.Indyuce.mmocore.tree.skilltree;
import io.lumine.mythic.lib.skill.Skill;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.tree.NodeState; import net.Indyuce.mmocore.tree.NodeState;
import net.Indyuce.mmocore.tree.IntegerCoordinates; import net.Indyuce.mmocore.tree.IntegerCoordinates;
import net.Indyuce.mmocore.tree.ParentType; import net.Indyuce.mmocore.tree.ParentType;
import net.Indyuce.mmocore.tree.SkillTreeNode; import net.Indyuce.mmocore.tree.SkillTreeNode;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull; 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) "); Validate.notNull(root, "Their must be a node(the root of the tree) at the coordinates (0,0) ");
} }
@Override @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(); //All the nodes with level >0 are unlocked
int y = node.getCoordinates().getY(); for (SkillTreeNode node : nodes.values()) {
List<IntegerCoordinates> checkCoordinates = Arrays.asList(new IntegerCoordinates(x + 1, y), if (playerData.getNodeLevel(node) > 0)
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); playerData.setNodeState(node, NodeState.UNLOCKED);
} else if (playerData.getNodeLevel(node) == 0 && node.isRoot()) { }
//Setup unlockable nodes
for (SkillTreeNode node : nodes.values()) {
if (isUnlockable(node, playerData) && !playerData.hasNodeState(node))
playerData.setNodeState(node, NodeState.UNLOCKABLE); playerData.setNodeState(node, NodeState.UNLOCKABLE);
} else { }
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<SkillTreeNode> 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));
}
}
}
private List<IntegerCoordinates> 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; boolean isUnlockable = false;
for (IntegerCoordinates coordinates : checkCoordinates) { for (IntegerCoordinates coordinates : getCheckCoordinates(node.getCoordinates())) {
if (isNode(coordinates)) if (isNode(coordinates))
if (isNode(coordinates) && playerData.getNodeState(getNode(coordinates)) == NodeState.UNLOCKED && numberNeighbours(coordinates, playerData) <= getNode(coordinates).getMaxChildren()) if (isNode(coordinates) && playerData.getNodeState(getNode(coordinates)) == NodeState.UNLOCKED && countUnlockedNeighbours(coordinates, playerData) <= getNode(coordinates).getMaxChildren())
isUnlockable = true; isUnlockable = true;
} }
if (isUnlockable) return isUnlockable;
playerData.setNodeState(node, NodeState.UNLOCKABLE);
else {
List<SkillTreeNode> 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);
} }
} /**
* Counts the number of unlocked neighbours of a node for a certain playerData
//We call the recursive algorithm on the rest of the points. Doesn't call the algorithm if already loaded. **/
for (IntegerCoordinates coordinates : checkCoordinates) { private int countUnlockedNeighbours(IntegerCoordinates coor, PlayerData playerData) {
if (isNode(coordinates) && !playerData.hasNodeState(getNode(coordinates)))
setupNodeStateFrom(getNode(coordinates), playerData);
}
}
//Counts the number of Unlocked Nieghbourgs of a node for a certain playerData
private int numberNeighbours(IntegerCoordinates coor, PlayerData playerData) {
int number = 0; int number = 0;
int x = coor.getX(); for (IntegerCoordinates coordinates : getCheckCoordinates(coor)) {
int y = coor.getY();
List<IntegerCoordinates> 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) {
if (isNode(coordinates) && playerData.getNodeLevel(getNode(coordinates)) > 0) if (isNode(coordinates) && playerData.getNodeLevel(getNode(coordinates)) > 0)
number++; 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<SkillTreeNode> 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<IntegerCoordinates> 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;
}
} }

View File

@ -157,12 +157,9 @@ public abstract class SkillTree extends PostLoadObject implements RegisteredObje
try { try {
String string = config.getString("type"); String string = config.getString("type");
Validate.notNull(string, "You must precise a type for the skill tree."); 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!" + Validate.isTrue(string.equals("linked") || string.equals("custom"), "You must precise the type of the skill tree in the yml!" +
"\nAllowed values: 'automatic','linked','custom'"); "\nAllowed values: 'linked','custom'");
if (string.equals("automatic")) {
skillTree = new AutomaticSkillTree(config);
skillTree.postLoad();
}
if (string.equals("linked")) { if (string.equals("linked")) {
skillTree = new LinkedSkillTree(config); skillTree = new LinkedSkillTree(config);
skillTree.postLoad(); skillTree.postLoad();

View File

@ -12,25 +12,25 @@ items:
item: PLAYER_HEAD item: PLAYER_HEAD
name: "Up" name: "Up"
texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTk5YWFmMjQ1NmE2MTIyZGU4ZjZiNjI2ODNmMmJjMmVlZDlhYmI4MWZkNWJlYTFiNGMyM2E1ODE1NmI2NjkifX19 texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTk5YWFmMjQ1NmE2MTIyZGU4ZjZiNjI2ODNmMmJjMmVlZDlhYmI4MWZkNWJlYTFiNGMyM2E1ODE1NmI2NjkifX19
slots: [ 52 ] slots: [ 50 ]
down: down:
function: down function: down
item: PLAYER_HEAD item: PLAYER_HEAD
name: "Down" name: "Down"
texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzkxMmQ0NWIxYzc4Y2MyMjQ1MjcyM2VlNjZiYTJkMTU3NzdjYzI4ODU2OGQ2YzFiNjJhNTQ1YjI5YzcxODcifX19 texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzkxMmQ0NWIxYzc4Y2MyMjQ1MjcyM2VlNjZiYTJkMTU3NzdjYzI4ODU2OGQ2YzFiNjJhNTQ1YjI5YzcxODcifX19
slots: [ 51 ] slots: [ 49 ]
right: right:
function: right function: right
item: PLAYER_HEAD item: PLAYER_HEAD
name: "Right" name: "Right"
texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTNmYzUyMjY0ZDhhZDllNjU0ZjQxNWJlZjAxYTIzOTQ3ZWRiY2NjY2Y2NDkzNzMyODliZWE0ZDE0OTU0MWY3MCJ9fX0= texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTNmYzUyMjY0ZDhhZDllNjU0ZjQxNWJlZjAxYTIzOTQ3ZWRiY2NjY2Y2NDkzNzMyODliZWE0ZDE0OTU0MWY3MCJ9fX0=
slots: [ 50 ] slots: [ 51 ]
left: left:
function: left function: left
item: PLAYER_HEAD item: PLAYER_HEAD
name: "Left" name: "Left"
texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzNlOTE5MTlkYjBhY2VmZGMyNzJkNjdmZDg3YjRiZTg4ZGM0NGE5NTg5NTg4MjQ0NzRlMjFlMDZkNTNlNiJ9fX0= texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzNlOTE5MTlkYjBhY2VmZGMyNzJkNjdmZDg3YjRiZTg4ZGM0NGE5NTg5NTg4MjQ0NzRlMjFlMDZkNTNlNiJ9fX0=
slots: [ 49 ] slots: [ 48 ]
skill-tree: skill-tree:
name: '{skill-tree-node}' name: '{skill-tree-node}'
@ -49,14 +49,14 @@ items:
next-tree-list-page: next-tree-list-page:
function: 'next-tree-list-page' function: 'next-tree-list-page'
item: ARROW item: PLAYER_HEAD
name: "Next Page" texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTk5YWFmMjQ1NmE2MTIyZGU4ZjZiNjI2ODNmMmJjMmVlZDlhYmI4MWZkNWJlYTFiNGMyM2E1ODE1NmI2NjkifX19
slots: [ 36 ] slots: [ 36 ]
previous-tree-list-page: previous-tree-list-page:
function: 'previous-tree-list-page' function: 'previous-tree-list-page'
item: 'ARROW' item: PLAYER_HEAD
name: "Previous Page" texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzkxMmQ0NWIxYzc4Y2MyMjQ1MjcyM2VlNjZiYTJkMTU3NzdjYzI4ODU2OGQ2YzFiNjJhNTQ1YjI5YzcxODcifX19
slots: [ 0 ] slots: [ 0 ]
reallocation: reallocation:
@ -76,7 +76,7 @@ items:
skill-tree-node: skill-tree-node:
function: '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 #The lore that will be displayed after the lore of the node
lore: lore:
- '&7Current State: &6{current-state}' - '&7Current State: &6{current-state}'

View File

@ -186,3 +186,4 @@ 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.' 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.' 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.' 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.'