Anton Tarasenko
2 years ago
17 changed files with 277 additions and 180 deletions
@ -0,0 +1,181 @@ |
|||||||
|
/** |
||||||
|
* Acedia's default implementation for `Timer` class. |
||||||
|
* Copyright 2021-2022 Anton Tarasenko |
||||||
|
*------------------------------------------------------------------------------ |
||||||
|
* This file is part of Acedia. |
||||||
|
* |
||||||
|
* Acedia is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation, version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* Acedia is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
class KF1_Timer extends Timer; |
||||||
|
|
||||||
|
// Is timer currently tracking time until the next event? |
||||||
|
var protected bool isTimerEnabled; |
||||||
|
// Should timer automatically reset after the next event to |
||||||
|
// also generate recurring signals? |
||||||
|
var protected bool isTimerAutoReset; |
||||||
|
// Currently elapsed time since this timer has started waiting for the |
||||||
|
// next event |
||||||
|
var protected float totalElapsedTime; |
||||||
|
// Time interval between timer's start and generating the signal |
||||||
|
var protected float eventInterval; |
||||||
|
// This flag tells `Timer` to stop trying to emit messages that accumulated |
||||||
|
// between two `Tick()` updates. Used in case `Timer` was disables or |
||||||
|
// stopped during one of them. |
||||||
|
var protected bool clearEventQueue; |
||||||
|
|
||||||
|
// `UnrealAPI` to use, has to be set to access `OnTick()` signal. |
||||||
|
var protected UnrealAPI api; |
||||||
|
|
||||||
|
var protected Timer_OnElapsed_Signal onElapsedSignal; |
||||||
|
|
||||||
|
protected function Constructor() |
||||||
|
{ |
||||||
|
onElapsedSignal = Timer_OnElapsed_Signal( |
||||||
|
_.memory.Allocate(class'Timer_OnElapsed_Signal')); |
||||||
|
} |
||||||
|
|
||||||
|
protected function Finalizer() |
||||||
|
{ |
||||||
|
_.memory.Free(onElapsedSignal); |
||||||
|
StopMe(); // Disconnects from listening to `api.OnTick()` |
||||||
|
api = none; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initializes caller `Timer` with given `UnrealAPI` instance that will be used |
||||||
|
* to track `OnTick()` signal. |
||||||
|
* |
||||||
|
* This is necessary, because we don't know where `KF1_Timer` will be used: |
||||||
|
* on server or on client. |
||||||
|
*/ |
||||||
|
public function Timer Initialize(UnrealAPI newAPI) |
||||||
|
{ |
||||||
|
if (api != none) { |
||||||
|
return self; |
||||||
|
} |
||||||
|
api = newAPI; |
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
/* SIGNAL */ |
||||||
|
public function Timer_OnElapsed_Slot OnElapsed(AcediaObject receiver) |
||||||
|
{ |
||||||
|
return Timer_OnElapsed_Slot(onElapsedSignal.NewSlot(receiver)); |
||||||
|
} |
||||||
|
|
||||||
|
protected function float HandleTimeDilation( |
||||||
|
float timeDelta, |
||||||
|
float dilationCoefficient) |
||||||
|
{ |
||||||
|
return timeDelta; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public function float GetInterval() |
||||||
|
{ |
||||||
|
return eventInterval; |
||||||
|
} |
||||||
|
|
||||||
|
public function Timer SetInterval(float newInterval) |
||||||
|
{ |
||||||
|
eventInterval = newInterval; |
||||||
|
if (eventInterval <= 0) |
||||||
|
{ |
||||||
|
StopMe(); |
||||||
|
return self; |
||||||
|
} |
||||||
|
if (isTimerEnabled) { |
||||||
|
Start(); |
||||||
|
} |
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
public function bool IsEnabled() |
||||||
|
{ |
||||||
|
return isTimerEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
public function bool IsAutoReset(float newInterval) |
||||||
|
{ |
||||||
|
return isTimerAutoReset; |
||||||
|
} |
||||||
|
|
||||||
|
public function Timer SetAutoReset(bool doAutoReset) |
||||||
|
{ |
||||||
|
isTimerAutoReset = doAutoReset; |
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
public function Timer Start() |
||||||
|
{ |
||||||
|
if (eventInterval <= 0) { |
||||||
|
return self; |
||||||
|
} |
||||||
|
if (!isTimerEnabled) { |
||||||
|
api.OnTick(self).connect = Tick; |
||||||
|
} |
||||||
|
isTimerEnabled = true; |
||||||
|
totalElapsedTime = 0.0; |
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
public function Timer StopMe() |
||||||
|
{ |
||||||
|
api.OnTick(self).Disconnect(); |
||||||
|
isTimerEnabled = false; |
||||||
|
clearEventQueue = true; |
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
public function float GetElapsedTime() |
||||||
|
{ |
||||||
|
return totalElapsedTime; |
||||||
|
} |
||||||
|
|
||||||
|
private function Tick(float delta, float dilationCoefficient) |
||||||
|
{ |
||||||
|
local int lifeVersion; |
||||||
|
|
||||||
|
if (onElapsedSignal == none || eventInterval <= 0.0) |
||||||
|
{ |
||||||
|
StopMe(); |
||||||
|
return; |
||||||
|
} |
||||||
|
totalElapsedTime += HandleTimeDilation(delta, dilationCoefficient); |
||||||
|
clearEventQueue = false; |
||||||
|
while (totalElapsedTime > eventInterval && !clearEventQueue) |
||||||
|
{ |
||||||
|
// It is important to modify _before_ the signal call in case `Timer` |
||||||
|
// is reset there and already has a zeroed `totalElapsedTime` |
||||||
|
totalElapsedTime -= eventInterval; |
||||||
|
// Stop `Timer` before emitting a signal, to allow user to potentially |
||||||
|
// restart it |
||||||
|
if (!isTimerAutoReset) { |
||||||
|
StopMe(); |
||||||
|
} |
||||||
|
// During signal emission caller `Timer` can get reallocated and |
||||||
|
// used to perform a completely different role. |
||||||
|
// In such a case we need to bail from this method as soom as |
||||||
|
// possible. |
||||||
|
lifeVersion = GetLifeVersion(); |
||||||
|
onElapsedSignal.Emit(self); |
||||||
|
if (!isTimerEnabled || lifeVersion != GetLifeVersion()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
defaultproperties |
||||||
|
{ |
||||||
|
} |
Loading…
Reference in new issue