forked from Upstream/mmocore
experience tables
This commit is contained in:
parent
0650138a77
commit
c1f3829e63
@ -11,7 +11,10 @@ import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
|
|||||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
|
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
|
||||||
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
|
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 net.Indyuce.mmocore.manager.SoundManager;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@ -26,6 +29,7 @@ import java.util.Map.Entry;
|
|||||||
public class PlayerProfessions {
|
public class PlayerProfessions {
|
||||||
private final Map<String, Integer> exp = new HashMap<>();
|
private final Map<String, Integer> exp = new HashMap<>();
|
||||||
private final Map<String, Integer> level = new HashMap<>();
|
private final Map<String, Integer> level = new HashMap<>();
|
||||||
|
private final Map<String, Integer> timesClaimed = new HashMap<>();
|
||||||
private final PlayerData playerData;
|
private final PlayerData playerData;
|
||||||
|
|
||||||
public PlayerProfessions(PlayerData playerData) {
|
public PlayerProfessions(PlayerData playerData) {
|
||||||
@ -39,6 +43,11 @@ public class PlayerProfessions {
|
|||||||
level.put(key, config.getInt(key + ".level"));
|
level.put(key, config.getInt(key + ".level"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +56,8 @@ public class PlayerProfessions {
|
|||||||
config.set(id + ".exp", exp.get(id));
|
config.set(id + ".exp", exp.get(id));
|
||||||
for (String id : level.keySet())
|
for (String id : level.keySet())
|
||||||
config.set(id + ".level", level.get(id));
|
config.set(id + ".level", level.get(id));
|
||||||
|
|
||||||
|
timesClaimed.forEach((key, value) -> config.set("times-claimed." + key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toJsonString() {
|
public String toJsonString() {
|
||||||
@ -58,18 +69,29 @@ public class PlayerProfessions {
|
|||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load(String json) {
|
public void load(String json) {
|
||||||
Gson parser = new Gson();
|
JsonObject obj = new Gson().fromJson(json, JsonObject.class);
|
||||||
JsonObject jo = parser.fromJson(json, JsonObject.class);
|
|
||||||
for (Entry<String, JsonElement> entry : jo.entrySet()) {
|
// Load profession exp and levels
|
||||||
|
for (Entry<String, JsonElement> entry : obj.entrySet())
|
||||||
if (MMOCore.plugin.professionManager.has(entry.getKey())) {
|
if (MMOCore.plugin.professionManager.has(entry.getKey())) {
|
||||||
exp.put(entry.getKey(), entry.getValue().getAsJsonObject().get("exp").getAsInt());
|
JsonObject value = entry.getValue().getAsJsonObject();
|
||||||
level.put(entry.getKey(), entry.getValue().getAsJsonObject().get("level").getAsInt());
|
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())
|
||||||
|
timesClaimed.put(entry.getKey(), entry.getValue().getAsInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerData getPlayerData() {
|
public PlayerData getPlayerData() {
|
||||||
@ -129,6 +151,8 @@ public class PlayerProfessions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
if (hasReachedMaxLevel(profession)) {
|
||||||
setExperience(profession, 0);
|
setExperience(profession, 0);
|
||||||
return;
|
return;
|
||||||
@ -137,7 +161,7 @@ public class PlayerProfessions {
|
|||||||
value = MMOCore.plugin.boosterManager.calculateExp(profession, value);
|
value = MMOCore.plugin.boosterManager.calculateExp(profession, value);
|
||||||
|
|
||||||
// display hologram
|
// display hologram
|
||||||
if (hologramLocation != null && playerData.isOnline())
|
if (hologramLocation != null )
|
||||||
MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", "" + value).message());
|
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);
|
PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(playerData, profession, (int) value, source);
|
||||||
@ -166,13 +190,17 @@ public class PlayerProfessions {
|
|||||||
playerData.giveExperience((int) profession.getExperience().calculate(level), null);
|
playerData.giveExperience((int) profession.getExperience().calculate(level), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check && playerData.isOnline()) {
|
if (check) {
|
||||||
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level));
|
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level));
|
||||||
new SmallParticleEffect(playerData.getPlayer(), Particle.SPELL_INSTANT);
|
new SmallParticleEffect(playerData.getPlayer(), Particle.SPELL_INSTANT);
|
||||||
new ConfigMessage("profession-level-up").addPlaceholders("level", "" + level, "profession", profession.getName())
|
new ConfigMessage("profession-level-up").addPlaceholders("level", "" + level, "profession", profession.getName())
|
||||||
.send(playerData.getPlayer());
|
.send(playerData.getPlayer());
|
||||||
MMOCore.plugin.soundManager.play(playerData.getPlayer(), SoundManager.SoundEvent.LEVEL_UP);
|
MMOCore.plugin.soundManager.play(playerData.getPlayer(), SoundManager.SoundEvent.LEVEL_UP);
|
||||||
playerData.getStats().updateStats();
|
playerData.getStats().updateStats();
|
||||||
|
|
||||||
|
// Apply profession experience table
|
||||||
|
if (profession.hasExperienceTable())
|
||||||
|
profession.getExperienceTable().claim(playerData, level, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder bar = new StringBuilder("" + ChatColor.BOLD);
|
StringBuilder bar = new StringBuilder("" + ChatColor.BOLD);
|
||||||
@ -183,4 +211,20 @@ public class PlayerProfessions {
|
|||||||
MMOCore.plugin.configManager.getSimpleMessage("exp-notification", "profession", profession.getName(), "progress", bar.toString(), "ratio",
|
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());
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,55 @@
|
|||||||
package net.Indyuce.mmocore.experience;
|
package net.Indyuce.mmocore.experience;
|
||||||
|
|
||||||
import io.lumine.mythic.lib.MythicLib;
|
|
||||||
import io.lumine.mythic.lib.api.MMOLineConfig;
|
import io.lumine.mythic.lib.api.MMOLineConfig;
|
||||||
import io.lumine.mythic.lib.api.util.PostLoadObject;
|
import io.lumine.mythic.lib.api.util.PostLoadObject;
|
||||||
import net.Indyuce.mmocore.MMOCore;
|
import net.Indyuce.mmocore.MMOCore;
|
||||||
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
|
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
|
||||||
|
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
|
||||||
import net.Indyuce.mmocore.experience.provider.ExperienceDispenser;
|
import net.Indyuce.mmocore.experience.provider.ExperienceDispenser;
|
||||||
import net.Indyuce.mmocore.experience.provider.ProfessionExperienceDispenser;
|
import net.Indyuce.mmocore.experience.provider.ProfessionExperienceDispenser;
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
|
||||||
import org.bukkit.potion.PotionType;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class Profession extends PostLoadObject {
|
public class Profession {
|
||||||
private final String id, name;
|
private final String id, name;
|
||||||
private final ExpCurve expCurve;
|
private final ExpCurve expCurve;
|
||||||
private final int maxLevel;
|
private final int maxLevel;
|
||||||
private final Map<ProfessionOption, Boolean> options = new HashMap<>();
|
private final Map<ProfessionOption, Boolean> options = new HashMap<>();
|
||||||
|
private final ExperienceTable expTable;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* experience given to the main player level whenever he levels up this
|
* Experience given to the main player level whenever he levels up this profession
|
||||||
* profession
|
*
|
||||||
|
* @deprecated Being replaced by {@link ExperienceTable}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
private final LinearValue experience;
|
private final LinearValue experience;
|
||||||
|
|
||||||
public Profession(String id, FileConfiguration config) {
|
public Profession(String id, FileConfiguration config) {
|
||||||
super(config);
|
|
||||||
|
|
||||||
this.id = id.toLowerCase().replace("_", "-").replace(" ", "-");
|
this.id = id.toLowerCase().replace("_", "-").replace(" ", "-");
|
||||||
this.name = config.getString("name");
|
this.name = config.getString("name");
|
||||||
Validate.notNull(name, "Could not load name");
|
Validate.notNull(name, "Could not load name");
|
||||||
|
|
||||||
expCurve = config.contains("exp-curve")
|
expCurve = config.contains("exp-curve")
|
||||||
? MMOCore.plugin.experience.getOrThrow(config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-"))
|
? MMOCore.plugin.experience.getCurveOrThrow(config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-"))
|
||||||
: ExpCurve.DEFAULT;
|
: ExpCurve.DEFAULT;
|
||||||
experience = new LinearValue(config.getConfigurationSection("experience"));
|
experience = new LinearValue(config.getConfigurationSection("experience"));
|
||||||
|
|
||||||
|
ExperienceTable expTable = null;
|
||||||
|
if (config.contains("exp-table"))
|
||||||
|
try {
|
||||||
|
expTable = loadExperienceTable(config.get("exp-table"));
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table from profession '" + id + "': " + exception.getMessage());
|
||||||
|
}
|
||||||
|
this.expTable = expTable;
|
||||||
|
|
||||||
if (config.contains("options"))
|
if (config.contains("options"))
|
||||||
for (String key : config.getConfigurationSection("options").getKeys(false))
|
for (String key : config.getConfigurationSection("options").getKeys(false))
|
||||||
try {
|
try {
|
||||||
@ -59,71 +66,25 @@ public class Profession extends PostLoadObject {
|
|||||||
ExperienceDispenser dispenser = new ProfessionExperienceDispenser(this);
|
ExperienceDispenser dispenser = new ProfessionExperienceDispenser(this);
|
||||||
for (String key : config.getStringList("exp-sources"))
|
for (String key : config.getStringList("exp-sources"))
|
||||||
try {
|
try {
|
||||||
MMOCore.plugin.professionManager.registerExpSource(MMOCore.plugin.loadManager.loadExperienceSource(new MMOLineConfig(key), dispenser));
|
MMOCore.plugin.experience.registerSource(MMOCore.plugin.loadManager.loadExperienceSource(new MMOLineConfig(key), dispenser));
|
||||||
} catch (IllegalArgumentException exception) {
|
} catch (IllegalArgumentException exception) {
|
||||||
MMOCore.plugin.getLogger().log(Level.WARNING,
|
MMOCore.plugin.getLogger().log(Level.WARNING,
|
||||||
"Could not register exp source '" + key + "' from profession '" + id + "': " + exception.getMessage());
|
"Could not register exp source '" + key + "' from profession '" + id + "': " + exception.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MMOCore.plugin.professionManager.loadProfessionConfigurations(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
private ExperienceTable loadExperienceTable(Object obj) {
|
||||||
* drop tables must be loaded after professions are initialized
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void whenPostLoaded(ConfigurationSection config) {
|
|
||||||
|
|
||||||
if (config.contains("on-fish"))
|
if (obj instanceof ConfigurationSection)
|
||||||
MMOCore.plugin.fishingManager.loadDropTables(config.getConfigurationSection("on-fish"));
|
return new ExperienceTable((ConfigurationSection) obj);
|
||||||
|
|
||||||
if (config.contains("on-mine"))
|
if (obj instanceof String)
|
||||||
MMOCore.plugin.mineManager.loadDropTables(config.getConfigurationSection("on-mine"));
|
return MMOCore.plugin.experience.getTableOrThrow(obj.toString());
|
||||||
|
|
||||||
if (config.contains("alchemy-experience")) {
|
throw new IllegalArgumentException("Please provide either a string (exp table name) or a config section (locally define an exp table)");
|
||||||
|
|
||||||
MMOCore.plugin.alchemyManager.splash = 1 + config.getDouble("alchemy-experience.special.splash") / 100;
|
|
||||||
MMOCore.plugin.alchemyManager.lingering = 1 + config.getDouble("alchemy-experience.special.lingering") / 100;
|
|
||||||
MMOCore.plugin.alchemyManager.extend = 1 + config.getDouble("alchemy-experience.special.extend") / 100;
|
|
||||||
MMOCore.plugin.alchemyManager.upgrade = 1 + config.getDouble("alchemy-experience.special.upgrade") / 100;
|
|
||||||
|
|
||||||
for (String key : config.getConfigurationSection("alchemy-experience.effects").getKeys(false))
|
|
||||||
try {
|
|
||||||
PotionType type = PotionType.valueOf(key.toUpperCase().replace("-", "_").replace(" ", "_"));
|
|
||||||
MMOCore.plugin.alchemyManager.registerBaseExperience(type, config.getDouble("alchemy-experience.effects." + key));
|
|
||||||
} catch (IllegalArgumentException exception) {
|
|
||||||
MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not read potion type from " + key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.contains("base-enchant-exp"))
|
|
||||||
for (String key : config.getConfigurationSection("base-enchant-exp").getKeys(false))
|
|
||||||
try {
|
|
||||||
Enchantment enchant = MythicLib.plugin.getVersion().getWrapper().getEnchantmentFromString(key.toLowerCase().replace("-", "_"));
|
|
||||||
MMOCore.plugin.enchantManager.registerBaseExperience(enchant, config.getDouble("base-enchant-exp." + key));
|
|
||||||
} catch (IllegalArgumentException exception) {
|
|
||||||
MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not read enchant from " + key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.contains("repair-exp"))
|
|
||||||
for (String key : config.getConfigurationSection("repair-exp").getKeys(false))
|
|
||||||
try {
|
|
||||||
Material material = Material.valueOf(key.toUpperCase().replace("-", "_").replace(" ", "_"));
|
|
||||||
MMOCore.plugin.smithingManager.registerBaseExperience(material, config.getDouble("repair-exp." + key));
|
|
||||||
} catch (IllegalArgumentException exception) {
|
|
||||||
MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not read material from " + key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (config.contains("effect-weight"))
|
|
||||||
// for (String key :
|
|
||||||
// config.getConfigurationSection("effect-weight").getKeys(false))
|
|
||||||
// try {
|
|
||||||
// MMOCore.plugin.alchemyManager.registerEffectWeight(PotionEffectType.getByName(key.toUpperCase().replace("-",
|
|
||||||
// "_").replace(" ", "_")), config.getDouble("effect-weight." + key));
|
|
||||||
// } catch (IllegalArgumentException exception) {
|
|
||||||
// MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not
|
|
||||||
// read
|
|
||||||
// potion effect type from " + key);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getOption(ProfessionOption option) {
|
public boolean getOption(ProfessionOption option) {
|
||||||
@ -158,6 +119,14 @@ public class Profession extends PostLoadObject {
|
|||||||
return experience;
|
return experience;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasExperienceTable() {
|
||||||
|
return expTable != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExperienceTable getExperienceTable() {
|
||||||
|
return Objects.requireNonNull(expTable, "Profession has no exp table");
|
||||||
|
}
|
||||||
|
|
||||||
public static enum ProfessionOption {
|
public static enum ProfessionOption {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package net.Indyuce.mmocore.experience.droptable;
|
||||||
|
|
||||||
|
import io.lumine.mythic.lib.api.MMOLineConfig;
|
||||||
|
import net.Indyuce.mmocore.MMOCore;
|
||||||
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
|
import net.Indyuce.mmocore.api.quest.trigger.Trigger;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class ExperienceItem {
|
||||||
|
private final String id;
|
||||||
|
private final int period;
|
||||||
|
private final double claimChance, failReduction;
|
||||||
|
private final List<Trigger> triggers;
|
||||||
|
|
||||||
|
private static final Random random = new Random();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One item for an experience table
|
||||||
|
*
|
||||||
|
* @param period The experience item is claimed every X level ups
|
||||||
|
* @param claimChance Chance for that item to be claimed every X level ups
|
||||||
|
* @param failReduction Between 0 and 1, by how much the fail chance is reduced
|
||||||
|
* every time the item is not claimed when leveling up.
|
||||||
|
* <p>
|
||||||
|
* Failing chance follows a geometric sequence therefore
|
||||||
|
* <code>successChance = 1 - (1 - initialSuccessChance) * failReduction^n</code>
|
||||||
|
* where n is the amount of successive claiming fails
|
||||||
|
* @param triggers Actions cast when the exp item is claimed
|
||||||
|
*/
|
||||||
|
public ExperienceItem(String id, int period, double claimChance, double failReduction, List<Trigger> triggers) {
|
||||||
|
this.id = id;
|
||||||
|
this.period = period;
|
||||||
|
this.claimChance = claimChance;
|
||||||
|
this.failReduction = failReduction;
|
||||||
|
this.triggers = triggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExperienceItem(ConfigurationSection config) {
|
||||||
|
Validate.notNull(config, "Config cannot be null");
|
||||||
|
Validate.isTrue(config.contains("triggers"));
|
||||||
|
id = config.getName();
|
||||||
|
period = config.getInt("period", 1);
|
||||||
|
claimChance = config.getDouble("chance", 100) / 100;
|
||||||
|
failReduction = config.getDouble("fail-reduction", 80) / 100;
|
||||||
|
triggers = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String triggerFormat : config.getStringList("triggers"))
|
||||||
|
triggers.add(MMOCore.plugin.loadManager.loadTrigger(new MMOLineConfig(triggerFormat)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param professionLevel The profession level the player just reached
|
||||||
|
* @param timesCollected Amount of times the exp item has already been claimed by the player
|
||||||
|
* @return If the item should be claimed right now taking into
|
||||||
|
* account the randomness factor from the 'chance' parameter
|
||||||
|
*/
|
||||||
|
public boolean roll(int professionLevel, int timesCollected) {
|
||||||
|
int claimsRequired = professionLevel - (timesCollected + 1) * period;
|
||||||
|
if (claimsRequired < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double chance = 1 - (1 - claimChance) * Math.pow(failReduction, claimsRequired);
|
||||||
|
return random.nextDouble() < chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyTriggers(PlayerData levelingUp) {
|
||||||
|
for (Trigger trigger : triggers)
|
||||||
|
trigger.apply(levelingUp);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
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 org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class ExperienceTable {
|
||||||
|
private final String id;
|
||||||
|
private final List<ExperienceItem> items = new ArrayList<>();
|
||||||
|
|
||||||
|
public ExperienceTable(ConfigurationSection config) {
|
||||||
|
Validate.notNull(config, "Config cannot be null");
|
||||||
|
id = config.getName();
|
||||||
|
|
||||||
|
for (String str : config.getKeys(false))
|
||||||
|
try {
|
||||||
|
Validate.isTrue(config.isConfigurationSection(str), "Key '" + str + "' is not a configuration section");
|
||||||
|
items.add(new ExperienceItem(config.getConfigurationSection(str)));
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load item '" + str + "' from experience table '" + id + "': " + exception.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ExperienceItem> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a player levels up one of his professions
|
||||||
|
*
|
||||||
|
* @param levelingUp Player leveling up
|
||||||
|
* @param professionLevel New profession level
|
||||||
|
* @param professionData Player profession data
|
||||||
|
*/
|
||||||
|
public void claim(PlayerData levelingUp, int professionLevel, PlayerProfessions professionData) {
|
||||||
|
for (ExperienceItem item : items) {
|
||||||
|
int timesClaimed = professionData.getTimesClaimed(this, item);
|
||||||
|
if (!item.roll(professionLevel, timesClaimed))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
professionData.setTimesClaimed(this, item, timesClaimed + 1);
|
||||||
|
item.applyTriggers(levelingUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -86,6 +86,7 @@ public class ConfigManager {
|
|||||||
loadDefaultFile("sounds.yml");
|
loadDefaultFile("sounds.yml");
|
||||||
loadDefaultFile("loot-chests.yml");
|
loadDefaultFile("loot-chests.yml");
|
||||||
loadDefaultFile("commands.yml");
|
loadDefaultFile("commands.yml");
|
||||||
|
loadDefaultFile("exp-tables.yml");
|
||||||
loadDefaultFile("guilds.yml");
|
loadDefaultFile("guilds.yml");
|
||||||
|
|
||||||
commandVerbose.reload(MMOCore.plugin.getConfig().getConfigurationSection("command-verbose"));
|
commandVerbose.reload(MMOCore.plugin.getConfig().getConfigurationSection("command-verbose"));
|
||||||
|
@ -1,38 +1,81 @@
|
|||||||
package net.Indyuce.mmocore.manager;
|
package net.Indyuce.mmocore.manager;
|
||||||
|
|
||||||
|
import net.Indyuce.mmocore.MMOCore;
|
||||||
|
import net.Indyuce.mmocore.api.ConfigFile;
|
||||||
|
import net.Indyuce.mmocore.experience.ExpCurve;
|
||||||
|
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.file.FileConfiguration;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
public class ExperienceManager implements MMOCoreManager {
|
||||||
|
|
||||||
import net.Indyuce.mmocore.MMOCore;
|
|
||||||
import net.Indyuce.mmocore.experience.ExpCurve;
|
|
||||||
|
|
||||||
public class ExperienceManager {
|
|
||||||
private final Map<String, ExpCurve> expCurves = new HashMap<>();
|
private final Map<String, ExpCurve> expCurves = new HashMap<>();
|
||||||
|
private final Map<String, ExperienceTable> expTables = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves different experience sources based on experience source type.
|
||||||
|
*/
|
||||||
|
private final Map<Class<?>, ExperienceSourceManager<?>> managers = new HashMap<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends ExperienceSource> ExperienceSourceManager<T> getManager(Class<T> t) {
|
||||||
|
return (ExperienceSourceManager<T>) managers.get(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends ExperienceSource> void registerSource(T source) {
|
||||||
|
Class<T> path = (Class<T>) source.getClass();
|
||||||
|
|
||||||
|
if (!managers.containsKey(path))
|
||||||
|
managers.put(path, source.newManager());
|
||||||
|
getManager(path).registerSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasCurve(String id) {
|
public boolean hasCurve(String id) {
|
||||||
return expCurves.containsKey(id);
|
return expCurves.containsKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpCurve getOrThrow(String id) {
|
public ExpCurve getCurveOrThrow(String id) {
|
||||||
Validate.isTrue(hasCurve(id), "Could not find exp curve with ID '" + id + "'");
|
Validate.isTrue(hasCurve(id), "Could not find exp curve with ID '" + id + "'");
|
||||||
return expCurves.get(id);
|
return expCurves.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpCurve getCurve(String id) {
|
public boolean hasTable(String id) {
|
||||||
return expCurves.get(id);
|
return expTables.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExperienceTable getTableOrThrow(String id) {
|
||||||
|
return Objects.requireNonNull(expTables.get(id), "Could not find exp table with ID '" + id + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<ExpCurve> getCurves() {
|
public Collection<ExpCurve> getCurves() {
|
||||||
return expCurves.values();
|
return expCurves.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reload() {
|
public Collection<ExperienceTable> getTables() {
|
||||||
|
return expTables.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(boolean clearBefore) {
|
||||||
|
if (clearBefore) {
|
||||||
|
expCurves.clear();
|
||||||
|
expTables.clear();
|
||||||
|
|
||||||
|
managers.values().forEach(HandlerList::unregisterAll);
|
||||||
|
managers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
expCurves.clear();
|
expCurves.clear();
|
||||||
for (File file : new File(MMOCore.plugin.getDataFolder() + "/expcurves").listFiles())
|
for (File file : new File(MMOCore.plugin.getDataFolder() + "/expcurves").listFiles())
|
||||||
try {
|
try {
|
||||||
@ -41,5 +84,15 @@ public class ExperienceManager {
|
|||||||
} catch (IllegalArgumentException | IOException exception) {
|
} catch (IllegalArgumentException | IOException exception) {
|
||||||
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp curve '" + file.getName() + "': " + exception.getMessage());
|
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp curve '" + file.getName() + "': " + exception.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expTables.clear();
|
||||||
|
FileConfiguration expTablesConfig = new ConfigFile("exp-tables").getConfig();
|
||||||
|
for (String key : expTablesConfig.getKeys(false))
|
||||||
|
try {
|
||||||
|
ExperienceTable table = new ExperienceTable(expTablesConfig.getConfigurationSection(key));
|
||||||
|
expTables.put(table.getId(), table);
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table '" + key + "': " + exception.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package net.Indyuce.mmocore.manager;
|
||||||
|
|
||||||
|
public interface MMOCoreManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called either when the server starts when initializing the manager for
|
||||||
|
* the first time, or when issuing a plugin reload; in that case, stuff
|
||||||
|
* like listeners must all be cleared before
|
||||||
|
*
|
||||||
|
* @param clearBefore True when issuing a plugin reload
|
||||||
|
*/
|
||||||
|
void initialize(boolean clearBefore);
|
||||||
|
}
|
46
src/main/resources/default/exp-tables.yml
Normal file
46
src/main/resources/default/exp-tables.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
example_exp_table:
|
||||||
|
first_table_item:
|
||||||
|
|
||||||
|
# This item will drop every 3 level ups
|
||||||
|
period: 3
|
||||||
|
|
||||||
|
# This item has a 80% chance to drop every 3 level ups
|
||||||
|
chance: 80
|
||||||
|
|
||||||
|
# Every successive fail in claiming the item will reduce
|
||||||
|
# the risk of failing future claims by X%. With a 80%
|
||||||
|
# fail reduction rate, chances become:
|
||||||
|
# - 80%
|
||||||
|
# - 96%
|
||||||
|
# - 99.2%
|
||||||
|
# - 99.84%
|
||||||
|
# so on forever..
|
||||||
|
#
|
||||||
|
# This is better than just increasing the claim chance by a
|
||||||
|
# certain amount each time because otherwise the claim chance
|
||||||
|
# just becomes/surpasses 100% at some point.
|
||||||
|
fail-reduction: 80
|
||||||
|
|
||||||
|
# What happens when that item is claimed
|
||||||
|
triggers:
|
||||||
|
- 'exp{amount=20}'
|
||||||
|
|
||||||
|
second_table_item:
|
||||||
|
period: 2
|
||||||
|
triggers:
|
||||||
|
- 'exp{amount=80}'
|
||||||
|
- 'command{format="broadcast Boy, %player_name% level up twice in one of his(her) professions!"}'
|
||||||
|
|
||||||
|
second_exp_table:
|
||||||
|
|
||||||
|
# Base exp every level up, sweet.
|
||||||
|
some_item:
|
||||||
|
period: 1
|
||||||
|
triggers:
|
||||||
|
- 'exp{amount=100}'
|
||||||
|
|
||||||
|
# Extra exp every 3 levels
|
||||||
|
some_other_item:
|
||||||
|
period: 3
|
||||||
|
triggers:
|
||||||
|
- 'exp{amount=100}'
|
Loading…
Reference in New Issue
Block a user