libecs-cpp 2.1.0
Entity Component System library in C++
Loading...
Searching...
No Matches
System.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <algorithm>
5#include <cstddef>
6#include <cstdint>
7#include <stdexcept>
8#include <unordered_map>
9#include <utility>
10#include <queue>
11#include <functional>
12#include <atomic>
13#include <memory>
14#include <mutex>
15#include <vector>
16#include <chrono>
17#include <concepts>
18#include <type_traits>
19#include <libecs-cpp/json.hpp>
21#include <libecs-cpp/Clock.hpp>
22#include <libecs-cpp/Timing.hpp>
23
24namespace ecs
25{
26 class Container;
27 class System;
28
42 class Timer
43 {
44 public:
47 Timer(std::string name,
48 std::function<void()> callback,
49 std::chrono::microseconds interval = std::chrono::seconds(30),
50 bool repeat = true)
51 : Repeat(repeat), length(interval)
52 {
53 this->Name = name;
54 this->callback = callback;
55 if(interval.count() >= 0 && interval <= MAX_INTERVAL)
56 {
57 this->timing.SetInterval(interval);
58 }
59 }
60
64 template<std::integral T>
65 [[deprecated("pass a std::chrono duration such as std::chrono::seconds(n) instead of a bare number")]]
66 Timer(std::string name,
67 std::function<void()> callback,
68 T seconds,
69 bool repeat = true)
70 : Timer(std::move(name), std::move(callback), Timer::fromSeconds(seconds), repeat)
71 {
72 }
73
78 {
79 if(this->valid() && this->timing.ShouldUpdate() && this->callback)
80 {
81 this->callback();
82 return true;
83 }
84 return false;
85 }
87 std::string Name;
89 bool Repeat;
90
91 private:
92 friend class ecs::System;
93 bool discarded = false;
94 std::chrono::microseconds length;
95
96 bool valid() const
97 {
98 return this->length.count() >= 0 && this->length <= MAX_INTERVAL;
99 }
101 void start(std::chrono::microseconds now)
102 {
103 this->timing.SetInterval(this->length);
104 this->timing.Restart(now);
105 }
106 bool due(std::chrono::microseconds now)
107 {
108 return this->timing.ShouldUpdate(now) && this->callback;
109 }
110 void fire()
111 {
112 this->callback();
113 }
114 template<typename T>
115 static std::chrono::microseconds fromSeconds(T seconds)
116 {
117 constexpr long long maximum = std::chrono::duration_cast<std::chrono::seconds>(MAX_INTERVAL).count();
118 if constexpr(std::is_signed_v<T>)
119 {
120 const long long value = seconds;
121 if(value < 0) return std::chrono::microseconds(-1);
122 if(value > maximum) return MAX_INTERVAL + std::chrono::microseconds(1);
123 return std::chrono::seconds(value);
124 }
125 else
126 {
127 const unsigned long long value = seconds;
128 if(value > static_cast<unsigned long long>(maximum)) return MAX_INTERVAL + std::chrono::microseconds(1);
129 return std::chrono::seconds(static_cast<long long>(value));
130 }
131 }
132 ecs::Timing timing;
133 std::function<void()> callback = nullptr;
134 };
135
137 /* Hand-off point for messages sent to one system. Internal: use System::MessageSubmit().
138 *
139 * Any thread appends to pending under lock. The container thread moves pending into the system's
140 * message queue. count mirrors pending.size() so the empty case needs no lock.
141 */
142 struct Mailbox
143 {
144 std::mutex lock;
145 std::vector<nlohmann::json> pending;
146 std::atomic<std::size_t> count{0};
147 };
177 class System
178 {
179 public:
195 System(const std::string &handle);
197 virtual ~System() = default;
214 virtual void Initialize() {};
233 virtual void Shutdown() {};
238 virtual void Configure(const nlohmann::json &config);
242 virtual void Update() {};
262 const std::string Handle;
275 void MessageSubmit(const nlohmann::json &message);
280 virtual nlohmann::json Export() const = 0;
310 std::chrono::microseconds ElapsedGet() const;
314 double ElapsedSecondsGet() const;
323 void ClockSet(const ecs::Clock *clock);
333 [[deprecated("use ElapsedGet() or ElapsedSecondsGet() instead")]]
334 uint32_t DeltaTimeGet();
342 void TimerClear(const std::string &name);
351 void TimerAdd(Timer timer);
359 void Log(const std::string &message, const std::string &level = "info");
360 private:
361 friend class ecs::Container;
362 std::shared_ptr<ecs::Mailbox> mailbox = std::make_shared<ecs::Mailbox>();
363 std::vector<nlohmann::json> staging;
364 void mailboxDrain();
365 uint32_t timerWalkDepth = 0;
366 bool timersDiscarded = false;
367 std::vector<ecs::Timer> timersAdded;
368 bool removed = false;
369 void timerWalkFinish();
373 void bufferedDeliver();
376 void updateSystem(std::chrono::microseconds now);
377 void elapsedMeasure(std::chrono::microseconds now);
378 const ecs::Clock *clock = &ecs::SteadyClock::Instance();
379 bool updated = false;
380 std::chrono::microseconds previousUpdate{0};
381 std::chrono::microseconds elapsed{0};
382 std::chrono::microseconds millisecondCarry{0};
383 uint32_t elapsedMilliseconds = 0;
384 protected:
388 std::queue<nlohmann::json> messages;
391 [[deprecated("use ElapsedGet() or ElapsedSecondsGet() instead")]]
392 std::chrono::steady_clock::time_point lastTime = std::chrono::steady_clock::now();
395 std::unordered_map<std::string, std::vector<std::string>> componentsToDelete;
400 std::vector<ecs::Timer> timers;
404 std::vector<std::pair<std::string, std::string>> bufferedLogMessages;
405 };
406}
A source of time for systems and containers.
Definition Clock.hpp:21
A container: the entities, components, systems and resources that are updated together.
Definition Container.hpp:70
static const SteadyClock & Instance()
The shared instance, which lives until the process ends.
Definition Clock.hpp:41
Base class for the logic that runs in a container.
Definition System.hpp:178
void Log(const std::string &message, const std::string &level="info")
Sends a line to the container's log destination with this system's handle as a prefix.
virtual void Update()
Called on each pass in which the system is due; override it with the system's work.
Definition System.hpp:242
uint32_t DeltaTimeGet()
Returns the whole milliseconds of this update's elapsed time.
virtual void Initialize()
Called once before the system's first Update(); override it to set the system up.
Definition System.hpp:214
double ElapsedSecondsGet() const
Returns ElapsedGet() in seconds.
std::unordered_map< std::string, std::vector< std::string > > componentsToDelete
Components a subclass has marked for removal, as entity handles by type name.
Definition System.hpp:395
ecs::TypeEntityComponentList * Components
The components of the system's container (Container::Components), or null before registration.
Definition System.hpp:285
std::chrono::microseconds ElapsedGet() const
Returns the time that passed between the previous update of this system and the current one.
const std::string Handle
The system's handle, given to the constructor and never changed.
Definition System.hpp:262
void UpdateSystem()
Fires the timers that are due, then calls Update().
virtual nlohmann::json Export() const =0
Describes the system as JSON; every subclass implements it.
std::vector< std::pair< std::string, std::string > > bufferedLogMessages
Lines logged before the system was registered, as (message, level) pairs in the order they were logge...
Definition System.hpp:404
std::chrono::steady_clock::time_point lastTime
The construction time.
Definition System.hpp:392
void TimerClear(const std::string &name)
Cancels every timer with this name.
std::vector< ecs::Timer > timers
The system's timers.
Definition System.hpp:400
virtual ~System()=default
Destroys the system.
ecs::Timing Timing
The schedule that decides on which passes the system is updated.
Definition System.hpp:290
void ClockSet(const ecs::Clock *clock)
Replaces the clock this system reads.
System()
Creates a system whose handle is a newly generated UUID.
virtual void Shutdown()
Called once before a started system is destroyed; override it to release what the system holds.
Definition System.hpp:233
void componentsClear()
Removes every component listed in componentsToDelete from the container and empties the list.
virtual void Configure(const nlohmann::json &config)
Receives the system's configuration; override it to read settings.
System(const std::string &handle)
Creates a system with the given handle.
void MessageSubmit(const nlohmann::json &message)
Delivers a message to this system.
std::queue< nlohmann::json > messages
Messages ready to read, oldest first.
Definition System.hpp:388
size_t MessagesWaiting()
Moves any delivered messages into messages, then returns how many messages are waiting to be read.
void TimerAdd(Timer timer)
Adds a timer, which first fires one full length from now.
A callback that fires after a length of time, owned by a System.
Definition System.hpp:43
Timer(std::string name, std::function< void()> callback, std::chrono::microseconds interval=std::chrono::seconds(30), bool repeat=true)
Creates a timer from a name, a callback, a length and whether it repeats.
Definition System.hpp:47
bool CallbackRun()
Runs the callback if the timer is due by the real steady clock, and says whether it ran.
Definition System.hpp:77
std::string Name
The name that System::TimerClear() cancels the timer by.
Definition System.hpp:87
bool Repeat
True for a timer that fires every length, false for one that fires once.
Definition System.hpp:89
Timer(std::string name, std::function< void()> callback, T seconds, bool repeat=true)
Creates a timer whose length is a bare number of seconds.
Definition System.hpp:66
A repeating schedule: says when the next update is due.
Definition Timing.hpp:38
void Restart(std::chrono::microseconds now)
Starts a new schedule at the given instant: the first update is due one full interval later.
Definition Timing.hpp:95
void SetInterval(std::chrono::microseconds interval)
Changes the interval.
Definition Timing.hpp:102
bool ShouldUpdate(std::chrono::microseconds now)
Says whether an update is due at the given instant and, when it is, moves the schedule on.
Definition Timing.hpp:60
Definition Clock.hpp:10
constexpr std::chrono::microseconds MAX_INTERVAL
The longest interval or timer length that is accepted: 100 years of 365.25 days.
Definition Timing.hpp:14
std::unordered_map< std::string, ecs::EntityComponentList > TypeEntityComponentList
The components of a container, by type name and then by entity handle.
Definition Component.hpp:48