Skip to main content

HealthManager.ixx File

Manager for processing damage commands and emitting health events. More...

Included Headers

Namespaces Index

namespacehelios
namespaceengine

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

namespacemechanics

High-level gameplay systems and components for game logic. More...

namespacehealth

Health management system for game entities. More...

Classes Index

classHealthManager

Manager that processes damage commands and updates entity health. More...

Macro Definitions Index

#defineHELIOS_LOG_SCOPE   "helios::engine::mechanics::health::HealthManager"

Description

Manager for processing damage commands and emitting health events.

Macro Definitions

HELIOS_LOG_SCOPE

#define HELIOS_LOG_SCOPE   "helios::engine::mechanics::health::HealthManager"

Definition at line 38 of file HealthManager.ixx.

38#define HELIOS_LOG_SCOPE "helios::engine::mechanics::health::HealthManager"

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file HealthManager.ixx
3 * @brief Manager for processing damage commands and emitting health events.
4 */
5module;
6
7#include <vector>
8
9export module helios.engine.mechanics.health.HealthManager;
10
11import helios.engine.runtime.world.GameWorld;
12import helios.engine.runtime.world.UpdateContext;
13
14import helios.engine.mechanics.damage.commands.ApplyDamageCommand;
15import helios.engine.common.types;
16import helios.engine.mechanics.damage.components.LastDamageComponent;
17
18import helios.engine.mechanics.health.components.HealthComponent;
19import helios.engine.mechanics.health.types;
20import helios.engine.mechanics.health.events;
21
22import helios.engine.mechanics.lifecycle.components;
23
24import helios.util.log;
25
26import helios.engine.common.tags;
27
37
38#define HELIOS_LOG_SCOPE "helios::engine::mechanics::health::HealthManager"
40
41 /**
42 * @brief Manager that processes damage commands and updates entity health.
43 *
44 * HealthManager implements the Manager interface for integration into the
45 * game loop flush cycle, and provides a registered submit function for
46 * ApplyDamageCommand so that incoming damage is queued and applied in batch.
47 *
48 * During flush(), each queued DamageContext is resolved: the target's
49 * HealthComponent is damaged, a HealthChangedEvent is emitted, and if
50 * health reaches zero a HealthDepletedEvent is pushed together with an
51 * optional DeadTagComponent.
52 *
53 * Event phases:
54 * - HealthChangedEvent is pushed to the **phase** bus
55 * (available to systems in the next phase).
56 * - HealthDepletedEvent is pushed to the **pass** bus
57 * (available to systems after commit within the same pass).
58 *
59 * @see ApplyDamageCommand
60 * @see HealthComponent
61 * @see HealthDepletedEvent
62 * @see Manager
63 */
65
66 /**
67 * @brief Logger scoped to HealthManager.
68 */
71
72 /**
73 * @brief Pending damage contexts collected via submit().
74 */
75 std::vector<DamageContext> damageContexts_;
76
77 public:
79
80 /**
81 * @brief Applies all queued damage and emits health events.
82 *
83 * For each pending DamageContext the target's HealthComponent is
84 * looked up and damaged. A HealthChangedEvent is pushed per hit.
85 * When health transitions from alive to dead, the configured
86 * HealthDepletedBehavior flags are evaluated and a
87 * HealthDepletedEvent is emitted.
88 *
89 * HealthChangedEvent is pushed to the phase bus (available next phase);
90 * HealthDepletedEvent is pushed to the pass bus (available after
91 * commit within the same pass).
92 *
93 * @param updateContext The current frame's update context.
94 */
95 void flush(UpdateContext& updateContext) noexcept {
96
97 for (const auto& damageContext : damageContexts_) {
98
99 auto interactionContext = damageContext.interactionContext;
100
101 auto target = updateContext.find(interactionContext.target);
102
103 auto* hc = target->get<HealthComponent>();
104 if (!hc) {
105 continue;
106 }
107
108 bool wasAlive = hc->isAlive();
109 auto damageApplied = damageContext.damage;
110 hc->takeDamage(damageApplied);
111
112 auto* lac = target->get<LastDamageComponent>();
113 if (lac && damageApplied > 0) {
114 lac->setDamageContext(damageContext);
115 }
116
117 auto huc = HealthChangeContext{
118 interactionContext,
119 -damageApplied
120 };
121
122 updateContext.pushPhase<HealthChangedEvent>(huc);
123
124 if (wasAlive && !hc->isAlive()) {
125 auto healthDepletedBehavior = hc->healthDepletedBehavior();
126
127 if (hasHealthDepletedFlag(healthDepletedBehavior, HealthDepletedBehavior::DeadTag)) {
128 target->add<DeadTagComponent>();
129 }
130
131 updateContext.pushPass<HealthDepletedEvent>(target->entityHandle(), damageContext);
132 }
133 }
134
135 damageContexts_.clear();
136 }
137
138 /**
139 * @brief Enqueues a damage command for deferred processing.
140 *
141 * @param applyDamageCommand The damage command to enqueue.
142 *
143 * @return True if the command was accepted.
144 */
145 bool submit(
146 const ApplyDamageCommand applyDamageCommand
147 ) noexcept {
148 damageContexts_.push_back(applyDamageCommand.damageContext());
149 return true;
150 };
151
152 /**
153 * @brief Registers this manager as the damage command handler.
154 *
155 * @param gameWorld The game world to register with.
156 */
157 void init(GameWorld& gameWorld) {
158 gameWorld.template registerCommandHandler<ApplyDamageCommand>(*this);
159 }
160
161 /**
162 * @brief Clears all pending damage contexts.
163 */
164 void reset() {
165 damageContexts_.clear();
166 }
167
168 };
169
170}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.