Merge remote-tracking branch 'origin/Skills-update'

# Conflicts:
#	MMOCore-API/pom.xml
#	MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
#	MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java
#	MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLDataProvider.java
#	MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java
#	MMOCore-API/src/main/java/net/Indyuce/mmocore/player/DefaultPlayerData.java
#	MMOCore-Dist/pom.xml
#	pom.xml
This commit is contained in:
Jules 2023-04-08 14:20:55 +02:00
commit 2746d7cda9
49 changed files with 936 additions and 428 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>MMOCore</artifactId>
<groupId>net.Indyuce</groupId>
<version>1.11.3-SNAPSHOT</version>
<version>1.12.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -45,6 +45,9 @@ import net.Indyuce.mmocore.script.mechanic.ManaMechanic;
import net.Indyuce.mmocore.script.mechanic.StaminaMechanic;
import net.Indyuce.mmocore.script.mechanic.StelliumMechanic;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import net.Indyuce.mmocore.skill.list.Ambers;
import net.Indyuce.mmocore.skill.list.Neptune_Gift;
import net.Indyuce.mmocore.skill.list.Sneaky_Picky;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -57,7 +60,6 @@ import java.util.logging.Level;
public class MMOCore extends JavaPlugin {
public static MMOCore plugin;
public final WaypointManager waypointManager = new WaypointManager();
public final SoundManager soundManager = new SoundManager();
public final RequestManager requestManager = new RequestManager();

View File

@ -0,0 +1,36 @@
package net.Indyuce.mmocore.api.event.unlocking;
import net.Indyuce.mmocore.api.event.PlayerDataEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
public abstract class ItemChangeEvent extends PlayerDataEvent {
private final String itemKey;
public ItemChangeEvent(PlayerData playerData, String itemKey) {
super(playerData);
this.itemKey = itemKey;
}
/**
* @return The full item key in the format <plugin-id>:<item-type-id>:<item-id>.
*/
public String getItemKey() {
return itemKey;
}
/**
* @return The item-type-id which is the first parameter in the key format <item-type-id>:<item-id>.
*/
public String getItemTypeId() {
return itemKey.split(":")[0];
}
/**
* @return The item--id which is the last parameter in the key format <item-type-id>:<item-id>.
*/
public String getItemId() {
return itemKey.split(":")[1];
}
}

View File

@ -0,0 +1,24 @@
package net.Indyuce.mmocore.api.event.unlocking;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class ItemLockedEvent extends ItemChangeEvent {
private static final HandlerList handlers = new HandlerList();
public ItemLockedEvent(PlayerData playerData, String itemKey) {
super(playerData, itemKey);
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -0,0 +1,22 @@
package net.Indyuce.mmocore.api.event.unlocking;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class ItemUnlockedEvent extends ItemChangeEvent {
private static final HandlerList handlers = new HandlerList();
public ItemUnlockedEvent(PlayerData playerData, String itemKey) {
super(playerData, itemKey);
}
@NotNull
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -19,10 +19,19 @@ public class DefaultMMOLoader extends MMOLoader {
public Trigger loadTrigger(MMOLineConfig config) {
if (config.getKey().equals("from"))
return new FromTrigger(config);
if (config.getKey().equals("stat"))
return new StatTrigger(config);
if (config.getKey().equals("unlock_skill"))
return new UnlockSkillTrigger(config);
if (config.getKey().equals("skill_buff"))
return new SkillBuffTrigger(config);
if (config.getKey().equals("message"))
return new MessageTrigger(config);
if (config.getKey().equals("sound") || config.getKey().equals("playsound"))
return new SoundTrigger(config);

View File

@ -12,12 +12,15 @@ import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent;
import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.event.unlocking.ItemLockedEvent;
import net.Indyuce.mmocore.api.event.unlocking.ItemUnlockedEvent;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes;
import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.api.player.profess.Subclass;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.profess.skillbinding.BoundSkillInfo;
import net.Indyuce.mmocore.api.player.social.FriendRequest;
import net.Indyuce.mmocore.api.player.stats.PlayerStats;
import net.Indyuce.mmocore.api.quest.PlayerQuests;
@ -28,14 +31,12 @@ import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.ExperienceTableClaimer;
import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import net.Indyuce.mmocore.party.AbstractParty;
import net.Indyuce.mmocore.player.ClassDataContainer;
import net.Indyuce.mmocore.party.provided.MMOCorePartyModule;
import net.Indyuce.mmocore.party.provided.Party;
import net.Indyuce.mmocore.player.CombatHandler;
import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
@ -45,7 +46,6 @@ import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import net.Indyuce.mmocore.skilltree.tree.display.DisplayInfo;
import net.Indyuce.mmocore.skilltree.tree.display.Icon;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
@ -79,13 +79,10 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
*/
@Nullable
private PlayerClass profess;
private int level, classPoints, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints;
private int level, classPoints, skillPoints, attributePoints, attributeReallocationPoints;
private int skillTreeReallocationPoints, skillReallocationPoints;
private double experience;
private double mana, stamina, stellium;
/**
* Health is stored in playerData because when saving the playerData we can't access the player health anymore as the payer is Offline.
*/
private double health;
private Guild guild;
private SkillCastingHandler skillCasting;
private final PlayerQuests questData;
@ -93,8 +90,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
private final List<UUID> friends = new ArrayList<>();
private final Set<String> waypoints = new HashSet<>();
private final Map<String, Integer> skills = new HashMap<>();
private final List<ClassSkill> boundSkills = new ArrayList<>();
private final List<PassiveSkill> boundPassiveSkills = new ArrayList<>();
private final Map<Integer, BoundSkillInfo> boundSkills = new HashMap<>();
private final PlayerProfessions collectSkills = new PlayerProfessions(this);
private final PlayerAttributes attributes = new PlayerAttributes(this);
private final Map<String, SavedClassInformation> classSlots = new HashMap<>();
@ -114,15 +110,13 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
private final Map<String, Integer> skillTreePoints = new HashMap<>();
/**
* Saves all the items that have been unlocked so far by
* the player. This is used for:
* - waypoints
* - skills
*
* @see {@link Unlockable}
* Saves the namespacedkey of the items that have been unlocked in the form item-type:item-key.
* This is used for:
* -Waypoints
* -Skills
* -Skill Books
*/
private final Set<String> unlockedItems = new HashSet<>();
private final Set<String> unlockedItems= new HashSet<>();
/**
* Saves the amount of times the player has claimed some
* exp item in exp tables, for both exp tables used
@ -164,13 +158,13 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
MMOCore.log(Level.SEVERE, "[Userdata] Could not find class " + getProfess().getId() + " while refreshing player data.");
}
int j = 0;
while (j < boundSkills.size())
Iterator<Integer> ite = boundSkills.keySet().iterator();
while (ite.hasNext())
try {
boundSkills.set(j, Objects.requireNonNull(getProfess().getSkill(boundSkills.get(j).getSkill())));
int slot = ite.next();
BoundSkillInfo boundSkillInfo = new BoundSkillInfo(boundSkills.get(slot));
boundSkills.put(slot, boundSkillInfo);
} catch (Exception ignored) {
} finally {
j++;
}
for (SkillTree skillTree : getProfess().getSkillTrees())
@ -218,6 +212,14 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return new HashMap(skillTreePoints);
}
@Override
public Map<Integer, String> mapBoundSkills() {
Map<Integer, String> result = new HashMap<>();
for (int slot : boundSkills.keySet())
result.put(slot, boundSkills.get(slot).getClassSkill().getSkill().getHandler().getId());
return result;
}
public void clearSkillTreePoints() {
skillTreePoints.clear();
}
@ -247,7 +249,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
}
}
public Map<SkillTreeNode, Integer> getNodeLevels() {
return new HashMap<>(nodeLevels);
}
@ -367,6 +368,62 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return result;
}
/**
* @return If the item is unlocked by the player
* This is used for skills that can be locked & unlocked.
* <p>
* Looks at the real value and thus remove the plugin identifier
*/
public boolean hasUnlocked(Unlockable unlockable) {
String unlockableKey = unlockable.getUnlockNamespacedKey().substring(unlockable.getUnlockNamespacedKey().indexOf(":"));
return unlockedItems
.stream()
.filter(key -> key.substring(key.indexOf(":")).equals(unlockableKey))
.collect(Collectors.toList()).size() != 0;
}
/**
* Unlocks an item for the player. This is mainly used to unlock skills.
*
* @return If the item was locked when calling this method.
*/
public boolean unlock(Unlockable unlockable) {
boolean wasLocked = unlockedItems.add(unlockable.getUnlockNamespacedKey());
if (wasLocked)
//Calls the event synchronously
Bukkit.getScheduler().runTask(MythicLib.plugin,
() -> Bukkit.getPluginManager().callEvent(new ItemUnlockedEvent(this, unlockable.getUnlockNamespacedKey())));
return wasLocked;
}
/**
* Locks an item for the player by removing it from the unlocked items map if it is present.
* This is mainly used to remove unlocked items when changing class or reallocating a skill tree.
*
* @return If the item was unlocked when calling this method.
*/
public boolean lock(Unlockable unlockable) {
boolean wasUnlocked = unlockedItems.remove(unlockable.getUnlockNamespacedKey());
if (wasUnlocked)
//Calls the event synchronously
Bukkit.getScheduler().runTask(MythicLib.plugin, () -> Bukkit.getPluginManager().callEvent(new ItemLockedEvent(this, unlockable.getUnlockNamespacedKey())));
return wasUnlocked;
}
public Set<String> getUnlockedItems() {
return new HashSet<>(unlockedItems);
}
public void setUnlockedItems(Set<String> unlockedItems) {
unlockedItems.clear();
unlockedItems.addAll(unlockedItems);
}
public void resetTimesClaimed() {
tableItemClaims.clear();
}
@ -374,6 +431,13 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
@Override
public void close() {
// Remove from party if it is MMO Party Module
if (MMOCore.plugin.partyModule instanceof MMOCorePartyModule) {
AbstractParty party = getParty();
if (party != null && party instanceof Party)
((Party) party).removeMember(this);
}
// Close combat handler
combat.close();
@ -518,26 +582,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return guild != null;
}
/**
* @return If the item is unlocked by the player
* @deprecated Not used yet
*/
@Deprecated
public boolean hasUnlocked(Unlockable unlockable) {
return unlockedItems.contains(unlockable.getUnlockNamespacedKey());
}
/**
* Unlocks an item for the player
*
* @return If the item was already unlocked when calling this method
* @deprecated Not used yet
*/
@Deprecated
public boolean unlock(Unlockable unlockable) {
return unlockedItems.add(unlockable.getUnlockNamespacedKey());
}
public void setLevel(int level) {
this.level = Math.max(1, level);
@ -943,17 +987,16 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
stellium = Math.max(0, Math.min(stellium + event.getAmount(), max));
}
@Override
public double getHealth() {
return getPlayer().getHealth();
}
@Override
public double getMana() {
return mana;
}
@Override
public double getHealth() {
return health;
}
@Override
public double getStamina() {
return stamina;
}
@ -963,7 +1006,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return stellium;
}
public PlayerStats getStats() {
return playerStats;
}
@ -972,14 +1014,14 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return attributes;
}
public void setMana(double amount) {
mana = Math.max(0, Math.min(amount, getStats().getStat("MAX_MANA")));
}
public void setHealth(double amount) {
this.health = amount;
}
public void setMana(double amount) {
mana = Math.max(0, Math.min(amount, getStats().getStat("MAX_MANA")));
}
public void setStamina(double amount) {
stamina = Math.max(0, Math.min(amount, getStats().getStat("MAX_STAMINA")));
}
@ -1047,20 +1089,19 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
public void setSkillLevel(String skill, int level) {
skills.put(skill, level);
//If it is a passive skill we rebind it to make sure to update the damages done by it.
for (int i = 0; i < boundPassiveSkills.size(); i++) {
PassiveSkill passiveSkill = boundPassiveSkills.get(i);
if (passiveSkill.getTriggeredSkill().getHandler().getId().equals(skill)) {
passiveSkill.unregister(mmoData);
passiveSkill.register(mmoData);
}
}
refreshBoundedSkill(skill);
}
public void resetSkillLevel(String skill) {
skills.remove(skill);
refreshBoundedSkill(skill);
}
public void refreshBoundedSkill(String skill) {
boundSkills.values()
.stream()
.filter(skillInfo -> skillInfo.getClassSkill().getSkill().getHandler().getId().equals(skill))
.forEach(BoundSkillInfo::refresh);
}
@Deprecated
@ -1118,58 +1159,33 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
this.profess = profess;
// Clear old skills
for (Iterator<ClassSkill> iterator = boundSkills.iterator(); iterator.hasNext(); )
if (!getProfess().hasSkill(iterator.next().getSkill()))
for (Iterator<BoundSkillInfo> iterator = boundSkills.values().iterator(); iterator.hasNext(); )
if (!getProfess().hasSkill(iterator.next().getClassSkill().getSkill()))
iterator.remove();
// Update stats
if (isOnline())
getStats().updateStats();
//Loads the classUnlockedSkills
profess.getSkills()
.stream()
.filter(ClassSkill::isUnlockedByDefault)
.forEach(skill ->unlock(skill.getSkill()));
}
public boolean hasSkillBound(int slot) {
return slot < boundSkills.size();
return boundSkills.containsKey(slot);
}
public ClassSkill getBoundSkill(int slot) {
return slot >= boundSkills.size() ? null : boundSkills.get(slot);
return boundSkills.containsKey(slot) ? boundSkills.get(slot).getClassSkill() : null;
}
/**
* Registers a passive skill in the list. This method guarantees interface
* between ML passive skills and the MMOCore list.
*
* @param slot Slot to which you're binding the skill.
* Use -1 to force-register the skill
* @param skill Skill being bound
*/
public void bindPassiveSkill(int slot, @NotNull PassiveSkill skill) {
Validate.notNull(skill, "Skill cannot be null");
final int maxBound = getProfess().getMaxBoundPassiveSkills();
if (slot >= 0 && boundPassiveSkills.size() >= maxBound) {
final @NotNull PassiveSkill current = boundPassiveSkills.set(slot, skill);
if (current != null)
current.unregister(mmoData);
skill.register(mmoData);
return;
}
boundPassiveSkills.add(skill);
skill.register(mmoData);
}
public boolean hasPassiveSkillBound(int slot) {
return slot < boundPassiveSkills.size();
}
@Nullable
public PassiveSkill getBoundPassiveSkill(int slot) {
return slot >= boundPassiveSkills.size() ? null : boundPassiveSkills.get(slot);
}
@Deprecated
public void setBoundSkill(int slot, ClassSkill skill) {
bindActiveSkill(slot, skill);
bindSkill(slot, skill);
}
/**
@ -1179,30 +1195,30 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* Use -1 to force-register the skill
* @param skill Skill being bound
*/
public void bindActiveSkill(int slot, ClassSkill skill) {
public void bindSkill(int slot, ClassSkill skill) {
Validate.notNull(skill, "Skill cannot be null");
if (slot >= 0 && boundSkills.size() >= getProfess().getMaxBoundActiveSkills())
boundSkills.set(slot, skill);
else
boundSkills.add(skill);
//Unbinds the previous skill (Important for passive skills.
if (boundSkills.containsKey(slot))
boundSkills.get(slot).unbind();
if (slot >= 0) {
if (skill.getSkill().getTrigger().isPassive()) {
PassiveSkill passiveSkill = skill.toPassive(this);
passiveSkill.register(mmoData);
boundSkills.put(slot, new BoundSkillInfo(skill, this, passiveSkill.getUniqueId()));
} else {
boundSkills.put(slot, new BoundSkillInfo(skill, this));
}
}
}
public void unbindSkill(int slot) {
boundSkills.remove(slot);
BoundSkillInfo boundSkillInfo = boundSkills.remove(slot);
boundSkillInfo.unbind();
}
public void unbindPassiveSkill(int slot) {
PassiveSkill skill = boundPassiveSkills.get(slot);
skill.unregister(getMMOPlayerData());
boundPassiveSkills.remove(slot);
}
public List<ClassSkill> getBoundSkills() {
return boundSkills;
}
public List<PassiveSkill> getBoundPassiveSkills() {
return boundPassiveSkills;
return boundSkills.values().stream().map(BoundSkillInfo::getClassSkill).collect(Collectors.toList());
}
@NotNull

View File

@ -1,13 +1,11 @@
package net.Indyuce.mmocore.player;
import net.Indyuce.mmocore.api.player.PlayerData;
package net.Indyuce.mmocore.api.player;
/**
* 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:
* - waypoints
* - skill tree nodes
* - skills using skill books? TODO
* - skills using skill books?
* - external plugins that implement other unlockable items
*
* @see {@link PlayerData#unlock(Unlockable)} and {@link PlayerData#hasUnlocked(Unlockable)}
@ -19,4 +17,8 @@ public interface Unlockable {
* key format, e.g "skill_tree:strength_1_5" for readability
*/
String getUnlockNamespacedKey();
void whenLocked(PlayerData playerData);
void whenUnlocked(PlayerData playerData);
}

View File

@ -21,6 +21,7 @@ import net.Indyuce.mmocore.api.player.profess.event.EventTrigger;
import net.Indyuce.mmocore.api.player.profess.resource.ManaDisplayOptions;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.profess.resource.ResourceRegeneration;
import net.Indyuce.mmocore.api.player.profess.skillbinding.SkillSlot;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.EXPSource;
@ -34,6 +35,7 @@ import net.Indyuce.mmocore.skill.cast.ComboMap;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
@ -67,8 +69,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
@Nullable
private final CastingParticle castParticle;
private final int maxBoundActiveSkills, maxBoundPassiveSkills;
private final Map<Integer, SkillSlot> skillSlots = new HashMap<>();
private final List<SkillTree> skillTrees = new ArrayList<>();
private final List<PassiveSkill> classScripts = new LinkedList();
private final Map<String, LinearValue> stats = new HashMap<>();
@ -103,7 +104,11 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
| SecurityException exception) {
throw new IllegalArgumentException("Could not apply playerhead texture: " + exception.getMessage());
}
Validate.isTrue(config.isConfigurationSection("skill-slots"), "You must define the skills-slots for class " + id);
for (String key : config.getConfigurationSection("skill-slots").getKeys(false)) {
SkillSlot skillSlot = new SkillSlot(config.getConfigurationSection("skill-slots." + key));
skillSlots.put(skillSlot.getSlot(), skillSlot);
}
for (String string : config.getStringList("display.lore"))
description.add(ChatColor.GRAY + MythicLib.plugin.parseColors(string));
for (String string : config.getStringList("display.attribute-lore"))
@ -118,8 +123,6 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
? MMOCore.plugin.experience.getCurveOrThrow(
config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-"))
: ExpCurve.DEFAULT;
maxBoundActiveSkills = config.getInt("max-bound-active-skills", MMOCore.plugin.configManager.maxBoundActiveSkills);
maxBoundPassiveSkills = config.getInt("max-bound-passive-skills", MMOCore.plugin.configManager.maxBoundPassiveSkills);
ExperienceTable expTable = null;
if (config.contains("exp-table"))
try {
@ -177,15 +180,13 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
+ id + "': " + exception.getMessage());
}
if (config.contains("skills"))
for (String key : config.getConfigurationSection("skills").getKeys(false))
try {
RegisteredSkill registered = MMOCore.plugin.skillManager.getSkillOrThrow(UtilityMethods.enumName(key));
skills.put(registered.getHandler().getId(), new ClassSkill(registered, config.getConfigurationSection("skills." + key)));
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load skill info '" + key + "' from class '"
+ id + "': " + exception.getMessage());
}
for (RegisteredSkill registered : MMOCore.plugin.skillManager.getAll()) {
String key = registered.getHandler().getId();
if (config.contains("skills." + key))
skills.put(key, new ClassSkill(registered, config.getConfigurationSection("skills." + key)));
else
skills.put(key, new ClassSkill(registered, 1, 1,false));
}
castParticle = config.contains("cast-particle") ? new CastingParticle(config.getConfigurationSection("cast-particle")) : null;
@ -252,8 +253,6 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
this.icon = new ItemStack(material);
setOption(ClassOption.DISPLAY, false);
setOption(ClassOption.DEFAULT, false);
maxBoundActiveSkills = 6;
maxBoundPassiveSkills = 3;
for (PlayerResource resource : PlayerResource.values())
resourceHandlers.put(resource, new ResourceRegeneration(resource));
}
@ -309,13 +308,6 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
return expCurve;
}
public int getMaxBoundActiveSkills() {
return maxBoundActiveSkills;
}
public int getMaxBoundPassiveSkills() {
return maxBoundPassiveSkills;
}
@NotNull
public ExperienceTable getExperienceTable() {
@ -424,10 +416,18 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
return skills.containsKey(id);
}
public boolean hasSlot(int slot) {
return skillSlots.containsKey(slot);
}
public List<SkillTree> getSkillTrees() {
return skillTrees;
}
public SkillSlot getSkillSlot(int slot) {
return skillSlots.get(slot);
}
public ClassSkill getSkill(RegisteredSkill skill) {
return getSkill(skill.getHandler().getId());
}

