Heavy debugging and refactor for skill trees.

This commit is contained in:
Ka0rX 2023-05-07 18:12:37 +01:00
parent a64faa02fd
commit a18a42ea2f
5 changed files with 18 additions and 150 deletions

View File

@ -14,6 +14,8 @@ import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem;
import net.Indyuce.mmocore.gui.skilltree.display.*;
import net.Indyuce.mmocore.skilltree.*;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@ -336,6 +338,7 @@ public class SkillTreeViewer extends EditableInventory {
return maxTreeListPage;
}
public Icon getIcon(IntegerCoordinates coordinates) {
boolean hasUpPath = skillTree.isPath(new IntegerCoordinates(coordinates.getX(), coordinates.getY() - 1));
boolean hasDownPath = skillTree.isPath(new IntegerCoordinates(coordinates.getX(), coordinates.getY() + 1));
@ -350,11 +353,15 @@ public class SkillTreeViewer extends EditableInventory {
return node.getIcon(nodeStatus);
NodeType nodeType = NodeType.getNodeType(hasUpPath, hasRightPath, hasDownPath, hasLeftPath);
return icons.get(new NodeDisplayInfo(nodeType, nodeStatus));
Icon icon = icons.get(new NodeDisplayInfo(nodeType, nodeStatus));
Validate.notNull(icon, "The node " + node.getFullId() + " has no icon for the type " + nodeType + " and the status " + nodeStatus);
return icon;
} else {
PathType pathType = PathType.getPathType(hasUpPath, hasRightPath, hasDownPath, hasLeftPath);
SkillTreePath path = skillTree.getPath(coordinates);
return icons.get(new PathDisplayInfo(pathType, path.getStatus(playerData)));
Icon icon = icons.get(new PathDisplayInfo(pathType, path.getStatus(playerData)));
Validate.notNull(icon, "There is no icon for the path type " + pathType + " and the status " + path.getStatus(playerData));
return icon;
}
}

View File

@ -14,6 +14,7 @@ import net.Indyuce.mmocore.gui.skilltree.display.Icon;
import net.Indyuce.mmocore.skilltree.tree.ParentInformation;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
@ -176,7 +177,6 @@ public class SkillTreeNode implements ExperienceObject {
return parents.entrySet().stream().filter(entry -> entry.getKey().type() == parentType).map((entry) -> entry.getKey().node()).collect(Collectors.toSet());
}
public List<SkillTreeNode> getChildren() {
return children;
}

View File

