forked from Upstream/mmocore
Fixes points spent in skill tree not updating when unlocking a node.
This commit is contained in:
parent
62e1ace7b5
commit
cba1631d44
@ -45,6 +45,7 @@ import net.Indyuce.mmocore.skill.binding.BoundSkillInfo;
|
||||
import net.Indyuce.mmocore.skill.binding.SkillSlot;
|
||||
import net.Indyuce.mmocore.skill.cast.SkillCastingInstance;
|
||||
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
|
||||
import net.Indyuce.mmocore.skilltree.NodeIncrementResult;
|
||||
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
|
||||
import net.Indyuce.mmocore.skilltree.SkillTreeStatus;
|
||||
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
|
||||
@ -63,6 +64,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -107,17 +109,13 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
||||
private final Map<PlayerActivity, Long> lastActivity = new HashMap<>();
|
||||
private final CombatHandler combat = new CombatHandler(this);
|
||||
|
||||
/**
|
||||
* Cached for easier access. Amount of points spent in each skill tree.
|
||||
*/
|
||||
private final Map<SkillTree, Integer> pointSpent = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Cached for easier access. Current status of each skill tree node.
|
||||
*/
|
||||
private final Map<SkillTreeNode, SkillTreeStatus> nodeStates = new HashMap<>();
|
||||
private final Map<SkillTreeNode, Integer> nodeLevels = new HashMap<>();
|
||||
private final Map<String, Integer> skillTreePoints = new HashMap<>();
|
||||
private final Map<SkillTree, Integer> skillTreePointsSpent = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Saves the namespacedkeys of the items that have been unlocked in the form "namespace:key".
|
||||
@ -224,19 +222,24 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
||||
skillTree.setupNodeStates(this);
|
||||
}
|
||||
|
||||
public int getPointSpent(SkillTree skillTree) {
|
||||
return pointSpent.getOrDefault(skillTree, 0);
|
||||
public int getPointsSpent(@NotNull SkillTree skillTree) {
|
||||
return skillTreePointsSpent.getOrDefault(skillTree, 0);
|
||||
}
|
||||
|
||||
public void setSkillTreePoints(String treeId, int points) {
|
||||
@Deprecated
|
||||
public int getPointSpent(SkillTree skillTree) {
|
||||
return getPointsSpent(skillTree);
|
||||
}
|
||||
|
||||
public void setSkillTreePoints(@NotNull String treeId, int points) {
|
||||
skillTreePoints.put(treeId, points);
|
||||
}
|
||||
|
||||
public void giveSkillTreePoints(String id, int val) {
|
||||
skillTreePoints.put(id, skillTreePoints.getOrDefault(id, 0) + val);
|
||||
public void giveSkillTreePoints(@NotNull String id, int val) {
|
||||
skillTreePoints.merge(id, val, (points, ignored) -> points + val);
|
||||
}
|
||||
|
||||
public int countSkillTreePoints(SkillTree skillTree) {
|
||||
public int countSkillTreePoints(@NotNull SkillTree skillTree) {
|
||||
return nodeLevels.keySet().stream().filter(node -> node.getTree().equals(skillTree)).mapToInt(node -> nodeLevels.get(node) * node.getSkillTreePointsConsumed()).sum();
|
||||
}
|
||||
|
||||
@ -244,6 +247,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
||||
* Make a copy to make sure that the object
|
||||
* created is independent of the state of playerData.
|
||||
*/
|
||||
@NotNull
|
||||
public Map<String, Integer> mapSkillTreePoints() {
|
||||
return new HashMap(skillTreePoints);
|
||||
}
|
||||
@ -290,7 +294,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
||||
// Node levels, states and points spent
|
||||
nodeLevels.clear();
|
||||
nodeStates.clear();
|
||||
pointSpent.clear();
|
||||
skillTreePointsSpent.clear();
|
||||
|
||||
// Skill tree points
|
||||
skillTreePoints.clear();
|
||||
@ -299,11 +303,24 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
||||
tableItemClaims.keySet().removeIf(s -> s.startsWith(SkillTreeNode.KEY_PREFIX));
|
||||
}
|
||||
|
||||
public boolean canIncrementNodeLevel(@NotNull SkillTreeNode node) {
|
||||
SkillTreeStatus skillTreeStatus = nodeStates.get(node);
|
||||
//Check the State of the node
|
||||
if (skillTreeStatus != SkillTreeStatus.UNLOCKED && skillTreeStatus != SkillTreeStatus.UNLOCKABLE) return false;
|
||||
return node.hasPermissionRequirement(this) && getNodeLevel(node) < node.getMaxLevel() && (skillTreePoints.getOrDefault(node.getTree().getId(), 0) + skillTreePoints.getOrDefault("global", 0) >= node.getSkillTreePointsConsumed());
|
||||
@NotNull
|
||||
public NodeIncrementResult canIncrementNodeLevel(@NotNull SkillTreeNode node) {
|
||||
final SkillTreeStatus skillTreeStatus = nodeStates.get(node);
|
||||
|
||||
// Check node state
|
||||
if (skillTreeStatus != SkillTreeStatus.UNLOCKED && skillTreeStatus != SkillTreeStatus.UNLOCKABLE)
|
||||
return NodeIncrementResult.LOCKED_NODE;
|
||||
|
||||
// Check permission
|
||||
if (!node.hasPermissionRequirement(this)) return NodeIncrementResult.PERMISSION_DENIED;
|
||||
|
||||
// Max node level
|
||||
if (getNodeLevel(node) >= node.getMaxLevel()) return NodeIncrementResult.MAX_LEVEL_REACHED;
|
||||
|
||||
final int skillTreePoints = this.skillTreePoints.getOrDefault(node.getTree().getId(), 0) + this.skillTreePoints.getOrDefault("global", 0);
|
||||
if (skillTreePoints < node.getSkillTreePointsConsumed()) return NodeIncrementResult.NOT_ENOUGH_POINTS;
|
||||
|
||||
return NodeIncrementResult.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,19 +329,22 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
||||
* global skill-tree points ('all')
|
||||
*/
|
||||
public void incrementNodeLevel(@NotNull SkillTreeNode node) {
|
||||
final int newLevel = nodeLevels.merge(node, 1, (level, ignored) -> level + 1);
|
||||
final int newLevel = addNodeLevels(node, 1);
|
||||
node.updateAdvancement(this, newLevel); // Claim the node exp table
|
||||
|
||||
if (nodeStates.get(node) == SkillTreeStatus.UNLOCKABLE) setNodeState(node, SkillTreeStatus.UNLOCKED);
|
||||
int cost = node.getSkillTreePointsConsumed();
|
||||
final int skillTreeSpecificPoints = skillTreePoints.getOrDefault(node.getTree().getId(), 0);
|
||||
if (skillTreeSpecificPoints > 0) {
|
||||
int pointWithdrawn = Math.min(cost, skillTreeSpecificPoints);
|
||||
withdrawSkillTreePoints(node.getTree().getId(), pointWithdrawn);
|
||||
cost -= pointWithdrawn;
|
||||
}
|
||||
if (cost > 0) withdrawSkillTreePoints("global", cost);
|
||||
// Unload the nodeStates map (for the skill tree) and reload it completely
|
||||
// Update node state
|
||||
nodeStates.compute(node, (key, status) -> status == SkillTreeStatus.UNLOCKABLE ? SkillTreeStatus.UNLOCKED : status);
|
||||
|
||||
// Consume skill tree points
|
||||
final AtomicInteger cost = new AtomicInteger(node.getSkillTreePointsConsumed());
|
||||
skillTreePoints.computeIfPresent(node.getTree().getId(), (key, points) -> {
|
||||
final int withdrawn = Math.min(points, cost.get());
|
||||
cost.set(cost.get() - withdrawn);
|
||||
return points == withdrawn ? null : points - withdrawn;
|
||||
});
|
||||
if (cost.get() > 0) withdrawSkillTreePoints("global", cost.get());
|
||||
|
||||
// Reload node states from full skill tree
|
||||
for (SkillTreeNode node1 : node.getTree().getNodes()) nodeStates.remove(node1);
|
||||
node.getTree().setupNodeStates(this);
|
||||
}
|
||||
@ -359,10 +379,19 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
|
||||
return nodeLevels.getOrDefault(node, 0);
|
||||
}
|
||||
|
||||
public void setNodeLevel(SkillTreeNode node, int nodeLevel) {
|
||||
int delta = (nodeLevel - nodeLevels.getOrDefault(node, 0)) * node.getSkillTreePointsConsumed();
|
||||
pointSpent.put(node.getTree(), pointSpent.getOrDefault(node.getTree(), 0) + delta);
|
||||
nodeLevels.put(node, nodeLevel);
|
||||
public void setNodeLevel(@NotNull SkillTreeNode node, int nodeLevel) {
|
||||
nodeLevels.compute(node, (ignored, currentLevelInteger) -> {
|
||||
final int currentLevel = currentLevelInteger == null ? 0 : currentLevelInteger;
|
||||
final int delta = (nodeLevel - currentLevel) * node.getSkillTreePointsConsumed();
|
||||
skillTreePointsSpent.merge(node.getTree(), delta, (level, ignored2) -> level + delta);
|
||||
return nodeLevel;
|
||||
});
|
||||
}
|
||||
|
||||
public int addNodeLevels(@NotNull SkillTreeNode node, int increment) {
|
||||
final int delta = increment * node.getSkillTreePointsConsumed();
|
||||
skillTreePointsSpent.merge(node.getTree(), delta, (points, ignored) -> points + delta);
|
||||
return nodeLevels.merge(node, increment, (level, ignored) -> level + increment);
|
||||
}
|
||||
|
||||
public void resetSkillTree(SkillTree skillTree) {
|
||||
|
@ -108,7 +108,7 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
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()));
|
||||
holders.register("point-spent", inv.getPlayerData().getPointsSpent(inv.getSkillTree()));
|
||||
|
||||
return holders;
|
||||
}
|
||||
@ -184,7 +184,7 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
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()));
|
||||
holders.register("point-spent", inv.getPlayerData().getPointsSpent(inv.getSkillTree()));
|
||||
holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoints(inv.getSkillTree().getId()));
|
||||
holders.register("global-points", inv.getPlayerData().getSkillTreePoints("global"));
|
||||
return holders;
|
||||
@ -315,7 +315,7 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
}
|
||||
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("point-spent", inv.getPlayerData().getPointsSpent(inv.getSkillTree()));
|
||||
holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoints(inv.getSkillTree().getId()));
|
||||
holders.register("global-points", inv.getPlayerData().getSkillTreePoints("global"));
|
||||
|
||||
@ -466,7 +466,7 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
open();
|
||||
}
|
||||
if (item.getFunction().equals("reallocation")) {
|
||||
int spent = playerData.getPointSpent(skillTree);
|
||||
int spent = playerData.getPointsSpent(skillTree);
|
||||
if (spent < 1) {
|
||||
ConfigMessage.fromKey("no-skill-tree-points-spent").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
@ -478,7 +478,7 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
return;
|
||||
} else {
|
||||
int reallocated = playerData.getPointSpent(skillTree);
|
||||
int reallocated = playerData.getPointsSpent(skillTree);
|
||||
//We remove all the nodeStates progress
|
||||
playerData.giveSkillTreePoints(skillTree.getId(), reallocated);
|
||||
playerData.giveSkillTreeReallocationPoints(-1);
|
||||
@ -501,47 +501,55 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.getFunction().equals("skill-tree-node")) {
|
||||
if (event.getClickType() == ClickType.LEFT) {
|
||||
PersistentDataContainer container = event.getClickedItem().getItemMeta().getPersistentDataContainer();
|
||||
int x = container.get(new NamespacedKey(MMOCore.plugin, "coordinates.x"), PersistentDataType.INTEGER);
|
||||
int y = container.get(new NamespacedKey(MMOCore.plugin, "coordinates.y"), PersistentDataType.INTEGER);
|
||||
if (!skillTree.isNode(new IntegerCoordinates(x, y))) {
|
||||
return;
|
||||
}
|
||||
SkillTreeNode node = skillTree.getNode(new IntegerCoordinates(x, y));
|
||||
if (playerData.getPointSpent(skillTree) >= skillTree.getMaxPointSpent()) {
|
||||
ConfigMessage.fromKey("max-points-reached").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
return;
|
||||
}
|
||||
if (item.getFunction().equals("skill-tree-node") && event.getClickType() == ClickType.LEFT) {
|
||||
|
||||
if (playerData.canIncrementNodeLevel(node)) {
|
||||
final PersistentDataContainer container = event.getClickedItem().getItemMeta().getPersistentDataContainer();
|
||||
final int x = container.get(new NamespacedKey(MMOCore.plugin, "coordinates.x"), PersistentDataType.INTEGER);
|
||||
final int y = container.get(new NamespacedKey(MMOCore.plugin, "coordinates.y"), PersistentDataType.INTEGER);
|
||||
if (!skillTree.isNode(new IntegerCoordinates(x, y))) return;
|
||||
|
||||
// Maximum amount of skill points spent in node
|
||||
final SkillTreeNode node = skillTree.getNode(new IntegerCoordinates(x, y));
|
||||
if (playerData.getPointsSpent(skillTree) >= skillTree.getMaxPointSpent()) {
|
||||
ConfigMessage.fromKey("max-points-reached").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (playerData.canIncrementNodeLevel(node)) {
|
||||
case SUCCESS: {
|
||||
playerData.incrementNodeLevel(node);
|
||||
ConfigMessage.fromKey("upgrade-skill-node", "skill-node", node.getName(), "level", "" + playerData.getNodeLevel(node)).send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_SKILL_TREE_NODE).playTo(getPlayer());
|
||||
open();
|
||||
} else if (playerData.getNodeStatus(node) == SkillTreeStatus.LOCKED || playerData.getNodeStatus(node) == SkillTreeStatus.FULLY_LOCKED) {
|
||||
ConfigMessage.fromKey("locked-node").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (playerData.getNodeLevel(node) >= node.getMaxLevel()) {
|
||||
ConfigMessage.fromKey("skill-node-max-level-hit").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
} else if (!node.hasPermissionRequirement(playerData)) {
|
||||
case PERMISSION_DENIED: {
|
||||
ConfigMessage.fromKey("missing-skill-node-permission").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
break;
|
||||
}
|
||||
|
||||
//Else the player doesn't doesn't have the skill tree points
|
||||
else {
|
||||
case LOCKED_NODE: {
|
||||
ConfigMessage.fromKey("locked-node").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
break;
|
||||
}
|
||||
|
||||
case MAX_LEVEL_REACHED: {
|
||||
ConfigMessage.fromKey("skill-node-max-level-hit").send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
break;
|
||||
}
|
||||
|
||||
case NOT_ENOUGH_POINTS: {
|
||||
ConfigMessage.fromKey("not-enough-skill-tree-points", "point", "" + node.getSkillTreePointsConsumed()).send(player);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package net.Indyuce.mmocore.skilltree;
|
||||
|
||||
public enum NodeIncrementResult {
|
||||
|
||||
SUCCESS,
|
||||
|
||||
/**
|
||||
* Node is still locked/not unlockable
|
||||
*/
|
||||
LOCKED_NODE,
|
||||
|
||||
/**
|
||||
* Player does not have required permission
|
||||
*/
|
||||
PERMISSION_DENIED,
|
||||
|
||||
/**
|
||||
* Maximum level of node is reached
|
||||
*/
|
||||
MAX_LEVEL_REACHED,
|
||||
|
||||
/**
|
||||
* Player does not have enough skill tree points
|
||||
*/
|
||||
NOT_ENOUGH_POINTS,
|
||||
}
|
Loading…
Reference in New Issue
Block a user