!support for player mods

This commit is contained in:
Indyuce 2022-01-15 18:34:54 +01:00
parent 46313abe3e
commit 0e6131b7e6
14 changed files with 189 additions and 71 deletions

View File

@ -125,7 +125,7 @@
<dependency>
<groupId>io.lumine</groupId>
<artifactId>MythicLib-dist</artifactId>
<version>1.3-R11</version>
<version>1.3</version>
<scope>provided</scope>
</dependency>

View File

@ -89,7 +89,7 @@ public class MMOCore extends LuminePlugin {
public boolean shouldDebugSQL = false;
private static final int MYTHICLIB_COMPATIBILITY_INDEX = 2;
private static final int MYTHICLIB_COMPATIBILITY_INDEX = 3;
public MMOCore() {
plugin = this;
@ -350,7 +350,8 @@ public class MMOCore extends LuminePlugin {
configManager = new ConfigManager();
//MythicLib.plugin.getSkills().initialize(clearBefore);
if (clearBefore)
MythicLib.plugin.getSkills().initialize(true);
skillManager.initialize(clearBefore);
mineManager.initialize(clearBefore);
partyManager.initialize(clearBefore);

View File

@ -0,0 +1,122 @@
package net.Indyuce.mmocore.api.player.attribute;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import io.lumine.mythic.lib.player.modifier.PlayerModifier;
import io.lumine.mythic.lib.util.configobject.ConfigObject;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate;
import java.text.DecimalFormat;
public class AttributeModifier extends PlayerModifier {
private final String attribute;
private final double value;
private final ModifierType type;
private static final DecimalFormat oneDigit = MythicLib.plugin.getMMOConfig().newDecimalFormat("0.#");
/**
* Flat attribute modifier (simplest modifier you can think about)
*/
public AttributeModifier(String key, String attribute, double value) {
this(key, attribute, value, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER);
}
/**
* Attribute modifier given by an external mecanic, like a party buff, item set bonuses,
* skills or abilities... Anything apart from items and armor.
*/
public AttributeModifier(String key, String attribute, double value, ModifierType type) {
this(key, attribute, value, type, EquipmentSlot.OTHER, ModifierSource.OTHER);
}
/**
* Attribute modifier given by an item, either a weapon or an armor piece.
*
* @param key Player modifier key
* @param attribute Attribute being modified
* @param value Value of stat modifier
* @param type Is the modifier flat or multiplicative
* @param slot Slot of the item granting the stat modifier
* @param source Type of the item granting the stat modifier
*/
public AttributeModifier(String key, String attribute, double value, ModifierType type, EquipmentSlot slot, ModifierSource source) {
super(key, slot, source);
this.attribute = attribute;
this.value = value;
this.type = type;
}
/**
* Used to parse a StatModifier from a string in a configuration section.
* Always returns a modifier with source OTHER. Can be used by MythicCore
* to handle party buffs, or MMOItems for item set bonuses. Throws IAE
*
* @param str The string to be parsed
*/
public AttributeModifier(String key, String attribute, String str) {
super(key, EquipmentSlot.OTHER, ModifierSource.OTHER);
Validate.notNull(str, "String cannot be null");
Validate.notEmpty(str, "String cannot be empty");
type = str.toCharArray()[str.length() - 1] == '%' ? io.lumine.mythic.lib.player.modifier.ModifierType.RELATIVE : io.lumine.mythic.lib.player.modifier.ModifierType.FLAT;
value = Double.parseDouble(type == io.lumine.mythic.lib.player.modifier.ModifierType.RELATIVE ? str.substring(0, str.length() - 1) : str);
this.attribute = attribute;
}
public AttributeModifier(ConfigObject object) {
super(object.getString("key"), EquipmentSlot.OTHER, ModifierSource.OTHER);
this.attribute = object.getString("attribute");
this.value = object.getDouble("value");
type = object.getBoolean("multiplicative", false) ? io.lumine.mythic.lib.player.modifier.ModifierType.RELATIVE : io.lumine.mythic.lib.player.modifier.ModifierType.FLAT;
}
public String getAttribute() {
return attribute;
}
public ModifierType getType() {
return type;
}
public double getValue() {
return value;
}
/**
* Used to multiply some existing stat modifier by a constant, usually an
* integer, for instance when MMOCore party modifiers scale with the
* number of the party member count
*
* @param coef The multiplicative constant
* @return A new instance of StatModifier with modified value
*/
public StatModifier multiply(double coef) {
return new StatModifier(getKey(), attribute, value * coef, type, getSlot(), getSource());
}
@Override
public void register(MMOPlayerData mmoPlayerData) {
PlayerData playerData = PlayerData.get(mmoPlayerData.getUniqueId());
playerData.getAttributes().getInstance(attribute).addModifier(this);
}
@Override
public void unregister(MMOPlayerData mmoPlayerData) {
PlayerData playerData = PlayerData.get(mmoPlayerData.getUniqueId());
playerData.getAttributes().getInstance(attribute).removeModifier(getKey());
}
@Override
public String toString() {
return oneDigit.format(value) + (type == io.lumine.mythic.lib.player.modifier.ModifierType.RELATIVE ? "%" : "");
}
}

View File

@ -6,19 +6,19 @@ import net.Indyuce.mmocore.MMOCore;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import java.util.HashMap;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
public class PlayerAttribute {
private final String id, name;
private final int max;
/*
* used to store stats using StatType, but attributes also need to access
/**
* Used to store stats using StatType, but attributes also need to access
* non basic MMOCore stats hence the string maps keys
*/
private final Map<String, StatModifier> buffs = new HashMap<>();
private final Set<StatModifier> buffs = new HashSet<>();
public PlayerAttribute(ConfigurationSection config) {
Validate.notNull(config, "Could not load config");
@ -31,7 +31,7 @@ public class PlayerAttribute {
for (String key : config.getConfigurationSection("buff").getKeys(false))
try {
String stat = key.toUpperCase().replace("-", "_").replace(" ", "_");
buffs.put(stat, new StatModifier(config.getString("buff." + key)));
buffs.add(new StatModifier("attribute." + id, stat, config.getString("buff." + key)));
} catch (IllegalArgumentException exception) {
MMOCore.log(Level.WARNING, "Could not load buff '" + key + "' from attribute '" + id + "': " + exception.getMessage());
}
@ -53,7 +53,7 @@ public class PlayerAttribute {
return max;
}
public Map<String, StatModifier> getBuffs() {
public Set<StatModifier> getBuffs() {
return buffs;
}
}

View File

@ -3,9 +3,10 @@ package net.Indyuce.mmocore.api.player.attribute;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.api.stat.modifier.Closable;
import io.lumine.mythic.lib.api.stat.modifier.ModifierType;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.player.modifier.Closeable;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate;
@ -33,7 +34,7 @@ public class PlayerAttributes {
Validate.isTrue(MMOCore.plugin.attributeManager.has(id), "Could not find attribute '" + id + "'");
PlayerAttribute attribute = MMOCore.plugin.attributeManager.get(id);
AttributeInstance ins = new AttributeInstance(attribute);
AttributeInstance ins = new AttributeInstance(attribute.getId());
ins.setBase(config.getInt(key));
instances.put(id, ins);
} catch (IllegalArgumentException exception) {
@ -61,7 +62,7 @@ public class PlayerAttributes {
Validate.isTrue(MMOCore.plugin.attributeManager.has(id), "Could not find attribute '" + id + "'");
PlayerAttribute attribute = MMOCore.plugin.attributeManager.get(id);
AttributeInstance ins = new AttributeInstance(attribute);
AttributeInstance ins = new AttributeInstance(attribute.getId());
ins.setBase(entry.getValue().getAsInt());
instances.put(id, ins);
} catch (IllegalArgumentException exception) {
@ -88,15 +89,19 @@ public class PlayerAttributes {
return map;
}
public AttributeInstance getInstance(PlayerAttribute attribute) {
if (instances.containsKey(attribute.getId()))
return instances.get(attribute.getId());
public AttributeInstance getInstance(String attribute) {
if (instances.containsKey(attribute))
return instances.get(attribute);
AttributeInstance ins = new AttributeInstance(attribute);
instances.put(attribute.getId(), ins);
instances.put(attribute, ins);
return ins;
}
public AttributeInstance getInstance(PlayerAttribute attribute) {
return getInstance(attribute.getId());
}
public int countSkillPoints() {
int n = 0;
for (AttributeInstance ins : instances.values())
@ -108,10 +113,10 @@ public class PlayerAttributes {
private int spent;
private final String id;
private final Map<String, StatModifier> map = new HashMap<>();
private final Map<String, AttributeModifier> map = new HashMap<>();
public AttributeInstance(PlayerAttribute attribute) {
id = attribute.getId();
public AttributeInstance(String attribute) {
id = attribute;
}
public int getBase() {
@ -138,11 +143,11 @@ public class PlayerAttributes {
public int getTotal() {
double d = spent;
for (StatModifier attr : map.values())
for (AttributeModifier attr : map.values())
if (attr.getType() == ModifierType.FLAT)
d += attr.getValue();
for (StatModifier attr : map.values())
for (AttributeModifier attr : map.values())
if (attr.getType() == ModifierType.RELATIVE)
d *= attr.getValue();
@ -150,16 +155,16 @@ public class PlayerAttributes {
return (int) d;
}
public StatModifier getModifier(String key) {
public AttributeModifier getModifier(String key) {
return map.get(key);
}
public void addModifier(String key, double value) {
addModifier(key, new StatModifier(value));
addModifier(new AttributeModifier(key, id, value, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER));
}
public void addModifier(String key, StatModifier modifier) {
map.put(key, modifier);
public void addModifier(AttributeModifier modifier) {
map.put(modifier.getKey(), modifier);
update();
}
@ -172,27 +177,25 @@ public class PlayerAttributes {
return map.containsKey(key);
}
public void remove(String key) {
public void removeModifier(String key) {
AttributeModifier mod = map.remove(key);
/*
* closing stat is really important with temporary stats because
* Closing stat is really important with temporary stats because
* otherwise the runnable will try to remove the key from the map
* even though the attribute was cancelled before hand
*/
StatModifier mod;
if (map.containsKey(key) && (mod = map.get(key)) instanceof Closable) {
((Closable) mod).close();
map.remove(key);
if (mod != null) {
if (mod instanceof Closeable)
((Closeable) mod).close();
update();
}
update();
}
public void update() {
PlayerAttribute attribute = MMOCore.plugin.attributeManager.get(id);
int total = getTotal();
attribute.getBuffs()
.forEach((key, buff) -> data.getStats().getInstance(key).addModifier("attribute." + attribute.getId(), buff.multiply(total)));
attribute.getBuffs().forEach(buff -> buff.multiply(total).register(data.getMMOPlayerData()));
}
public String getId() {

View File

@ -151,12 +151,11 @@ public class Party {
}
private void applyAttributes(PlayerData player) {
MMOCore.plugin.partyManager.getBonuses().forEach(stat -> player.getStats().getInstance(stat).addModifier("mmocoreParty",
MMOCore.plugin.partyManager.getBonus(stat).multiply(members.size() - 1)));
MMOCore.plugin.partyManager.getBonuses().forEach(buff -> buff.multiply(members.size() - 1).register(player.getMMOPlayerData()));
}
private void clearAttributes(PlayerData player) {
MMOCore.plugin.partyManager.getBonuses().forEach(stat -> player.getStats().getInstance(stat).remove("mmocoreParty"));
MMOCore.plugin.partyManager.getBonuses().forEach(buff -> player.getStats().getInstance(buff.getStat()).remove("mmocoreParty"));
}
}
}

View File

@ -3,9 +3,9 @@ package net.Indyuce.mmocore.api.player.stats;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.stat.StatInstance;
import io.lumine.mythic.lib.api.stat.StatMap;
import io.lumine.mythic.lib.api.stat.modifier.ModifierSource;
import io.lumine.mythic.lib.api.stat.modifier.ModifierType;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.ClassSkill;
@ -67,7 +67,7 @@ public class PlayerStats {
// Add newest one
double total = getBase(stat) - instance.getBase();
if (total != 0)
packet.addModifier("mmocoreClass", new StatModifier(total, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER));
packet.addModifier(new StatModifier("mmocoreClass", stat.name(), total, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER));
// Then update the stat
packet.runUpdate();
@ -80,9 +80,9 @@ public class PlayerStats {
*
* This updates the player's passive skills
*/
data.getMMOPlayerData().unregisterSkillTriggers("MMOCorePassiveSkill");
data.getMMOPlayerData().getPassiveSkillMap().removeModifiers("MMOCorePassiveSkill");
for (ClassSkill skill : data.getProfess().getSkills())
if (skill.getSkill().hasTrigger())
data.getMMOPlayerData().registerSkillTrigger(skill.toPassive(data));
data.getMMOPlayerData().getPassiveSkillMap().addModifier(skill.toPassive(data));
}
}

View File

@ -64,9 +64,9 @@ public class AttributeView extends EditableInventory {
holders.register("max", attribute.getMax());
holders.register("current", total);
holders.register("attribute_points", inv.getPlayerData().getAttributePoints());
attribute.getBuffs().forEach((key, buff) -> {
holders.register("buff_" + key.toLowerCase(), buff);
holders.register("total_" + key.toLowerCase(), buff.multiply(total));
attribute.getBuffs().forEach(buff -> {
holders.register("buff_" + buff.getStat().toLowerCase(), buff.getValue());
holders.register("total_" + buff.getStat().toLowerCase(), buff.multiply(total).getValue());
});
return holders;
}

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmocore.gui;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.version.VersionMaterial;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.experience.Booster;
@ -178,8 +179,8 @@ public class PlayerStats extends EditableInventory {
int count = inv.getPlayerData().getParty().getMembers().count();
holders.register("count", "" + count);
for (StatType stat : MMOCore.plugin.partyManager.getBonuses())
holders.register("buff_" + stat.name().toLowerCase(), MMOCore.plugin.partyManager.getBonus(stat).multiply(count - 1).toString());
for (StatModifier buff : MMOCore.plugin.partyManager.getBonuses())
holders.register("buff_" + buff.getStat().toLowerCase(), buff.multiply(count - 1).toString());
return holders;
}

View File

@ -16,7 +16,7 @@ import java.util.logging.Level;
public class PartyManager implements MMOCoreManager {
private final Set<Party> parties = new HashSet<>();
private final Map<StatType, StatModifier> buffs = new HashMap<>();
private final Set<StatModifier> buffs = new HashSet<>();
public void registerParty(Party party) {
parties.add(party);
@ -38,16 +38,8 @@ public class PartyManager implements MMOCoreManager {
parties.remove(party);
}
public boolean hasBonus(StatType stat) {
return buffs.containsKey(stat);
}
public StatModifier getBonus(StatType stat) {
return buffs.get(stat);
}
public Set<StatType> getBonuses() {
return buffs.keySet();
public Set<StatModifier> getBonuses() {
return buffs;
}
@Override
@ -60,7 +52,7 @@ public class PartyManager implements MMOCoreManager {
for (String key : config.getKeys(false))
try {
StatType stat = StatType.valueOf(key.toUpperCase().replace("-", "_").replace(" ", "_"));
buffs.put(stat, new StatModifier(config.getString(key)));
buffs.add(new StatModifier("mmocoreParty", stat.name(), config.getString(key)));
} catch (IllegalArgumentException exception) {
MMOCore.log(Level.WARNING, "Could not load party buff '" + key + "': " + exception.getMessage());
}

View File

@ -1,9 +1,9 @@
package net.Indyuce.mmocore.skill;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.stat.modifier.ModifierSource;
import io.lumine.mythic.lib.player.cooldown.CooldownObject;
import io.lumine.mythic.lib.skill.trigger.PassiveSkill;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;

View File

@ -4,10 +4,10 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
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 io.lumine.mythic.lib.skill.trigger.PassiveSkill;
import io.lumine.mythic.lib.skill.trigger.TriggerMetadata;
import io.lumine.mythic.lib.util.EntityLocationType;
import io.lumine.mythic.lib.util.ParabolicProjectile;
@ -49,7 +49,7 @@ public class Ambers extends SkillHandler<SimpleSkillResult> implements Listener
if (!event.getAttack().getDamage().hasType(DamageType.SKILL))
return;
PassiveSkill passive = data.getPassiveSkill(this);
PassiveSkill passive = data.getPassiveSkillMap().getSkill(this);
if (passive == null)
return;

View File

@ -1,9 +1,9 @@
package net.Indyuce.mmocore.skill.list;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
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 io.lumine.mythic.lib.skill.trigger.PassiveSkill;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Material;
@ -31,7 +31,7 @@ public class Neptune_Gift extends SkillHandler<SimpleSkillResult> implements Lis
public void a(PlayerResourceUpdateEvent event) {
PlayerData data = event.getData();
if (event.getPlayer().getLocation().getBlock().getType() == Material.WATER) {
PassiveSkill skill = event.getData().getMMOPlayerData().getPassiveSkill(this);
PassiveSkill skill = event.getData().getMMOPlayerData().getPassiveSkillMap().getSkill(this);
if (skill == null)
return;

View File

@ -3,10 +3,10 @@ package net.Indyuce.mmocore.skill.list;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
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 io.lumine.mythic.lib.skill.trigger.PassiveSkill;
import io.lumine.mythic.lib.skill.trigger.TriggerMetadata;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Particle;
@ -41,7 +41,7 @@ public class Sneaky_Picky extends SkillHandler<SimpleSkillResult> implements Lis
if (!event.getAttack().getDamage().hasType(DamageType.WEAPON) || PlayerData.get(data.getUniqueId()).isInCombat())
return;
PassiveSkill skill = data.getPassiveSkill(this);
PassiveSkill skill = data.getPassiveSkillMap().getSkill(this);
if (skill == null)
return;