Fixed NPE when clicking certain skill tree nodes

This commit is contained in:
Jules 2024-06-03 22:48:11 -07:00
parent 5c2bd9b637
commit fb84e2f96e
4 changed files with 40 additions and 28 deletions

View File

@ -2,8 +2,6 @@ package net.Indyuce.mmocore.api.player;
import io.lumine.mythic.lib.MythicLib; 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.api.stat.StatInstance;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.data.SynchronizedDataHolder; import io.lumine.mythic.lib.data.SynchronizedDataHolder;
import io.lumine.mythic.lib.player.cooldown.CooldownMap; import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import io.lumine.mythic.lib.util.Closeable; import io.lumine.mythic.lib.util.Closeable;
@ -22,7 +20,6 @@ import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.social.FriendRequest; import net.Indyuce.mmocore.api.player.social.FriendRequest;
import net.Indyuce.mmocore.api.player.stats.PlayerStats; import net.Indyuce.mmocore.api.player.stats.PlayerStats;
import net.Indyuce.mmocore.api.quest.PlayerQuests; import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.api.quest.trigger.StatTrigger;
import net.Indyuce.mmocore.api.quest.trigger.Trigger; import net.Indyuce.mmocore.api.quest.trigger.Trigger;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable; import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
@ -90,7 +87,11 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
private final List<UUID> friends = new ArrayList<>(); private final List<UUID> friends = new ArrayList<>();
/** /**
* @deprecated Use {@link #hasUnlocked(Unlockable)} instead * TODO Use {@link #hasUnlocked(Unlockable)} instead
* <p>
* Merge waypoints with unlocked items, and create a method
* plugin-scope to check if some item is class-specific and
* should be reset when switching class
*/ */
@Deprecated @Deprecated
private final Set<String> waypoints = new HashSet<>(); private final Set<String> waypoints = new HashSet<>();
@ -281,11 +282,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
skillTreePoints.clear(); skillTreePoints.clear();
// Clear node claim count // Clear node claim count
final Iterator<String> ite = tableItemClaims.keySet().iterator(); tableItemClaims.keySet().removeIf(s -> s.startsWith(SkillTreeNode.KEY_PREFIX));
while (ite.hasNext()) if (ite.next().startsWith(SkillTreeNode.KEY_PREFIX)) ite.remove();
} }
public boolean canIncrementNodeLevel(SkillTreeNode node) { public boolean canIncrementNodeLevel(@NotNull SkillTreeNode node) {
SkillTreeStatus skillTreeStatus = nodeStates.get(node); SkillTreeStatus skillTreeStatus = nodeStates.get(node);
//Check the State of the node //Check the State of the node
if (skillTreeStatus != SkillTreeStatus.UNLOCKED && skillTreeStatus != SkillTreeStatus.UNLOCKABLE) return false; if (skillTreeStatus != SkillTreeStatus.UNLOCKED && skillTreeStatus != SkillTreeStatus.UNLOCKABLE) return false;
@ -297,32 +297,37 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* Consumes skill tree points from the tree first and then consumes the * Consumes skill tree points from the tree first and then consumes the
* global skill-tree points ('all') * global skill-tree points ('all')
*/ */
public void incrementNodeLevel(SkillTreeNode node) { public void incrementNodeLevel(@NotNull SkillTreeNode node) {
setNodeLevel(node, getNodeLevel(node) + 1); nodeLevels.merge(node, 1, (level, ignored) -> level + 1);
// Claims the nodes experience table. // Claims the nodes experience table.
node.getExperienceTable().claim(this, getNodeLevel(node), node); node.getExperienceTable().claim(this, getNodeLevel(node), node);
if (nodeStates.get(node) == SkillTreeStatus.UNLOCKABLE) setNodeState(node, SkillTreeStatus.UNLOCKED); if (nodeStates.get(node) == SkillTreeStatus.UNLOCKABLE) setNodeState(node, SkillTreeStatus.UNLOCKED);
int pointToWithdraw = node.getSkillTreePointsConsumed(); int cost = node.getSkillTreePointsConsumed();
if (skillTreePoints.get(node.getTree().getId()) > 0) { final int skillTreeSpecificPoints = skillTreePoints.getOrDefault(node.getTree().getId(), 0);
int pointWithdrawn = Math.min(pointToWithdraw, skillTreePoints.get(node.getTree().getId())); if (skillTreeSpecificPoints > 0) {
int pointWithdrawn = Math.min(cost, skillTreeSpecificPoints);
withdrawSkillTreePoints(node.getTree().getId(), pointWithdrawn); withdrawSkillTreePoints(node.getTree().getId(), pointWithdrawn);
pointToWithdraw -= pointWithdrawn; cost -= pointWithdrawn;
} }
if (pointToWithdraw > 0) withdrawSkillTreePoints("global", pointToWithdraw); if (cost > 0) withdrawSkillTreePoints("global", cost);
// We unload the nodeStates map (for the skill tree) and reload it completely // Unload the nodeStates map (for the skill tree) and reload it completely
for (SkillTreeNode node1 : node.getTree().getNodes()) for (SkillTreeNode node1 : node.getTree().getNodes()) nodeStates.remove(node1);
nodeStates.remove(node1);
node.getTree().setupNodeStates(this); node.getTree().setupNodeStates(this);
} }
@Deprecated
public int getSkillTreePoint(String treeId) { public int getSkillTreePoint(String treeId) {
return getSkillTreePoints(treeId);
}
public int getSkillTreePoints(@NotNull String treeId) {
return skillTreePoints.getOrDefault(treeId, 0); return skillTreePoints.getOrDefault(treeId, 0);
} }
public void withdrawSkillTreePoints(String treeId, int withdraw) { public void withdrawSkillTreePoints(@NotNull String treeId, int withdrawn) {
skillTreePoints.put(treeId, skillTreePoints.get(treeId) - withdraw); final int cost = Math.max(0, withdrawn);
skillTreePoints.computeIfPresent(treeId, (ignored, points) -> cost >= points ? null : points - cost);
} }
public void setNodeState(SkillTreeNode node, SkillTreeStatus skillTreeStatus) { public void setNodeState(SkillTreeNode node, SkillTreeStatus skillTreeStatus) {

View File

@ -29,7 +29,7 @@ public class AdminCommandTreeNode extends CommandTreeNode {
addChild(new PointsCommandTreeNode("attr-realloc", this, PlayerData::setAttributeReallocationPoints, PlayerData::giveAttributeReallocationPoints, PlayerData::getAttributeReallocationPoints)); addChild(new PointsCommandTreeNode("attr-realloc", this, PlayerData::setAttributeReallocationPoints, PlayerData::giveAttributeReallocationPoints, PlayerData::getAttributeReallocationPoints));
addChild(new PointsCommandTreeNode("skill-realloc", this, PlayerData::setSkillReallocationPoints, PlayerData::giveSkillReallocationPoints, PlayerData::getSkillReallocationPoints)); addChild(new PointsCommandTreeNode("skill-realloc", this, PlayerData::setSkillReallocationPoints, PlayerData::giveSkillReallocationPoints, PlayerData::getSkillReallocationPoints));
addChild(new PointsCommandTreeNode("skill-tree-realloc", this, PlayerData::setSkillTreeReallocationPoints, PlayerData::giveSkillTreeReallocationPoints, PlayerData::getSkillTreeReallocationPoints)); addChild(new PointsCommandTreeNode("skill-tree-realloc", this, PlayerData::setSkillTreeReallocationPoints, PlayerData::giveSkillTreeReallocationPoints, PlayerData::getSkillTreeReallocationPoints));
addChild(new SkillTreePointsCommandTreeNode(this, (playerData, integer, s) -> playerData.setSkillTreePoints(s, integer), (playerData, integer, s) -> playerData.giveSkillTreePoints(s, integer), ((playerData, s) -> playerData.getSkillTreePoint(s)))); addChild(new SkillTreePointsCommandTreeNode(this, (playerData, integer, s) -> playerData.setSkillTreePoints(s, integer), (playerData, integer, s) -> playerData.giveSkillTreePoints(s, integer), PlayerData::getSkillTreePoints));
for (PlayerResource res : PlayerResource.values()) for (PlayerResource res : PlayerResource.values())
addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res)); addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res));
} }

