package TimerUtils import NoWurst import ErrorHandling import Basics import HashMap import Trigger import public Timer /* Basic Timer Recycling and data attachment */ timer array freeTimers int freeTimersCount = 0 constant timerData = new Table() constant HELD = 0x28829022 /** Attach Data to this timer */ public function timer.setData(int data) timerData.saveInt(this.getTCHandleId(), data) /** Retrieve the data attached to this timer */ public function timer.getData() returns int return timerData.loadInt(this.getTCHandleId()) /** Get a new timer. Use this instead of "CreateTimer". You can attach data to the timer with .setData and retrieve it with .getData If you're done with the timer, release it with .release */ public function getTimer() returns timer if freeTimersCount > 0 freeTimersCount-- freeTimers[freeTimersCount].setData(0) return freeTimers[freeTimersCount] else return CreateTimer()..setData(0) /** Release the timer. Use this instead of "DestroyTimer" ! */ public function timer.release() if this == null error("Trying to release a null timer") return if this.getData() == HELD error("ReleaseTimer: Double free!") return this.setData(HELD) this.pause() freeTimers[freeTimersCount] = this freeTimersCount++ /* TimedLoop for classes */ class TimedLoopTimer constant loopTimer = getTimer()..setData(this castTo int) constant loopTrigger = CreateTrigger() int conditionsCount = 0 real period static constant timerMap = new HashMap construct(real period) this.period = period static function get(real period) returns thistype var instance = timerMap.get(period) if instance == null instance = new TimedLoopTimer(period) timerMap.put(period, instance) return instance function add(conditionfunc condition) returns triggercondition let triggerCondition = loopTrigger.addCondition(condition) conditionsCount++ if conditionsCount == 1 loopTimer.startPeriodic(period, function triggerEval) return triggerCondition static function triggerEval() let instance = GetExpiredTimer().getData() castTo thistype instance.loopTrigger.evaluate() if instance.conditionsCount == 0 instance.loopTimer.pause() function release(triggercondition condition) loopTrigger.removeCondition(condition) conditionsCount-- public enum TimedLoopState RUNNING PAUSED STOPPED STOPPED_FOR_GOOD public module TimedLoop static private thistype array instances static private int instanceCount = 0 static private TimedLoopTimer timedLoopTimer static private triggercondition condition protected TimedLoopState timedLoopState = PAUSED abstract function onTimedLoop() /** Returns the period of the timed loop. Ovewrite this to set a custom period */ function getPeriod() returns real return ANIMATION_PERIOD private static function onExpire() returns boolean int i = instanceCount - 1 while i >= 0 let t = instances[i] if t.timedLoopState != RUNNING instanceCount-- instances[i] = instances[instanceCount] if t.timedLoopState == STOPPED_FOR_GOOD t.timedLoopState = PAUSED destroy t else t.timedLoopState = PAUSED else t.onTimedLoop() i-- if instanceCount == 0 timedLoopTimer.release(condition) condition = null return false /** Stops the periodic update of this object. */ function stopTimedLoop() timedLoopState = STOPPED /** Stops the periodic update and destroys the object. */ function stopTimedLoopAndDestroy() timedLoopState = STOPPED_FOR_GOOD /** Starts the periodic updates for this object */ function startTimedLoop() instances[instanceCount] = this instanceCount++ if instanceCount == 1 if condition == null timedLoopTimer = TimedLoopTimer.get(getPeriod()) condition = timedLoopTimer.add(Condition(function onExpire)) timedLoopState = RUNNING ondestroy if timedLoopState != PAUSED stopTimedLoop()