diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt index ab4d15544..2ec316d3d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt @@ -15,17 +15,80 @@ import net.minecraftforge.eventbus.api.EventPriority import net.minecraftforge.eventbus.api.SubscribeEvent import org.apache.logging.log4j.LogManager import java.util.* +import kotlin.ConcurrentModificationException import kotlin.collections.ArrayList -private val preServerTick = ArrayList() -private val postServerTick = ArrayList() -private val preServerTickOnce = ArrayList() -private val postServerTickOnce = ArrayList() +private class TickList { + private val conditional = LinkedList() + private val once = LinkedList() -private val preWorldTick = WeakHashMap>() -private val postWorldTick = WeakHashMap>() -private val preWorldTickOnce = WeakHashMap>() -private val postWorldTickOnce = WeakHashMap>() + private val conditionalValveTime = LinkedList() + private val onceValveTime = LinkedList() + + private var inTicker = false + + fun add(ticker: IConditionalTickable) { + if (inTicker) { + conditionalValveTime.add(ticker) + } else { + conditional.add(ticker) + } + } + + fun add(ticker: ITickable) { + if (inTicker) { + onceValveTime.add(ticker) + } else { + once.add(ticker) + } + } + + fun tick() { + if (inTicker) { + throw ConcurrentModificationException("Already ticking") + } + + inTicker = true + val iterator = conditional.iterator() + + for (ticker in iterator) { + if (!ticker.canTick) { + iterator.remove() + } else { + ticker.tick() + } + } + + for (ticker in once) { + ticker.tick() + } + + once.clear() + + for (ticker in conditionalValveTime) { + conditional.addFirst(ticker) + } + + for (ticker in onceValveTime) { + once.addFirst(ticker) + } + + conditionalValveTime.clear() + onceValveTime.clear() + + inTicker = false + } + + fun clear() { + conditional.clear() + once.clear() + } +} + +private val preServerTick = TickList() +private val postServerTick = TickList() +private val preWorldTick = WeakHashMap() +private val postWorldTick = WeakHashMap() private val preServerTickTimers = TimerQueue() private val postServerTickTimers = TimerQueue() @@ -191,38 +254,10 @@ interface IConditionalTickable : ITickable { fun onServerTick(event: ServerTickEvent) { if (event.phase === TickEvent.Phase.START) { preServerTickTimers.tick() - - for (i in preServerTick.size - 1 downTo 0) { - val ticker = preServerTick[i] - - if (!ticker.canTick) { - preServerTick.removeAt(i) - } else { - ticker.tick() - } - } - - for (i in preServerTickOnce.size - 1 downTo 0) { - preServerTickOnce[i].tick() - preServerTickOnce.removeAt(i) - } + preServerTick.tick() } else { postServerTickTimers.tick() - - for (i in postServerTick.size - 1 downTo 0) { - val ticker = postServerTick[i] - - if (!ticker.canTick) { - postServerTick.removeAt(i) - } else { - ticker.tick() - } - } - - for (i in postServerTickOnce.size - 1 downTo 0) { - postServerTickOnce[i].tick() - postServerTickOnce.removeAt(i) - } + postServerTick.tick() } } @@ -250,7 +285,7 @@ fun addPreServerTickerOnce(ticker: ITickable) { return } - preServerTickOnce.add(ticker) + preServerTick.add(ticker) } fun addPostServerTickerOnce(ticker: ITickable) { @@ -259,56 +294,14 @@ fun addPostServerTickerOnce(ticker: ITickable) { return } - postServerTickOnce.add(ticker) + postServerTick.add(ticker) } fun onWorldTick(event: LevelTickEvent) { if (event.phase === TickEvent.Phase.START) { - val it = preWorldTick[event.level] - - if (it != null) { - for (i in it.size - 1 downTo 0) { - val ticker = it[i] - - if (!ticker.canTick) { - it.removeAt(i) - } else { - ticker.tick() - } - } - } - - val it2 = preWorldTickOnce.remove(event.level) - - if (it2 != null) { - for (i in it2.size - 1 downTo 0) { - it2[i].tick() - it2.removeAt(i) - } - } + preWorldTick[event.level]?.tick() } else { - val it = postWorldTick[event.level] - - if (it != null) { - for (i in it.size - 1 downTo 0) { - val ticker = it[i] - - if (!ticker.canTick) { - it.removeAt(i) - } else { - ticker.tick() - } - } - } - - val it2 = postWorldTickOnce.remove(event.level) - - if (it2 != null) { - for (i in it2.size - 1 downTo 0) { - it2[i].tick() - it2.removeAt(i) - } - } + postWorldTick[event.level]?.tick() } } @@ -318,7 +311,7 @@ fun addPreWorldTicker(level: Level, ticker: IConditionalTickable) { return } - preWorldTick.computeIfAbsent(level) { ArrayList() }.add(ticker) + preWorldTick.computeIfAbsent(level) { TickList() }.add(ticker) } fun addPostWorldTicker(level: Level, ticker: IConditionalTickable) { @@ -327,7 +320,7 @@ fun addPostWorldTicker(level: Level, ticker: IConditionalTickable) { return } - postWorldTick.computeIfAbsent(level) { ArrayList() }.add(ticker) + postWorldTick.computeIfAbsent(level) { TickList() }.add(ticker) } fun addPreWorldTickerOnce(level: Level, ticker: ITickable) { @@ -336,7 +329,7 @@ fun addPreWorldTickerOnce(level: Level, ticker: ITickable) { return } - preWorldTickOnce.computeIfAbsent(level) { ArrayList() }.add(ticker) + preWorldTick.computeIfAbsent(level) { TickList() }.add(ticker) } fun addPostWorldTickerOnce(level: Level, ticker: ITickable) { @@ -345,7 +338,7 @@ fun addPostWorldTickerOnce(level: Level, ticker: ITickable) { return } - postWorldTickOnce.computeIfAbsent(level) { ArrayList() }.add(ticker) + postWorldTick.computeIfAbsent(level) { TickList() }.add(ticker) } private fun clear() { @@ -355,10 +348,6 @@ private fun clear() { postServerTick.clear() preWorldTick.clear() postWorldTick.clear() - preServerTickOnce.clear() - postServerTickOnce.clear() - preWorldTickOnce.clear() - postWorldTickOnce.clear() } fun onServerStarting(event: ServerAboutToStartEvent) {