R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
SystemScheduler.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** rtype
4** File description:
5** SystemScheduler implementation
6*/
7
8#include "SystemScheduler.hpp"
9#include <algorithm>
10#include "../Logger/Logger.hpp"
11
12namespace ecs::wrapper {
13
14 SystemScheduler::SystemScheduler(ECSWorld *world) : _world(world), _needsReorder(false) {}
15
16 SystemScheduler &SystemScheduler::registerSystem(const std::string &name, int priority) {
17 SystemInfo info;
18 info.name = name;
19 info.priority = priority;
20 info.enabled = true;
21
22 _systemInfos[name] = info;
23 _needsReorder = true;
24
25 return *this;
26 }
27
28 SystemScheduler &SystemScheduler::runBefore(const std::string &systemName,
29 const std::string &afterSystemName) {
30 if (_systemInfos.find(systemName) == _systemInfos.end()) {
31 LOG_ERROR("SystemScheduler::runBefore - System '", systemName, "' not registered");
32 return *this;
33 }
34
35 _systemInfos[systemName].runBefore.push_back(afterSystemName);
36 _needsReorder = true;
37
38 return *this;
39 }
40
41 SystemScheduler &SystemScheduler::runAfter(const std::string &systemName,
42 const std::string &beforeSystemName) {
43 if (_systemInfos.find(systemName) == _systemInfos.end()) {
44 LOG_ERROR("SystemScheduler::runAfter - System '", systemName, "' not registered");
45 return *this;
46 }
47
48 _systemInfos[systemName].runAfter.push_back(beforeSystemName);
49 _needsReorder = true;
50
51 return *this;
52 }
53
54 void SystemScheduler::enable(const std::string &name) {
55 auto it = _systemInfos.find(name);
56 if (it != _systemInfos.end()) {
57 it->second.enabled = true;
58 }
59 }
60
61 void SystemScheduler::disable(const std::string &name) {
62 auto it = _systemInfos.find(name);
63 if (it != _systemInfos.end()) {
64 it->second.enabled = false;
65 }
66 }
67
68 bool SystemScheduler::isEnabled(const std::string &name) const {
69 auto it = _systemInfos.find(name);
70 if (it != _systemInfos.end()) {
71 return it->second.enabled;
72 }
73 return false;
74 }
75
77 if (!_needsReorder) {
78 return;
79 }
80
81 _executionOrder.clear();
82
83 // Collect all system names
84 for (const auto &[name, info] : _systemInfos) {
85 _executionOrder.push_back(name);
86 }
87
88 // Sort by priority first (higher priority first)
89 std::sort(_executionOrder.begin(), _executionOrder.end(),
90 [this](const std::string &a, const std::string &b) {
91 return _systemInfos[a].priority > _systemInfos[b].priority;
92 });
93
94 // Apply topological sort for dependencies
96
97 _needsReorder = false;
98 }
99
101 // Build dependency graph
102 std::unordered_map<std::string, std::vector<std::string>> graph;
103 std::unordered_map<std::string, int> inDegree;
104
105 // Initialize
106 for (const auto &name : _executionOrder) {
107 graph[name] = {};
108 inDegree[name] = 0;
109 }
110
111 // Build edges from dependencies
112 for (const auto &[name, info] : _systemInfos) {
113 // runBefore: name -> target
114 for (const auto &target : info.runBefore) {
115 if (_systemInfos.find(target) != _systemInfos.end()) {
116 graph[name].push_back(target);
117 inDegree[target]++;
118 }
119 }
120
121 // runAfter: dependency -> name
122 for (const auto &dependency : info.runAfter) {
123 if (_systemInfos.find(dependency) != _systemInfos.end()) {
124 graph[dependency].push_back(name);
125 inDegree[name]++;
126 }
127 }
128 }
129
130 // Kahn's algorithm for topological sort
131 std::vector<std::string> sorted;
132 std::vector<std::string> queue;
133
134 // Find all nodes with no incoming edges
135 for (const auto &[name, degree] : inDegree) {
136 if (degree == 0) {
137 queue.push_back(name);
138 }
139 }
140
141 // Sort queue by priority before processing
142 std::sort(queue.begin(), queue.end(), [this](const std::string &a, const std::string &b) {
143 return _systemInfos[a].priority > _systemInfos[b].priority;
144 });
145
146 while (!queue.empty()) {
147 std::string current = queue.back();
148 queue.pop_back();
149 sorted.push_back(current);
150
151 // Reduce in-degree of neighbors
152 for (const auto &neighbor : graph[current]) {
153 inDegree[neighbor]--;
154 if (inDegree[neighbor] == 0) {
155 queue.push_back(neighbor);
156 }
157 }
158
159 // Keep queue sorted by priority
160 std::sort(queue.begin(), queue.end(), [this](const std::string &a, const std::string &b) {
161 return _systemInfos[a].priority > _systemInfos[b].priority;
162 });
163 }
164
165 // Check for cycles
166 if (sorted.size() != _executionOrder.size()) {
167 LOG_WARNING("Circular dependencies detected. Some systems may not execute in optimal order.");
168 } else {
169 _executionOrder = sorted;
170 }
171 }
172
173 void SystemScheduler::update(float deltaTime) {
174 if (_needsReorder) {
176 }
177
178 for (const auto &systemName : _executionOrder) {
179 auto it = _systemInfos.find(systemName);
180 if (it != _systemInfos.end() && it->second.enabled) {
181 _world->updateSystem(systemName, deltaTime);
182 }
183 }
184 }
185
186 const std::vector<std::string> &SystemScheduler::getExecutionOrder() const {
187 return _executionOrder;
188 }
189
191 std::cout << "=== System Execution Order ===" << std::endl;
192 for (size_t i = 0; i < _executionOrder.size(); ++i) {
193 const auto &name = _executionOrder[i];
194 auto it = _systemInfos.find(name);
195 if (it != _systemInfos.end()) {
196 std::cout << (i + 1) << ". " << name << " (priority: " << it->second.priority
197 << ", enabled: " << (it->second.enabled ? "yes" : "no") << ")" << std::endl;
198 }
199 }
200 std::cout << "==============================" << std::endl;
201 }
202
203} // namespace ecs::wrapper
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
High-level ECS manager providing clean server-side API.
Definition ECSWorld.hpp:122
bool updateSystem(const std::string &name, float deltaTime)
Update a specific system by name.
Definition ECSWorld.cpp:127
Advanced scheduler for controlling system execution order and dependencies.
const std::vector< std::string > & getExecutionOrder() const
Get the computed execution order.
void disable(const std::string &name)
Disable a system.
bool isEnabled(const std::string &name) const
Check if a system is enabled.
void printExecutionOrder() const
Print the execution order for debugging.
SystemScheduler & registerSystem(const std::string &name, int priority=0)
Register a system with the scheduler.
std::unordered_map< std::string, SystemInfo > _systemInfos
SystemScheduler & runBefore(const std::string &systemName, const std::string &afterSystemName)
Specify that a system must run before another.
std::vector< std::string > _executionOrder
SystemScheduler & runAfter(const std::string &systemName, const std::string &beforeSystemName)
Specify that a system must run after another.
void update(float deltaTime)
Update all enabled systems in the scheduled order.
void enable(const std::string &name)
Enable a system.
SystemScheduler(ECSWorld *world)
Construct a SystemScheduler.
Information about a scheduled system.
int priority
Higher priority systems run first.