Skip to main content

CyclicSpawnScheduler.ixx File

Scheduler that cycles through spawn rules in round-robin order. More...

Included Headers

Namespaces Index

namespacehelios
namespaceengine

Main engine module aggregating core infrastructure and game systems. More...

namespaceruntime

Runtime infrastructure for game execution and lifecycle orchestration. More...

namespacespawn

Entity spawning infrastructure for the helios engine. More...

namespacescheduling

Spawn scheduling and plan management. More...

Classes Index

structRuleConfig

Configuration pairing a spawn profile with its rule. More...

classCyclicSpawnScheduler<N>

Scheduler that cycles through spawn rules in round-robin order. More...

Description

Scheduler that cycles through spawn rules in round-robin order.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file CyclicSpawnScheduler.ixx
3 * @brief Scheduler that cycles through spawn rules in round-robin order.
4 */
5module;
6
7#include <cassert>
8#include <memory>
9#include <queue>
10#include <ranges>
11#include <unordered_map>
12#include <vector>
13#include <algorithm>
14
15export module helios.engine.runtime.spawn.scheduling.CyclicSpawnScheduler;
16
17import helios.engine.runtime.spawn.scheduling.SpawnScheduler;
18import helios.engine.runtime.spawn.scheduling.DefaultRuleProcessor;
19
20import helios.engine.runtime.world.UpdateContext;
21import helios.engine.runtime.spawn.SpawnManager;
22import helios.engine.runtime.world.GameWorld;
23import helios.engine.runtime.spawn.scheduling.SpawnPlan;
24import helios.engine.runtime.spawn.scheduling.ScheduledSpawnPlan;
25import helios.engine.runtime.spawn.types;
26import helios.engine.runtime.spawn.policy.SpawnRule;
27import helios.engine.runtime.spawn.policy.SpawnRuleState;
28import helios.engine.runtime.pooling.GameObjectPoolManager;
29
30import helios.core.types;
31
35
36 /**
37 * @brief Configuration pairing a spawn profile with its rule.
38 */
39 struct RuleConfig {
40
41 /**
42 * @brief The spawn profile ID for this rule.
43 */
45
46 /**
47 * @brief The spawn rule controlling when spawns occur.
48 */
49 std::unique_ptr<helios::engine::runtime::spawn::policy::SpawnRule> spawnRule;
50 };
51
52 /**
53 * @brief Scheduler that cycles through spawn rules in round-robin order.
54 *
55 * @details CyclicSpawnScheduler evaluates one rule per frame in a fixed-size
56 * ring buffer, advancing only when a spawn successfully occurs. This creates
57 * predictable, sequential spawn patterns ideal for wave-based gameplay.
58 *
59 * ## Behavior
60 *
61 * - Evaluates the current rule each `evaluate()` call
62 * - Advances cursor only when a spawn plan is successfully produced
63 * - Rules that don't trigger are re-evaluated on subsequent frames
64 * - Uses compile-time fixed capacity via template parameter
65 *
66 * ## Use Cases
67 *
68 * - **Wave spawning:** Sequential enemy types, each wave completes before next
69 * - **Boss patterns:** Predictable attack phase cycling
70 * - **Resource spawning:** Alternating pickup types
71 *
72 * ## Usage
73 *
74 * ```cpp
75 * CyclicSpawnScheduler<3> scheduler;
76 * scheduler
77 * .addRule(enemyAProfileId, std::make_unique<TimerSpawnRule>(ruleA, 2.0f, 1))
78 * .addRule(enemyBProfileId, std::make_unique<TimerSpawnRule>(ruleB, 2.0f, 1))
79 * .addRule(bossProfileId, std::make_unique<TimerSpawnRule>(ruleC, 5.0f, 1));
80 *
81 * // Evaluates ruleA until spawn occurs, then advances to ruleB, etc.
82 * // Cycle: A → B → Boss → A → B → Boss → ...
83 * ```
84 *
85 * @tparam N Maximum number of rules the scheduler can hold.
86 *
87 * @see SpawnScheduler
88 * @see DefaultSpawnScheduler
89 * @see RuleConfig
90 */
91 template<std::size_t N>
93
94 /**
95 * @brief Fixed-size ring buffer of rule configurations.
96 */
97 std::array<RuleConfig, N> ringBuffer_{};
98
99 /**
100 * @brief Current position in the ring buffer.
101 */
102 size_t cursor_ = 0;
103
104 /**
105 * @brief Number of rules currently registered.
106 */
107 size_t count_ = 0;
108
109 /**
110 * @brief Map from spawn rule IDs to their runtime state.
111 */
112 std::unordered_map<
115 > spawnRuleStates_;
116
117 /**
118 * @brief Processor for evaluating individual rules.
119 */
120 DefaultRuleProcessor ruleProcessor_;
121
122 public:
123
124 /**
125 * @brief Evaluates the current rule in the cycle.
126 *
127 * @details Processes only the rule at the current cursor position.
128 * If the rule produces a spawn plan, the cursor advances to the next rule.
129 * Otherwise, the same rule is evaluated again next frame.
130 *
131 * @param gameWorld The game world where evaluation takes place.
132 * @param updateContext Current frame context.
133 * @param spawnContext Context for spawn operations.
134 */
136 const GameWorld& gameWorld,
137 const UpdateContext& updateContext,
138 const SpawnContext& spawnContext ) noexcept override {
139
141
142 // Process queue
143 auto& [spawnProfileId, spawnRule] = ringBuffer_[cursor_];
144 auto spawnPlan = ruleProcessor_.processRule(
145 gameWorld, updateContext, spawnContext, spawnProfileId, *spawnRule,
146 spawnRuleStates_[spawnRule->spawnRuleId()]);
147
148 if (spawnPlan.amount > 0) {
149 scheduledSpawnPlans_.push_back({
150 spawnProfileId,
151 std::move(spawnPlan),
152 spawnContext
153 });
154 cursor_ = (cursor_ + 1) % (count_);
155 }
156
157 }
158
159 /**
160 * @brief Adds a spawn rule to the cycle.
161 *
162 * @details Appends the rule to the ring buffer. Rules are evaluated
163 * in the order they are added.
164 *
165 * @param spawnProfileId Profile ID for the spawned entities.
166 * @param spawnRule The spawn rule. Ownership transferred.
167 *
168 * @return Reference to this scheduler for chaining.
169 *
170 * @pre The scheduler has capacity (count_ < N).
171 * @pre No duplicate profile IDs or rule IDs.
172 */
175 std::unique_ptr<helios::engine::runtime::spawn::policy::SpawnRule> spawnRule
176 ) {
177 assert(count_ < N);
178
179 assert(!spawnRuleStates_.contains(spawnRule->spawnRuleId()) && "Duplicate SpawnRuleId entry");
180
181 for (const auto& item : ringBuffer_) {
182 assert(item.spawnProfileId != spawnProfileId && "Duplicate SpawnProfile entry");
183 }
184
185 spawnRuleStates_.try_emplace(spawnRule->spawnRuleId());
186
187 ringBuffer_[count_++] = {
188 spawnProfileId, std::move(spawnRule)
189 };
190
191 return *this;
192 }
193
194 /**
195 * @brief Commits a completed spawn to update rule state.
196 *
197 * @details Called after entities are spawned to update the rule's
198 * internal state (e.g., spawn count tracking).
199 *
200 * @param spawnRuleId The rule that triggered the spawn.
201 * @param spawnCount Number of entities actually spawned.
202 */
203 void commit(const helios::engine::runtime::spawn::types::SpawnRuleId spawnRuleId, const size_t spawnCount) noexcept override{
204
205 for (auto& ruleConfig : ringBuffer_) {
206
207 if (ruleConfig.spawnRule->spawnRuleId() == spawnRuleId) {
208
209 auto it = spawnRuleStates_.find(spawnRuleId);
210 assert(it != spawnRuleStates_.end() && "Unexpected missing spawnRuleState");
211
212 ruleConfig.spawnRule->commit(it->second, spawnCount);
213 }
214 }
215 }
216
217 /**
218 * @brief Resets all rule states and the cursor to initial values.
219 *
220 * @details Iterates through all rules and resets their state.
221 * Also resets the cursor to the first rule in the cycle.
222 */
223 void reset() noexcept override {
224 for (auto& ruleConfig : ringBuffer_) {
225
226 auto it = spawnRuleStates_.find(ruleConfig.spawnRule->spawnRuleId());
227 assert(it != spawnRuleStates_.end() && "Unexpected missing spawnRuleState");
228
229 ruleConfig.spawnRule->reset(it->second);
230
231 }
232 cursor_ = 0;
233 }
234
235 };
236
237}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.