Eliminate most of TickList's internal logic, greatly speeding it up

This commit is contained in:
DBotThePony 2024-05-16 18:06:09 +07:00
parent 884caba048
commit f416cd69e5
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -4,24 +4,16 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectAVLTreeSet import it.unimi.dsi.fastutil.objects.ObjectAVLTreeSet
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.addSorted import ru.dbotthepony.mc.otm.core.addSorted
import java.util.LinkedList
import java.util.PriorityQueue import java.util.PriorityQueue
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
class TickList : ITickable { class TickList : ITickable {
private val conditional = ArrayList<IConditionalTickable>() private val tickers = LinkedList<IConditionalTickable>()
private val conditionalQueued = ArrayList<IConditionalTickable>() private val queuedTickers = ArrayList<IConditionalTickable>()
private val once = ArrayList<ITickable>()
private val onceQueued = ArrayList<ITickable>()
private val always = ArrayList<ITickable>()
private val alwaysQueued = ArrayList<ITickable>()
private val toRemoveFromAlways = ArrayList<ITickable>()
private val timers = PriorityQueue<Timer>() private val timers = PriorityQueue<Timer>()
private val namedTimers = Object2ObjectOpenHashMap<Any, Timer>(0) private val namedTimers = HashMap<Any?, Timer>()
private var shouldTick = false
var inTicker = false var inTicker = false
private set private set
@ -37,7 +29,6 @@ class TickList : ITickable {
private set private set
init { init {
shouldTick = true
timers.add(this) timers.add(this)
} }
@ -66,9 +57,9 @@ class TickList : ITickable {
return timer return timer
} }
inner class Ticker(parent: ITickable) : ITickable by parent { inner class Ticker(private val parent: ITickable) : IConditionalTickable {
init { init {
add(this, always, alwaysQueued) add(this)
} }
var isEnabled = true var isEnabled = true
@ -77,17 +68,19 @@ class TickList : ITickable {
field = value field = value
if (value) { if (value) {
add(this, always, alwaysQueued) add(this)
} else { } else {
alwaysQueued.remove(this) queuedTickers.remove(this)
}
}
}
if (inTicker) { override fun tick(): Boolean {
toRemoveFromAlways.add(this) if (!isEnabled)
} else { return false
always.remove(this)
} parent.tick()
} return true
}
} }
fun disable() { fun disable() {
@ -99,20 +92,14 @@ class TickList : ITickable {
} }
} }
private fun <T : Any> add(value: T, regular: MutableList<T>, queue: MutableList<T>) { fun add(value: IConditionalTickable) {
shouldTick = true
if (inTicker) { if (inTicker) {
queue.add(value) queuedTickers.add(value)
} else { } else {
regular.add(value) tickers.add(value)
} }
} }
fun add(ticker: IConditionalTickable) {
add(ticker, conditional, conditionalQueued)
}
fun add(ticker: IConditionalTickable, condition: Boolean, reason: String) { fun add(ticker: IConditionalTickable, condition: Boolean, reason: String) {
if (!condition) { if (!condition) {
LOGGER.error("Refusing to add tickable $ticker because we $reason", IllegalStateException(reason)) LOGGER.error("Refusing to add tickable $ticker because we $reason", IllegalStateException(reason))
@ -123,7 +110,7 @@ class TickList : ITickable {
} }
fun once(ticker: ITickable) { fun once(ticker: ITickable) {
add(ticker, once, onceQueued) add(IConditionalTickable { ticker.tick(); false })
} }
fun once(ticker: ITickable, condition: Boolean, reason: String) { fun once(ticker: ITickable, condition: Boolean, reason: String) {
@ -136,7 +123,7 @@ class TickList : ITickable {
} }
fun always(ticker: ITickable) { fun always(ticker: ITickable) {
add(ticker, always, alwaysQueued) add(IConditionalTickable { ticker.tick(); true })
} }
fun timer(timerTicks: Int, action: Runnable, condition: Boolean, reason: String): Timer? { fun timer(timerTicks: Int, action: Runnable, condition: Boolean, reason: String): Timer? {
@ -170,59 +157,15 @@ class TickList : ITickable {
} }
ticks++ ticks++
if (!shouldTick) return
inTicker = true inTicker = true
shouldTick = timers.isNotEmpty()
try { try {
if (conditional.isNotEmpty()) { tickers.removeIf { !it.tick() }
shouldTick = true
conditional.removeIf { !it.tick() }
}
if (once.isNotEmpty()) { if (queuedTickers.isNotEmpty()) {
shouldTick = true tickers.addAll(queuedTickers)
queuedTickers.clear()
for (ticker in once) ticker.tick()
once.clear()
}
if (toRemoveFromAlways.isNotEmpty()) {
shouldTick = true
for (v in toRemoveFromAlways) always.remove(v)
toRemoveFromAlways.clear()
}
if (always.isNotEmpty()) {
shouldTick = true
for (ticker in always) {
ticker.tick()
}
}
if (alwaysQueued.isNotEmpty()) {
shouldTick = true
always.ensureCapacity(always.size + alwaysQueued.size)
for (v in alwaysQueued) always.add(v) // avoid toArray()
alwaysQueued.clear()
}
if (conditionalQueued.isNotEmpty()) {
shouldTick = true
for (ticker in conditionalQueued) conditional.add(ticker)
conditionalQueued.clear()
}
if (onceQueued.isNotEmpty()) {
shouldTick = true
for (ticker in onceQueued) once.add(ticker)
onceQueued.clear()
} }
while (timers.isNotEmpty()) { while (timers.isNotEmpty()) {
@ -243,14 +186,8 @@ class TickList : ITickable {
fun clear() { fun clear() {
if (inTicker) throw ConcurrentModificationException() if (inTicker) throw ConcurrentModificationException()
conditional.clear() tickers.clear()
conditionalQueued.clear() queuedTickers.clear()
once.clear()
onceQueued.clear()
always.clear()
alwaysQueued.clear()
timers.clear() timers.clear()
} }