From c7dc332340ddeca8d6847ae9b44bfd07722ae126 Mon Sep 17 00:00:00 2001 From: Auxilor Date: Thu, 13 Jul 2023 15:14:09 +0100 Subject: [PATCH] Optimised trigger dispatching, reworked counters --- .../com/willfp/libreforge/counters/Counter.kt | 11 ++- .../libreforge/counters/CounterHandler.kt | 80 ------------------- .../libreforge/counters/bind/BoundCounter.kt | 67 ++++++++++++++++ .../libreforge/counters/bind/BoundCounters.kt | 23 ++++++ .../willfp/libreforge/effects/EffectBlock.kt | 5 +- .../triggers/PotentiallyTriggerable.kt | 8 ++ .../com/willfp/libreforge/triggers/Trigger.kt | 18 ++++- 7 files changed, 125 insertions(+), 87 deletions(-) delete mode 100644 core/src/main/kotlin/com/willfp/libreforge/counters/CounterHandler.kt create mode 100644 core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounter.kt create mode 100644 core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounters.kt create mode 100644 core/src/main/kotlin/com/willfp/libreforge/triggers/PotentiallyTriggerable.kt diff --git a/core/src/main/kotlin/com/willfp/libreforge/counters/Counter.kt b/core/src/main/kotlin/com/willfp/libreforge/counters/Counter.kt index 22276c4bc..985cc45dc 100644 --- a/core/src/main/kotlin/com/willfp/libreforge/counters/Counter.kt +++ b/core/src/main/kotlin/com/willfp/libreforge/counters/Counter.kt @@ -3,8 +3,10 @@ package com.willfp.libreforge.counters import com.willfp.eco.core.config.interfaces.Config import com.willfp.libreforge.ConfigurableElement import com.willfp.libreforge.conditions.ConditionList +import com.willfp.libreforge.counters.bind.BoundCounters import com.willfp.libreforge.effects.arguments.EffectArgumentList import com.willfp.libreforge.filters.FilterList +import com.willfp.libreforge.triggers.PotentiallyTriggerable import com.willfp.libreforge.triggers.Trigger import java.util.Objects import java.util.UUID @@ -16,23 +18,26 @@ class Counter internal constructor( override val config: Config, val arguments: EffectArgumentList, val multiplierExpression: String -) : ConfigurableElement { +) : ConfigurableElement, PotentiallyTriggerable { override val uuid: UUID = UUID.randomUUID() /** * Bind this counter to an [accumulator]. */ fun bind(accumulator: Accumulator) { - bindCounter(this, accumulator) + BoundCounters.bind(this, accumulator) } /** * Unbind this counter from all accumulators. */ fun unbind() { - unbindCounter(this) + BoundCounters.unbind(this) } + override fun canBeTriggeredBy(trigger: Trigger) = + this.trigger == trigger + override fun equals(other: Any?): Boolean { if (other !is Counter) { return false diff --git a/core/src/main/kotlin/com/willfp/libreforge/counters/CounterHandler.kt b/core/src/main/kotlin/com/willfp/libreforge/counters/CounterHandler.kt deleted file mode 100644 index d8a0a3210..000000000 --- a/core/src/main/kotlin/com/willfp/libreforge/counters/CounterHandler.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.willfp.libreforge.counters - -import com.willfp.eco.core.map.listMap -import com.willfp.eco.core.placeholder.context.placeholderContext -import com.willfp.eco.util.evaluateExpression -import com.willfp.libreforge.triggers.event.TriggerDispatchEvent -import org.bukkit.event.EventHandler -import org.bukkit.event.Listener - -private val counters = listMap() - -internal fun bindCounter(counter: Counter, accumulator: Accumulator) { - counters[counter] += accumulator -} - -internal fun unbindCounter(counter: Counter) { - counters.remove(counter) -} - -object CounterHandler : Listener { - - /* - - This isn't particularly clean, but I'll refactor it out eventually. - - */ - - @EventHandler - fun handle(event: TriggerDispatchEvent) { - val trigger = event.trigger - val data = trigger.data - - val player = trigger.player - val value = data.value - - val applicableCounters = counters.filter { (counter, _) -> - counter.trigger == trigger.trigger - } - - for ((counter, accumulators) in applicableCounters) { - if (!counter.conditions.areMet(player, data.holder)) { - continue - } - - if (!counter.filters.isMet(data)) { - continue - } - - val config = counter.config - - // Inject placeholders, totally not stolen from ElementLike - listOf(counter.filters, counter.conditions) - .flatten() - .map { it.config } - .plusElement(config) - .forEach { it.addInjectablePlaceholder(trigger.placeholders) } - - val (argumentsMet, met, notMet) = counter.arguments.checkMet(counter, trigger) - - if (!argumentsMet) { - continue - } - - val multiplier = evaluateExpression( - counter.multiplierExpression, - placeholderContext( - player = player, - injectable = config - ) - ) - - met.forEach { it.ifMet(counter, trigger) } - notMet.forEach { it.ifNotMet(counter, trigger) } - - for (accumulator in accumulators) { - accumulator.accept(player, value * multiplier) - } - } - } -} diff --git a/core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounter.kt b/core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounter.kt new file mode 100644 index 000000000..b0bcd67e1 --- /dev/null +++ b/core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounter.kt @@ -0,0 +1,67 @@ +package com.willfp.libreforge.counters.bind + +import com.willfp.eco.core.placeholder.context.placeholderContext +import com.willfp.eco.util.evaluateExpression +import com.willfp.libreforge.counters.Accumulator +import com.willfp.libreforge.counters.Counter +import com.willfp.libreforge.triggers.DispatchedTrigger + +/* + +The current binding system feels a bit messy, so it's all marked as internal since +I'll probably change it later, and I don't want someone to hook into a system +that may break between updates. + + */ + +internal data class BoundCounter( + val counter: Counter, + val accumulator: Accumulator +) { + fun accept(trigger: DispatchedTrigger) { + val data = trigger.data + + val player = trigger.player + val value = data.value + + if (!counter.canBeTriggeredBy(trigger.trigger)) { + return + } + + if (!counter.conditions.areMet(player, data.holder)) { + return + } + + if (!counter.filters.isMet(data)) { + return + } + + val config = counter.config + + // Inject placeholders, totally not stolen from ElementLike + listOf(counter.filters, counter.conditions) + .flatten() + .map { it.config } + .plusElement(config) + .forEach { it.addInjectablePlaceholder(trigger.placeholders) } + + val (argumentsMet, met, notMet) = counter.arguments.checkMet(counter, trigger) + + if (!argumentsMet) { + notMet.forEach { it.ifNotMet(counter, trigger) } + return + } + + val multiplier = evaluateExpression( + counter.multiplierExpression, + placeholderContext( + player = player, + injectable = config + ) + ) + + met.forEach { it.ifMet(counter, trigger) } + + accumulator.accept(player, value * multiplier) + } +} diff --git a/core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounters.kt b/core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounters.kt new file mode 100644 index 000000000..a55968128 --- /dev/null +++ b/core/src/main/kotlin/com/willfp/libreforge/counters/bind/BoundCounters.kt @@ -0,0 +1,23 @@ +package com.willfp.libreforge.counters.bind + +import com.willfp.eco.core.map.listMap +import com.willfp.libreforge.counters.Accumulator +import com.willfp.libreforge.counters.Counter + +internal object BoundCounters { + private val bindings = listMap() + + fun bind(counter: Counter, accumulator: Accumulator) { + bindings[counter] += BoundCounter(counter, accumulator) + } + + fun unbind(counter: Counter) { + bindings.remove(counter) + } + + fun values(): List = + bindings.keys.toList() + + val Counter.bindings: List + get() = BoundCounters.bindings[this].toList() +} diff --git a/core/src/main/kotlin/com/willfp/libreforge/effects/EffectBlock.kt b/core/src/main/kotlin/com/willfp/libreforge/effects/EffectBlock.kt index 140917c1f..d478b3319 100644 --- a/core/src/main/kotlin/com/willfp/libreforge/effects/EffectBlock.kt +++ b/core/src/main/kotlin/com/willfp/libreforge/effects/EffectBlock.kt @@ -8,6 +8,7 @@ import com.willfp.libreforge.effects.arguments.EffectArgumentList import com.willfp.libreforge.filters.FilterList import com.willfp.libreforge.mutators.MutatorList import com.willfp.libreforge.triggers.DispatchedTrigger +import com.willfp.libreforge.triggers.PotentiallyTriggerable import com.willfp.libreforge.triggers.Trigger import org.bukkit.entity.Player import java.util.Objects @@ -26,7 +27,7 @@ class EffectBlock internal constructor( override val mutators: MutatorList, override val filters: FilterList, override val isElementOwnChain: Boolean -) : ElementLike() { +) : ElementLike(), PotentiallyTriggerable { override val supportsDelay = effects.all { it.supportsDelay } val weight = effects.weight @@ -51,7 +52,7 @@ class EffectBlock internal constructor( } } - fun canBeTriggeredBy(trigger: Trigger) = + override fun canBeTriggeredBy(trigger: Trigger) = trigger in triggers override fun doTrigger(trigger: DispatchedTrigger) = diff --git a/core/src/main/kotlin/com/willfp/libreforge/triggers/PotentiallyTriggerable.kt b/core/src/main/kotlin/com/willfp/libreforge/triggers/PotentiallyTriggerable.kt new file mode 100644 index 000000000..a8d2ced3d --- /dev/null +++ b/core/src/main/kotlin/com/willfp/libreforge/triggers/PotentiallyTriggerable.kt @@ -0,0 +1,8 @@ +package com.willfp.libreforge.triggers + +interface PotentiallyTriggerable { + /** + * Check if this can be triggered by some [trigger]. + */ + fun canBeTriggeredBy(trigger: Trigger): Boolean +} diff --git a/core/src/main/kotlin/com/willfp/libreforge/triggers/Trigger.kt b/core/src/main/kotlin/com/willfp/libreforge/triggers/Trigger.kt index cb17f4854..25aa3c635 100644 --- a/core/src/main/kotlin/com/willfp/libreforge/triggers/Trigger.kt +++ b/core/src/main/kotlin/com/willfp/libreforge/triggers/Trigger.kt @@ -2,6 +2,8 @@ package com.willfp.libreforge.triggers import com.willfp.eco.core.registry.KRegistrable import com.willfp.libreforge.ProvidedHolder +import com.willfp.libreforge.counters.bind.BoundCounters +import com.willfp.libreforge.counters.bind.BoundCounters.bindings import com.willfp.libreforge.generatePlaceholders import com.willfp.libreforge.getProvidedActiveEffects import com.willfp.libreforge.plugin @@ -42,16 +44,23 @@ abstract class Trigger( ) { val dispatch = plugin.dispatchedTriggerFactory.create(player, this, data) ?: return + val effects = forceHolders?.getProvidedActiveEffects(player) ?: player.providedActiveEffects + + // Prevent dispatching useless triggers + val potentialDestinations = effects.flatMap { it.effects } + BoundCounters.values() + if (potentialDestinations.none { it.canBeTriggeredBy(this) }) { + return + } + dispatch.generatePlaceholders(data) val dispatchEvent = TriggerDispatchEvent(player, dispatch) Bukkit.getPluginManager().callEvent(dispatchEvent) + if (dispatchEvent.isCancelled) { return } - val effects = forceHolders?.getProvidedActiveEffects(player) ?: player.providedActiveEffects - for ((holder, blocks) in effects) { // Avoid generating placeholders for nothing if (blocks.none { it.canBeTriggeredBy(this) }) { @@ -69,6 +78,11 @@ abstract class Trigger( block.tryTrigger(dispatchWithHolder) } } + + // Probably a better way to work with counters, but this works for now. + for (counter in BoundCounters.values()) { + counter.bindings.forEach { it.accept(dispatch) } + } } final override fun onRegister() {