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.spawn.SpawnContext;
23import helios.engine.runtime.world.GameWorld;
24import helios.engine.runtime.spawn.scheduling.SpawnPlan;
25import helios.engine.runtime.spawn.scheduling.ScheduledSpawnPlan;
26import helios.engine.core.data.SpawnProfileId;
27import helios.engine.core.data.SpawnRuleId;
28import helios.engine.runtime.spawn.policy.SpawnRule;
29import helios.engine.runtime.spawn.policy.SpawnRuleState;
30import helios.engine.runtime.pooling.GameObjectPoolManager;
31
32import helios.core.types;
33
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 updateContext Current frame context.
132 * @param spawnContext Context for spawn operations.
133 */
136 const helios::engine::runtime::spawn::SpawnContext& spawnContext ) noexcept override {
137
139
140 // Process queue
141 auto& [spawnProfileId, spawnRule] = ringBuffer_[cursor_];
142 auto spawnPlan = ruleProcessor_.processRule(
143 updateContext, spawnContext, spawnProfileId, *spawnRule,
144 spawnRuleStates_[spawnRule->spawnRuleId()]);
145
146 if (spawnPlan.amount > 0) {
147 scheduledSpawnPlans_.push_back({
148 spawnProfileId,
149 std::move(spawnPlan),
150 spawnContext
151 });
152 cursor_ = (cursor_ + 1) % (count_);
153 }
154
155 }
156
157 /**
158 * @brief Adds a spawn rule to the cycle.
159 *
160 * @details Appends the rule to the ring buffer. Rules are evaluated
161 * in the order they are added.
162 *
163 * @param spawnProfileId Profile ID for the spawned entities.
164 * @param spawnRule The spawn rule. Ownership transferred.
165 *
166 * @return Reference to this scheduler for chaining.
167 *
168 * @pre The scheduler has capacity (count_ < N).
169 * @pre No duplicate profile IDs or rule IDs.
170 */
173 std::unique_ptr<helios::engine::runtime::spawn::policy::SpawnRule> spawnRule
174 ) {
175 assert(count_ < N);
176
177 assert(!spawnRuleStates_.contains(spawnRule->spawnRuleId()) && "Duplicate SpawnRuleId entry");
178
179 for (const auto& item : ringBuffer_) {
180 assert(item.spawnProfileId != spawnProfileId && "Duplicate SpawnProfile entry");
181 }
182
183 spawnRuleStates_.try_emplace(spawnRule->spawnRuleId());
184
185 ringBuffer_[count_++] = {
186 spawnProfileId, std::move(spawnRule)
187 };
188
189 return *this;
190 }
191
192 /**
193 * @brief Commits a completed spawn to update rule state.
194 *
195 * @details Called after entities are spawned to update the rule's
196 * internal state (e.g., spawn count tracking).
197 *
198 * @param spawnRuleId The rule that triggered the spawn.
199 * @param spawnCount Number of entities actually spawned.
200 */
201 void commit(const helios::engine::core::data::SpawnRuleId spawnRuleId, const size_t spawnCount) noexcept override{
202
203 for (auto& ruleConfig : ringBuffer_) {
204
205 if (ruleConfig.spawnRule->spawnRuleId() == spawnRuleId) {
206
207 auto it = spawnRuleStates_.find(spawnRuleId);
208 assert(it != spawnRuleStates_.end() && "Unexpected missing spawnRuleState");
209
210 ruleConfig.spawnRule->commit(it->second, spawnCount);
211 }
212 }
213 }
214
215 };
216
217}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.