@ -19,8 +19,8 @@ public class CustomSkillTree extends SkillTree {
// Setup the children and parents for each node.
for (SkillTreeNode node : nodes.values()) {
if (config.isConfigurationSection("nodes." + node.getId() + ".children"))
for (String key : config.getConfigurationSection("nodes." + node.getId() + "parents").getKeys(false)) {
if (config.isConfigurationSection("nodes." + node.getId() + ".parents"))
for (String key : config.getConfigurationSection("nodes." + node.getId() + ".parents").getKeys(false)) {
ConfigurationSection section = config.getConfigurationSection("nodes." + node.getId() + ".parents." + key);
if (section != null) {
for (String parent : section.getKeys(false)) {

View File

@ -1,129 +0,0 @@
package net.Indyuce.mmocore.skilltree.tree;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skilltree.IntegerCoordinates;
import net.Indyuce.mmocore.skilltree.NodeStatus;
import net.Indyuce.mmocore.skilltree.ParentType;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
/**
* For linked skillTrees there is no notion of children and
* parents you must have some neighbours unlocked in order to
* be unlockable. All the relationships in the tree are
* defined by the coordinates you nodes have.
*/
public class LinkedSkillTree extends SkillTree {
public LinkedSkillTree(ConfigurationSection config) {
super(config);
// Setup the coordinate map because coordinates are given in the yml for linked skill tree
coordinatesSetup();
}
@Override
protected void whenPostLoaded(@NotNull ConfigurationSection config) {
// Setup the children and parents if a node precise a required level for upgrade.
// If it is not filled the algorithm will put the required level to 1
for (SkillTreeNode node : nodes.values()) {
if (config.contains(node.getId() + ".children")) {
ConfigurationSection section = config.getConfigurationSection(node.getId() + ".children.soft");
if (section != null) {
for (String child : section.getKeys(false)) {
node.addChild(getNode(child));
getNode(child).addParent(node, section.getInt(child), ParentType.SOFT);
}
}
section = config.getConfigurationSection(node.getId() + ".children.strong");
if (section != null) {
for (String child : section.getKeys(false)) {
node.addChild(getNode(child));
getNode(child).addParent(node, section.getInt(child), ParentType.STRONG);
}
}
}
}
SkillTreeNode root = getNode(new IntegerCoordinates(0, 0));
Validate.notNull(root, "Their must be a node(the root of the tree) at the coordinates (0,0) ");
}
@Override
public void setupNodeStates(PlayerData playerData) {
// Values are labelled as unlockable
for (SkillTreeNode root : roots)
playerData.setNodeState(root, NodeStatus.UNLOCKABLE);
// All the nodes with level >0 are unlocked
for (SkillTreeNode node : nodes.values()) {
if (playerData.getNodeLevel(node) > 0)
playerData.setNodeState(node, NodeStatus.UNLOCKED);
}
// Setup unlockable nodes
for (SkillTreeNode node : nodes.values()) {
if (isUnlockable(node, playerData) && !playerData.hasNodeState(node))
playerData.setNodeState(node, NodeStatus.UNLOCKABLE);
}
labelLockedNodes(playerData);
// Label all the remaining nodes to FULLY LOCKED
for (SkillTreeNode node : nodes.values())
if (!playerData.hasNodeState(node))
playerData.setNodeState(node, NodeStatus.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.getNodeStatus(node) == NodeStatus.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), NodeStatus.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;
for (IntegerCoordinates coordinates : getCheckCoordinates(node.getCoordinates())) {
if (isNode(coordinates))
if (isNode(coordinates) && playerData.getNodeStatus(getNode(coordinates)) == NodeStatus.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;
for (IntegerCoordinates coordinates : getCheckCoordinates(coor)) {
if (isNode(coordinates) && playerData.getNodeLevel(getNode(coordinates)) > 0)
number++;
}
return number;
}
}

View File

@ -121,19 +121,8 @@ public abstract class SkillTree extends PostLoadObject implements RegisteredObje
SkillTree skillTree = null;
try {
String string = config.getString("type");
Validate.notNull(string, "You must precise a type for the skill tree.");
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();
}
if (string.equals("custom")) {
skillTree = new CustomSkillTree(config);
skillTree.postLoad();
}
skillTree = new CustomSkillTree(config);
skillTree.postLoad();
} catch (Exception e) {
MMOCore.log("Couldn't load skill tree " + config.getString("id") + ": " + e.getMessage());
}
@ -170,6 +159,7 @@ public abstract class SkillTree extends PostLoadObject implements RegisteredObje
Set<SkillTreeNode> softParents = node.getParents(ParentType.SOFT);
Set<SkillTreeNode> incompatibleParents = node.getParents(ParentType.INCOMPATIBLE);
boolean isUnlockableFromStrongParent = true;
boolean isUnlockableFromSoftParent = softParents.size() == 0;
boolean isFullyLockedFromStrongParent = false;
@ -192,7 +182,7 @@ public abstract class SkillTree extends PostLoadObject implements RegisteredObje
}
for (SkillTreeNode softParent : node.getParents(ParentType.SOFT)) {
for (SkillTreeNode softParent : softParents) {
if (playerData.getNodeLevel(softParent) >= node.getParentNeededLevel(softParent, ParentType.SOFT)) {
isUnlockableFromSoftParent = true;
}
@ -204,8 +194,8 @@ public abstract class SkillTree extends PostLoadObject implements RegisteredObje
if (numberChildren < softParent.getMaxChildren() && playerData.getNodeStatus(softParent) != NodeStatus.FULLY_LOCKED)
isFullyLockedFromSoftParent = false;
}
for (SkillTreeNode incompatibleParent : node.getParents(ParentType.INCOMPATIBLE)) {
if (playerData.getNodeLevel(incompatibleParent) > 0) {
for (SkillTreeNode incompatibleParent : incompatibleParents) {
if (playerData.getNodeLevel(incompatibleParent) >= node.getParentNeededLevel(incompatibleParent, ParentType.INCOMPATIBLE)) {
isFullyLockedFromIncompatibleParent = true;
break;
}