!skill trees api, item unlocks api, exp tables for classes

This commit is contained in:
Jules 2022-01-21 21:55:58 +01:00
parent 604bc2ff48
commit 420d309ac3
30 changed files with 785 additions and 480 deletions

View File

@ -9,7 +9,7 @@ import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.PlayerActionBar;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.social.guilds.Guild;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.debug.DebugMode;
import net.Indyuce.mmocore.command.*;

View File

@ -11,7 +11,7 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.social.guilds.Guild;
import net.Indyuce.mmocore.guild.provided.Guild;
public class ConfigFile {
private final File file;

View File

@ -5,7 +5,7 @@ import org.bukkit.event.HandlerList;
import net.Indyuce.mmocore.api.event.PlayerDataEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.social.guilds.Guild;
import net.Indyuce.mmocore.guild.provided.Guild;
public class GuildChatEvent extends PlayerDataEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();

View File

@ -1,45 +1,49 @@
package net.Indyuce.mmocore.api.player;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitRunnable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.PlayerCombatEvent;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitRunnable;
public class CombatRunnable extends BukkitRunnable {
private final PlayerData player;
private final PlayerData player;
private long lastHit = System.currentTimeMillis();
private long lastHit = System.currentTimeMillis();
public CombatRunnable(PlayerData player) {
this.player = player;
private boolean open = true;
if (player.isOnline()) {
MMOCore.plugin.configManager.getSimpleMessage("now-in-combat").send(player.getPlayer());
Bukkit.getPluginManager().callEvent(new PlayerCombatEvent(player, true));
runTaskTimer(MMOCore.plugin, 20, 20);
}
}
public CombatRunnable(PlayerData player) {
this.player = player;
public void update() {
lastHit = System.currentTimeMillis();
}
if (player.isOnline()) {
MMOCore.plugin.configManager.getSimpleMessage("now-in-combat").send(player.getPlayer());
Bukkit.getPluginManager().callEvent(new PlayerCombatEvent(player, true));
runTaskTimer(MMOCore.plugin, 20, 20);
}
}
@Override
public void run() {
if (!player.isOnline()) {
close();
return;
}
if (lastHit + MMOCore.plugin.configManager.combatLogTimer < System.currentTimeMillis()) {
Bukkit.getPluginManager().callEvent(new PlayerCombatEvent(player, false));
MMOCore.plugin.configManager.getSimpleMessage("leave-combat").send(player.getPlayer());
close();
}
}
public void update() {
lastHit = System.currentTimeMillis();
}
private void close() {
player.combat = null;
cancel();
}
@Override
public void run() {
if (!player.isOnline()) {
close();
return;
}
if (lastHit + MMOCore.plugin.configManager.combatLogTimer < System.currentTimeMillis()) {
Bukkit.getPluginManager().callEvent(new PlayerCombatEvent(player, false));
MMOCore.plugin.configManager.getSimpleMessage("leave-combat").send(player.getPlayer());
close();
}
}
private void close() {
Validate.isTrue(open, "Combat runnable has already been closed");
player.combat = null;
cancel();
open = false;
}
}

View File

@ -17,7 +17,6 @@ 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.social.FriendRequest;
import net.Indyuce.mmocore.api.player.social.guilds.Guild;
import net.Indyuce.mmocore.api.player.stats.PlayerStats;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.quest.PlayerQuests;
@ -25,7 +24,12 @@ import net.Indyuce.mmocore.api.util.Closable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
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.party.AbstractParty;
import net.Indyuce.mmocore.party.provided.Party;
import net.Indyuce.mmocore.skill.ClassSkill;
@ -47,7 +51,7 @@ import java.util.*;
import java.util.logging.Level;
public class PlayerData extends OfflinePlayerData implements Closable {
public class PlayerData extends OfflinePlayerData implements Closable, ExperienceTableClaimer {
/**
* Corresponds to the MythicLib player data. It is used to keep
@ -78,6 +82,21 @@ public class PlayerData extends OfflinePlayerData implements Closable {
private final Map<String, SavedClassInformation> classSlots = new HashMap<>();
private final Map<PlayerActivity, Long> lastActivity = new HashMap<>();
/**
* Saves all the items that have been unlocked so far by
* the player. This can be used by other plugins by
* implementing the {@link Unlockable} interface
*
* @see {@link Unlockable}
*/
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
*/
private final Map<String, Integer> tableItemClaims = new HashMap<>();
// NON-FINAL player data stuff made public to facilitate field change
public int skillGuiDisplayOffset;
public boolean noCooldown;
@ -225,6 +244,24 @@ public class PlayerData extends OfflinePlayerData implements Closable {
return skillPoints;
}
@Override
public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) {
String key = object.geyKey() + "." + table.getId() + "." + item.getId();
return tableItemClaims.get(key);
}
@Override
public void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int times) {
String key = object.geyKey() + "." + table.getId() + "." + item.getId();
tableItemClaims.put(key, times);
}
@Deprecated(since = "1.9")
public void setProfessionExpItemClaims(String professionTableItemKey, int times) {
Validate.isTrue(!professionTableItemKey.startsWith("class.") && !professionTableItemKey.startsWith("profession."), "Invalid exp item key");
tableItemClaims.put("profession." + professionTableItemKey, times);
}
/**
* @return Experience needed in order to reach next level
*/
@ -252,6 +289,19 @@ public class PlayerData extends OfflinePlayerData implements Closable {
return guild != null;
}
public boolean hasUnlocked(Unlockable unlockable) {
throw new RuntimeException("Not implemented yet");
}
/**
* Unlocks an item for the player
*
* @return If the item was already unlocked when calling this method
*/
public boolean unlock(Unlockable unlockable) {
throw new RuntimeException("Not implemented yet");
}
public void setLevel(int level) {
this.level = Math.max(1, level);
@ -820,7 +870,7 @@ public class PlayerData extends OfflinePlayerData implements Closable {
* checks if they could potentially upgrade to one of these
*
* @return If the player can change its current class to
* a subclass
* a subclass
*/
public boolean canChooseSubclass() {
for (Subclass subclass : getProfess().getSubclasses())

View File

@ -0,0 +1,15 @@
package net.Indyuce.mmocore.api.player;
/**
* Some item that can be unlocked
*
* @see {@link PlayerData#unlock(Unlockable)} and {@link PlayerData#hasUnlocked(Unlockable)}
*/
public interface Unlockable {
/**
* Format being used is the minecraft's default
* namespaced key format, e.g skill_tree:strength_1_5
*/
String getUnlockNamespacedKey();
}

View File

@ -15,6 +15,8 @@ import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.api.util.math.particle.CastingParticle;
import net.Indyuce.mmocore.experience.ExpCurve;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.experience.provider.ExperienceDispenser;
import net.Indyuce.mmocore.experience.provider.MainExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
@ -28,12 +30,14 @@ import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.logging.Level;
public class PlayerClass extends PostLoadObject {
public class PlayerClass extends PostLoadObject implements ExperienceObject {
private final String name, id, actionBarFormat;
private final List<String> description = new ArrayList<>(), attrDescription = new ArrayList<>();
private final ItemStack icon;
@ -41,6 +45,7 @@ public class PlayerClass extends PostLoadObject {
private final ManaDisplayOptions manaDisplay;
private final int maxLevel, displayOrder;
private final ExpCurve expCurve;
private final ExperienceTable expTable;
private final Map<StatType, LinearValue> stats = new HashMap<>();
private final Map<String, ClassSkill> skills = new LinkedHashMap<>();
@ -87,6 +92,15 @@ public class PlayerClass extends PostLoadObject {
config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-"))
: ExpCurve.DEFAULT;
ExperienceTable expTable = null;
if (config.contains("exp-table"))
try {
expTable = MMOCore.plugin.experience.loadExperienceTable(config.get("exp-table"));
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table from class '" + id + "': " + exception.getMessage());
}
this.expTable = expTable;
if (config.contains("attributes"))
for (String key : config.getConfigurationSection("attributes").getKeys(false))
try {
@ -168,6 +182,7 @@ public class PlayerClass extends PostLoadObject {
maxLevel = 0;
displayOrder = 0;
expCurve = ExpCurve.DEFAULT;
expTable = null;
castParticle = new CastingParticle(Particle.SPELL_INSTANT);
actionBarFormat = "";
@ -202,10 +217,17 @@ public class PlayerClass extends PostLoadObject {
return name;
}
@Override
public String geyKey() {
return "class." + getId();
}
@NotNull
public ManaDisplayOptions getManaDisplay() {
return manaDisplay;
}
@NotNull
public ResourceRegeneration getHandler(PlayerResource resource) {
return resourceHandlers.get(resource);
}
@ -218,10 +240,16 @@ public class PlayerClass extends PostLoadObject {
return displayOrder;
}
@Override
public ExpCurve getExpCurve() {
return expCurve;
}
@Override
public ExperienceTable getExperienceTable() {
return expTable;
}
public ItemStack getIcon() {
return icon.clone();
}
@ -246,8 +274,13 @@ public class PlayerClass extends PostLoadObject {
return options.containsKey(option) ? options.get(option) : option.getDefault();
}
@Deprecated
public void setStat(StatType type, double base, double perLevel) {
stats.put(type, new LinearValue(base, perLevel));
setStat(type, new LinearValue(base, perLevel));
}
public void setStat(StatType type, LinearValue value) {
stats.put(type, value);
}
public double calculateStat(StatType stat, int level) {

View File

@ -14,7 +14,7 @@ import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.MMOCommandEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.social.Request;
import net.Indyuce.mmocore.api.player.social.guilds.GuildInvite;
import net.Indyuce.mmocore.guild.provided.GuildInvite;
import net.Indyuce.mmocore.manager.InventoryManager;
public class GuildCommand extends BukkitCommand {

View File

@ -0,0 +1,29 @@
package net.Indyuce.mmocore.experience;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import javax.annotation.Nullable;
/**
* Either a profession or a class
*
* @author jules
*/
public interface ExperienceObject {
String geyKey();
/**
* Indicates the amount of exp required to level up
*
* @return Exp curve of that object
*/
@Nullable
ExpCurve getExpCurve();
/**
* @return Table read when leveling up
*/
@Nullable
ExperienceTable getExperienceTable();
}

View File

@ -0,0 +1,21 @@
package net.Indyuce.mmocore.experience;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
/**
* Professions and classes share the same properties because
* they have both exp curves and tables.
* <p>
* A 'claimer' is an object that can claim exp tables and therefore
* needs to save how many times it has already claimed some item
* before.
* <p>
* Since MMOCore 1.9 it's all centralized in the player class data
*/
public interface ExperienceTableClaimer {
int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item);
void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int claims);
}

View File

@ -12,9 +12,6 @@ import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.manager.SoundManager;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -28,204 +25,194 @@ import java.util.Map;
import java.util.Map.Entry;
public class PlayerProfessions {
private final Map<String, Integer> exp = new HashMap<>();
private final Map<String, Integer> level = new HashMap<>();
private final Map<String, Integer> timesClaimed = new HashMap<>();
private final PlayerData playerData;
private final Map<String, Integer> exp = new HashMap<>();
private final Map<String, Integer> level = new HashMap<>();
public PlayerProfessions(PlayerData playerData) {
this.playerData = playerData;
}
private final PlayerData playerData;
public PlayerProfessions load(ConfigurationSection config) {
for (String key : config.getKeys(false))
if (MMOCore.plugin.professionManager.has(key)) {
exp.put(key, config.getInt(key + ".exp"));
level.put(key, config.getInt(key + ".level"));
}
public PlayerProfessions(PlayerData playerData) {
this.playerData = playerData;
}
if (config.contains("times-claimed"))
// Watch out for the deep section lookup
for (String key : config.getConfigurationSection("times-claimed").getKeys(true))
this.timesClaimed.put(key, config.getInt("times-claimed." + key));
/**
* When loading data through YAML
*/
public PlayerProfessions load(ConfigurationSection config) {
for (String key : config.getKeys(false))
if (MMOCore.plugin.professionManager.has(key)) {
exp.put(key, config.getInt(key + ".exp"));
level.put(key, config.getInt(key + ".level"));
}
return this;
}
if (config.contains("times-claimed"))
// Watch out for the deep section lookup
for (String key : config.getConfigurationSection("times-claimed").getKeys(true))
playerData.setProfessionExpItemClaims(key, config.getInt("times-claimed." + key));
public void save(ConfigurationSection config) {
for (String id : exp.keySet())
config.set(id + ".exp", exp.get(id));
for (String id : level.keySet())
config.set(id + ".level", level.get(id));
return this;
}
timesClaimed.forEach((key, value) -> config.set("times-claimed." + key, value));
}
/**
* When saving data through YAML
*/
public void save(ConfigurationSection config) {
for (String id : exp.keySet())
config.set(id + ".exp", exp.get(id));
for (String id : level.keySet())
config.set(id + ".level", level.get(id));
}
public String toJsonString() {
JsonObject json = new JsonObject();
for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
JsonObject object = new JsonObject();
object.addProperty("exp", getExperience(profession));
object.addProperty("level", getLevel(profession));
/**
* When saving data through SQL
*/
public String toJsonString() {
JsonObject json = new JsonObject();
for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
JsonObject object = new JsonObject();
object.addProperty("exp", getExperience(profession));
object.addProperty("level", getLevel(profession));
json.add(profession.getId(), object);
}
json.add(profession.getId(), object);
}
JsonObject timesClaimed = new JsonObject();
this.timesClaimed.forEach((key, value) -> timesClaimed.addProperty(key, value));
json.add("timesClaimed", timesClaimed);
return json.toString();
}
return json.toString();
}
/**
* When loading data through SQL
*/
public void load(String json) {
JsonObject obj = new Gson().fromJson(json, JsonObject.class);
public void load(String json) {
JsonObject obj = new Gson().fromJson(json, JsonObject.class);
// Load profession exp and levels
for (Entry<String, JsonElement> entry : obj.entrySet())
if (MMOCore.plugin.professionManager.has(entry.getKey())) {
JsonObject value = entry.getValue().getAsJsonObject();
exp.put(entry.getKey(), value.get("exp").getAsInt());
level.put(entry.getKey(), value.get("level").getAsInt());
}
// Load profession exp and levels
for (Entry<String, JsonElement> entry : obj.entrySet())
if (MMOCore.plugin.professionManager.has(entry.getKey())) {
JsonObject value = entry.getValue().getAsJsonObject();
exp.put(entry.getKey(), value.get("exp").getAsInt());
level.put(entry.getKey(), value.get("level").getAsInt());
}
// Load times claimed
if (obj.has("timesClaimed"))
for (Entry<String, JsonElement> entry : obj.getAsJsonObject("timesClaimed").entrySet())
playerData.setProfessionExpItemClaims(entry.getKey(), entry.getValue().getAsInt());
}
// Load times claimed
if (obj.has("timesClaimed"))
for (Entry<String, JsonElement> entry : obj.getAsJsonObject("timesClaimed").entrySet())
timesClaimed.put(entry.getKey(), entry.getValue().getAsInt());
}
public PlayerData getPlayerData() {
return playerData;
}
public PlayerData getPlayerData() {
return playerData;
}
public int getLevel(String profession) {
return Math.max(1, level.getOrDefault(profession, 1));
}
public int getLevel(String profession) {
return Math.max(1, level.getOrDefault(profession, 1));
}
public int getLevel(Profession profession) {
return getLevel(profession.getId());
}
public int getLevel(Profession profession) {
return getLevel(profession.getId());
}
public int getExperience(String id) {
return exp.getOrDefault(id, 0);
}
public int getExperience(String id) {
return exp.getOrDefault(id, 0);
}
public int getExperience(Profession profession) {
return getExperience(profession.getId());
}
public int getExperience(Profession profession) {
return getExperience(profession.getId());
}
public int getLevelUpExperience(Profession profession) {
return profession.getExpCurve().getExperience(getLevel(profession) + 1);
}
public int getLevelUpExperience(Profession profession) {
return profession.getExpCurve().getExperience(getLevel(profession) + 1);
}
public int getLevelUpExperience(String id) {
return MMOCore.plugin.professionManager.has(id) ? MMOCore.plugin.professionManager.get(id).getExpCurve().getExperience(getLevel(id) + 1) : 0;
}
public int getLevelUpExperience(String id) {
return MMOCore.plugin.professionManager.has(id) ? MMOCore.plugin.professionManager.get(id).getExpCurve().getExperience(getLevel(id) + 1) : 0;
}
public void setLevel(Profession profession, int value) {
level.put(profession.getId(), value);
}
public void setLevel(Profession profession, int value) {
level.put(profession.getId(), value);
}
public void takeLevels(Profession profession, int value) {
int current = level.getOrDefault(profession.getId(), 1);
level.put(profession.getId(), Math.max(1, current - value));
}
public void takeLevels(Profession profession, int value) {
int current = level.getOrDefault(profession.getId(), 1);
level.put(profession.getId(), Math.max(1, current - value));
}
public void setExperience(Profession profession, int value) {
exp.put(profession.getId(), value);
}
public void setExperience(Profession profession, int value) {
exp.put(profession.getId(), value);
}
public void giveLevels(Profession profession, int value, EXPSource source) {
int total = 0, level = getLevel(profession);
while (value-- > 0)
total += profession.getExpCurve().getExperience(level + value + 1);
giveExperience(profession, total, source);
}
public void giveLevels(Profession profession, int value, EXPSource source) {
int total = 0, level = getLevel(profession);
while (value-- > 0)
total += profession.getExpCurve().getExperience(level + value + 1);
giveExperience(profession, total, source);
}
public void giveExperience(Profession profession, int value, EXPSource source) {
giveExperience(profession, value, source, null);
}
public void giveExperience(Profession profession, int value, EXPSource source) {
giveExperience(profession, value, source, null);
}
public boolean hasReachedMaxLevel(Profession profession) {
return profession.hasMaxLevel() && getLevel(profession) >= profession.getMaxLevel();
}
public boolean hasReachedMaxLevel(Profession profession) {
return profession.hasMaxLevel() && getLevel(profession) >= profession.getMaxLevel();
}
public void giveExperience(Profession profession, double value, EXPSource source, @Nullable Location hologramLocation) {
public void giveExperience(Profession profession, double value, EXPSource source, @Nullable Location hologramLocation) {
Validate.isTrue(playerData.isOnline(), "Cannot give experience to offline player");
if (hasReachedMaxLevel(profession)) {
setExperience(profession, 0);
return;
}
setExperience(profession, 0);
return;
}
value = MMOCore.plugin.boosterManager.calculateExp(profession, value);
value = MMOCore.plugin.boosterManager.calculateExp(profession, value);
// display hologram
if (hologramLocation != null )
MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", "" + value).message());
// Display hologram
if (hologramLocation != null)
MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", "" + value).message());
PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(playerData, profession, (int) value, source);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return;
PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(playerData, profession, (int) value, source);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return;
exp.put(profession.getId(), exp.containsKey(profession.getId()) ? exp.get(profession.getId()) + event.getExperience() : event.getExperience());
int needed, exp, level, oldLevel = getLevel(profession);
exp.put(profession.getId(), exp.containsKey(profession.getId()) ? exp.get(profession.getId()) + event.getExperience() : event.getExperience());
int needed, exp, level, oldLevel = getLevel(profession);
/*
* loop for exp overload when leveling up, will continue looping until
* exp is 0 or max level has been reached
*/
boolean check = false;
while ((exp = this.exp.get(profession.getId())) >= (needed = profession.getExpCurve().getExperience((level = getLevel(profession)) + 1))) {
if (hasReachedMaxLevel(profession)) {
setExperience(profession, 0);
check = true;
break;
}
/*
* Loop for exp overload when leveling up, will continue
* looping until exp is 0 or max level has been reached
*/
boolean check = false;
while ((exp = this.exp.get(profession.getId())) >= (needed = profession.getExpCurve().getExperience((level = getLevel(profession)) + 1))) {
if (hasReachedMaxLevel(profession)) {
setExperience(profession, 0);
check = true;
break;
}
this.exp.put(profession.getId(), exp - needed);
this.level.put(profession.getId(), level + 1);
check = true;
playerData.giveExperience((int) profession.getExperience().calculate(level), null);
}
this.exp.put(profession.getId(), exp - needed);
this.level.put(profession.getId(), level + 1);
check = true;
playerData.giveExperience((int) profession.getExperience().calculate(level), null);
}
if (check) {
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level));
new SmallParticleEffect(playerData.getPlayer(), Particle.SPELL_INSTANT);
new ConfigMessage("profession-level-up").addPlaceholders("level", "" + level, "profession", profession.getName())
.send(playerData.getPlayer());
MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_UP).playTo(playerData.getPlayer());
playerData.getStats().updateStats();
if (check) {
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level));
new SmallParticleEffect(playerData.getPlayer(), Particle.SPELL_INSTANT);
new ConfigMessage("profession-level-up").addPlaceholders("level", "" + level, "profession", profession.getName())
.send(playerData.getPlayer());
MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_UP).playTo(playerData.getPlayer());
playerData.getStats().updateStats();
// Apply profession experience table
if (profession.hasExperienceTable())
profession.getExperienceTable().claim(playerData, level, this);
}
// Apply profession experience table
if (profession.hasExperienceTable())
profession.getExperienceTable().claim(playerData, level, profession);
}
StringBuilder bar = new StringBuilder("" + ChatColor.BOLD);
int chars = (int) ((double) exp / needed * 20);
for (int j = 0; j < 20; j++)
bar.append(j == chars ? "" + ChatColor.WHITE + ChatColor.BOLD : "").append("|");
if (playerData.isOnline())
MMOCore.plugin.configManager.getSimpleMessage("exp-notification", "profession", profession.getName(), "progress", bar.toString(), "ratio",
MythicLib.plugin.getMMOConfig().decimal.format((double) exp / needed * 100)).send(playerData.getPlayer());
}
/**
* @return The amount of times that specific experience item was claimed by the player
*/
public int getTimesClaimed(ExperienceTable table, ExperienceItem item) {
String path = table.getId() + "." + item.getId();
return timesClaimed.getOrDefault(path, 0);
}
/**
* See {@link #getTimesClaimed(ExperienceTable, ExperienceItem)}
*/
public void setTimesClaimed(ExperienceTable table, ExperienceItem item, int timesClaimed) {
String path = table.getId() + "." + item.getId();
this.timesClaimed.put(path, timesClaimed);
StringBuilder bar = new StringBuilder("" + ChatColor.BOLD);
int chars = (int) ((double) exp / needed * 20);
for (int j = 0; j < 20; j++)
bar.append(j == chars ? "" + ChatColor.WHITE + ChatColor.BOLD : "").append("|");
if (playerData.isOnline())
MMOCore.plugin.configManager.getSimpleMessage("exp-notification", "profession", profession.getName(), "progress", bar.toString(), "ratio",
MythicLib.plugin.getMMOConfig().decimal.format((double) exp / needed * 100)).send(playerData.getPlayer());
}
}

View File

@ -16,15 +16,16 @@ import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
public class Profession {
public class Profession implements ExperienceObject {
private final String id, name;
private final ExpCurve expCurve;
private final int maxLevel;
private final Map<ProfessionOption, Boolean> options = new HashMap<>();
private final ExpCurve expCurve;
private final ExperienceTable expTable;
/**
* Experience given to the main player level whenever he levels up this profession
* Experience given to the main player level
* whenever he levels up this profession
*/
private final LinearValue experience;
@ -41,7 +42,7 @@ public class Profession {
ExperienceTable expTable = null;
if (config.contains("exp-table"))
try {
expTable = loadExperienceTable(config.get("exp-table"));
expTable = MMOCore.plugin.experience.loadExperienceTable(config.get("exp-table"));
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table from profession '" + id + "': " + exception.getMessage());
}
@ -73,16 +74,7 @@ public class Profession {
MMOCore.plugin.professionManager.loadProfessionConfigurations(this, config);
}
private ExperienceTable loadExperienceTable(Object obj) {
if (obj instanceof ConfigurationSection)
return new ExperienceTable((ConfigurationSection) obj);
if (obj instanceof String)
return MMOCore.plugin.experience.getTableOrThrow(obj.toString());
throw new IllegalArgumentException("Please provide either a string (exp table name) or a config section (locally define an exp table)");
}
public boolean getOption(ProfessionOption option) {
return options.getOrDefault(option, option.getDefault());
@ -96,6 +88,12 @@ public class Profession {
return name;
}
@Override
public String geyKey() {
return "profession." + getId();
}
@Override
public ExpCurve getExpCurve() {
return expCurve;
}

View File

@ -2,7 +2,7 @@ package net.Indyuce.mmocore.experience.droptable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.ExperienceObject;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -40,15 +40,15 @@ public class ExperienceTable {
*
* @param levelingUp Player leveling up
* @param professionLevel New profession level
* @param professionData Player profession data
* @param object Either profession or class leveling up
*/
public void claim(PlayerData levelingUp, int professionLevel, PlayerProfessions professionData) {
public void claim(PlayerData levelingUp, int professionLevel, ExperienceObject object) {
for (ExperienceItem item : items) {
int timesClaimed = professionData.getTimesClaimed(this, item);
int timesClaimed = levelingUp.getClaims(object, this, item);
if (!item.roll(professionLevel, timesClaimed))
continue;
professionData.setTimesClaimed(this, item, timesClaimed + 1);
levelingUp.setClaims(object, this, item, timesClaimed + 1);
item.applyTriggers(levelingUp);
}
}

View File

@ -1,4 +1,8 @@
package net.Indyuce.mmocore.guild;
import net.Indyuce.mmocore.api.player.PlayerData;
public interface GuildModule {
public AbstractGuild getGuild(PlayerData playerData);
}

View File

@ -1,165 +1,164 @@
package net.Indyuce.mmocore.api.player.social.guilds;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.social.Request;
import net.Indyuce.mmocore.gui.api.PluginInventory;
import net.Indyuce.mmocore.gui.social.guild.EditableGuildView.GuildViewInventory;
import net.Indyuce.mmocore.manager.InventoryManager;
public class Guild {
private final GuildMembers members = new GuildMembers();
private final Map<UUID, Long> invites = new HashMap<>();
private final String guildId;
private final String guildName;
private final String guildTag;
/*
* owner changes when the old owner leaves guild
*/
private UUID owner;
public Guild(UUID owner, String name, String tag) {
this.owner = owner;
this.guildId = tag.toLowerCase();
this.guildName = name;
this.guildTag = tag;
}
public UUID getOwner() {
return owner;
}
public String getName() {
return guildName;
}
public String getId() {
return guildId;
}
public String getTag() {
return guildTag;
}
public GuildMembers getMembers() {
return members;
}
public long getLastInvite(Player player) {
return invites.containsKey(player.getUniqueId()) ? invites.get(player.getUniqueId()) : 0;
}
public void removeLastInvite(Player player) {
invites.remove(player.getUniqueId());
}
public void removeMember(UUID uuid)
{ removeMember(uuid, false); }
// Disband boolean is to prevent co-modification exception when disbanding a guild
public void removeMember(UUID uuid, boolean disband) {
PlayerData data = PlayerData.get(uuid);
if (data != null && data.isOnline() && data.getPlayer().getOpenInventory() != null && data.getPlayer().getOpenInventory().getTopInventory().getHolder() instanceof GuildViewInventory)
InventoryManager.GUILD_CREATION.newInventory(data).open();
if(!disband) members.remove(uuid);
if(data != null) data.setGuild(null);
reopenInventories();
//if(!disband) {
// disband the guild if no member left
if (members.count() < 1) {
MMOCore.plugin.dataProvider.getGuildManager().unregisterGuild(this);
return;
}
// transfer ownership
if (owner.equals(uuid)) {
owner = members.get(0);
MMOCore.plugin.configManager.getSimpleMessage("transfer-guild-ownership").send(Bukkit.getPlayer(owner));
}
//}
}
public void addMember(UUID uuid) {
PlayerData data = PlayerData.get(uuid);
if (data.inGuild())
data.getGuild().removeMember(uuid);
data.setGuild(this);
members.add(uuid);
reopenInventories();
}
public void registerMember(UUID uuid) {
members.add(uuid);
}
public void reopenInventories() {
for (UUID uuid : members.members) {
PlayerData member = PlayerData.get(uuid);
if (member != null && member.isOnline() && member.getPlayer().getOpenInventory() != null && member.getPlayer().getOpenInventory().getTopInventory().getHolder() instanceof GuildViewInventory)
((PluginInventory) member.getPlayer().getOpenInventory().getTopInventory().getHolder()).open();
}
}
public void sendGuildInvite(PlayerData inviter, PlayerData target) {
invites.put(target.getUniqueId(), System.currentTimeMillis());
Request request = new GuildInvite(this, inviter, target);
new ConfigMessage("guild-invite").addPlaceholders("player", inviter.getPlayer().getName(), "uuid", request.getUniqueId().toString()).sendAsJSon(target.getPlayer());
MMOCore.plugin.requestManager.registerRequest(request);
}
public static class GuildMembers {
private final List<UUID> members = new ArrayList<>();
public UUID get(int count) {
return members.get(count);
}
public boolean has(UUID player) {
return members.contains(player);
}
public void add(UUID player) {
members.add(player);
}
public void remove(UUID player) {
members.remove(player);
}
public void forEach(Consumer<? super UUID> action) {
members.forEach(action);
}
public int countOnline() {
int online = 0;
for(UUID member : members)
if(Bukkit.getOfflinePlayer(member).isOnline())
online += 1;
return online;
}
public int count()
{ return members.size(); }
public void clear()
{ members.clear(); }
}
}
package net.Indyuce.mmocore.guild.provided;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import net.Indyuce.mmocore.guild.AbstractGuild;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.social.Request;
import net.Indyuce.mmocore.gui.api.PluginInventory;
import net.Indyuce.mmocore.gui.social.guild.EditableGuildView.GuildViewInventory;
import net.Indyuce.mmocore.manager.InventoryManager;
public class Guild implements AbstractGuild {
private final GuildMembers members = new GuildMembers();
private final Map<UUID, Long> invites = new HashMap<>();
private final String guildId, guildName, guildTag;
/**
* Owner changes when the old owner leaves guild
*/
private UUID owner;
public Guild(UUID owner, String name, String tag) {
this.owner = owner;
this.guildId = tag.toLowerCase();
this.guildName = name;
this.guildTag = tag;
}
public UUID getOwner() {
return owner;
}
public String getName() {
return guildName;
}
public String getId() {
return guildId;
}
public String getTag() {
return guildTag;
}
public GuildMembers getMembers() {
return members;
}
public long getLastInvite(Player player) {
return invites.containsKey(player.getUniqueId()) ? invites.get(player.getUniqueId()) : 0;
}
public void removeLastInvite(Player player) {
invites.remove(player.getUniqueId());
}
public void removeMember(UUID uuid)
{ removeMember(uuid, false); }
// Disband boolean is to prevent co-modification exception when disbanding a guild
public void removeMember(UUID uuid, boolean disband) {
PlayerData data = PlayerData.get(uuid);
if (data != null && data.isOnline() && data.getPlayer().getOpenInventory() != null && data.getPlayer().getOpenInventory().getTopInventory().getHolder() instanceof GuildViewInventory)
InventoryManager.GUILD_CREATION.newInventory(data).open();
if(!disband) members.remove(uuid);
if(data != null) data.setGuild(null);
reopenInventories();
//if(!disband) {
// disband the guild if no member left
if (members.count() < 1) {
MMOCore.plugin.dataProvider.getGuildManager().unregisterGuild(this);
return;
}
// transfer ownership
if (owner.equals(uuid)) {
owner = members.get(0);
MMOCore.plugin.configManager.getSimpleMessage("transfer-guild-ownership").send(Bukkit.getPlayer(owner));
}
//}
}
public void addMember(UUID uuid) {
PlayerData data = PlayerData.get(uuid);
if (data.inGuild())
data.getGuild().removeMember(uuid);
data.setGuild(this);
members.add(uuid);
reopenInventories();
}
public void registerMember(UUID uuid) {
members.add(uuid);
}
public void reopenInventories() {
for (UUID uuid : members.members) {
PlayerData member = PlayerData.get(uuid);
if (member != null && member.isOnline() && member.getPlayer().getOpenInventory() != null && member.getPlayer().getOpenInventory().getTopInventory().getHolder() instanceof GuildViewInventory)
((PluginInventory) member.getPlayer().getOpenInventory().getTopInventory().getHolder()).open();
}
}
public void sendGuildInvite(PlayerData inviter, PlayerData target) {
invites.put(target.getUniqueId(), System.currentTimeMillis());
Request request = new GuildInvite(this, inviter, target);
new ConfigMessage("guild-invite").addPlaceholders("player", inviter.getPlayer().getName(), "uuid", request.getUniqueId().toString()).sendAsJSon(target.getPlayer());
MMOCore.plugin.requestManager.registerRequest(request);
}
public static class GuildMembers {
private final List<UUID> members = new ArrayList<>();
public UUID get(int count) {
return members.get(count);
}
public boolean has(UUID player) {
return members.contains(player);
}
public void add(UUID player) {
members.add(player);
}
public void remove(UUID player) {
members.remove(player);
}
public void forEach(Consumer<? super UUID> action) {
members.forEach(action);
}
public int countOnline() {
int online = 0;
for(UUID member : members)
if(Bukkit.getOfflinePlayer(member).isOnline())
online += 1;
return online;
}
public int count()
{ return members.size(); }
public void clear()
{ members.clear(); }
}
}

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmocore.api.player.social.guilds;
package net.Indyuce.mmocore.guild.provided;
import org.bukkit.Bukkit;

View File

@ -0,0 +1,13 @@
package net.Indyuce.mmocore.guild.provided;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.guild.AbstractGuild;
import net.Indyuce.mmocore.guild.GuildModule;
public class MMOCoreGuildModule implements GuildModule {
@Override
public AbstractGuild getGuild(PlayerData playerData) {
return playerData.getGuild();
}
}

View File

@ -7,6 +7,7 @@ import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.HandlerList;
@ -58,6 +59,18 @@ public class ExperienceManager implements MMOCoreManager {
return Objects.requireNonNull(expTables.get(id), "Could not find exp table with ID '" + id + "'");
}
@Deprecated
public ExperienceTable loadExperienceTable(Object obj) {
if (obj instanceof ConfigurationSection)
return new ExperienceTable((ConfigurationSection) obj);
if (obj instanceof String)
return MMOCore.plugin.experience.getTableOrThrow(obj.toString());
throw new IllegalArgumentException("Please provide either a string (exp table name) or a config section (locally define an exp table)");
}
public Collection<ExpCurve> getCurves() {
return expCurves.values();
}

View File

@ -1,14 +1,15 @@
package net.Indyuce.mmocore.manager.data;
/**
* Used to separate MySQL data storage from YAML data storage.
* <p>
* There is one data provider per storage mecanism (one for YAML, one for MySQL).
* A data provider provides corresponding MMOManagers to correctly save and load
* data
*/
public interface DataProvider {
/*
* used to separate MySQL data storage from YAML data storage. there is one
* dataProvider per storage mecanism (one for YAML, one for MySQL). a
* dataProvider provides corresponding mmoManagers to correctly save and load
* data
*/
PlayerDataManager getDataManager();
PlayerDataManager getDataManager();
GuildDataManager getGuildManager();
GuildDataManager getGuildManager();
}

View File

@ -9,7 +9,7 @@ import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.player.social.guilds.Guild;
import net.Indyuce.mmocore.guild.provided.Guild;
public abstract class GuildDataManager {
protected final Map<String, Guild> guilds = new HashMap<>();
@ -39,14 +39,6 @@ public abstract class GuildDataManager {
delete(guild);
}
// TODO has nothing to do here
public Guild stillInGuild(UUID uuid, String id) {
Guild guild = getGuild(id);
if (guild != null && guild.getMembers().has(uuid))
return guild;
return null;
}
public Guild getGuild(String guild) {
return guilds.get(guild);
}

View File

@ -138,7 +138,7 @@ public abstract class PlayerDataManager {
*/
public abstract void saveData(PlayerData data);
public static class DefaultPlayerData {
public class DefaultPlayerData {
private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints;
public DefaultPlayerData(ConfigurationSection config) {

View File

@ -1,49 +0,0 @@
package net.Indyuce.mmocore.manager.data.mysql;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.player.social.guilds.Guild;
import net.Indyuce.mmocore.manager.data.GuildDataManager;
public class MySQLGuildDataManager extends GuildDataManager {
@Override
public void save(Guild guild) {
ConfigFile config = new ConfigFile(guild);
config.getConfig().set("name", guild.getName());
config.getConfig().set("tag", guild.getTag());
config.getConfig().set("owner", guild.getOwner().toString());
List<String> memberList = new ArrayList<>();
guild.getMembers().forEach(uuid -> memberList.add(uuid.toString()));
config.getConfig().set("members", memberList);
config.save();
}
@Override
public void load() {
File guildsFolder = new File(MMOCore.plugin.getDataFolder(), "guilds");
if(!guildsFolder.exists()) guildsFolder.mkdirs();
for (File file : guildsFolder.listFiles()) {
if (!file.isDirectory() && file.getName().substring(file.getName().lastIndexOf('.')).equalsIgnoreCase(".yml")) {
FileConfiguration c = YamlConfiguration.loadConfiguration(file);
Guild guild = newRegisteredGuild(UUID.fromString(c.getString("owner")), c.getString("name"), c.getString("tag"));
for(String m : c.getStringList("members"))
guild.registerMember(UUID.fromString(m));
}
}
}
@Override
public void delete(Guild guild) {
new ConfigFile(guild).delete();
}
}

View File

@ -2,26 +2,22 @@ package net.Indyuce.mmocore.manager.data.mysql;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.OfflinePlayerData;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.PlayerDataManager;
import net.Indyuce.mmocore.manager.data.mysql.MySQLTableEditor.Table;
import io.lumine.mythic.lib.MythicLib;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.*;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.logging.Level;
import java.util.stream.Collectors;
@ -73,8 +69,10 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM));
}
if (!isEmpty(result.getString("guild")))
data.setGuild(MMOCore.plugin.dataProvider.getGuildManager().stillInGuild(data.getUniqueId(), result.getString("guild")));
if (!isEmpty(result.getString("guild"))) {
Guild guild = provider.getGuildManager().getGuild(result.getString("guild"));
data.setGuild(guild.getMembers().has(data.getUniqueId()) ? guild : null);
}
if (!isEmpty(result.getString("attributes"))) data.getAttributes().load(result.getString("attributes"));
if (!isEmpty(result.getString("professions")))
data.getCollectionSkills().load(result.getString("professions"));

View File

@ -5,7 +5,7 @@ import net.Indyuce.mmocore.manager.data.GuildDataManager;
import net.Indyuce.mmocore.manager.data.PlayerDataManager;
public class YAMLDataProvider implements DataProvider {
private final YAMLPlayerDataManager playerManager = new YAMLPlayerDataManager();
private final YAMLPlayerDataManager playerManager = new YAMLPlayerDataManager(this);
private final YAMLGuildDataManager guildManager = new YAMLGuildDataManager();
@Override

View File

@ -10,7 +10,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.player.social.guilds.Guild;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.GuildDataManager;
public class YAMLGuildDataManager extends GuildDataManager {

View File

@ -11,8 +11,8 @@ import net.Indyuce.mmocore.api.player.profess.PlayerClass;
public class YAMLOfflinePlayerData extends OfflinePlayerData {
private final ConfigFile config;
/*
* supports offline player data operations like friend removals which can't
/**
* Supports offline player data operations like friend removals which can't
* be handled when their player data is not loaded in the data map.
*/
public YAMLOfflinePlayerData(UUID uuid) {

View File

@ -1,14 +1,5 @@
package net.Indyuce.mmocore.manager.data.yaml;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.file.FileConfiguration;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.player.OfflinePlayerData;
@ -16,10 +7,25 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.DataProvider;
import net.Indyuce.mmocore.manager.data.PlayerDataManager;
import org.apache.commons.lang.Validate;
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.logging.Level;
import java.util.stream.Collectors;
public class YAMLPlayerDataManager extends PlayerDataManager {
private final DataProvider provider;
public YAMLPlayerDataManager(DataProvider provider) {
this.provider = provider;
}
@Override
public void loadData(PlayerData data) {
@ -40,8 +46,10 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM));
}
if (config.contains("guild"))
data.setGuild(MMOCore.plugin.dataProvider.getGuildManager().stillInGuild(data.getUniqueId(), config.getString("guild")));
if (config.contains("guild")) {
Guild guild = provider.getGuildManager().getGuild(config.getString("guild"));
data.setGuild(guild.getMembers().has(data.getUniqueId()) ? guild : null);
}
if (config.contains("attribute"))
data.getAttributes().load(config.getConfigurationSection("attribute"));
if (config.contains("profession"))

View File

@ -0,0 +1,48 @@
package net.Indyuce.mmocore.tree;
import org.apache.commons.lang.Validate;
import java.util.Objects;
public class IntegerCoordinates {
private final int x, y;
public IntegerCoordinates(int x, int y) {
this.x = x;
this.y = y;
}
@Deprecated
public IntegerCoordinates(String str) {
String[] split = str.split("\\.");
Validate.isTrue(split.length == 2, "Invalid format");
x = Integer.parseInt(split[0]);
y = Integer.parseInt(split[1]);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IntegerCoordinates that = (IntegerCoordinates) o;
return x == that.x && y == that.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
@Override
public String toString() {
return x + "." + y;
}
}

View File

@ -0,0 +1,71 @@
package net.Indyuce.mmocore.tree;
import net.Indyuce.mmocore.MMOCore;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
/**
* A passive skill tree that features nodes, or passive skills.
* <p>
* The player can explore the passive skill tree using the right GUI
* and unlock nodes by spending passive skill points. Unlocking nodes
* grant permanent player modifiers, including
* - stats
* - active or passive MythicLib skills
* - active or passive MMOCore skills
* - extra attribute pts
* - particle or potion effects
*
* @author jules
* @see {@link SkillTreeNode}
*/
public class SkillTree {
private final String id, name;
private final Map<IntegerCoordinates, SkillTreeNode> nodes = new HashMap<>();
public SkillTree(ConfigurationSection config) {
this.id = config.getName();
this.name = Objects.requireNonNull(config.getString("name"), "Could not find skill tree name");
Validate.isTrue(config.isConfigurationSection("nodes"), "Could not find tree passive skills");
for (String xKey : config.getConfigurationSection("nodes").getKeys(false))
for (String yKey : config.getConfigurationSection("nodes." + xKey).getKeys(false))
try {
int x = Integer.parseInt(xKey), y = Integer.parseInt(yKey);
SkillTreeNode node = new SkillTreeNode(this, x, y, config.getConfigurationSection("nodes." + xKey + "." + yKey));
nodes.put(node.getCoordinates(), node);
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load tree node '" + xKey + "." + yKey + "' for skill tree '" + id + "': " + exception.getMessage());
}
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public Collection<SkillTreeNode> getNodes() {
return nodes.values();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SkillTree skillTree = (SkillTree) o;
return id.equals(skillTree.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@ -0,0 +1,70 @@
package net.Indyuce.mmocore.tree;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.player.modifier.PlayerModifier;
import io.lumine.mythic.lib.util.configobject.ConfigSectionObject;
import net.Indyuce.mmocore.api.player.Unlockable;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class SkillTreeNode implements Unlockable {
private final SkillTree tree;
private final String name;
private final IntegerCoordinates coordinates;
private final List<String> lore;
private final Set<PlayerModifier> modifiers = new HashSet<>();
public SkillTreeNode(SkillTree tree, int x, int y, ConfigurationSection config) {
Validate.notNull(config, "Config cannot be null");
this.tree = tree;
name = Objects.requireNonNull(config.getString("name"), "Could not find node name");
coordinates = new IntegerCoordinates(x, y);
lore = config.getStringList("lore");
for (String key : config.getConfigurationSection("modifiers").getKeys(false)) {
PlayerModifier mod = MythicLib.plugin.getModifiers().loadPlayerModifier(new ConfigSectionObject(config.getConfigurationSection(key)));
modifiers.add(mod);
}
}
public String getName() {
return name;
}
public IntegerCoordinates getCoordinates() {
return coordinates;
}
public Set<PlayerModifier> getModifiers() {
return modifiers;
}
/**
* @return Uncolored lore with no placeholders
*/
public List<String> getLore() {
return lore;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SkillTreeNode that = (SkillTreeNode) o;
return tree.equals(that.tree) && coordinates.equals(that.coordinates);
}
@Override
public int hashCode() {
return Objects.hash(tree, coordinates);
}
@Override
public String getUnlockNamespacedKey() {
return "skill_tree:" + tree.getId() + "_" + coordinates.getX() + "_" + coordinates.getY();
}
}