Merge TimerQueue into TickList

This commit is contained in:
DBotThePony 2023-03-17 14:32:22 +07:00
parent a289d9d1c1
commit 8511c2c01b
Signed by: DBot
GPG Key ID: DCC23B5715498507
5 changed files with 151 additions and 165 deletions

View File

@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
import ru.dbotthepony.mc.otm.core.util.ITickable
import ru.dbotthepony.mc.otm.core.util.TickList
import ru.dbotthepony.mc.otm.core.util.TimerQueue
import java.util.*
private val preServerTick = TickList()
@ -27,25 +26,22 @@ private val postServerTick = TickList()
private val preWorldTick = WeakHashMap<Level, TickList>()
private val postWorldTick = WeakHashMap<Level, TickList>()
private val preServerTickTimers = TimerQueue()
private val postServerTickTimers = TimerQueue()
fun onceServerPre(inTicks: Int, callback: Runnable): TimerQueue.Timer? {
fun onceServerPre(inTicks: Int, callback: Runnable): TickList.Timer? {
if (!SERVER_IS_LIVE) {
LOGGER.error("Refusing to add timer $callback in ticks $inTicks while server is dying", IllegalStateException("Server is stopping"))
return null
}
return preServerTickTimers.Timer(inTicks, callback)
return preServerTick.Timer(inTicks, callback)
}
fun onceServer(inTicks: Int, callback: Runnable): TimerQueue.Timer? {
fun onceServer(inTicks: Int, callback: Runnable): TickList.Timer? {
if (!SERVER_IS_LIVE) {
LOGGER.error("Refusing to add ticker $callback in ticks $inTicks while server is dying", IllegalStateException("Server is stopping"))
return null
}
return postServerTickTimers.Timer(inTicks, callback)
return postServerTick.Timer(inTicks, callback)
}
private var _server: MinecraftServer? = null
@ -146,10 +142,8 @@ private val LOGGER = LogManager.getLogger()
fun onServerTick(event: ServerTickEvent) {
if (event.phase === TickEvent.Phase.START) {
preServerTickTimers.tick()
preServerTick.tick()
} else {
postServerTickTimers.tick()
postServerTick.tick()
}
}
@ -259,8 +253,6 @@ fun Level.whilePre(condition: () -> Boolean, ticker: () -> Unit) {
}
private fun clear() {
preServerTickTimers.clear()
postServerTickTimers.clear()
preServerTick.clear()
postServerTick.clear()
preWorldTick.clear()

View File

@ -5,13 +5,11 @@ import net.minecraftforge.event.TickEvent
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
import ru.dbotthepony.mc.otm.core.util.ITickable
import ru.dbotthepony.mc.otm.core.util.TickList
import ru.dbotthepony.mc.otm.core.util.TimerQueue
import ru.dbotthepony.mc.otm.isClient
private val preTickList = TickList()
private val postTickList = TickList()
private val preTimerList = TimerQueue()
private val postTimerList = TimerQueue()
var LOGGED_IN = false
private set
@ -27,12 +25,12 @@ fun onceClientPre(ticker: ITickable) {
fun onceClient(inTicks: Int, ticker: Runnable) {
check(isClient) { "Illegal side" }
postTimerList.add(inTicks, ticker, LOGGED_IN, "Not logged in")
postTickList.timer(inTicks, ticker, LOGGED_IN, "Not logged in")
}
fun onceClientPre(inTicks: Int, ticker: Runnable) {
check(isClient) { "Illegal side" }
preTimerList.add(inTicks, ticker, LOGGED_IN, "Not logged in")
preTickList.timer(inTicks, ticker, LOGGED_IN, "Not logged in")
}
fun tickClient(ticker: IConditionalTickable) {
@ -63,10 +61,8 @@ fun tickWhileClientPre(condition: () -> Boolean, ticker: () -> Unit) {
fun onClientTick(event: TickEvent.ClientTickEvent) {
if (event.phase == TickEvent.Phase.START) {
preTimerList.tick()
preTickList.tick()
} else {
postTimerList.tick()
postTickList.tick()
}
}
@ -74,17 +70,13 @@ fun onClientTick(event: TickEvent.ClientTickEvent) {
fun onClientDisconnected(event: ClientPlayerNetworkEvent.LoggingOut) {
LOGGED_IN = false
preTimerList.clear()
preTickList.clear()
postTimerList.clear()
postTickList.clear()
}
fun onClientConnected(event: ClientPlayerNetworkEvent.LoggingIn) {
LOGGED_IN = true
preTimerList.clear()
preTickList.clear()
postTimerList.clear()
postTickList.clear()
}

View File

@ -2,16 +2,66 @@ package ru.dbotthepony.mc.otm.core.util
import org.apache.logging.log4j.LogManager
class TickList {
class TickList : ITickable {
private val conditional = ArrayDeque<IConditionalTickable>()
private val conditionalValveTime = ArrayList<IConditionalTickable>()
private val once = ArrayDeque<ITickable>()
private val onceValveTime = ArrayList<ITickable>()
private val always = ArrayList<ITickable>()
private val alwaysValveTime = ArrayList<ITickable>()
private val conditionalValveTime = ArrayList<IConditionalTickable>()
private val onceValveTime = ArrayList<ITickable>()
private val timers = ArrayDeque<Timer>()
private var inTicker = false
var inTicker = false
private set
var ticks = 0
private set
inner class Timer(val timerTicks: Int, val runnable: Runnable) {
val ringAt = ticks + timerTicks
var finished = false
private set
init {
if (timers.isEmpty()) {
timers.addLast(this)
} else {
val iterator = timers.listIterator()
var hit = false
for (value in iterator) {
if (value.ringAt == ringAt) {
hit = true
iterator.add(this)
break
} else if (value.ringAt > ringAt) {
if (iterator.hasPrevious()) {
iterator.previous()
iterator.add(this)
} else {
timers.addFirst(this)
}
hit = true
break
}
}
if (!hit) {
timers.addLast(this)
}
}
}
fun execute() {
if (finished) return
runnable.run()
finished = true
}
}
fun add(ticker: IConditionalTickable) {
if (inTicker) {
@ -21,22 +71,6 @@ class TickList {
}
}
fun once(ticker: ITickable) {
if (inTicker) {
onceValveTime.add(ticker)
} else {
once.addFirst(ticker)
}
}
fun always(ticker: ITickable) {
if (inTicker) {
alwaysValveTime.add(ticker)
} else {
always.add(ticker)
}
}
fun add(ticker: IConditionalTickable, condition: Boolean, reason: String) {
if (!condition) {
LOGGER.error("Refusing to add tickable $ticker because we $reason", IllegalStateException(reason))
@ -46,6 +80,14 @@ class TickList {
return add(ticker)
}
fun once(ticker: ITickable) {
if (inTicker) {
onceValveTime.add(ticker)
} else {
once.addFirst(ticker)
}
}
fun once(ticker: ITickable, condition: Boolean, reason: String) {
if (!condition) {
LOGGER.error("Refusing to add tickable $ticker because we $reason", IllegalStateException(reason))
@ -55,6 +97,27 @@ class TickList {
return once(ticker)
}
fun always(ticker: ITickable) {
if (inTicker) {
alwaysValveTime.add(ticker)
} else {
always.add(ticker)
}
}
fun timer(timerTicks: Int, action: Runnable, condition: Boolean, reason: String): Timer? {
if (!condition) {
LOGGER.error("Refusing to add timer $action in $timerTicks ticks because we $reason", IllegalStateException(reason))
return null
}
return Timer(timerTicks, action)
}
fun timer(timerTicks: Int, action: Runnable): Timer {
return Timer(timerTicks, action)
}
fun until(ticker: () -> Boolean) = add(IConditionalTickable.wrap(ticker))
fun `while`(tickerCondition: () -> Boolean, ticker: () -> Unit) = add(
IConditionalTickable.wrap(
@ -67,66 +130,90 @@ class TickList {
fun `while`(tickerCondition: () -> Boolean, ticker: () -> Unit, condition: Boolean, reason: String) = add(
IConditionalTickable.wrap(tickerCondition, ticker), condition, reason)
fun tick() {
override fun tick() {
if (inTicker) {
throw ConcurrentModificationException("Already ticking")
}
ticks++
inTicker = true
if (conditional.isNotEmpty()) {
val iterator = conditional.iterator()
try {
if (conditional.isNotEmpty()) {
val iterator = conditional.iterator()
for (ticker in iterator) {
if (!ticker.canTick) {
iterator.remove()
} else {
for (ticker in iterator) {
if (!ticker.canTick) {
iterator.remove()
} else {
ticker.tick()
}
}
}
if (once.isNotEmpty()) {
for (ticker in once) {
ticker.tick()
}
once.clear()
}
if (always.isNotEmpty()) {
for (ticker in always) {
ticker.tick()
}
}
}
if (once.isNotEmpty()) {
for (ticker in once) {
ticker.tick()
if (alwaysValveTime.isNotEmpty()) {
always.addAll(alwaysValveTime)
alwaysValveTime.clear()
}
once.clear()
}
if (conditionalValveTime.isNotEmpty()) {
for (ticker in conditionalValveTime) {
conditional.addFirst(ticker)
}
if (always.isNotEmpty()) {
for (ticker in always) {
ticker.tick()
}
}
if (alwaysValveTime.isNotEmpty()) {
always.addAll(alwaysValveTime)
alwaysValveTime.clear()
}
if (conditionalValveTime.isNotEmpty()) {
for (ticker in conditionalValveTime) {
conditional.addFirst(ticker)
conditionalValveTime.clear()
}
conditionalValveTime.clear()
}
if (onceValveTime.isNotEmpty()) {
for (ticker in onceValveTime) {
once.addFirst(ticker)
}
if (onceValveTime.isNotEmpty()) {
for (ticker in onceValveTime) {
once.addFirst(ticker)
onceValveTime.clear()
}
onceValveTime.clear()
}
while (timers.isNotEmpty()) {
val head = timers.first()
inTicker = false
if (head.ringAt <= ticks) {
head.execute()
timers.removeFirst()
} else {
break
}
}
} finally {
inTicker = false
}
}
fun clear() {
if (inTicker) throw ConcurrentModificationException()
conditional.clear()
conditionalValveTime.clear()
once.clear()
onceValveTime.clear()
always.clear()
alwaysValveTime.clear()
timers.clear()
}
companion object {

View File

@ -1,85 +0,0 @@
package ru.dbotthepony.mc.otm.core.util
import org.apache.logging.log4j.LogManager
class TimerQueue {
private var ticks = 0
private val list = ArrayDeque<Timer>()
inner class Timer(val timerTicks: Int, val runnable: Runnable) {
val ringAt = ticks + timerTicks
var finished = false
private set
init {
if (list.isEmpty()) {
list.addLast(this)
} else {
val iterator = list.listIterator()
var hit = false
for (value in iterator) {
if (value.ringAt == ringAt) {
hit = true
iterator.add(this)
break
} else if (value.ringAt > ringAt) {
if (iterator.hasPrevious()) {
iterator.previous()
iterator.add(this)
} else {
list.addFirst(this)
}
hit = true
break
}
}
if (!hit) {
list.addLast(this)
}
}
}
fun execute() {
if (finished) return
runnable.run()
finished = true
}
}
fun add(timerTicks: Int, ticker: Runnable, condition: Boolean, reason: String): Timer? {
if (!condition) {
LOGGER.error("Refusing to add timer $ticker in $timerTicks ticks because we $reason", IllegalStateException(reason))
return null
}
return Timer(timerTicks, ticker)
}
fun tick() {
ticks++
while (list.isNotEmpty()) {
val head = list.first()
if (head.ringAt <= ticks) {
head.execute()
list.removeFirst()
} else {
break
}
}
}
fun clear() {
ticks = 0
list.clear()
}
companion object {
private val LOGGER = LogManager.getLogger()
}
}

View File

@ -3,13 +3,13 @@ package ru.dbotthepony.mc.otm.tests
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import ru.dbotthepony.mc.otm.core.util.TimerQueue
import ru.dbotthepony.mc.otm.core.util.TickList
object TimerQueueTests {
@Test
@DisplayName("TimerQueue test")
fun test() {
val queue = TimerQueue()
val queue = TickList()
var state = 0