View File

@ -5,16 +5,16 @@ import com.google.gson.JsonObject;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.player.ClassDataContainer;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import org.bukkit.attribute.Attribute;
import org.bukkit.configuration.ConfigurationSection;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class SavedClassInformation {
private final int level, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints;
@ -24,7 +24,8 @@ public class SavedClassInformation {
private final Map<String, Integer> skillTreePoints = new HashMap<>();
private final Map<String, Integer> nodeLevels = new HashMap<>();
private final Map<String, Integer> nodeTimesClaimed = new HashMap<>();
private final List<String> boundSkills = new ArrayList<>();
private final Map<Integer, String> boundSkills = new HashMap<>();
private final Set<String> unlockedItems = new HashSet<>();
/**
* Used by YAML storage
@ -42,17 +43,29 @@ public class SavedClassInformation {
stamina = config.getDouble("stamina", 0);
stellium = config.getDouble("stellium", 0);
if (config.contains("attribute"))
config.getConfigurationSection("attribute").getKeys(false).forEach(key -> attributeLevels.put(key, config.getInt("attribute." + key)));
config.getConfigurationSection("attribute").getKeys(false)
.forEach(key -> attributeLevels.put(key, config.getInt("attribute." + key)));
if (config.contains("skill"))
config.getConfigurationSection("skill").getKeys(false).forEach(key -> skillLevels.put(key, config.getInt("skill." + key)));
config.getConfigurationSection("skill").getKeys(false)
.forEach(key -> skillLevels.put(key, config.getInt("skill." + key)));
if (config.contains("skill-tree-points"))
config.getConfigurationSection("skill-tree-points").getKeys(false).forEach(key -> skillTreePoints.put(key, config.getInt("skill-tree-points." + key)));
config.getConfigurationSection("skill-tree-points").getKeys(false)
.forEach(key -> skillTreePoints.put(key, config.getInt("skill-tree-points." + key)));
if (config.contains("node-levels"))
config.getConfigurationSection("node-levels").getKeys(false).forEach(key -> nodeLevels.put(key, config.getInt("node-levels." + key)));
config.getConfigurationSection("node-levels").getKeys(false)
.forEach(key -> nodeLevels.put(key, config.getInt("node-levels." + key)));
if (config.contains("node-times-claimed"))
config.getConfigurationSection("node-times-claimed").getKeys(false).forEach(key -> nodeTimesClaimed.put(key, config.getInt("node-times-claimed." + key)));
if (config.contains("bound-skills"))
config.getStringList("bound-skills").forEach(id -> boundSkills.add(id));
config.getConfigurationSection("node-times-claimed").getKeys(false)
.forEach(key -> nodeTimesClaimed.put(key, config.getInt("node-times-claimed." + key)));
/**
* 'bound-skills' used to be a list. This condition makes
* sure that the config is using the newest format.
*/
if (config.isConfigurationSection("bound-skills"))
config.getConfigurationSection("bound-skills").getKeys(false)
.forEach(key -> boundSkills.put(Integer.parseInt(key), config.getString("bound-skills." + key)));
unlockedItems.addAll(config.getStringList("unlocked-items"));
}
/**
@ -70,7 +83,6 @@ public class SavedClassInformation {
mana = json.has("mana") ? json.get("mana").getAsDouble() : 0;
stamina = json.has("stamina") ? json.get("stamina").getAsDouble() : 0;
stellium = json.has("stellium") ? json.get("stellium").getAsDouble() : 0;
if (json.has("attribute"))
for (Entry<String, JsonElement> entry : json.getAsJsonObject("attribute").entrySet())
attributeLevels.put(entry.getKey(), entry.getValue().getAsInt());
@ -86,8 +98,15 @@ public class SavedClassInformation {
if (json.has("node-times-claimed"))
for (Entry<String, JsonElement> entry : json.getAsJsonObject("node-times-claimed").entrySet())
nodeTimesClaimed.put(entry.getKey(), entry.getValue().getAsInt());
if (json.has("bound-skills"))
json.getAsJsonArray("bound-skills").forEach(id -> boundSkills.add(id.getAsString()));
//Old system was using a JsonArray. If it saved with the old system the if condition won't be respected.
if (json.has("bound-skills") && json.get("bound-skills").isJsonObject())
for (Entry<String, JsonElement> entry : json.getAsJsonObject("bound-skills").entrySet())
boundSkills.put(Integer.parseInt(entry.getKey()), entry.getValue().getAsString());
if(json.has("unlocked-items")){
for(JsonElement unlockedItem: json.get("unlocked-items").getAsJsonArray()){
unlockedItems.add(unlockedItem.getAsString());
}
}
}
public SavedClassInformation(ClassDataContainer data) {
@ -108,9 +127,8 @@ public class SavedClassInformation {
data.mapSkillTreePoints().forEach((key, val) -> skillTreePoints.put(key, val));
data.getNodeLevels().forEach((node, level) -> nodeLevels.put(node.getFullId(), level));
data.getNodeTimesClaimed().forEach((key, val) -> nodeTimesClaimed.put(key, val));
data.getBoundPassiveSkills().forEach(skill -> boundSkills.add(skill.getTriggeredSkill().getHandler().getId()));
data.getBoundSkills().forEach(skill -> boundSkills.add(skill.getSkill().getHandler().getId()));
data.mapBoundSkills().forEach((slot, skill) -> boundSkills.put(slot, skill));
data.getUnlockedItems().forEach(item->unlockedItems.add(item));
}
public int getLevel() {
@ -165,6 +183,10 @@ public class SavedClassInformation {
registerSkillLevel(skill.getHandler().getId(), level);
}
public Map<Integer, String> getBoundSkills() {
return boundSkills;
}
public int getSkillTreeReallocationPoints() {
return skillTreeReallocationPoints;
}
@ -238,9 +260,6 @@ public class SavedClassInformation {
if (player.getProfess().hasExperienceTable())
player.getProfess().getExperienceTable().removePermStats(player, player.getProfess());
while (player.hasPassiveSkillBound(0))
player.unbindPassiveSkill(0);
while (player.hasSkillBound(0))
player.unbindSkill(0);
player.clearNodeTimesClaimed();
@ -258,13 +277,10 @@ public class SavedClassInformation {
player.setAttributeReallocationPoints(attributeReallocationPoints);
player.setSkillTreeReallocationPoints(skillTreeReallocationPoints);
player.setSkillReallocationPoints(skillReallocationPoints);
for (String id : boundSkills) {
ClassSkill skill = profess.getSkill(id);
if (skill.getSkill().getTrigger().isPassive())
player.bindPassiveSkill(-1, skill.toPassive(player));
else
player.getBoundSkills().add(skill);
}
player.setUnlockedItems(unlockedItems);
for (int slot : boundSkills.keySet())
player.bindSkill(slot, profess.getSkill(boundSkills.get(slot)));
skillLevels.forEach(player::setSkillLevel);
attributeLevels.forEach((id, pts) -> player.getAttributes().setBaseAttribute(id, pts));
@ -295,12 +311,12 @@ public class SavedClassInformation {
player.setClass(profess);
player.unloadClassInfo(profess);
//These should be loaded after to make sure that the MAX_MANA, MAX_STAMINA & MAX_STELLIUM stats are already loaded.
//This needs to be done at the end to make sure the MAX_HEALTH/MAX_MANA/... stats are loaded.
player.getPlayer().setHealth(Math.min(health, player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
player.setMana(mana);
player.setStellium(stellium);
player.setStamina(stamina);
player.getPlayer().setHealth(Math.min(health,player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
// Updates level on exp bar
player.refreshVanillaExp();
}

View File

@ -0,0 +1,67 @@
package net.Indyuce.mmocore.api.player.profess.skillbinding;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.ClassSkill;
import java.util.Objects;
import java.util.UUID;
public class BoundSkillInfo {
private final PlayerData playerData;
private final ClassSkill classSkill;
private UUID passiveSkillUUID;
public BoundSkillInfo(ClassSkill classSkill, PlayerData playerData) {
this.classSkill = classSkill;
this.playerData = playerData;
}
public BoundSkillInfo(ClassSkill classSkill, PlayerData playerData, UUID passiveSkillUUID) {
this.classSkill = classSkill;
this.playerData = playerData;
this.passiveSkillUUID = passiveSkillUUID;
}
/**
* Used on update to refresh the classSkill & all references to old data.
*/
public BoundSkillInfo(BoundSkillInfo info) {
this.playerData=info.getPlayerData();
this.classSkill= Objects.requireNonNull(playerData.getProfess().getSkill(info.getClassSkill().getSkill()));
info.unbind();
PassiveSkill passiveSkill = classSkill.toPassive(playerData);
passiveSkill.register(playerData.getMMOPlayerData());
this.passiveSkillUUID=passiveSkill.getUniqueId();
}
public ClassSkill getClassSkill() {
return classSkill;
}
public PlayerData getPlayerData() {
return playerData;
}
public UUID getPassiveSkillUUID() {
return passiveSkillUUID;
}
/**
* This is used to refresh the PassiveSkill playerModifier so it is always associated to the
*/
public void refresh() {
if (classSkill.getSkill().getTrigger().isPassive()) {
playerData.getMMOPlayerData().getPassiveSkillMap().removeModifier(passiveSkillUUID);
PassiveSkill passiveSkill = classSkill.toPassive(playerData);
passiveSkill.register(playerData.getMMOPlayerData());
this.passiveSkillUUID=passiveSkill.getUniqueId();
}
}
public void unbind() {
if (classSkill.getSkill().getTrigger().isPassive()) {
playerData.getMMOPlayerData().getPassiveSkillMap().removeModifier(passiveSkillUUID);
}
}
}

