r-type  0.0.0
R-Type main
Loading...
Searching...
No Matches
EntityManager.cpp
Go to the documentation of this file.
1///
2/// @file EntityManager.cpp
3/// @brief Implementation of EntityManager for RTypeServer
4/// @namespace gme
5///
6
8#include "Utils/Logger.hpp"
10#include <algorithm>
11
12namespace gme
13{
14 EntityManager::EntityManager(ecs::Registry &registry) : m_registry(registry) {}
15
16 ecs::Entity EntityManager::createPlayer(std::uint32_t sessionId, float x, float y)
17 {
18 if (hasPlayer(sessionId))
19 {
20 utl::Logger::log("EntityManager: Player with sessionId " + std::to_string(sessionId) + " already exists",
22 return m_playerEntities[sessionId];
23 }
24
25 // Validate spawn position
26 x = std::max(0.0f, std::min(x, utl::GameConfig::Server::SCREEN_WIDTH));
27 y = std::max(0.0f, std::min(y, utl::GameConfig::Server::SCREEN_HEIGHT));
28
29 ecs::Entity playerEntity =
31 .with<ecs::Transform>("player_transform_" + std::to_string(sessionId), x, y, 0.0f)
32 .with<ecs::Velocity>("player_velocity_" + std::to_string(sessionId), 0.0f, 0.0f)
33 .with<ecs::Player>("player_" + std::to_string(sessionId), true)
34 .with<ecs::Health>("player_health_" + std::to_string(sessionId), 100.0f, 100.0f)
35 .with<ecs::BeamCharge>("beam_charge_" + std::to_string(sessionId), 0.0f, 1.0f)
36 .with<ecs::Hitbox>("player_hitbox_" + std::to_string(sessionId), 10.0f, 0.0f, 0.0f)
37 .build();
38
39 m_playerEntities[sessionId] = playerEntity;
40 registerEntity(playerEntity, ServerEntityType::PLAYER, sessionId, -1.0f);
41
42 // Initialize score
43 m_playerScores[sessionId] = 0;
44
45 utl::Logger::log("EntityManager: Created player entity for sessionId " + std::to_string(sessionId) +
46 " at position (" + std::to_string(x) + ", " + std::to_string(y) + ")",
48
49 return playerEntity;
50 }
51
52 void EntityManager::destroyPlayer(std::uint32_t sessionId)
53 {
54 // Mark player as inactive so it won't be included in next world state broadcast
55 auto *metadata = getEntityMetadata(sessionId);
56 if (metadata)
57 {
58 metadata->isActive = false;
59 }
60
61 // Add to destroy queue for cleanup
62 m_destroyQueue.push_back(sessionId);
63
64 utl::Logger::log("EntityManager: Marked player " + std::to_string(sessionId) + " for destruction",
66 }
67
68 ecs::Entity EntityManager::getPlayer(std::uint32_t sessionId)
69 {
70 auto it = m_playerEntities.find(sessionId);
71 return (it != m_playerEntities.end()) ? it->second : ecs::INVALID_ENTITY;
72 }
73
74 bool EntityManager::hasPlayer(std::uint32_t sessionId) const
75 {
76 return m_playerEntities.find(sessionId) != m_playerEntities.end();
77 }
78
79 ecs::Entity EntityManager::getPlayerEntity(std::uint32_t sessionId) const
80 {
81 auto it = m_playerEntities.find(sessionId);
82 return (it != m_playerEntities.end()) ? it->second : ecs::INVALID_ENTITY;
83 }
84
85 void EntityManager::markPlayerAsDead(std::uint32_t sessionId)
86 {
87 m_deadPlayers.insert(sessionId);
88 utl::Logger::log("EntityManager: Player " + std::to_string(sessionId) + " marked as dead", utl::LogLevel::INFO);
89 }
90
92 {
93 std::uint32_t aliveCount = 0;
94 for (const auto &[sessionId, entity] : m_playerEntities)
95 {
96 if (m_deadPlayers.find(sessionId) == m_deadPlayers.end())
97 {
98 aliveCount++;
99 }
100 }
101 return aliveCount;
102 }
103
104 // ========== Score Management ==========
105
106 void EntityManager::addScore(std::uint32_t sessionId, int points)
107 {
108 m_playerScores[sessionId] += points;
109 utl::Logger::log("EntityManager: Player " + std::to_string(sessionId) + " earned " + std::to_string(points) +
110 " points. Total: " + std::to_string(m_playerScores[sessionId]),
112 }
113
114 int EntityManager::getScore(std::uint32_t sessionId) const
115 {
116 auto it = m_playerScores.find(sessionId);
117 return (it != m_playerScores.end()) ? it->second : 0;
118 }
119
120 void EntityManager::resetScore(std::uint32_t sessionId)
121 {
122 m_playerScores[sessionId] = 0;
123 utl::Logger::log("EntityManager: Reset score for player " + std::to_string(sessionId), utl::LogLevel::INFO);
124 }
125
126 ecs::Entity EntityManager::createBasicEnemy(float x, float y, float health)
127 {
128 // Validate parameters
129 if (health <= 0.0f)
130 health = 50.0f;
131
132 std::uint32_t enemyId = m_nextEnemyId++;
133
134 ecs::Entity enemyEntity =
136 .with<ecs::Transform>("enemy_transform_" + std::to_string(enemyId), x, y, 0.0f)
137 .with<ecs::Velocity>("enemy_velocity_" + std::to_string(enemyId), -200.0f, 0.0f) // Move left
138 .with<ecs::Enemy>("enemy_" + std::to_string(enemyId), health, health, 10.0f, 200.0f, 0.0f, 2.0f)
139 .with<ecs::Hitbox>("enemy_hitbox_" + std::to_string(enemyId), 30.0f, 0.0f,
140 0.0f) // Increased from 15 to 30 for better collision
141 .build();
142
143 m_enemyEntities[enemyId] = enemyEntity;
144 registerEntity(enemyEntity, ServerEntityType::ENEMY_BASIC, enemyId, -1.0f);
145
146 utl::Logger::log("EntityManager: Created basic enemy " + std::to_string(enemyId) + " at position (" +
147 std::to_string(x) + ", " + std::to_string(y) + ")",
149
150 return enemyEntity;
151 }
152
153 ecs::Entity EntityManager::createAdvancedEnemy(float x, float y, float health)
154 {
155 // Validate parameters
156 if (health <= 0.0f)
157 health = 100.0f;
158
159 std::uint32_t enemyId = m_nextEnemyId++;
160
161 ecs::Entity enemyEntity =
163 .with<ecs::Transform>("enemy_transform_" + std::to_string(enemyId), x, y, 0.0f)
164 .with<ecs::Velocity>("enemy_velocity_" + std::to_string(enemyId), -150.0f, 0.0f)
165 .with<ecs::Enemy>("enemy_" + std::to_string(enemyId), health, health, 20.0f, 150.0f, 0.0f, 1.5f)
166 .with<ecs::Hitbox>("enemy_hitbox_" + std::to_string(enemyId), 35.0f, 0.0f,
167 0.0f) // Increased from 20 to 35 for better collision
168 .build();
169
170 m_enemyEntities[enemyId] = enemyEntity;
171 registerEntity(enemyEntity, ServerEntityType::ENEMY_ADVANCED, enemyId, -1.0f);
172
173 utl::Logger::log("EntityManager: Created advanced enemy " + std::to_string(enemyId) + " at position (" +
174 std::to_string(x) + ", " + std::to_string(y) + ")",
176
177 return enemyEntity;
178 }
179
180 ecs::Entity EntityManager::createBoss(float x, float y, float health)
181 {
182 // Validate parameters
183 if (health <= 0.0f)
184 health = 1000.0f;
185
186 std::uint32_t enemyId = m_nextEnemyId++;
187
188 ecs::Entity bossEntity =
190 .with<ecs::Transform>("boss_transform_" + std::to_string(enemyId), x, y, 0.0f)
191 .with<ecs::Velocity>("boss_velocity_" + std::to_string(enemyId), -50.0f, 0.0f)
192 .with<ecs::Enemy>("boss_" + std::to_string(enemyId), health, health, 50.0f, 50.0f, 0.0f, 0.5f)
193 .with<ecs::Hitbox>("boss_hitbox_" + std::to_string(enemyId), 90.0f, 0.0f,
194 0.0f) // Increased from 50 to 90 for better collision with large sprite
195 .build();
196
197 m_enemyEntities[enemyId] = bossEntity;
198 registerEntity(bossEntity, ServerEntityType::BOSS, enemyId, -1.0f);
199
200 utl::Logger::log("EntityManager: Created boss " + std::to_string(enemyId) + " at position (" +
201 std::to_string(x) + ", " + std::to_string(y) + ")",
203
204 return bossEntity;
205 }
206
207 void EntityManager::destroyEnemy(std::uint32_t enemyId)
208 {
209 auto *metadata = getEntityMetadata(enemyId);
210 if (metadata)
211 {
212 metadata->isActive = false;
213 }
214 m_destroyQueue.push_back(enemyId);
215 }
216
218 {
219 auto it = m_enemyEntities.find(enemyId);
220 return (it != m_enemyEntities.end()) ? it->second : ecs::INVALID_ENTITY;
221 }
222
223 ecs::Entity EntityManager::createPlayerProjectile(std::uint32_t playerId, float x, float y, float vx, float vy,
224 bool isSupercharged)
225 {
226 std::uint32_t projectileId = m_nextProjectileId++;
227
229 float damage = isSupercharged ? 50.0f : 25.0f;
230 int pierce = isSupercharged ? 3 : 1;
231 float hitboxRadius = isSupercharged ? 8.0f : 5.0f; // Match GameConfig::Hitbox values
232
233 ecs::Entity projectileEntity =
235 .with<ecs::Transform>("projectile_transform_" + std::to_string(projectileId), x, y, 0.0f)
236 .with<ecs::Velocity>("projectile_velocity_" + std::to_string(projectileId), vx, vy)
237 .with<ecs::Projectile>("projectile_" + std::to_string(projectileId), projType, damage, 5.0f, 0.0f,
238 pierce)
239 .with<ecs::Hitbox>("projectile_hitbox_" + std::to_string(projectileId), hitboxRadius, 0.0f, 0.0f)
240 .build();
241
242 m_projectileEntities[projectileId] = projectileEntity;
243 registerEntity(projectileEntity, ServerEntityType::PROJECTILE_PLAYER, projectileId, 5.0f, playerId);
244
245 return projectileEntity;
246 }
247
248 ecs::Entity EntityManager::createEnemyProjectile(std::uint32_t enemyId, float x, float y, float vx, float vy)
249 {
250 std::uint32_t projectileId = m_nextProjectileId++;
251
252 ecs::Entity projectileEntity =
254 .with<ecs::Transform>("enemy_projectile_transform_" + std::to_string(projectileId), x, y, 0.0f)
255 .with<ecs::Velocity>("enemy_projectile_velocity_" + std::to_string(projectileId), vx, vy)
256 .with<ecs::Projectile>("enemy_projectile_" + std::to_string(projectileId), ecs::Projectile::BASIC,
257 15.0f, 10.0f, 0.0f, 1)
258 .with<ecs::Hitbox>("enemy_projectile_hitbox_" + std::to_string(projectileId), 5.0f, 0.0f, 0.0f)
259 .build();
260
261 m_projectileEntities[projectileId] = projectileEntity;
262 registerEntity(projectileEntity, ServerEntityType::PROJECTILE_ENEMY, projectileId, 10.0f, enemyId);
263
264 return projectileEntity;
265 }
266
267 void EntityManager::destroyProjectile(std::uint32_t projectileId)
268 {
269 auto *metadata = getEntityMetadata(projectileId);
270 if (metadata)
271 {
272 metadata->isActive = false;
273 }
274 m_destroyQueue.push_back(projectileId);
275 }
276
277 ecs::Entity EntityManager::getProjectile(std::uint32_t projectileId)
278 {
279 auto it = m_projectileEntities.find(projectileId);
280 return (it != m_projectileEntities.end()) ? it->second : ecs::INVALID_ENTITY;
281 }
282
283 void EntityManager::updateLifetimes(float deltaTime)
284 {
285 for (auto &[networkId, metadata] : m_entityMetadata)
286 {
287 if (metadata.lifetime > 0.0f && metadata.isActive)
288 {
289 metadata.currentLife += deltaTime;
290 if (metadata.currentLife >= metadata.lifetime)
291 {
292 // Mark for destruction
293 m_destroyQueue.push_back(networkId);
294 }
295 }
296 }
297 }
298
300
302 {
303 auto it = m_entityMetadata.find(networkId);
304 return (it != m_entityMetadata.end()) ? &it->second : nullptr;
305 }
306
307 const EntityMetadata *EntityManager::getEntityMetadata(std::uint32_t networkId) const
308 {
309 auto it = m_entityMetadata.find(networkId);
310 return (it != m_entityMetadata.end()) ? &it->second : nullptr;
311 }
312
314 {
315 auto it = m_entityToNetworkId.find(entity);
316 return (it != m_entityToNetworkId.end()) ? it->second : 0;
317 }
318
319 std::vector<rnp::EntityState> EntityManager::getAllEntityStates() const
320 {
321 std::vector<rnp::EntityState> states;
322
323 auto addEntityState = [&](std::uint32_t networkId, ecs::Entity entity, rnp::EntityType netType,
325 {
326 auto *transform = m_registry.getComponent<ecs::Transform>(entity);
327 auto *velocity = m_registry.getComponent<ecs::Velocity>(entity);
328
329 if (transform && velocity)
330 {
331 rnp::EntityState state;
332 state.id = networkId;
333 state.type = static_cast<std::uint16_t>(netType);
334 state.subtype = static_cast<std::uint8_t>(subtype);
335 state.x = transform->x;
336 state.y = transform->y;
337 state.vx = velocity->x;
338 state.vy = velocity->y;
339
340 // Handle health percentage
341 state.healthPercent = 255; // Default: no health bar
342
343 if (netType == rnp::EntityType::PLAYER)
344 {
345 auto *health = m_registry.getComponent<ecs::Health>(entity);
346 if (health && health->max > 0.0f)
347 {
348 float healthPct = (health->current / health->max) * 100.0f;
349 state.healthPercent = static_cast<std::uint8_t>(std::max(0.0f, std::min(100.0f, healthPct)));
350 }
351 }
352 else if (netType == rnp::EntityType::ENEMY || netType == rnp::EntityType::BOSS)
353 {
354 auto *enemy = m_registry.getComponent<ecs::Enemy>(entity);
355 if (enemy && enemy->max_health > 0.0f)
356 {
357 float healthPct = (enemy->health / enemy->max_health) * 100.0f;
358 state.healthPercent = static_cast<std::uint8_t>(std::max(0.0f, std::min(100.0f, healthPct)));
359 }
360 }
361
362 // Handle special state flags
363 state.stateFlags = 0;
364 if (netType == rnp::EntityType::PLAYER)
365 {
366 auto *beamCharge = m_registry.getComponent<ecs::BeamCharge>(entity);
367 if (beamCharge)
368 {
369 state.stateFlags = static_cast<std::uint8_t>(beamCharge->current_charge * 255.0f);
370 }
371 }
372
373 // Initialize score to 0 (will be set for players below)
374 state.score = 0;
375
376 states.push_back(state);
377 }
378 };
379
380 for (const auto &[sessionId, entity] : m_playerEntities)
381 {
382 const auto *metadata = getEntityMetadata(sessionId);
383 if (metadata && metadata->isActive)
384 {
385 addEntityState(sessionId, entity, rnp::EntityType::PLAYER);
386 // Set the player's score in the last added state
387 if (!states.empty())
388 {
389 states.back().score = static_cast<std::uint32_t>(getScore(sessionId));
390 }
391 }
392 }
393
394 for (const auto &[enemyId, entity] : m_enemyEntities)
395 {
396 const auto *metadata = getEntityMetadata(enemyId);
397 if (metadata && metadata->isActive)
398 {
399 rnp::EntityType netType;
400 rnp::EntitySubtype subtype;
401
402 if (metadata->type == ServerEntityType::BOSS)
403 {
404 netType = rnp::EntityType::BOSS;
406 }
407 else if (metadata->type == ServerEntityType::ENEMY_ADVANCED)
408 {
409 netType = rnp::EntityType::ENEMY;
411 }
412 else // ENEMY_BASIC
413 {
414 netType = rnp::EntityType::ENEMY;
416 }
417
418 addEntityState(enemyId, entity, netType, subtype);
419 }
420 }
421
422 for (const auto &[projectileId, entity] : m_projectileEntities)
423 {
424 const auto *metadata = getEntityMetadata(projectileId);
425 if (metadata && metadata->isActive)
426 {
428
429 if (metadata->type == ServerEntityType::PROJECTILE_PLAYER)
430 {
431 // Check if supercharged
432 auto *projectile = m_registry.getComponent<ecs::Projectile>(entity);
433 if (projectile && projectile->type == ecs::Projectile::SUPERCHARGED)
434 {
436 }
437 else
438 {
440 }
441 }
442 else if (metadata->type == ServerEntityType::PROJECTILE_ENEMY)
443 {
445 }
446
447 addEntityState(projectileId, entity, rnp::EntityType::PROJECTILE, subtype);
448 }
449 }
450
451 return states;
452 }
453
472
474 {
475 // Clear all players
476 for (auto &[sessionId, entity] : m_playerEntities)
477 {
490 }
491 m_playerEntities.clear();
492
493 // Clear all enemies
494 for (auto &[enemyId, entity] : m_enemyEntities)
495 {
504 }
505 m_enemyEntities.clear();
506
507 // Clear all projectiles
508 for (auto &[projectileId, entity] : m_projectileEntities)
509 {
518 }
519 m_projectileEntities.clear();
520
521 // Clear all powerups
522 for (auto &[powerupId, entity] : m_powerupEntities)
523 {
530 }
531 m_powerupEntities.clear();
532
533 m_entityMetadata.clear();
534 m_entityToNetworkId.clear();
535 m_destroyQueue.clear();
536 m_deadPlayers.clear();
537 }
538
540 {
541 return m_playerEntities.size() + m_enemyEntities.size() + m_projectileEntities.size() +
542 m_powerupEntities.size();
543 }
544
545 void EntityManager::registerEntity(ecs::Entity entity, ServerEntityType type, std::uint32_t networkId,
546 float lifetime, std::uint32_t ownerId)
547 {
548 EntityMetadata metadata;
549 metadata.entity = entity;
550 metadata.type = type;
551 metadata.networkId = networkId;
552 metadata.isActive = true;
553 metadata.lifetime = lifetime;
554 metadata.currentLife = 0.0f;
555 metadata.ownerId = ownerId;
556
557 m_entityMetadata[networkId] = metadata;
558 m_entityToNetworkId[entity] = networkId;
559 }
560
561 void EntityManager::unregisterEntity(std::uint32_t networkId)
562 {
563 auto it = m_entityMetadata.find(networkId);
564 if (it != m_entityMetadata.end())
565 {
566 m_entityToNetworkId.erase(it->second.entity);
567 m_entityMetadata.erase(it);
568 }
569 }
570
572 {
573 for (std::uint32_t networkId : m_destroyQueue)
574 {
575 // Check which container this entity belongs to
576 auto playerIt = m_playerEntities.find(networkId);
577 if (playerIt != m_playerEntities.end())
578 {
579 ecs::Entity entity = playerIt->second;
580
581 // Remove components
594
595 unregisterEntity(networkId);
596
597 // Clear score and other player data
598 m_playerScores.erase(networkId);
599 m_deadPlayers.erase(networkId);
600 m_playerEntities.erase(playerIt);
601
602 utl::Logger::log("EntityManager: Destroyed player entity for sessionId " + std::to_string(networkId),
604 continue;
605 }
606
607 auto enemyIt = m_enemyEntities.find(networkId);
608 if (enemyIt != m_enemyEntities.end())
609 {
610 ecs::Entity entity = enemyIt->second;
619
620 unregisterEntity(networkId);
621 m_enemyEntities.erase(enemyIt);
622 continue;
623 }
624
625 auto projIt = m_projectileEntities.find(networkId);
626 if (projIt != m_projectileEntities.end())
627 {
628 ecs::Entity entity = projIt->second;
637
638 unregisterEntity(networkId);
639 m_projectileEntities.erase(projIt);
640 continue;
641 }
642
643 auto powerupIt = m_powerupEntities.find(networkId);
644 if (powerupIt != m_powerupEntities.end())
645 {
646 ecs::Entity entity = powerupIt->second;
653
654 unregisterEntity(networkId);
655 m_powerupEntities.erase(powerupIt);
656 continue;
657 }
658 }
659
660 m_destroyQueue.clear();
661 }
662
663} // namespace gme
Centralized entity lifecycle management system for R-Type server.
Configuration constants for the multiplayer game.
This file contains the Logger class.
EntityBuilder & with(Args &&...args)
Definition Registry.hpp:40
Class for managing entities and their components.
Definition Registry.hpp:25
EntityBuilder createEntity()
Definition Registry.hpp:53
bool hasComponent(Entity e)
Definition Registry.hpp:79
T * getComponent(Entity e)
Definition Registry.hpp:71
void removeComponent(Entity e)
Definition Registry.hpp:85
ecs::Entity getPlayer(std::uint32_t sessionId)
Get player entity by session ID.
std::unordered_map< std::uint32_t, EntityMetadata > m_entityMetadata
Entity metadata by network ID.
ecs::Entity getProjectile(std::uint32_t projectileId)
Get projectile entity by network ID.
void addScore(std::uint32_t sessionId, int points)
Add points to a player's score.
std::uint32_t m_nextEnemyId
Next available enemy network ID.
bool hasPlayer(std::uint32_t sessionId) const
Check if player exists.
void cleanupDestroyedEntities()
Process destruction queue and remove destroyed entities.
void markPlayerAsDead(std::uint32_t sessionId)
Mark a player as dead without destroying the entity.
void destroyPlayer(std::uint32_t sessionId)
Destroy a player entity.
ecs::Entity createPlayerProjectile(std::uint32_t playerId, float x, float y, float vx, float vy, bool isSupercharged=false)
Create a player projectile entity.
void updateLifetimes(float deltaTime)
Update lifetime counters for temporary entities.
EntityManager(ecs::Registry &registry)
Constructor.
std::unordered_map< std::uint32_t, ecs::Entity > m_powerupEntities
Powerup entities by network ID.
std::vector< std::uint32_t > m_destroyQueue
Queue of network IDs pending destruction.
std::uint32_t getNetworkIdForEntity(ecs::Entity entity) const
Get network ID for an entity handle.
rnp::EntityType getNetworkEntityType(ServerEntityType type) const
Convert server entity type to network protocol entity type.
std::unordered_set< std::uint32_t > m_deadPlayers
Set of dead player session IDs.
ecs::Entity createBoss(float x, float y, float health=1000.0f)
Create a boss enemy entity.
void processDestroyQueue()
Process pending entity destructions from queue.
ecs::Entity getPlayerEntity(std::uint32_t sessionId) const
Get player entity by session ID (const version)
int getScore(std::uint32_t sessionId) const
Get player's current score.
ecs::Entity createAdvancedEnemy(float x, float y, float health=100.0f)
Create an advanced enemy entity.
std::unordered_map< ecs::Entity, std::uint32_t > m_entityToNetworkId
Reverse lookup map.
std::unordered_map< std::uint32_t, ecs::Entity > m_projectileEntities
Projectile entities by network ID.
ecs::Entity createPlayer(std::uint32_t sessionId, float x, float y)
Create a new player entity.
std::unordered_map< std::uint32_t, ecs::Entity > m_playerEntities
Player entities by session ID.
EntityMetadata * getEntityMetadata(std::uint32_t networkId)
Get entity metadata by network ID.
void destroyProjectile(std::uint32_t projectileId)
Destroy a projectile entity.
std::vector< rnp::EntityState > getAllEntityStates() const
Get network state for all entities.
ecs::Registry & m_registry
Reference to ECS registry.
void clear()
Clear all entities and reset manager state.
void destroyEnemy(std::uint32_t enemyId)
Destroy an enemy entity.
size_t getTotalEntityCount() const
Get total count of all managed entities.
std::unordered_map< std::uint32_t, ecs::Entity > m_enemyEntities
Enemy entities by network ID.
std::uint32_t getAlivePlayerCount() const
Get count of alive players.
ecs::Entity createBasicEnemy(float x, float y, float health=50.0f)
Create a basic enemy entity.
std::uint32_t m_nextProjectileId
Next available projectile network ID.
ecs::Entity createEnemyProjectile(std::uint32_t enemyId, float x, float y, float vx, float vy)
Create an enemy projectile entity.
void registerEntity(ecs::Entity entity, ServerEntityType type, std::uint32_t networkId, float lifetime=-1.0f, std::uint32_t ownerId=0)
Register a new entity with the manager.
std::unordered_map< std::uint32_t, int > m_playerScores
Player scores by session ID.
void resetScore(std::uint32_t sessionId)
Reset player's score to zero.
void unregisterEntity(std::uint32_t networkId)
Unregister an entity from the manager.
ecs::Entity getEnemy(std::uint32_t enemyId)
Get enemy entity by network ID.
static void log(const std::string &message, const LogLevel &logLevel)
Definition Logger.hpp:51
std::uint32_t Entity
Definition Entity.hpp:13
constexpr Entity INVALID_ENTITY
Definition Entity.hpp:14
ServerEntityType
Enumeration of entity types managed by the server.
@ ENEMY_ADVANCED
Advanced enemy type (complex behavior)
@ PLAYER
Player-controlled entity.
@ PROJECTILE_PLAYER
Player-fired projectile.
@ ENEMY_BASIC
Basic enemy type (simple behavior)
@ PROJECTILE_ENEMY
Enemy-fired projectile.
@ BOSS
Boss enemy (high health, special patterns)
EntityType
Entity types for world state.
Definition Protocol.hpp:106
EntitySubtype
Entity subtype enumeration.
Definition Protocol.hpp:167
constexpr float SCREEN_WIDTH
constexpr float SCREEN_HEIGHT
Metadata structure for tracking entity lifecycle and properties.
ecs::Entity entity
ECS entity handle.
float lifetime
Maximum lifetime in seconds (-1 for infinite)
float currentLife
Elapsed lifetime counter in seconds.
ServerEntityType type
Entity type classification.
std::uint32_t ownerId
Owner entity ID (for projectiles, the spawner)
bool isActive
Whether entity is currently active.
std::uint32_t networkId
Unique ID used in network synchronization packets.
Entity state for WORLD_STATE packet.
Definition Protocol.hpp:183
std::uint32_t id
Definition Protocol.hpp:184
std::uint16_t type
Definition Protocol.hpp:185
std::uint32_t score
Definition Protocol.hpp:191
std::uint8_t stateFlags
Definition Protocol.hpp:190
std::uint8_t healthPercent
Definition Protocol.hpp:189
std::uint8_t subtype
Definition Protocol.hpp:186