Fixed /rpg reload increasing player skill levels when using skill trees

This commit is contained in:
Jules 2024-04-06 23:15:33 -07:00
parent 3231a69bf3
commit d4bea3dba7
11 changed files with 67 additions and 64 deletions

View File

@ -24,6 +24,7 @@ import net.Indyuce.mmocore.api.player.stats.PlayerStats;
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.api.Removable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.experience.*;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
@ -173,7 +174,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
if (!nodeLevels.containsKey(node)) nodeLevels.put(node, 0);
setupSkillTree();
updateTemporaryTriggers();
applyTemporaryTriggers();
getStats().updateStats();
}
@ -184,7 +185,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Override
public void markAsSynchronized() {
setupSkillTree();
updateTemporaryTriggers();
applyTemporaryTriggers();
getStats().updateStats(true);
/*
@ -203,25 +204,19 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Deprecated
public void setupRemovableTrigger() {
updateTemporaryTriggers();
applyTemporaryTriggers();
}
/**
* Some triggers are marked with the Removable interface as
* they are non-permanent triggers and they need to be updated
* everytime their MMOPlayerData gets flushed from ML cache.
* Some triggers are marked with the {@link Removable} interface as
* they are non-permanent triggers, and they need to be re-applied
* everytime their MMOPlayerData gets flushed from the MythicLib cache
* (everytime the player logs out).
* <p>
* This method should go through ALL {@link ExperienceTable}
* that the player has spent points into and register all
* non-permanent triggers.
* <p>
* For ease of implementation, these non-permanent triggers are
* refreshed everytime the player joins the server ie on every
* player data fetch.
*
* @see {@link net.Indyuce.mmocore.api.quest.trigger.api.Removable}
* This method goes through all the player's experience tables that
* they have spent points into and register all their non-permanent triggers.
*/
public void updateTemporaryTriggers() {
public void applyTemporaryTriggers() {
// Remove all stats and buffs associated to triggers
getMMOPlayerData().getStatMap().getInstances().forEach(statInstance -> statInstance.removeIf(Trigger.STAT_MODIFIER_KEY::equals));
@ -229,17 +224,17 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
// Experience tables from main class
if (getProfess().hasExperienceTable())
getProfess().getExperienceTable().claimRemovableTrigger(this, getProfess());
getProfess().getExperienceTable().applyTemporaryTriggers(this, getProfess());
// Experience tables from professions
for (Profession profession : MMOCore.plugin.professionManager.getAll())
if (profession.hasExperienceTable())
profession.getExperienceTable().claimRemovableTrigger(this, profession);
profession.getExperienceTable().applyTemporaryTriggers(this, profession);
// Experience tables from skill tree nodes
for (SkillTree skillTree : MMOCore.plugin.skillTreeManager.getAll())
for (SkillTreeNode node : skillTree.getNodes())
node.getExperienceTable().claimRemovableTrigger(this, node);
node.getExperienceTable().applyTemporaryTriggers(this, node);
}
public void setupSkillTree() {
@ -383,7 +378,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
public void resetSkillTree(SkillTree skillTree) {
for (SkillTreeNode node : skillTree.getNodes()) {
node.getExperienceTable().reset(this, node);
node.getExperienceTable().unclaim(this, node, true);
setNodeLevel(node, 0);
nodeStates.remove(node);
}
@ -1216,7 +1211,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
// Clear bound skills
boundSkills.forEach((slot, info) -> info.close());
boundSkills.clear();
updateTemporaryTriggers();
applyTemporaryTriggers();
// Update stats
if (isOnline()) getStats().updateStats();

View File

@ -297,9 +297,9 @@ public class SavedClassInformation implements ClassDataContainer {
// Remove perm stats for nodes and class
for (SkillTree skillTree : player.getProfess().getSkillTrees())
for (SkillTreeNode node : skillTree.getNodes())
node.getExperienceTable().removePermStats(player, node);
node.getExperienceTable().unclaim(player, node, false);
if (player.getProfess().hasExperienceTable())
player.getProfess().getExperienceTable().removePermStats(player, player.getProfess());
player.getProfess().getExperienceTable().unclaim(player, player.getProfess(), false);
/*
* Resets information which much be reset after everything is saved.
@ -356,7 +356,7 @@ public class SavedClassInformation implements ClassDataContainer {
player.setMana(mana);
player.setStellium(stellium);
player.setStamina(stamina);
player.updateTemporaryTriggers();
player.applyTemporaryTriggers();
player.getStats().updateStats();
}
}

View File

@ -8,12 +8,13 @@ import io.lumine.mythic.lib.skill.handler.SkillHandler;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.quest.trigger.api.Temporary;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import java.util.ArrayList;
import java.util.List;
public class SkillModifierTrigger extends Trigger implements Removable {
public class SkillModifierTrigger extends Trigger implements Removable, Temporary {
private final SkillModifier mod;
private final double amount;

View File

@ -5,9 +5,10 @@ import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.quest.trigger.api.Temporary;
import org.apache.commons.lang.Validate;
public class StatTrigger extends Trigger implements Removable {
public class StatTrigger extends Trigger implements Removable, Temporary {
private final StatModifier modifier;
private final String stat;
private final double amount;

View File

@ -2,8 +2,12 @@ package net.Indyuce.mmocore.api.quest.trigger.api;
import net.Indyuce.mmocore.api.player.PlayerData;
// TODO rename to non-permanent
// TODO merge with MythicLib
/**
* Cancelable triggers cause problems when letting the player reset
* their advancement on things they can spend points in/level up.
* If you give access to some resource to the player via a trigger,
* you must take it away when resetting their progression.
*/
public interface Removable {
public void remove(PlayerData playerData);
}

View File

@ -0,0 +1,12 @@
package net.Indyuce.mmocore.api.quest.trigger.api;
/**
* Non-permanent triggers are triggers which are not saved
* by the player and taken off when the player logs off,
* for instance temporary player modifiers. They need to
* be re-applied everytime the player logs back.
*
* @author jules
*/
public interface Temporary {
}

View File

@ -250,7 +250,7 @@ public class ResetCommandTreeNode extends CommandTreeNode {
for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
data.getCollectionSkills().setExperience(profession, 0);
data.getCollectionSkills().setLevel(profession, 0);
profession.getExperienceTable().reset(data, profession);
profession.getExperienceTable().unclaim(data, profession, true);
}
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,

View File

@ -68,7 +68,6 @@ public class SkillCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
int amount;
try {
amount = Integer.parseInt(args[5]);

View File

@ -3,9 +3,9 @@ package net.Indyuce.mmocore.experience.droptable;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.StatTrigger;
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.Temporary;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -132,12 +132,11 @@ public class ExperienceItem {
}
/**
* Used when a player connects back to give back all the stats that he should have.
*
* @param playerData
* Used when a player logs back, in order to apply again
* all the temporary triggers.
*/
public void applyRemovableTrigger(PlayerData playerData) {
public void applyTemporaryTriggers(PlayerData playerData) {
for (Trigger trigger : triggers)
if (trigger instanceof Removable) trigger.apply(playerData);
if (trigger instanceof Temporary) trigger.apply(playerData);
}
}

View File

@ -55,42 +55,30 @@ public class ExperienceTable {
}
/**
* Called when a player changes its class.
* Removes the perm stat but keeps the item claims in memory.
* Called for example when a player changes its class. This takes
* off triggers which can be canceled.
*/
public void removePermStats(PlayerData playerData, ExperienceObject object) {
public void unclaim(PlayerData playerData, ExperienceObject object, boolean reset) {
for (ExperienceItem item : items) {
int timesClaimed = playerData.getClaims(object, this, item);
final int timesClaimed = playerData.getClaims(object, this, item);
if (reset) playerData.setClaims(object, this, item, 0);
for (int i = 0; i < timesClaimed; i++)
item.removeTriggers(playerData);
}
}
/**
* Called when the progression is reset(e.g skill tree reallocation)
*/
public void reset(PlayerData playerData, ExperienceObject object) {
for (ExperienceItem item : items) {
int timesClaimed = playerData.getClaims(object, this, item);
playerData.setClaims(object, this, item, 0);
for (int i = 0; i < timesClaimed; i++)
item.removeTriggers(playerData);
}
}
/**
* Called when a player joins and all the removable triggers get claimed back.
* Called when a player joins. All non-permanent/temporary triggers
* must be granted back to the player, including player modifiers.
*
* @param data PlayerData
* @param object Either profession, skillTreeNode or class leveling up
*/
public void claimRemovableTrigger(PlayerData data, ExperienceObject object) {
public void applyTemporaryTriggers(PlayerData data, ExperienceObject object) {
for (ExperienceItem item : items) {
int timesClaimed = data.getClaims(object, this, item);
for (int i = 0; i < timesClaimed; i++)
item.applyRemovableTrigger(data);
item.applyTemporaryTriggers(data);
}
}
}

View File

@ -3,19 +3,23 @@ package net.Indyuce.mmocore.player;
import net.Indyuce.mmocore.api.player.PlayerData;
/**
* Some item that can be unlocked. All unlockables are saved in the
* same list in the player data. This useful list can be used for:
* Some object that can be unlocked. All unlockables are saved in the
* same list in the player data, in the form of name-spaced keys. This
* tool is currently by:
* - skills
* - skill slots
* - waypoints
* - skill tree nodes
* - skills using skill books?
* - external plugins that implement other unlockable items
* <p>
* These objects are specific to the player's class and will not be
* transferred over to the new class if the player switches classes.
*
* @see {@link PlayerData#unlock(Unlockable)} and {@link PlayerData#hasUnlocked(Unlockable)}
* @see PlayerData#unlock(Unlockable)
* @see PlayerData#hasUnlocked(Unlockable)
*/
public interface Unlockable {
/**
* Format being used is the minecraft's default namespaced
* Format being used is the minecraft's default name-spaced
* key format, e.g "skill_tree:strength_1_5" for readability
*/
String getUnlockNamespacedKey();