View File

@ -0,0 +1,62 @@
package net.Indyuce.mmocore.api.player.profess.skillbinding;
import net.Indyuce.mmocore.skill.ClassSkill;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import java.util.List;
public class SkillSlot {
private final int slot, modelData;
private final String formula;
private final String name;
private final List<String> lore;
private Material item;
public SkillSlot(int slot, int modelData, String formula, String name, List<String> lore, Material item) {
this.slot = slot;
this.modelData = modelData;
this.formula = formula;
this.name = name;
this.lore = lore;
this.item = item;
}
public SkillSlot(ConfigurationSection section) {
this.slot = Integer.parseInt(section.getName());
this.formula = section.contains("expression") ? section.getString("expression") : "true";
this.name = section.getString("name");
this.lore = section.getStringList("lore");
if (section.contains("item"))
this.item = Material.valueOf(section.getString("item"));
this.modelData = section.getInt("model-data", 0);
}
public int getSlot() {
return slot;
}
public String getName() {
return name;
}
public List<String> getLore() {
return lore;
}
public Material getItem() {
return item;
}
public boolean hasItem() {
return item != null;
}
public int getModelData() {
return modelData;
}
public boolean canPlaceSkill(ClassSkill classSkill) {
return classSkill.getSkill().matchesFormula(formula);
}
}

