1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 2020-2021, The LegacyClonk Team and contributors
5 *
6 * Distributed under the terms of the ISC license; see accompanying file
7 * "COPYING" for details.
8 *
9 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10 * See accompanying file "TRADEMARK" for details.
11 *
12 * To redistribute this file separately, substitute the full license texts
13 * for the above references.
14 */
15
16#pragma once
17
18#include "StdCompiler.h"
19
20#include <chrono>
21#include <utility>
22
23template<typename Rep, typename Period = std::ratio<1>, typename Clock = std::chrono::steady_clock>
24class C4Cooldown
25{
26public:
27 using DurationType = std::chrono::duration<Rep, Period>;
28
29public:
30 C4Cooldown(const DurationType &cooldown = {}) noexcept : cooldown{cooldown} {}
31 C4Cooldown(C4Cooldown &&other) noexcept : cooldown{std::exchange(other.cooldown, 0)}, lastReset{std::exchange(other.lastReset, 0)} {}
32
33public:
34 void Reset() { lastReset = Clock::now(); }
35 bool Elapsed() const noexcept { return std::chrono::duration_cast<DurationType>(Clock::now() - lastReset) >= GetCooldown(); }
36 bool TryReset();
37
38 auto GetRemainingTime() const noexcept -> DurationType;
39 DurationType GetCooldown() const noexcept { return cooldown; }
40
41 void CompileFunc(class StdCompiler *comp);
42 void CompileFunc(class StdCompiler *comp, DurationType minimumCooldown);
43
44 bool operator==(const C4Cooldown &other) { return cooldown == other.cooldown; }
45
46 template<typename R, typename P>
47 C4Cooldown &operator=(const std::chrono::duration<R, P> &other) { cooldown = std::chrono::duration_cast<DurationType>(other); return *this; }
48
49private:
50 typename Clock::time_point lastReset;
51 DurationType cooldown;
52};
53
54template<typename Rep, typename Period, typename Clock>
55bool C4Cooldown<Rep, Period, Clock>::TryReset()
56{
57 const bool success{Elapsed()};
58 if (success)
59 {
60 Reset();
61 }
62
63 return success;
64}
65
66template<typename Rep, typename Period, typename Clock>
67auto C4Cooldown<Rep, Period, Clock>::GetRemainingTime() const noexcept -> DurationType
68{
69 if (const auto difference = Clock::now() - lastReset; difference >= cooldown)
70 {
71 return {};
72 }
73 else
74 {
75 return std::chrono::duration_cast<DurationType>(cooldown - difference);
76 }
77}
78
79template<typename Rep, typename Period, typename Clock>
80void C4Cooldown<Rep, Period, Clock>::CompileFunc(StdCompiler *comp)
81{
82 comp->Value(cooldown);
83}
84
85template<typename Rep, typename Period, typename Clock>
86void C4Cooldown<Rep, Period, Clock>::CompileFunc(StdCompiler *comp, DurationType minimumCooldown)
87{
88 CompileFunc(comp);
89
90 if (comp->isCompiler())
91 {
92 cooldown = std::max(cooldown, minimumCooldown);
93 }
94}
95
96template<typename Rep, typename Period> C4Cooldown(std::chrono::duration<Rep, Period>) -> C4Cooldown<Rep, Period>;
97
98using C4CooldownSeconds = C4Cooldown<std::chrono::seconds::rep, std::chrono::seconds::period, std::chrono::steady_clock>;
99