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);
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);

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.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<UUID> friends = new ArrayList<>();
@ -209,6 +210,10 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return nodeLevelsString.entrySet();
}
public Map<SkillTreeNode, Integer> 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<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) {
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<SkillTree> 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);
}

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.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<SkillTree> skillTrees = new ArrayList<>();
private final List<PassiveSkill> classScripts = new LinkedList();
private final Map<String, LinearValue> stats = new HashMap<>();
private final Map<String, ClassSkill> 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<SkillTree> getSkillTrees() {
return skillTrees;
}
public ClassSkill getSkill(RegisteredSkill skill) {
return getSkill(skill.getHandler().getId());
}

View File

@ -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<String, Integer> attributes;
private final Map<String, Integer> skills;
private final int level, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints;
private final double experience;
private final Map<String, Integer> attributes;
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) {
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<String, JsonElement> entry : json.getAsJsonObject("attribute").entrySet())
attributes.put(entry.getKey(), entry.getValue().getAsInt());
skills = new HashMap<>();
if (json.has("skill"))
for (Entry<String, JsonElement> entry : json.getAsJsonObject("skill").entrySet())
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());
attributes = new HashMap<>();
if (json.has("attribute"))
for (Entry<String, JsonElement> entry : json.getAsJsonObject("attribute").entrySet())
attributes.put(entry.getKey(), entry.getValue().getAsInt());
skills = new HashMap<>();
if (json.has("skill"))
for (Entry<String, JsonElement> 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<String, Integer> attributes, Map<String, Integer> 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<String, Integer> attributes, Map<String, Integer> skills, Map<String, Integer> skillTreePoints, Map<SkillTreeNode, Integer> nodeLevels,Map<String, Integer> 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<String> getSkillKeys() {
return skills.keySet();
}
public Set<String> 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<String> 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<SkillTreeNode> 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<String> 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<String> 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();
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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<SkillTree> skillTrees;
private SkillTree skillTree;
private final List<Integer> 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);

View File

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

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 + ".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();
}

View File

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

View File

@ -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<Integer,List<String>> lores = new HashMap<>();
private final Map<Integer, List<String>> 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<String> getLore(PlayerData playerData) {
Placeholders holders = getPlaceholders(playerData);
List<String> parsedLore = new ArrayList<>();
if(!lores.containsKey(playerData.getNodeLevel(this)))
if (!lores.containsKey(playerData.getNodeLevel(this)))
return parsedLore;
List<String> lore= lores.get(playerData.getNodeLevel(this));
List<String> lore = lores.get(playerData.getNodeLevel(this));
lore.forEach(string -> parsedLore.add(
MythicLib.plugin.parseColors(holders.apply(playerData.getPlayer(), string))));
return parsedLore;

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;
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<IntegerCoordinates> 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<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);
}
}
//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<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));
}
}
}
//Counts the number of Unlocked Nieghbourgs of a node for a certain playerData
private int numberNeighbours(IntegerCoordinates coor, PlayerData playerData) {
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;
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<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) {
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<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 {
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();

View File

@ -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}'

View File

@ -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.'
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.'