View File

@ -0,0 +1,50 @@
package net.Indyuce.mmocore.api.quest.trigger;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.api.skill.SkillBuff;
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.skill.RegisteredSkill;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class SkillBuffTrigger extends Trigger implements Removable {
private final SkillBuff skillBuff;
private final String buffKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
private final double amount;
public SkillBuffTrigger(MMOLineConfig config) {
super(config);
config.validateKeys("modifier");
config.validateKeys("amount");
config.validateKeys("formula");
config.validateKeys("type");
amount = config.getDouble("amount");
String skillModifier = config.getString("modifier");
String formula = config.getString("formula");
List<String> targetSkills = new ArrayList<>();
for (RegisteredSkill skill : MMOCore.plugin.skillManager.getAll()) {
if (skill.matchesFormula(formula))
targetSkills.add(skill.getHandler().getId());
}
skillBuff = new SkillBuff(buffKey, skillModifier, targetSkills, amount);
}
@Override
public void apply(PlayerData player) {
if (player.getMMOPlayerData().getSkillBuffMap().hasSkillBuff(buffKey)) {
player.getMMOPlayerData().getSkillBuffMap().getSkillBuff(buffKey).add(amount).register(player.getMMOPlayerData());
} else {
skillBuff.register(player.getMMOPlayerData());
}
}
@Override
public void remove(PlayerData playerData) {
skillBuff.unregister(playerData.getMMOPlayerData());
}
}

View File

