Anton Tarasenko
4 years ago
6 changed files with 468 additions and 0 deletions
@ -0,0 +1,38 @@
|
||||
/** |
||||
* Signal class implementation for `Timer`'s `OnElapsed` signal. |
||||
* Copyright 2021 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 Timer_OnElapsed_Signal extends Signal; |
||||
|
||||
public final function Emit(Timer source) |
||||
{ |
||||
local Slot nextSlot; |
||||
StartIterating(); |
||||
nextSlot = GetNextSlot(); |
||||
while (nextSlot != none) |
||||
{ |
||||
Timer_OnElapsed_Slot(nextSlot).connect(source); |
||||
nextSlot = GetNextSlot(); |
||||
} |
||||
CleanEmptySlots(); |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
relatedSlotClass = class'Timer_OnElapsed_Slot' |
||||
} |
@ -0,0 +1,40 @@
|
||||
/** |
||||
* Slot class implementation for `Timer`'s `OnElapsed` signal. |
||||
* Copyright 2021 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 Timer_OnElapsed_Slot extends Slot; |
||||
|
||||
delegate connect(Timer source) |
||||
{ |
||||
DummyCall(); |
||||
} |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
connect = none; |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
super.Finalizer(); |
||||
connect = none; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,32 @@
|
||||
/** |
||||
* Class that acts like `Timer`, except it measures real, instead of in-game, |
||||
* time. |
||||
* Copyright 2021 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 RealTimer extends Timer; |
||||
|
||||
protected function float HandleTimeDilation( |
||||
float timeDelta, |
||||
float dilationCoefficient) |
||||
{ |
||||
return timeDelta / dilationCoefficient; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,108 @@
|
||||
/** |
||||
* API that provides time-related methods. |
||||
* Copyright 2021 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 TimeAPI extends AcediaObject; |
||||
|
||||
/** |
||||
* Creates new `Timer`. Does not start it. |
||||
* |
||||
* @param interval Returned `Timer` will be configured to emit |
||||
* `OnElapsed()` signals every `interval` seconds. |
||||
* @param autoReset `true` will configure caller `Timer` to repeatedly emit |
||||
* `OnElapsed()` every `interval` seconds, `false` (default value) will |
||||
* make returned `Timer` emit that signal only once. |
||||
* @return `Timer`, configured to emit `OnElapsed()` every `interval` seconds. |
||||
* Not started. Guaranteed to be not `none`. |
||||
*/ |
||||
public final function Timer NewTimer( |
||||
optional float interval, |
||||
optional bool autoReset) |
||||
{ |
||||
return Timer(_.memory.Allocate(class'Timer')) |
||||
.SetInterval(interval) |
||||
.SetAutoReset(autoReset); |
||||
} |
||||
|
||||
/** |
||||
* Creates and starts new `Timer`. |
||||
* |
||||
* @param interval Returned `Timer` will be configured to emit |
||||
* `OnElapsed()` signals every `interval` seconds. |
||||
* @param autoReset Setting this to `true` will configure caller `Timer` to |
||||
* repeatedly emit `OnElapsed()` signal every `interval` seconds, `false` |
||||
* (default value) will make returned `Timer` emit that signal only once. |
||||
* @return `Timer`, configured to emit `OnElapsed()` every `interval` seconds. |
||||
* Guaranteed to be not `none`. |
||||
*/ |
||||
public final function Timer StartTimer(float interval, optional bool autoReset) |
||||
{ |
||||
return Timer(_.memory.Allocate(class'Timer')) |
||||
.SetInterval(interval) |
||||
.SetAutoReset(autoReset) |
||||
.Start(); |
||||
} |
||||
|
||||
/** |
||||
* Creates new `RealTimer`. Does not start it. |
||||
* |
||||
* @param interval Returned `RealTimer` will be configured to emit |
||||
* `OnElapsed()` signals every `interval` seconds. |
||||
* @param autoReset `true` will configure caller `RealTimer` to repeatedly |
||||
* emit `OnElapsed()` every `interval` seconds, `false` (default value) |
||||
* will make returned `RealTimer` emit that signal only once. |
||||
* @return `RealTimer`, configured to emit `OnElapsed()` every `interval` |
||||
* seconds. Not started. Guaranteed to be not `none`. |
||||
*/ |
||||
public final function RealTimer NewRealTimer( |
||||
optional float interval, |
||||
optional bool autoReset) |
||||
{ |
||||
local RealTimer newTimer; |
||||
newTimer = RealTimer(_.memory.Allocate(class'RealTimer')); |
||||
newTimer.SetInterval(interval).SetAutoReset(autoReset); |
||||
return newTimer; |
||||
} |
||||
|
||||
/** |
||||
* Creates and starts new `RealTimer`. |
||||
* |
||||
* @param interval Returned `RealTimer` will be configured to emit |
||||
* `OnElapsed()` signals every `interval` seconds. |
||||
* @param autoReset Setting this to `true` will configure caller `RealTimer` |
||||
* to repeatedly emit `OnElapsed()` signal every `interval` seconds, |
||||
* `false` (default value) will make returned `RealTimer` emit that signal |
||||
* only once. |
||||
* @return `RealTimer`, configured to emit `OnElapsed()` every `interval` |
||||
* seconds. Guaranteed to be not `none`. |
||||
*/ |
||||
public final function RealTimer StartRealTimer( |
||||
float interval, |
||||
optional bool autoReset) |
||||
{ |
||||
local RealTimer newTimer; |
||||
newTimer = RealTimer(_.memory.Allocate(class'RealTimer')); |
||||
newTimer.SetInterval(interval) |
||||
.SetAutoReset(autoReset) |
||||
.Start(); |
||||
return newTimer; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,248 @@
|
||||
/** |
||||
* Timer class that generates a signal after a set interval, with an option |
||||
* to generate recurring signals. |
||||
* Copyright 2021 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 Timer extends AcediaObject; |
||||
|
||||
/** |
||||
* Because the `Timer` depends on the `Tick()` event, it has the same |
||||
* resolution as a server's tick rate (frame rate for clients). This means that |
||||
* the `OnElapsed()` signal will be emitted at an interval defined by the |
||||
* `Tick()`. If the set interval between two signals is less than that, then |
||||
* `Timer` might emit several signals at the same point of time. |
||||
* Supposing server's tick rate is 30, but `Timer` is set to emit a signal |
||||
* 60 time per second, then on average it will emit two signals each tick at |
||||
* the same exact time. |
||||
*/ |
||||
|
||||
// Is timer currently tracking time until the next event? |
||||
var private bool isTimerEnabled; |
||||
// Should timer automatically reset after the next event to |
||||
// also generate recurring signals? |
||||
var private bool isTimerAutoReset; |
||||
// Currently elapsed time since this timer has started waiting for the |
||||
// next event |
||||
var private float totalElapsedTime; |
||||
// Time interval between timer's start and generating the signal |
||||
var private 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 private bool clearEventQueue; |
||||
|
||||
var private 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 `_.unreal.OnTick()` |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted every time timer's interval is elapsed. |
||||
* |
||||
* [Signature] |
||||
* void <slot>(Timer source) |
||||
* |
||||
* @param source `Timer` that emitted the signal. |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function Timer_OnElapsed_Slot OnElapsed(AcediaObject receiver) |
||||
{ |
||||
return Timer_OnElapsed_Slot(onElapsedSignal.NewSlot(receiver)); |
||||
} |
||||
|
||||
/** |
||||
* This method is called every tick while the caller `Timer` is running and |
||||
* can be overloaded to modify how passed time is affected by the |
||||
* time dilation. |
||||
* |
||||
* For example, to make caller `Timer` count real time you need to passed time |
||||
* by the `dilationCoefficient`: |
||||
* `return timeDelta / dilationCoefficient;`. |
||||
* |
||||
* @param timeDelta In-game time that has passed since the last |
||||
* `Tick()` event. To obtain real time should be divided by |
||||
* `dilationCoefficient`. |
||||
* @param dilationCoefficient Coefficient of time dilation for the passed |
||||
* `Tick()`. Regular speed is `1.0` (corrected from native value `1.1` |
||||
* for Unreal Engine 2). |
||||
*/ |
||||
protected function float HandleTimeDilation( |
||||
float timeDelta, |
||||
float dilationCoefficient) |
||||
{ |
||||
return timeDelta; |
||||
} |
||||
|
||||
/** |
||||
* Returns current interval between `OnElapsed()` signals for the |
||||
* caller `Timer`. In seconds. |
||||
* |
||||
* @return How many seconds separate two `OnElapsed()` signals |
||||
* (or starting a timer and next `OnElapsed()` event). |
||||
*/ |
||||
public final function float GetInterval() |
||||
{ |
||||
return eventInterval; |
||||
} |
||||
|
||||
/** |
||||
* Sets current interval between `OnElapsed()` signals for the |
||||
* caller `Timer`. In seconds. |
||||
* |
||||
* Setting this value while the caller `Timer` is running resets it (same as |
||||
* calling `StopMe().Start()`). |
||||
* |
||||
* @param newInterval How many seconds should separate two `OnElapsed()` |
||||
* signals (or starting a timer and next `OnElapsed()` event)? |
||||
* Setting a value `<= 0` disables the timer. |
||||
* @return Caller `Timer` to allow for method chaining. |
||||
*/ |
||||
public final function Timer SetInterval(float newInterval) |
||||
{ |
||||
eventInterval = newInterval; |
||||
if (eventInterval <= 0) |
||||
{ |
||||
StopMe(); |
||||
return self; |
||||
} |
||||
if (isTimerEnabled) { |
||||
Start(); |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether the timer is currently enabled (emitting signals with |
||||
* set interval). |
||||
* |
||||
* @return `true` if caller `Timer` is enabled and `false` otherwise. |
||||
*/ |
||||
public final function bool IsEnabled() |
||||
{ |
||||
return isTimerEnabled; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether this `Timer` would automatically reset after the emitted |
||||
* `OnElapsed()` signal, allowing for recurring signals. |
||||
* |
||||
* @return `true` if `Timer` will emit `OnElapse()` signal each time |
||||
* the interval elapses and `false` otherwise. |
||||
*/ |
||||
public final function bool IsAutoReset(float newInterval) |
||||
{ |
||||
return isTimerAutoReset; |
||||
} |
||||
|
||||
/** |
||||
* Sets whether this `Timer` would automatically reset after the emitted |
||||
* `OnElapsed()` signal, allowing for recurring signals. |
||||
* |
||||
* @param doAutoReset `true` if `Timer` will emit `OnElapse()` signal |
||||
* each time the interval elapses and `false` otherwise. |
||||
* @return Caller `Timer` to allow for method chaining. |
||||
*/ |
||||
public final function Timer SetAutoReset(bool doAutoReset) |
||||
{ |
||||
isTimerAutoReset = doAutoReset; |
||||
return self; |
||||
} |
||||
|
||||
/** |
||||
* Starts emitting `OneElapsed()` signal. |
||||
* |
||||
* Does nothing if current timer interval (set by `SetInterval()`) is set |
||||
* to a value that's `<= 0`. |
||||
* |
||||
* If caller `Timer` is already running, resets it (same as calling |
||||
* `StopMe().Start()`). |
||||
* |
||||
* @return Caller `Timer` to allow for method chaining. |
||||
*/ |
||||
public final function Timer Start() |
||||
{ |
||||
if (eventInterval <= 0) { |
||||
return self; |
||||
} |
||||
if (!isTimerEnabled) { |
||||
_.unreal.OnTick(self).connect = Tick; |
||||
} |
||||
isTimerEnabled = true; |
||||
totalElapsedTime = 0.0; |
||||
return self; |
||||
} |
||||
|
||||
/** |
||||
* Stops emitting `OneElapsed()` signal. |
||||
* |
||||
* @return Caller `Timer` to allow for method chaining. |
||||
*/ |
||||
public final function Timer StopMe() |
||||
{ |
||||
_.unreal.OnTick(self).Disconnect(); |
||||
isTimerEnabled = false; |
||||
clearEventQueue = true; |
||||
return self; |
||||
} |
||||
|
||||
/** |
||||
* Returns currently elapsed time since caller `Timer` has started waiting for |
||||
* the next event. |
||||
* |
||||
* @return Elapsed time since caller `Timer` has started. |
||||
*/ |
||||
public final function float GetElapsedTime() |
||||
{ |
||||
return totalElapsedTime; |
||||
} |
||||
|
||||
private final function Tick(float delta, float dilationCoefficient) |
||||
{ |
||||
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; |
||||
onElapsedSignal.Emit(self); |
||||
if (!isTimerAutoReset) |
||||
{ |
||||
StopMe(); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
Loading…
Reference in new issue