diff --git a/api/src/main/java/dev/aurelium/auraskills/api/source/type/DamageXpSource.java b/api/src/main/java/dev/aurelium/auraskills/api/source/type/DamageXpSource.java index c382b83f0..4f6d3681d 100644 --- a/api/src/main/java/dev/aurelium/auraskills/api/source/type/DamageXpSource.java +++ b/api/src/main/java/dev/aurelium/auraskills/api/source/type/DamageXpSource.java @@ -23,13 +23,31 @@ public interface DamageXpSource extends XpSource { /** * Gets the damager of the source. This is only applicable if the - * player was damaged by an entity. + * player was damaged by an entity. If there are multiple valid damagers, + * it returns the first one. * * @return The damager, or null if not applicable. */ @Nullable String getDamager(); + /** + * Gets the valid damagers of the source. This is only applicable if the + * player was damaged by an entity. + * + * @return the damager, or null if not defined. + */ + @Nullable + String[] getDamagers(); + + /** + * Gets the excluded damagers of the source. + * + * @return the excluded damagers, or null if not defined. + */ + @Nullable + String[] getExcludedDamagers(); + /** * Gets whether the player must survive to be granted xp. * @@ -52,6 +70,14 @@ public interface DamageXpSource extends XpSource { */ boolean includeProjectiles(); + /** + * Gets the cooldown of gaining XP again in milliseconds. The cooldown applies + * globally to all damage source instances. + * + * @return the cooldown in milliseconds + */ + int getCooldownMs(); + enum DamageCause { CONTACT, ENTITY_ATTACK, diff --git a/bukkit/src/main/java/dev/aurelium/auraskills/bukkit/source/DamageLeveler.java b/bukkit/src/main/java/dev/aurelium/auraskills/bukkit/source/DamageLeveler.java index cd15af1eb..60b02f6a1 100644 --- a/bukkit/src/main/java/dev/aurelium/auraskills/bukkit/source/DamageLeveler.java +++ b/bukkit/src/main/java/dev/aurelium/auraskills/bukkit/source/DamageLeveler.java @@ -15,8 +15,15 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.projectiles.ProjectileSource; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + public class DamageLeveler extends SourceLeveler { + private final Map lastGainTime = new HashMap<>(); + public DamageLeveler(AuraSkills plugin) { super(plugin, SourceTypes.DAMAGE); } @@ -37,6 +44,13 @@ public void onDamage(EntityDamageEvent event) { DamageXpSource source = skillSource.source(); Skill skill = skillSource.skill(); + // Check cooldown + long lastGain = lastGainTime.getOrDefault(player.getUniqueId(), 0L); + int cooldownMs = source.getCooldownMs(); + if (lastGain + cooldownMs > System.currentTimeMillis()) { + return; + } + // Disregard self inflected damage if (event instanceof EntityDamageByEntityEvent entityEvent) { if (isSelfInflicted(entityEvent.getDamager(), player)) return; @@ -81,6 +95,9 @@ public void onDamage(EntityDamageEvent event) { plugin.getLevelManager().addDamageXp(user, skill, source, xp, DamageCause.valueOf(event.getCause().name()), damager, event); + + // Mark last gained time + lastGainTime.put(player.getUniqueId(), System.currentTimeMillis()); } private boolean isSelfInflicted(Entity damager, Player player) { @@ -126,10 +143,22 @@ private SkillSource getSource(EntityDamageEvent event) { continue; } } + // Check excluded damagers + if (source.getExcludedDamagers() != null) { + if (event instanceof EntityDamageByEntityEvent entityEvent) { + if (Arrays.stream(source.getExcludedDamagers()) + .anyMatch(excludedDamager -> damagerMatches(source, entityEvent.getDamager(), excludedDamager))) { + continue; + } + } else { + continue; + } + } // Check damager - if (source.getDamager() != null) { + if (source.getDamagers() != null) { if (event instanceof EntityDamageByEntityEvent entityEvent) { - if (!damagerMatches(source, entityEvent.getDamager(), source.getDamager())) { + if (Arrays.stream(source.getDamagers()) + .noneMatch(damagerName -> damagerMatches(source, entityEvent.getDamager(), damagerName))) { continue; } } else { diff --git a/common/src/main/java/dev/aurelium/auraskills/common/source/parser/DamageSourceParser.java b/common/src/main/java/dev/aurelium/auraskills/common/source/parser/DamageSourceParser.java index 1bb1785d0..25971423c 100644 --- a/common/src/main/java/dev/aurelium/auraskills/common/source/parser/DamageSourceParser.java +++ b/common/src/main/java/dev/aurelium/auraskills/common/source/parser/DamageSourceParser.java @@ -17,11 +17,13 @@ public DamageSourceParser(AuraSkillsPlugin plugin) { public DamageSource parse(ConfigurationNode source, ConfigurateSourceContext context) throws SerializationException { DamageXpSource.DamageCause[] causes = context.pluralizedArray("cause", source, DamageXpSource.DamageCause.class); DamageXpSource.DamageCause[] excludedCauses = context.pluralizedArray("excluded_cause", source, DamageXpSource.DamageCause.class); - String damager = source.node("damager").getString(); + String[] damagers = context.pluralizedArray("damager", source, String.class); + String[] excludedDamagers = context.pluralizedArray("excluded_damager", source, String.class); boolean mustSurvive = source.node("must_survive").getBoolean(true); boolean useOriginalDamage = source.node("use_original_damage").getBoolean(true); boolean includeProjectiles = source.node("include_projectiles").getBoolean(true); + int cooldownMsg = source.node("cooldown_ms").getInt(200); - return new DamageSource(plugin, context.parseValues(source), causes, excludedCauses, damager, mustSurvive, useOriginalDamage, includeProjectiles); + return new DamageSource(plugin, context.parseValues(source), causes, excludedCauses, damagers, excludedDamagers, mustSurvive, useOriginalDamage, includeProjectiles, cooldownMsg); } } diff --git a/common/src/main/java/dev/aurelium/auraskills/common/source/type/DamageSource.java b/common/src/main/java/dev/aurelium/auraskills/common/source/type/DamageSource.java index ed9b0a736..e43e0545d 100644 --- a/common/src/main/java/dev/aurelium/auraskills/common/source/type/DamageSource.java +++ b/common/src/main/java/dev/aurelium/auraskills/common/source/type/DamageSource.java @@ -10,19 +10,24 @@ public class DamageSource extends Source implements DamageXpSource { private final DamageCause[] causes; private final DamageCause[] excludedCauses; - private final String damager; + private final @Nullable String[] damagers; + private final @Nullable String[] excludedDamagers; private final boolean mustSurvive; private final boolean useOriginalDamage; private final boolean includeProjectiles; + private final int cooldownMs; - public DamageSource(AuraSkillsPlugin plugin, SourceValues values, DamageCause[] causes, DamageCause[] excludedCauses, String damager, boolean mustSurvive, boolean useOriginalDamage, boolean includeProjectiles) { + public DamageSource(AuraSkillsPlugin plugin, SourceValues values, DamageCause[] causes, DamageCause[] excludedCauses, + String[] damagers, String[] excludedDamagers, boolean mustSurvive, boolean useOriginalDamage, boolean includeProjectiles, int cooldownMs) { super(plugin, values); this.causes = causes; this.excludedCauses = excludedCauses; - this.damager = damager; + this.damagers = damagers; + this.excludedDamagers = excludedDamagers; this.mustSurvive = mustSurvive; this.useOriginalDamage = useOriginalDamage; this.includeProjectiles = includeProjectiles; + this.cooldownMs = cooldownMs; } @Override @@ -37,7 +42,17 @@ public DamageSource(AuraSkillsPlugin plugin, SourceValues values, DamageCause[] @Override public @Nullable String getDamager() { - return damager; + return damagers == null ? null : damagers[0]; + } + + @Override + public @Nullable String[] getDamagers() { + return damagers; + } + + @Override + public @Nullable String[] getExcludedDamagers() { + return excludedDamagers; } @Override @@ -54,4 +69,9 @@ public boolean useOriginalDamage() { public boolean includeProjectiles() { return includeProjectiles; } + + @Override + public int getCooldownMs() { + return cooldownMs; + } }