@ -4,12 +4,12 @@ import io.lumine.mythic.lib.api.MMOLineConfig;
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 org.apache.commons.lang.Validate;
import java.util.UUID;
public class StatTrigger extends Trigger {
public static String TRIGGER_PREFIX = "mmocore_trigger";
public class StatTrigger extends Trigger implements Removable {
private final StatModifier statModifier;
private final String stat;
private final String modifierKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
@ -42,6 +42,7 @@ public class StatTrigger extends Trigger {
* opposite amount. (Little corrective term for the relative to have the inverse.
* Not a problem to store twice the stat modifiers are there only remain in the RAM.
*/
@Override
public void remove(PlayerData playerData) {
playerData.getMMOPlayerData().getStatMap().getInstance(stat).remove(modifierKey);
}

View File

@ -6,6 +6,8 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Bukkit;
public abstract class Trigger {
public static String TRIGGER_PREFIX = "mmocore_trigger";
private final long delay;
public Trigger(MMOLineConfig config) {

View File

@ -0,0 +1,29 @@
package net.Indyuce.mmocore.api.quest.trigger;
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.api.Removable;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import java.util.Objects;
public class UnlockSkillTrigger extends Trigger implements Removable {
private final RegisteredSkill skill;
public UnlockSkillTrigger(MMOLineConfig config) {
super(config);
config.validateKeys("skill");
skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(config.getString("skill")));
}
@Override
public void apply(PlayerData player) {
player.unlock(skill);
}
@Override
public void remove(PlayerData playerData) {
playerData.lock(skill);
}
}

View File

@ -0,0 +1,7 @@
package net.Indyuce.mmocore.api.quest.trigger.api;
import net.Indyuce.mmocore.api.player.PlayerData;
public interface Removable {
public void remove(PlayerData playerData);
}

View File

@ -66,10 +66,8 @@ public class ResetCommandTreeNode extends CommandTreeNode {
}
data.resetTimesClaimed();
while (data.hasSkillBound(0))
data.unbindSkill(0);
while (data.hasPassiveSkillBound(0))
data.unbindPassiveSkill(0);
for(int slot:data.mapBoundSkills().keySet())
data.unbindSkill(slot);
data.getQuestData().resetFinishedQuests();
data.getQuestData().start(null);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,

View File

@ -18,7 +18,8 @@ import java.util.function.BiFunction;
public class SkillCommandTreeNode extends CommandTreeNode {
public SkillCommandTreeNode(CommandTreeNode parent) {
super(parent, "skill");
addChild(new LockSkillCommandTreeNode(this, "lock", true));
addChild(new LockSkillCommandTreeNode(this, "unlock", false));
addChild(new ActionCommandTreeNode(this, "give", (old, amount) -> old + amount));
addChild(new ActionCommandTreeNode(this, "set", (old, amount) -> amount));
}
@ -31,7 +32,7 @@ public class SkillCommandTreeNode extends CommandTreeNode {
super(parent, type);
this.change = change;
addParameter(Parameter.PLAYER);
addParameter(new Parameter("<attribute>",
addParameter(new Parameter("<skill>",
(explorer, list) -> MMOCore.plugin.skillManager.getAll().forEach(skill -> list.add(skill.getHandler().getId().toUpperCase()))));
addParameter(Parameter.AMOUNT);
}
@ -55,15 +56,14 @@ public class SkillCommandTreeNode extends CommandTreeNode {
}
ClassSkill classSkill=null;
for(ClassSkill var:playerData.getProfess().getSkills()) {
if(var.getSkill().equals(skill))
classSkill=var;
ClassSkill classSkill = null;
for (ClassSkill var : playerData.getProfess().getSkills()) {
if (var.getSkill().equals(skill))
classSkill = var;
}
if(classSkill==null||classSkill.getUnlockLevel() > playerData.getLevel()) {
sender.sendMessage(ChatColor.RED+ skill.getName()+" is not unlockable for "+player.getName()+".");
if (classSkill == null || classSkill.getUnlockLevel() > playerData.getLevel()) {
sender.sendMessage(ChatColor.RED + skill.getName() + " is not unlockable for " + player.getName() + ".");
return CommandResult.FAILURE;
}
@ -83,6 +83,53 @@ public class SkillCommandTreeNode extends CommandTreeNode {
}
}
public class LockSkillCommandTreeNode extends CommandTreeNode {
private final boolean lock;
public LockSkillCommandTreeNode(CommandTreeNode parent, String id, boolean lock) {
super(parent, id);
this.lock = lock;
addParameter(Parameter.PLAYER);
addParameter(new Parameter("<skill>",
(explorer, list) -> MMOCore.plugin.skillManager.getAll().forEach(skill -> list.add(skill.getHandler().getId().toUpperCase()))));
}
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 5)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
sender.sendMessage(ChatColor.RED + "Could not find the player called " + args[3] + ".");
return CommandResult.FAILURE;
}
PlayerData playerData = PlayerData.get(player);
ClassSkill skill = playerData.getProfess().getSkill(args[4]);
if (skill == null) {
sender.sendMessage(ChatColor.RED + "The player's class doesn't have a skill called " + args[4] + ".");
return CommandResult.FAILURE;
}
if (lock) {
if (!playerData.hasUnlocked(skill.getSkill())) {
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "The skill " + skill.getSkill().getName() + " is already locked" + " for " + player.getName());
return CommandResult.SUCCESS;
}
playerData.lock(skill.getSkill());
} else {
if (playerData.hasUnlocked(skill.getSkill())) {
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "The skill " + skill.getSkill().getName() + " is already unlocked" + " for " + player.getName());
return CommandResult.SUCCESS;
}
playerData.unlock(skill.getSkill());
}
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill " + skill.getSkill().getName() + " is now " + (lock ? "locked" : "unlocked" + " for " + player.getName()));
return CommandResult.SUCCESS;
}
}
@Override
public CommandResult execute(CommandSender sender, String[] args) {
return CommandResult.THROW_USAGE;

View File

@ -5,6 +5,7 @@ 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 org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -105,15 +106,16 @@ public class ExperienceItem {
* Used when the player level is reset to 0 ( reallocate point in skill tree for instance)
* Creates an opposite playerModifier to compensate all the effect that existed before.
*/
public void removeStatTriggers(PlayerData playerData) {
public void removeTriggers(PlayerData playerData) {
for (Trigger trigger : triggers) {
if (trigger instanceof StatTrigger statTrigger)
statTrigger.remove(playerData);
if (trigger instanceof Removable)
((Removable) trigger).remove(playerData);
}
}
/**
* Used when a player connects back to give back all the stats that he should have.
*
* @param playerData
*/
public void applyStatTriggers(PlayerData playerData) {

View File

@ -4,7 +4,6 @@ import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.ExperienceObject;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import java.util.ArrayList;
@ -62,7 +61,7 @@ public class ExperienceTable {
for (ExperienceItem item : items) {
int timesClaimed = playerData.getClaims(object, this, item);
for (int i = 0; i < timesClaimed; i++)
item.removeStatTriggers(playerData);
item.removeTriggers(playerData);
}
}
@ -74,7 +73,7 @@ public class ExperienceTable {
int timesClaimed = playerData.getClaims(object, this, item);
playerData.setClaims(object, this, item, 0);
for (int i = 0; i < timesClaimed; i++)
item.removeStatTriggers(playerData);
item.removeTriggers(playerData);
}
}

View File

@ -5,6 +5,7 @@ import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.skillbinding.SkillSlot;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.gui.api.EditableInventory;
import net.Indyuce.mmocore.gui.api.GeneratedInventory;
@ -16,6 +17,7 @@ import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.api.SoundEvent;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
@ -28,8 +30,9 @@ import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class SkillList extends EditableInventory {
public class SkillList extends EditableInventory {
public SkillList() {
super("skill-list");
}
@ -61,68 +64,50 @@ public class SkillList extends EditableInventory {
};
}
if (function.equals("active-slot"))
if (function.equals("slot"))
return new SlotItem(config) {
@Override
public ItemStack display(SkillViewerInventory inv, int n) {
if (n >= inv.getPlayerData().getProfess().getMaxBoundActiveSkills()) {
if (!inv.getPlayerData().getProfess().hasSlot(n+1)) {
return new ItemStack(Material.AIR);
}
SkillSlot skillSlot = inv.getPlayerData().getProfess().getSkillSlot(n+1);
ItemStack item = super.display(inv, n);
if (!inv.getPlayerData().hasSkillBound(n)) {
item.setType(super.emptyMaterial);
if (!inv.getPlayerData().hasSkillBound(n+1)) {
//If there is an item filled in the slot config it shows it, else shows the default item.
Material material = skillSlot.hasItem() ? skillSlot.getItem() : super.emptyMaterial;
int customModelData = skillSlot.hasItem() ? skillSlot.getModelData() : super.emptyCMD;
item.setType(material);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(),skillSlot.getName()));
List<String> lore=skillSlot.getLore()
.stream()
.map(str->MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(),str))
.collect(Collectors.toList());
meta.setLore(lore);
if (MythicLib.plugin.getVersion().isStrictlyHigher(1, 13)) {
ItemMeta meta = item.getItemMeta();
meta.setCustomModelData(super.emptyCMD);
item.setItemMeta(meta);
meta.setCustomModelData(customModelData);
}
item.setItemMeta(meta);
}
return item;
}
/**
* This should only be called when there is a skill bound.
*/
@Override
public Placeholders getPlaceholders(SkillViewerInventory inv, int n) {
Placeholders holders= super.getPlaceholders(inv, n);
Placeholders holders = super.getPlaceholders(inv, n);
String none = MythicLib.plugin.parseColors(config.getString("no-skill"));
RegisteredSkill skill = inv.getPlayerData().hasSkillBound(n) ? inv.getPlayerData().getBoundSkill(n).getSkill() : null;
RegisteredSkill skill = inv.getPlayerData().hasSkillBound(n+1) ? inv.getPlayerData().getBoundSkill(n+1).getSkill() : null;
holders.register("skill", skill == null ? none : skill.getName());
return holders;
}
};
if (function.equals("passive-slot"))
return new SlotItem(config) {
@Override
public ItemStack display(SkillViewerInventory inv, int n) {
if (n >= inv.getPlayerData().getProfess().getMaxBoundPassiveSkills()) {
return new ItemStack(Material.AIR);
}
ItemStack item = super.display(inv, n);
if (!inv.getPlayerData().hasPassiveSkillBound(n)) {
item.setType(super.emptyMaterial);
if (MythicLib.plugin.getVersion().isStrictlyHigher(1, 13)) {
ItemMeta meta = item.getItemMeta();
meta.setCustomModelData(super.emptyCMD);
item.setItemMeta(meta);
}
}
return item;
}
@Override
public Placeholders getPlaceholders(SkillViewerInventory inv, int n) {
Placeholders holders= super.getPlaceholders(inv, n);
String none = MythicLib.plugin.parseColors(config.getString("no-skill"));
RegisteredSkill skill = inv.getPlayerData().hasPassiveSkillBound(n) ?
MMOCore.plugin.skillManager.getSkill(inv.getPlayerData().getBoundPassiveSkill(n).getTriggeredSkill().getHandler().getId())
: null;
holders.register("skill", skill == null ? none : skill.getName());
return holders;
}
};
if (function.equals("previous"))
return new SimplePlaceholderItem<SkillViewerInventory>(config) {
@ -329,8 +314,7 @@ public class SkillList extends EditableInventory {
// Cached information
private final List<ClassSkill> skills;
private final List<Integer> skillSlots;
private final List<Integer> activeSlotSlots;
private final List<Integer> passiveSlotSlots;
private final List<Integer> slotSlots;
//The skill the player Selected
private ClassSkill selected;
@ -338,12 +322,13 @@ public class SkillList extends EditableInventory {
public SkillViewerInventory(PlayerData playerData, EditableInventory editable) {
super(playerData, editable);
skills = new ArrayList<>(playerData.getProfess().getSkills());
skills = playerData.getProfess().getSkills()
.stream()
.filter((classSkill)->playerData.hasUnlocked(classSkill.getSkill()))
.collect(Collectors.toList());
skillSlots = getEditable().getByFunction("skill").getSlots();
Validate.notNull(getEditable().getByFunction("active-slot"), "Your skill GUI config file is out-of-date, please regenerate it.");
activeSlotSlots = getEditable().getByFunction("active-slot").getSlots();
passiveSlotSlots = getEditable().getByFunction("passive-slot").getSlots();
Validate.notNull(getEditable().getByFunction("slot"), "Your skill GUI config file is out-of-date, please regenerate it.");
slotSlots = getEditable().getByFunction("slot").getSlots();
selected = skills.get(page * skillSlots.size());
}
@ -408,55 +393,12 @@ public class SkillList extends EditableInventory {
return;
}
/*
* binding or unbinding passive skills.
*/
if (item.getFunction().equals("passive-slot")) {
int index = passiveSlotSlots.indexOf(context.getSlot());
// unbind if there is a current spell.
if (context.getClickType() == ClickType.RIGHT) {
if (!playerData.hasPassiveSkillBound(index)) {
MMOCore.plugin.configManager.getSimpleMessage("no-skill-bound").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 2);
playerData.unbindPassiveSkill(index);
open();
return;
}
if (selected == null)
return;
if (!selected.getSkill().getTrigger().isPassive()) {
MMOCore.plugin.configManager.getSimpleMessage("not-passive-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
if (!playerData.hasSkillUnlocked(selected)) {
MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 2);
playerData.bindPassiveSkill(index, selected.toPassive(playerData));
open();
return;
}
/*
* binding or unbinding skills.
*/
if (item.getFunction().equals("active-slot")) {
int index = activeSlotSlots.indexOf(context.getSlot());
if (item.getFunction().equals("slot")) {
int index = slotSlots.indexOf(context.getSlot())+1;
SkillSlot skillSlot=playerData.getProfess().getSkillSlot(index);
// unbind if there is a current spell.
if (context.getClickType() == ClickType.RIGHT) {
if (!playerData.hasSkillBound(index)) {
@ -473,21 +415,21 @@ public class SkillList extends EditableInventory {
if (selected == null)
return;
if (selected.getSkill().getTrigger().isPassive()) {
MMOCore.plugin.configManager.getSimpleMessage("not-active-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
if (!playerData.hasSkillUnlocked(selected)) {
MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
if(!skillSlot.canPlaceSkill(selected)){
MMOCore.plugin.configManager.getSimpleMessage("not-compatible-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 2);
playerData.bindActiveSkill(index, selected);
playerData.bindSkill(index, selected);
open();
return;
}

View File

@ -1,9 +1,6 @@
package net.Indyuce.mmocore.manager.data.mysql;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.*;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.sql.DataSynchronizer;
import net.Indyuce.mmocore.MMOCore;
@ -23,8 +20,7 @@ import org.jetbrains.annotations.Nullable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.logging.Level;
public class MMOCoreDataSynchronizer extends DataSynchronizer {
@ -74,8 +70,11 @@ public class MMOCoreDataSynchronizer extends DataSynchronizer {
}
}
data.setupSkillTree();
Set<String> unlockedItems = new HashSet<>();
JsonArray unlockedItemsArray = new JsonParser().parse(result.getString("unlocked_items")).getAsJsonArray();
for (JsonElement item : unlockedItemsArray)
unlockedItems.add(item.getAsString());
data.setUnlockedItems(unlockedItems);
if (!isEmpty(result.getString("guild"))) {
Guild guild = MMOCore.plugin.dataProvider.getGuildManager().getGuild(result.getString("guild"));
data.setGuild(guild.hasMember(data.getUniqueId()) ? guild : null);
@ -96,15 +95,11 @@ public class MMOCoreDataSynchronizer extends DataSynchronizer {
for (Map.Entry<String, JsonElement> entry : object.entrySet())
data.setSkillLevel(entry.getKey(), entry.getValue().getAsInt());
}
if (!isEmpty(result.getString("bound_skills")))
for (String id : MMOCoreUtils.jsonArrayToList(result.getString("bound_skills")))
if (data.getProfess().hasSkill(id)) {
ClassSkill skill = data.getProfess().getSkill(id);
if (skill.getSkill().getTrigger().isPassive())
data.bindPassiveSkill(-1, skill.toPassive(data));
else
data.getBoundSkills().add(skill);
}
if (!isEmpty(result.getString("bound_skills"))) {
JsonObject object = new Gson().fromJson(result.getString("bound_skills"), JsonObject.class);
for (Map.Entry<String, JsonElement> entry : object.entrySet())
data.bindSkill(Integer.parseInt(entry.getKey()), data.getProfess().getSkill(entry.getValue().getAsString()));
}
if (!isEmpty(result.getString("class_info"))) {
JsonObject object = new Gson().fromJson(result.getString("class_info"), JsonObject.class);
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {

View File

@ -21,6 +21,7 @@ public class MySQLDataProvider extends MMODataSource implements DataProvider {
"skill_tree_reallocation_points", "INT(11)",
"skill_tree_points", "LONGTEXT",
"skill_tree_levels", "LONGTEXT",
"unlocked_items","LONGTEXT",
"health", "FLOAT",
"mana", "FLOAT",
"stamina", "FLOAT",
@ -61,6 +62,7 @@ public class MySQLDataProvider extends MMODataSource implements DataProvider {
"mana FLOAT," +
"stamina FLOAT," +
"stellium FLOAT," +
"unlocked_items LONGTEXT," +
"class_info LONGTEXT," +
"is_saved TINYINT," +
"PRIMARY KEY (uuid));");

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmocore.manager.data.mysql;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.UtilityMethods;
import net.Indyuce.mmocore.MMOCore;
@ -11,7 +12,6 @@ import net.Indyuce.mmocore.manager.data.PlayerDataManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@ -55,10 +55,7 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
updater.addData("guild", data.hasGuild() ? data.getGuild().getId() : null);
updater.addJSONArray("waypoints", data.getWaypoints());
updater.addJSONArray("friends", data.getFriends().stream().map(UUID::toString).collect(Collectors.toList()));
List<String> boundSkills = new ArrayList<>();
data.getBoundSkills().forEach(skill -> boundSkills.add(skill.getSkill().getHandler().getId()));
data.getBoundPassiveSkills().forEach(skill -> boundSkills.add(skill.getTriggeredSkill().getHandler().getId()));
updater.addJSONArray("bound_skills", boundSkills);
updater.addJSONObject("bound_skills", data.mapBoundSkills().entrySet());
updater.addJSONObject("skills", data.mapSkillLevels().entrySet());
updater.addJSONObject("times_claimed", data.getItemClaims().entrySet());
updater.addJSONObject("skill_tree_points", data.mapSkillTreePoints().entrySet());
@ -67,6 +64,7 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
updater.addData("professions", data.getCollectionSkills().toJsonString());
updater.addData("quests", data.getQuestData().toJsonString());
updater.addData("class_info", createClassInfoData(data).toString());
updater.addJSONArray("unlocked_items", data.getUnlockedItems());
if (logout)
updater.addData("is_saved", 1);
@ -88,7 +86,15 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
classinfo.addProperty("attribute-realloc-points", info.getAttributeReallocationPoints());
classinfo.addProperty("skill-reallocation-points", info.getSkillReallocationPoints());
classinfo.addProperty("skill-tree-reallocation-points", info.getSkillTreeReallocationPoints());
classinfo.addProperty("health", info.getHealth());
classinfo.addProperty("mana", info.getMana());
classinfo.addProperty("stamina", info.getStamina());
classinfo.addProperty("stellium", info.getStellium());
JsonArray array = new JsonArray();
for (String unlockedItem : playerData.getUnlockedItems()) {
array.add(unlockedItem);
}
classinfo.add("unlocked-items", array);
JsonObject skillinfo = new JsonObject();
for (String skill : info.getSkillKeys())
skillinfo.addProperty(skill, info.getSkillLevel(skill));
@ -108,6 +114,11 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
skillTreePointsInfo.addProperty(skillTreeId, info.getSkillTreePoints(skillTreeId));
classinfo.add("skill-tree-points", skillTreePointsInfo);
JsonObject boundSkillInfo = new JsonObject();
for (int slot : info.getBoundSkills().keySet())
boundSkillInfo.addProperty(slot + "", info.getBoundSkills().get(slot));
classinfo.add("bound-skills", boundSkillInfo);
json.add(c, classinfo);
}
@ -160,8 +171,8 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
@Override
public void removeFriend(UUID uuid) {
// TODO recode
// friends.remove(uuid);
// new PlayerDataTableUpdater(provider, uuid).updateData("friends", friends.stream().map(UUID::toString).collect(Collectors.toList()));
// friends.remove(uuid);
// new PlayerDataTableUpdater(provider, uuid).updateData("friends", friends.stream().map(UUID::toString).collect(Collectors.toList()));
}
@Override

View File

@ -95,10 +95,10 @@ public class PlayerDataTableUpdater {
addData(key, json.toString());
}
public void addJSONObject(String key, Set<Map.Entry<String, Integer>> collection) {
public <T,V> void addJSONObject(String key, Set<Map.Entry<T, V>> collection) {
JsonObject json = new JsonObject();
for (Map.Entry<String, Integer> entry : collection)
json.addProperty(entry.getKey(), entry.getValue());
for (Map.Entry<T, V> entry : collection)
json.addProperty(entry.getKey().toString(), entry.getValue().toString());
addData(key, json.toString());
}
}

View File

@ -17,9 +17,7 @@ import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Collectors;
@ -65,25 +63,27 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
config.getStringList("friends").forEach(str -> data.getFriends().add(UUID.fromString(str)));
if (config.contains("skill"))
config.getConfigurationSection("skill").getKeys(false).forEach(id -> data.setSkillLevel(id, config.getInt("skill." + id)));
if (config.contains("bound-skills"))
for (String id : config.getStringList("bound-skills"))
if (data.getProfess().hasSkill(id)) {
ClassSkill skill = data.getProfess().getSkill(id);
if (skill.getSkill().getTrigger().isPassive())
data.bindPassiveSkill(-1, skill.toPassive(data));
else
data.getBoundSkills().add(skill);
if (config.isConfigurationSection("bound-skills"))
for (String key : config.getConfigurationSection("bound-skills").getKeys(false)) {
ClassSkill skill = data.getProfess().getSkill(config.getString("bound-skills." + key));
data.bindSkill(Integer.parseInt(key), skill);
}
}
for (String key : MMOCore.plugin.skillTreeManager.getAll().stream().map(skillTree -> skillTree.getId()).toList()) {
for (
String key : MMOCore.plugin.skillTreeManager.getAll().
stream().
map(skillTree -> skillTree.getId()).
toList()) {
data.setSkillTreePoints(key, config.getInt("skill-tree-points." + key, 0));
}
data.setSkillTreePoints("global", config.getInt("skill-tree-points.global", 0));
if (config.contains("times-claimed"))
for (String key : config.getConfigurationSection("times-claimed").getKeys(false)) {
for (
String key : config.getConfigurationSection("times-claimed").
getKeys(false)) {
ConfigurationSection section = config.getConfigurationSection("times-claimed." + key);
if (section != null)
for (String key1 : section.getKeys(false)) {
@ -96,7 +96,9 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
}
}
for (SkillTreeNode node : MMOCore.plugin.skillTreeManager.getAllNodes()) {
data.setUnlockedItems(config.getStringList("unlocked-items").stream().collect(Collectors.toSet()));
for (
SkillTreeNode node : MMOCore.plugin.skillTreeManager.getAllNodes()) {
data.setNodeLevel(node, config.getInt("skill-tree-level." + node.getFullId(), 0));
}
data.setupSkillTree();
@ -157,11 +159,8 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
data.mapSkillLevels().forEach((key1, value) -> config.set("skill." + key1, value));
data.getItemClaims().forEach((key, times) -> config.set("times-claimed." + key, times));
List<String> boundSkills = new ArrayList<>();
data.getBoundSkills().forEach(skill -> boundSkills.add(skill.getSkill().getHandler().getId()));
data.getBoundPassiveSkills().forEach(skill -> boundSkills.add(skill.getTriggeredSkill().getHandler().getId()));
config.set("bound-skills", boundSkills);
data.mapBoundSkills().forEach((slot, skill) -> config.set("bound-skills." + slot, skill));
config.set("unlocked-items", data.getUnlockedItems().stream().collect(Collectors.toList()));
config.set("attribute", null);
config.createSection("attribute");
data.getAttributes().save(config.getConfigurationSection("attribute"));
@ -184,10 +183,16 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
config.set("class-info." + key + ".attribute-realloc-points", info.getAttributeReallocationPoints());
config.set("class-info." + key + ".skill-tree-reallocation-points", info.getSkillTreeReallocationPoints());
config.set("class-info." + key + ".skill-reallocation-points", info.getSkillReallocationPoints());
config.set("class-info." + key + ".health", info.getHealth());
config.set("class-info." + key + ".mana", info.getMana());
config.set("class-info." + key + ".stamina", info.getStamina());
config.set("class-info." + key + ".stellium", info.getStellium());
info.getSkillKeys().forEach(skill -> config.set("class-info." + key + ".skill." + skill, info.getSkillLevel(skill)));
info.getAttributeKeys().forEach(attribute -> config.set("class-info." + key + ".attribute." + attribute, info.getAttributeLevel(attribute)));
info.getNodeKeys().forEach(node -> config.set("class-info." + key + ".node-levels." + node, info.getNodeLevel(node)));
info.getSkillTreePointsKeys().forEach(skillTreeId -> config.set("class-info." + key + ".skill-tree-points." + skillTreeId, info.getAttributeLevel(skillTreeId)));
info.getBoundSkills().forEach((slot, skill) -> config.set("class-info." + key + ".bound-skills." + slot, skill));
config.set("class-info." + key + ".unlocked-items", info.getUnlockedItems());
}
file.save();

View File

@ -1,12 +1,10 @@
package net.Indyuce.mmocore.player;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* All the class-specific information i.e information being saved
@ -43,11 +41,11 @@ public interface ClassDataContainer {
Map<String, Integer> mapSkillTreePoints();
List<ClassSkill> getBoundSkills();
List<PassiveSkill> getBoundPassiveSkills();
Map<Integer,String> mapBoundSkills();
Map<SkillTreeNode, Integer> getNodeLevels();
Map<String, Integer> getNodeTimesClaimed();
Set<String> getUnlockedItems();
}

View File

@ -1,19 +1,16 @@
package net.Indyuce.mmocore.player;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import org.bukkit.attribute.Attribute;
import org.bukkit.configuration.ConfigurationSection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class DefaultPlayerData implements ClassDataContainer {
private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints, skillReallocPoints, skillTreeReallocPoints;
private final double health, mana, stamina, stellium;
public static final DefaultPlayerData DEFAULT = new DefaultPlayerData(1, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0);
public DefaultPlayerData(ConfigurationSection config) {
@ -24,10 +21,10 @@ public class DefaultPlayerData implements ClassDataContainer {
attrReallocPoints = config.getInt("attribute-realloc-points");
skillReallocPoints = config.getInt("skill-realloc-points", 0);
skillTreeReallocPoints = config.getInt("skill-tree-realloc-points", 0);
health=config.getDouble("health",20);
mana=config.getDouble("mana",20);
stamina=config.getDouble("stamina",20);
stellium=config.getDouble("stellium",20);
health = config.getDouble("health", 20);
mana = config.getDouble("mana", 20);
stamina = config.getDouble("stamina", 20);
stellium = config.getDouble("stellium", 20);
}
public DefaultPlayerData(int level, int classPoints, int skillPoints, int attributePoints, int attrReallocPoints, int skillReallocPoints, int skillTreeReallocPoints, double health, double mana, double stamina, double stellium) {
@ -122,19 +119,19 @@ public class DefaultPlayerData implements ClassDataContainer {
return new HashMap<>();
}
@Override
public Set<String> getUnlockedItems() {
return new HashSet<>();
}
@Override
public Map<String, Integer> mapAttributeLevels() {
return new HashMap<>();
}
@Override
public List<ClassSkill> getBoundSkills() {
return new ArrayList<>();
}
@Override
public List<PassiveSkill> getBoundPassiveSkills() {
return new ArrayList<>();
public Map<Integer,String> mapBoundSkills() {
return new HashMap<>();
}
public void apply(PlayerData player) {
@ -145,5 +142,9 @@ public class DefaultPlayerData implements ClassDataContainer {
player.setAttributeReallocationPoints(attrReallocPoints);
player.setSkillTreeReallocationPoints(skillTreeReallocPoints);
player.setSkillReallocationPoints(skillReallocPoints);
player.getPlayer().setHealth(Math.min(health, player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
player.setMana(mana);
player.setStamina(stamina);
player.setStellium(stellium);
}
}

View File

@ -1,6 +1,7 @@
package net.Indyuce.mmocore.skill;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.comp.flags.CustomFlag;
import io.lumine.mythic.lib.player.cooldown.CooldownInfo;
import io.lumine.mythic.lib.skill.Skill;
@ -49,13 +50,13 @@ public class CastableSkill extends Skill {
}
// Mana cost
if (playerData.getMana() < getModifier("mana")) {
if (loud) MMOCore.plugin.configManager.getSimpleMessage("casting.no-mana", "mana-required",MythicLib.plugin.getMMOConfig().decimal.format((getModifier("mana")-playerData.getMana())),"mana", playerData.getProfess().getManaDisplay().getName()).send(playerData.getPlayer());
if (playerData.getMana() < getModifier("mana",playerData.getMMOPlayerData())) {
if (loud) MMOCore.plugin.configManager.getSimpleMessage("casting.no-mana", "mana-required",MythicLib.plugin.getMMOConfig().decimal.format((getModifier("mana",playerData.getMMOPlayerData())-playerData.getMana())),"mana", playerData.getProfess().getManaDisplay().getName()).send(playerData.getPlayer());
return false;
}
// Stamina cost
if (playerData.getStamina() < getModifier("stamina")) {
if (playerData.getStamina() < getModifier("stamina",skillMeta.getCaster().getData())) {
if (loud) MMOCore.plugin.configManager.getSimpleMessage("casting.no-stamina").send(playerData.getPlayer());
return false;
}
@ -76,11 +77,11 @@ public class CastableSkill extends Skill {
// Cooldown
double flatCooldownReduction = Math.max(0, Math.min(1, skillMeta.getCaster().getStat("COOLDOWN_REDUCTION") / 100));
CooldownInfo cooldownHandler = skillMeta.getCaster().getData().getCooldownMap().applyCooldown(this, getModifier("cooldown"));
CooldownInfo cooldownHandler = skillMeta.getCaster().getData().getCooldownMap().applyCooldown(this, getModifier("cooldown",casterData.getMMOPlayerData()));
cooldownHandler.reduceInitialCooldown(flatCooldownReduction);
casterData.giveMana(-getModifier("mana"), PlayerResourceUpdateEvent.UpdateReason.SKILL_COST);
casterData.giveStamina(-getModifier("stamina"), PlayerResourceUpdateEvent.UpdateReason.SKILL_COST);
casterData.giveMana(-getModifier("mana",skillMeta.getCaster().getData()), PlayerResourceUpdateEvent.UpdateReason.SKILL_COST);
casterData.giveStamina(-getModifier("stamina",casterData.getMMOPlayerData()), PlayerResourceUpdateEvent.UpdateReason.SKILL_COST);
}
if (!getTrigger().isPassive())
@ -93,7 +94,8 @@ public class CastableSkill extends Skill {
}
@Override
public double getModifier(String mod) {
return skill.getModifier(mod, skillLevel);
public double getModifier(String mod, MMOPlayerData playerData) {
return playerData.getSkillBuffMap().getSkillInstance(getHandler().getId())
.getSkillModifier(mod).getTotal(skill.getModifier(mod, skillLevel));
}
}

View File

@ -17,6 +17,7 @@ import java.util.*;
public class ClassSkill implements CooldownObject {
private final RegisteredSkill skill;
private final int unlockLevel, maxSkillLevel;
private final boolean unlockedByDefault;
private final Map<String, LinearValue> modifiers = new HashMap<>();
@Deprecated
@ -32,10 +33,14 @@ public class ClassSkill implements CooldownObject {
* It is also used by the MMOCore API to force players to cast abilities.
*/
public ClassSkill(RegisteredSkill skill, int unlockLevel, int maxSkillLevel) {
this(skill, unlockLevel, maxSkillLevel, true);
}
public ClassSkill(RegisteredSkill skill, int unlockLevel, int maxSkillLevel, boolean unlockedByDefault) {
this.skill = skill;
this.unlockLevel = unlockLevel;
this.maxSkillLevel = maxSkillLevel;
this.unlockedByDefault = unlockedByDefault;
for (String mod : skill.getHandler().getModifiers())
this.modifiers.put(mod, skill.getModifierInfo(mod));
}
@ -44,7 +49,7 @@ public class ClassSkill implements CooldownObject {
this.skill = skill;
unlockLevel = config.getInt("level");
maxSkillLevel = config.getInt("max-level");
unlockedByDefault = config.getBoolean("unlocked-by-default", true);
for (String mod : skill.getHandler().getModifiers()) {
LinearValue defaultValue = skill.getModifierInfo(mod);
this.modifiers.put(mod, config.isConfigurationSection(mod) ? readLinearValue(defaultValue, config.getConfigurationSection(mod)) : defaultValue);
@ -68,6 +73,10 @@ public class ClassSkill implements CooldownObject {
return maxSkillLevel;
}
public boolean isUnlockedByDefault() {
return unlockedByDefault;
}
/**
* This method can only override default modifiers and
* will throw an error when trying to define non existing modifiers
@ -98,7 +107,9 @@ public class ClassSkill implements CooldownObject {
// Calculate placeholders
Placeholders placeholders = new Placeholders();
modifiers.keySet().forEach(modifier -> placeholders.register(modifier, modifiers.get(modifier).getDisplay(x)));
modifiers.keySet().forEach(modifier ->
placeholders.register(modifier, data.getMMOPlayerData().getSkillBuffMap()
.getSkillInstance(skill.getHandler().getId()).getSkillModifier(modifier).getTotal(modifiers.get(modifier).calculate(x))));
placeholders.register("mana_name", data.getProfess().getManaDisplay().getName());
placeholders.register("mana_color", data.getProfess().getManaDisplay().getFull().toString());

View File

@ -1,21 +1,22 @@
package net.Indyuce.mmocore.skill;
import bsh.EvalError;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.skill.handler.SkillHandler;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.Unlockable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.player.Unlockable;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
public class RegisteredSkill implements Unlockable {
private final SkillHandler<?> handler;
@ -23,7 +24,7 @@ public class RegisteredSkill implements Unlockable {
private final Map<String, LinearValue> defaultModifiers = new HashMap<>();
private final ItemStack icon;
private final List<String> lore;
private final List<String> categories;
@NotNull
private final TriggerType triggerType;
@ -33,9 +34,14 @@ public class RegisteredSkill implements Unlockable {
name = Objects.requireNonNull(config.getString("name"), "Could not find skill name");
icon = MMOCoreUtils.readIcon(Objects.requireNonNull(config.getString("material"), "Could not find skill icon"));
lore = Objects.requireNonNull(config.getStringList("lore"), "Could not find skill lore");
categories = config.getStringList("categories");
// Trigger type
triggerType = getHandler().isTriggerable() ? (config.contains("passive-type") ? TriggerType.valueOf(UtilityMethods.enumName(config.getString("passive-type"))) : TriggerType.CAST) : TriggerType.API;
categories.add(getHandler().getId());
if (triggerType.isPassive())
categories.add("passive");
else
categories.add("active");
// Load default modifier formulas
for (String mod : handler.getModifiers())
@ -54,11 +60,27 @@ public class RegisteredSkill implements Unlockable {
this.icon = icon;
this.lore = lore;
this.triggerType = triggerType;
this.categories = new ArrayList<>();
}
@Override
public String getUnlockNamespacedKey() {
return "registered_skill:" + handler.getId().toLowerCase();
return "skill:" + handler.getId().toLowerCase();
}
@Override
public void whenLocked(PlayerData playerData) {
playerData.mapBoundSkills()
.forEach((slot, skill) ->
{
if (skill.equals(getUnlockNamespacedKey().split(":")[1]))
playerData.unbindSkill(slot);
});
}
@Override
public void whenUnlocked(PlayerData playerData) {
}
public SkillHandler<?> getHandler() {
@ -73,6 +95,10 @@ public class RegisteredSkill implements Unlockable {
return lore;
}
public List<String> getCategories() {
return categories;
}
public ItemStack getIcon() {
return icon.clone();
}
@ -98,7 +124,7 @@ public class RegisteredSkill implements Unlockable {
/**
* @return Modifier formula.
* Not null as long as the modifier is well defined
* Not null as long as the modifier is well defined
*/
@NotNull
public LinearValue getModifierInfo(String modifier) {
@ -109,6 +135,19 @@ public class RegisteredSkill implements Unlockable {
return defaultModifiers.get(modifier).calculate(level);
}
public boolean matchesFormula(String formula) {
String parsedExpression = formula;
for (String category : categories)
parsedExpression = parsedExpression.replace("<" + category + ">", "true");
parsedExpression = parsedExpression.replaceAll("<.*>", "false");
try {
boolean res = (boolean) MythicLib.plugin.getInterpreter().eval(parsedExpression);
return res;
} catch (EvalError e) {
throw new RuntimeException(e);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -11,6 +11,7 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.cast.PlayerKey;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
@ -116,13 +117,13 @@ public class SkillBar implements Listener {
private String getFormat(PlayerData data) {
StringBuilder str = new StringBuilder();
if (!data.isOnline()) return str.toString();
for (int j = 0; j < data.getBoundSkills().size(); j++) {
ClassSkill skill = data.getBoundSkill(j);
for (int slot : data.mapBoundSkills().keySet()) {
ClassSkill skill = data.getBoundSkill(slot);
str.append((str.length() == 0) ? "" : split).append((onCooldown(data, skill) ? onCooldown.replace("{cooldown}",
String.valueOf(data.getCooldownMap().getInfo(skill).getRemaining() / 1000)) : noMana(data, skill) ? noMana : (noStamina(
data, skill) ? noStamina : ready)).replace("{index}",
"" + (j + 1 + (data.getPlayer().getInventory().getHeldItemSlot() <= j ? 1 : 0)))
.replace("{skill}", data.getBoundSkill(j).getSkill().getName()));
"" + (slot + 1 + (data.getPlayer().getInventory().getHeldItemSlot() <= slot ? 1 : 0)))
.replace("{skill}", data.getBoundSkill(slot).getSkill().getName()));
}
return MMOCore.plugin.placeholderParser.parse(data.getPlayer(), str.toString());
}

View File

@ -5,6 +5,7 @@ import io.lumine.mythic.lib.skill.SkillMetadata;
import io.lumine.mythic.lib.skill.handler.SkillHandler;
import io.lumine.mythic.lib.skill.result.def.SimpleSkillResult;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -33,7 +34,7 @@ public class Neptune_Gift extends SkillHandler<SimpleSkillResult> implements Lis
if (skill == null)
return;
event.setAmount(event.getAmount() * (1 + skill.getTriggeredSkill().getModifier("extra") / 100));
event.setAmount(event.getAmount() * (1 + skill.getTriggeredSkill().getModifier("extra", PlayerData.get(event.getPlayer()).getMMOPlayerData()) / 100));
}
}
}

View File

@ -3,9 +3,10 @@ package net.Indyuce.mmocore.waypoint;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.api.util.PostLoadObject;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.Unlockable;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
import net.Indyuce.mmocore.player.Unlockable;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -212,6 +213,16 @@ public class Waypoint extends PostLoadObject implements Unlockable {
return "waypoint:" + getId();
}
@Override
public void whenLocked(PlayerData playerData) {
}
@Override
public void whenUnlocked(PlayerData playerData) {
}
@Override
public int hashCode() {
return Objects.hash(id);

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>MMOCore</artifactId>
<groupId>net.Indyuce</groupId>
<version>1.11.3-SNAPSHOT</version>
<version>1.12.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -67,7 +67,7 @@
<dependency>
<groupId>net.Indyuce</groupId>
<artifactId>MMOCore-API</artifactId>
<version>1.11.3-SNAPSHOT</version>
<version>1.12.0-SNAPSHOT</version>
<optional>true</optional>
</dependency>

View File

@ -30,6 +30,11 @@ default-playerdata:
skill-realloc-points: 0
attribute-points: 0
attribute-realloc-points: 0
health: 20
mana: 0
stellium: 0
stamina: 0
# The list of all conditions which must be met for the
# BLOCK REGEN and BLOCK RESTRICTIONS to apply. Set to

View File

@ -31,6 +31,16 @@ display:
# Must match an existing exp curve filename from the 'expcurves' folder
exp-curve: levels
skill-slots:
1:
name: "Skill Slot I"
2:
name: "Skill Slot II"
3:
name: "Skill Slot III"
4:
name: "Skill Slot IV"
# The maximum level players can reach
max-level: 100

View File

@ -20,6 +20,16 @@ options:
# Must match an existing exp curve filename from the 'expcurves' folder
exp-curve: levels
skill-slots:
1:
name: "Skill Slot I"
2:
name: "Skill Slot II"
3:
name: "Skill Slot III"
4:
name: "Skill Slot IV"
#The number of skills a player can bound.
max-bound-active-skills: 5

View File

@ -38,6 +38,15 @@ skill-trees:
exp-table: class_exp_table
skill-slots:
1:
name: "Skill Slot I"
2:
name: "Skill Slot II"
3:
name: "Skill Slot III"
4:
name: "Skill Slot IV"
# This is the default mana display options, however it is not mandatory
# to have it in your class config file. Other classes do not have this
# section and therefore have the default mana display options.
@ -55,6 +64,8 @@ mana:
empty: WHITE
name: 'Mana'
cast-particle:
particle: SPELL_INSTANT

View File

@ -33,6 +33,16 @@ max-level: 100
exp-table: class_exp_table
skill-slots:
1:
name: "Skill Slot I"
2:
name: "Skill Slot II"
3:
name: "Skill Slot III"
4:
name: "Skill Slot IV"
skill-trees:
- 'general'
- 'rogue-marksman'

View File

@ -30,6 +30,15 @@ display:
# Must match an existing exp curve filename from the 'expcurves' folder
exp-curve: levels
skill-slots:
1:
name: "Skill Slot I"
2:
name: "Skill Slot II"
3:
name: "Skill Slot III"
4:
name: "Skill Slot IV"
skill-trees:
- 'general'

View File

@ -33,6 +33,15 @@ max-level: 100
exp-table: class_exp_table
skill-slots:
1:
name: "Skill Slot I"
2:
name: "Skill Slot II"
3:
name: "Skill Slot III"
4:
name: "Skill Slot IV"
skill-trees:
- 'general'

View File

@ -61,6 +61,16 @@ mana:
exp-table: class_exp_table
skill-slots:
1:
name: "Skill Slot I"
2:
name: "Skill Slot II"
3:
name: "Skill Slot III"
4:
name: "Skill Slot IV"
# Rage charges when dealing weapon and physical damage.
triggers:
weapon-damage:

View File

@ -46,26 +46,9 @@ items:
- '&eCosts 1 skill reallocation point.'
- '&e◆ Skill Reallocation Points: &6{points}'
passive-skill-slot:
slots: [ 7,16,25,34,43,52 ]
function: passive-slot
item: BOOK
# Material used when the slot is empty
empty-item: BLUE_DYE
name: '&aPassive Skill Slot {slot}'
no-skill: '&cNone'
lore:
- '&7Current Passive Skill: &6{skill}'
- ''
- '&e► Left click to bind {selected}.'
- '&e► Right click to unbind.'
skill-slot:
slot:
slots: [ 8,17,26,35,44,53 ]
function: active-slot
function: slot
item: BOOK
# Material used when the slot is empty

View File

@ -202,8 +202,7 @@ not-enough-skill-points-shift: '&cYou need {shift_points} skill points.'
upgrade-skill: '&eYour &6{skill} &eis now Level &6{level}&e!'
not-unlocked-skill: '&cYou have not unlocked that skill yet.'
no-skill-bound: '&cYou don''t have any skill bound to this slot.'
not-active-skill: '&cThis is not an active skill.'
not-passive-skill: '&cThis is not a passive skill.'
not-compatible-skill: '&cThe selected skill is not compatible with this slot.'
skill-max-level-hit: '&cYou already hit the max level for that skill.'
no-skill-placeholder: 'No Skill Bound'
not-skill-reallocation-point: '&cYou do not have 1 skill reallocation point.'

View File

@ -0,0 +1,42 @@
name: Arcane Hail
lore:
- Surprise your foes with this
- quick firing hail of magic
- ''
- '&e{cooldown}s Cooldown'
- '&9Costs {mana} {mana_name}'
material: END_ROD
duration:
base: 4
per-level: 1
min: 0
max: 0
timer:
base: 0
per-level: 0
min: 0
max: 0
damage:
base: 3
per-level: 1
delay:
base: 2
per-level: 1
min: 0
max: 0
mana:
base: 2
per-level: 1.1
stamina:
base: 0
per-level: 0
min: 0
max: 0
cooldown:
base: 1
per-level: -0.2
radius:
base: 4
per-level: 0.5
min: 0
max: 0

View File

@ -13,7 +13,7 @@ And then add MMOCore-API as dependency
<dependency>
<groupId>net.Indyuce</groupId>
<artifactId>MMOCore-API</artifactId>
<version>1.11.2-SNAPSHOT</version>
<version>1.12.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
```

View File

@ -5,7 +5,7 @@
<groupId>net.Indyuce</groupId>
<artifactId>MMOCore</artifactId>
<packaging>pom</packaging>
<version>1.11.3-SNAPSHOT</version>
<version>1.12.0-SNAPSHOT</version>
<modules>
<module>MMOCore-API</module>
@ -75,7 +75,7 @@
<dependency>
<groupId>io.lumine</groupId>
<artifactId>MythicLib-dist</artifactId>
<version>1.5.1-SNAPSHOT</version>
<version>1.5.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>