Total refactor of the linked skill trees implementation.

This commit is contained in:
Ka0rX 2022-10-16 20:40:40 +02:00
parent 5f20681a51
commit 110dad2f5e

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)); playerData.setNodeState(node, NodeState.UNLOCKED);
if (playerData.getNodeLevel(node) > 0) { }
playerData.setNodeState(node, NodeState.UNLOCKED); //Setup unlockable nodes
} else if (playerData.getNodeLevel(node) == 0 && node.isRoot()) { for (SkillTreeNode node : nodes.values()) {
playerData.setNodeState(node, NodeState.UNLOCKABLE); if (isUnlockable(node, playerData)&&!playerData.hasNodeState(node))
} 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)
playerData.setNodeState(node, NodeState.UNLOCKABLE); 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. labelLockedNodes(playerData);
for (IntegerCoordinates coordinates : checkCoordinates) {
if (isNode(coordinates) && !playerData.hasNodeState(getNode(coordinates))) //We label all the remaining nodes to FULLY LOCKED
setupNodeStateFrom(getNode(coordinates), playerData); for (SkillTreeNode node : nodes.values()) {
if (!playerData.hasNodeState(node))
playerData.setNodeState(node, NodeState.FULLY_LOCKED);
}
}
/**
* We recursively label all the locked node 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 List<IntegerCoordinates> getCheckCoordinates(IntegerCoordinates coor) {
private int numberNeighbours(IntegerCoordinates coor, PlayerData playerData) { 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 number = 0;
int x = coor.getX(); int x = coor.getX();
int y = coor.getY(); int y = coor.getY();
List<IntegerCoordinates> checkCoordinates = Arrays.asList(new IntegerCoordinates(x + 1, y), for (IntegerCoordinates coordinates : getCheckCoordinates(coor)) {
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;
}
} }