View File

@ -103,8 +103,8 @@ public class SkillTreeViewer extends EditableInventory {
@Override @Override
public Placeholders getPlaceholders(SkillTreeInventory inv, int n) { public Placeholders getPlaceholders(SkillTreeInventory inv, int n) {
Placeholders holders = new Placeholders(); Placeholders holders = new Placeholders();
holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoint(inv.getSkillTree().getId())); holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoints(inv.getSkillTree().getId()));
holders.register("global-points", inv.getPlayerData().getSkillTreePoint("global")); holders.register("global-points", inv.getPlayerData().getSkillTreePoints("global"));
holders.register("realloc-points", inv.getPlayerData().getSkillTreeReallocationPoints()); holders.register("realloc-points", inv.getPlayerData().getSkillTreeReallocationPoints());
int maxPointSpent = inv.getSkillTree().getMaxPointSpent(); int maxPointSpent = inv.getSkillTree().getMaxPointSpent();
holders.register("max-point-spent", maxPointSpent == Integer.MAX_VALUE ? "" : maxPointSpent); holders.register("max-point-spent", maxPointSpent == Integer.MAX_VALUE ? "" : maxPointSpent);
@ -185,8 +185,8 @@ public class SkillTreeViewer extends EditableInventory {
int maxPointSpent = inv.getSkillTree().getMaxPointSpent(); int maxPointSpent = inv.getSkillTree().getMaxPointSpent();
holders.register("max-point-spent", maxPointSpent == Integer.MAX_VALUE ? "" : maxPointSpent); 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().getPointSpent(inv.getSkillTree()));
holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoint(inv.getSkillTree().getId())); holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoints(inv.getSkillTree().getId()));
holders.register("global-points", inv.getPlayerData().getSkillTreePoint("global")); holders.register("global-points", inv.getPlayerData().getSkillTreePoints("global"));
return holders; return holders;
} }
} }
@ -316,8 +316,8 @@ public class SkillTreeViewer extends EditableInventory {
int maxPointSpent = inv.getSkillTree().getMaxPointSpent(); int maxPointSpent = inv.getSkillTree().getMaxPointSpent();
holders.register("max-point-spent", maxPointSpent == Integer.MAX_VALUE ? "" : maxPointSpent); 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().getPointSpent(inv.getSkillTree()));
holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoint(inv.getSkillTree().getId())); holders.register("skill-tree-points", inv.getPlayerData().getSkillTreePoints(inv.getSkillTree().getId()));
holders.register("global-points", inv.getPlayerData().getSkillTreePoint("global")); holders.register("global-points", inv.getPlayerData().getSkillTreePoints("global"));
return holders; return holders;
} }
@ -484,7 +484,7 @@ public class SkillTreeViewer extends EditableInventory {
playerData.giveSkillTreeReallocationPoints(-1); playerData.giveSkillTreeReallocationPoints(-1);
playerData.resetSkillTree(skillTree); playerData.resetSkillTree(skillTree);
skillTree.setupNodeStates(playerData); skillTree.setupNodeStates(playerData);
ConfigMessage.fromKey("reallocated-points", "points", "" + playerData.getSkillTreePoint(skillTree.getId()), "skill-tree", skillTree.getName()).send(player); ConfigMessage.fromKey("reallocated-points", "points", "" + playerData.getSkillTreePoints(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);
open(); open();
return; return;

View File

@ -94,6 +94,13 @@ public class ExperienceManager implements MMOCoreManager {
return expTables.values(); return expTables.values();
} }
// TODO when required, define class-specific unlockable items.
// TODO - Skill, skill slots are class-specific
// TODO - Waypoints are not
public boolean isClassSpecific(@NotNull String namespacedKey) {
return true;
}
@Override @Override
public void initialize(boolean clearBefore) { public void initialize(boolean clearBefore) {
if (clearBefore) { if (clearBefore) {