161 lines
4.0 KiB
GDScript3
161 lines
4.0 KiB
GDScript3
|
|
extends PeriodicScheduler
|
||
|
|
class_name VirtualTimeScheduler
|
||
|
|
|
||
|
|
const MAX_SPINNING = 100
|
||
|
|
|
||
|
|
var _clock : float
|
||
|
|
var _is_enabled : bool
|
||
|
|
var _lock : Lock
|
||
|
|
var _queue : PriorityQueue
|
||
|
|
|
||
|
|
func _init(initial_clock = 0):
|
||
|
|
super._init()
|
||
|
|
self._clock = initial_clock
|
||
|
|
self._is_enabled = false
|
||
|
|
self._lock = Lock.new()
|
||
|
|
self._queue = PriorityQueue.new()
|
||
|
|
|
||
|
|
func _get_clock() -> float:
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
return self._clock
|
||
|
|
|
||
|
|
var clock : float:
|
||
|
|
get:
|
||
|
|
return _get_clock()
|
||
|
|
|
||
|
|
func now() -> float:
|
||
|
|
return self._clock
|
||
|
|
|
||
|
|
## Schedule a new action for future execution
|
||
|
|
func schedule(action : Callable, state = null) -> DisposableBase:
|
||
|
|
return self.schedule_absolute(self._clock, action, state)
|
||
|
|
|
||
|
|
## Schedule a new action for future execution in [code]duetime[/code] seconds.
|
||
|
|
func schedule_relative(duetime, action : Callable, state = null) -> DisposableBase:
|
||
|
|
var time : float = self.add(self._clock, duetime)
|
||
|
|
return self.schedule_absolute(time, action, state)
|
||
|
|
|
||
|
|
## Schedule a new action for future execution at [code]duetime[/code].
|
||
|
|
func schedule_absolute(duetime, action : Callable, state = null) -> DisposableBase:
|
||
|
|
var dt : float = duetime
|
||
|
|
var si : ScheduledItem = ScheduledItem.new(self, dt, state, action)
|
||
|
|
if true:
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
self._queue.enqueue(si)
|
||
|
|
return si.disposable
|
||
|
|
|
||
|
|
## Starts the virtual time scheduler.
|
||
|
|
func start():
|
||
|
|
if true:
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
if self._is_enabled:
|
||
|
|
return
|
||
|
|
self._is_enabled = true
|
||
|
|
|
||
|
|
var spinning : int = 0
|
||
|
|
|
||
|
|
while true:
|
||
|
|
var item : ScheduledItem
|
||
|
|
if true:
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
if not self._is_enabled or self._queue.is_empty():
|
||
|
|
break
|
||
|
|
|
||
|
|
item = self._queue.dequeue()
|
||
|
|
|
||
|
|
if item.duetime > self.now():
|
||
|
|
self._clock = item.duetime
|
||
|
|
spinning = 0
|
||
|
|
|
||
|
|
elif spinning > MAX_SPINNING:
|
||
|
|
self._clock += 1.0
|
||
|
|
spinning = 0
|
||
|
|
|
||
|
|
if not item.is_cancelled():
|
||
|
|
item.invoke()
|
||
|
|
spinning += 1
|
||
|
|
|
||
|
|
self.stop()
|
||
|
|
|
||
|
|
## Stops the virtual time scheduler.
|
||
|
|
func stop():
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
self._is_enabled = false
|
||
|
|
|
||
|
|
## Advances the schedulers clock to the specified absolute time,
|
||
|
|
## running all work til that point.
|
||
|
|
## [br][br]
|
||
|
|
## [b]Args:[/b] [br]
|
||
|
|
## [code]time[/code]: Absolute time to advance the schedulers clock to.
|
||
|
|
func advance_to(time : float):
|
||
|
|
var dt : float = time
|
||
|
|
if true:
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
if self.now() > dt:
|
||
|
|
ArgumentOutOfRangeError.raise()
|
||
|
|
return
|
||
|
|
|
||
|
|
if self.now() == dt or self._is_enabled:
|
||
|
|
return
|
||
|
|
|
||
|
|
self._is_enabled = true
|
||
|
|
|
||
|
|
while true:
|
||
|
|
var item : ScheduledItem
|
||
|
|
if true:
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
if not self._is_enabled or self._queue.is_empty():
|
||
|
|
break
|
||
|
|
|
||
|
|
item = self._queue.peek()
|
||
|
|
|
||
|
|
if item.duetime > dt:
|
||
|
|
break
|
||
|
|
|
||
|
|
if item.duetime > self.now():
|
||
|
|
self._clock = item.duetime
|
||
|
|
|
||
|
|
self._queue.dequeue()
|
||
|
|
|
||
|
|
if not item.is_cancelled():
|
||
|
|
item.invoke()
|
||
|
|
|
||
|
|
if true:
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
self._is_enabled = false
|
||
|
|
self._clock = dt
|
||
|
|
|
||
|
|
## Advances the schedulers clock by the specified relative time,
|
||
|
|
## running all work scheduled for that timespan.
|
||
|
|
## [br][br]
|
||
|
|
## [b]Args:[/b] [br]
|
||
|
|
## [code]time[/code]: Relative time to advance the schedulers clock by.
|
||
|
|
func advance_by(time : float):
|
||
|
|
self.advance_to(self.add(self.now(), time))
|
||
|
|
|
||
|
|
## Advances the schedulers clock by the specified relative time.
|
||
|
|
## [br][br]
|
||
|
|
## [b]Args:[/b] [br]
|
||
|
|
## [code]time[/code]: Relative time to advance the schedulers clock by.
|
||
|
|
func sleep(time : float):
|
||
|
|
var absolute = self.add(self.now(), time)
|
||
|
|
var dt : float = absolute
|
||
|
|
|
||
|
|
if self.now() > dt:
|
||
|
|
ArgumentOutOfRangeError.raise()
|
||
|
|
return
|
||
|
|
|
||
|
|
var __ = LockGuard.new(self._lock)
|
||
|
|
self._clock = dt
|
||
|
|
|
||
|
|
## Adds a relative time value to an absolute time value.
|
||
|
|
## [br][br]
|
||
|
|
## [b]Args:[/b] [br]
|
||
|
|
## [code]absolute[/code]: Absolute virtual time value. [br]
|
||
|
|
## [code]relative[/code]: Relative virtual time value to add. [br]
|
||
|
|
## [br]
|
||
|
|
## [b]Returns:[/b] [br]
|
||
|
|
## The resulting absolute virtual time sum value.
|
||
|
|
static func add(absolute : float, relative : float) -> float:
|
||
|
|
return absolute + relative
|