80 for (
const auto &event : events)
126 if (event.
data.size() >=
sizeof(std::uint32_t))
128 size_t playerCount =
event.data.size() /
sizeof(std::uint32_t);
130 for (
size_t i = 0; i < playerCount; ++i)
132 std::uint32_t sessionId;
133 std::memcpy(&sessionId, event.
data.data() + i *
sizeof(std::uint32_t),
sizeof(std::uint32_t));
137 float startX = 200.0f + (i * 200.0f);
138 float startY = 100.0f + (i * 100.0f);
144 utl::Logger::log(
"RTypeServer: Created player entity for sessionId " + std::to_string(sessionId),
164 if (event.
data.size() >= 5)
166 bool up =
event.data[0] != 0;
167 bool down =
event.data[1] != 0;
168 bool left =
event.data[2] != 0;
169 bool right =
event.data[3] != 0;
170 bool shoot =
event.data[4] != 0;
172 std::uint32_t sessionId =
event.sourceId;
178 float spawnX = 200.0f;
179 float spawnY = 200.0f + ((sessionId % 4) * 200.0f);
192 if (velocity && transform)
195 constexpr float SPEED = 500.0f;
196 constexpr float DIAGONAL_SPEED = SPEED * 0.707f;
204 velocity->x = DIAGONAL_SPEED;
205 velocity->y = -DIAGONAL_SPEED;
209 velocity->x = -DIAGONAL_SPEED;
210 velocity->y = -DIAGONAL_SPEED;
212 else if (down && right)
214 velocity->x = DIAGONAL_SPEED;
215 velocity->y = DIAGONAL_SPEED;
217 else if (down && left)
219 velocity->x = -DIAGONAL_SPEED;
220 velocity->y = DIAGONAL_SPEED;
226 velocity->y = -SPEED;
230 velocity->x = -SPEED;
241 catch (
const std::exception &e)
276 for (
const auto &sessionId :
m_entityManager->getPlayers() | std::views::keys)
293 const std::uint32_t totalPlayerCount =
static_cast<std::uint32_t
>(
m_entityManager->getPlayers().size());
294 if (totalPlayerCount == 0)
310 const std::uint32_t alivePlayerCount =
m_entityManager->getAlivePlayerCount();
315 bool shouldGameOver =
false;
318 if (alivePlayerCount == 0)
320 shouldGameOver =
true;
321 reason =
"All players died";
324 else if (totalPlayerCount > 1 && alivePlayerCount == 1)
326 shouldGameOver =
true;
327 reason =
"Only one player remaining";
330 else if (allWavesComplete)
332 shouldGameOver =
true;
333 reason =
"All waves completed";
342 std::vector<std::uint8_t> gameOverData;
343 gameOverData.resize(1);
344 gameOverData[0] =
static_cast<std::uint8_t
>(
m_levelState);
355 std::uint32_t sessionId =
event.sourceId;
363 utl::Logger::log(
"RTypeServer: Removed player " + std::to_string(sessionId) +
" from game",
407 if (!beamCharge || !transform)
413 constexpr float CHARGE_RATE = 2.0f;
414 beamCharge->current_charge += CHARGE_RATE * deltaTime;
415 if (beamCharge->current_charge > beamCharge->max_charge)
416 beamCharge->current_charge = beamCharge->max_charge;
418 else if (beamCharge->current_charge > 0.01f)
425 const float projectileX = transform->x + PLAYER_WIDTH + 10.0f;
426 const float projectileY = transform->y + PLAYER_HEIGHT / 2.0f;
429 const float projectileSpeed = isSupercharged ? 1200.0f : 800.0f;
431 m_entityManager->createPlayerProjectile(sessionId, projectileX, projectileY, projectileSpeed, 0.0f,
434 beamCharge->current_charge = 0.0f;
442 for (
const auto &players =
m_entityManager->getPlayers();
const auto &entity : players | std::views::values)
448 if (transform && velocity)
450 transform->x += velocity->
x * deltaTime;
451 transform->y += velocity->
y * deltaTime;
455 constexpr float PLAYER_WIDTH =
457 constexpr float PLAYER_HEIGHT =
459 const float hitboxRadius = hitbox->radius;
464 transform->
x = std::max(hitboxRadius, std::min(transform->x, maxX));
465 transform->y = std::max(hitboxRadius, std::min(transform->y, maxY));
476 for (
const auto &enemies =
m_entityManager->getEnemies();
const auto &[enemyId, entity] : enemies)
479 if (
const auto *metadata =
m_entityManager->getEntityMetadata(enemyId); !metadata || !metadata->isActive)
487 if (transform && velocity)
489 transform->
x += velocity->
x * deltaTime;
490 transform->y += velocity->
y * deltaTime;
504 for (
const auto &[projectileId, entity] : projectiles)
506 if (
const auto *metadata =
m_entityManager->getEntityMetadata(projectileId);
507 !metadata || !metadata->isActive)
515 if (transform && velocity)
517 transform->
x += velocity->
x * deltaTime;
518 transform->y += velocity->
y * deltaTime;
546 for (
const auto &sessionId : players | std::views::keys)
558 header.
length =
static_cast<std::uint16_t
>(tempSerializer.
getData().size());
565 std::vector<std::uint8_t> packet = packetSerializer.
getData();
569 std::vector<std::uint8_t> eventData(
sizeof(std::uint32_t) + packet.size());
570 std::memcpy(eventData.data(), &sessionId,
sizeof(std::uint32_t));
571 std::memcpy(eventData.data() +
sizeof(std::uint32_t), packet.data(), packet.size());
572 broadcastEvent.
data = eventData;
576 catch (
const std::exception &e)
578 utl::Logger::log(
"RTypeServer: Error broadcasting world state: " + std::string(e.what()),
This file contains the component definitions.
Thread-safe event bus implementation for inter-component communication.
Configuration constants for the multiplayer game.
This file contains the Logger class.
Main game server plugin for R-Type multiplayer.
Network packet serializer for RNP protocol.
T * getComponent(Entity e)
std::unique_ptr< EntityManager > m_entityManager
Centralized entity lifecycle manager.
void update(float deltaTime) override
Update the game server (called each tick)
ecs::Registry m_registry
ECS registry containing all game entities.
State m_gameState
Current server state.
std::unordered_map< std::uint32_t, bool > m_playerShooting
Map of session ID to shooting state.
std::unique_ptr< WaveManager > m_waveManager
Wave-based enemy spawning manager.
RTypeServer()
Constructor.
float m_lastBroadcastTime
Time since last world state broadcast.
LevelState m_levelState
Current level state.
void updateEntities(float deltaTime)
Update entity lifetimes and physics.
void checkGameOver()
Check for game over conditions.
void broadcastWorldState() const
Broadcast complete world state to all clients.
utl::EventBus & m_eventBus
Event bus for inter-system communication.
std::unordered_map< std::uint32_t, float > m_lastShotTime
Map of session ID to last shot timestamp.
void processServerStartEvent(const utl::Event &event)
Process server start event from network layer.
std::unique_ptr< EnemyAISystem > m_enemyAISystem
Enemy behavior and AI system.
void stop() override
Stop the game server.
void start() override
Start the game server.
std::unique_ptr< EnemySpawnSystem > m_enemySpawnSystem
Enemy spawning system (legacy/unused)
void processGameStartEvent(const utl::Event &event)
Process game start event from lobby system.
void updateSystems(float deltaTime)
Update all game systems (AI, collision, spawning)
const float PROJECTILE_COOLDOWN
Cooldown between player shots (seconds)
void processPlayerInputEvent(const utl::Event &event)
Process player input event.
void processPlayerDisconnectEvent(const utl::Event &event)
Process player disconnect event.
void handlePlayerShooting(std::uint32_t sessionId, float deltaTime)
Handle player shooting logic.
std::unique_ptr< CollisionSystem > m_collisionSystem
Collision detection and resolution system.
Binary serializer for RNP protocol packets.
void serializeWorldState(const PacketWorldState &packet)
Serialize WORLD_STATE packet.
void serializeHeader(const PacketHeader &header)
Serialize packet header.
const std::vector< std::uint8_t > & getData() const
Get the serialized data.
bool publish(const Event &event)
Publish an event to the bus.
std::vector< Event > consumeForTarget(std::uint32_t targetId, std::uint32_t maxEvents=100)
Consume events targeted to specific component.
void registerComponent(std::uint32_t componentId, const std::string &name)
Register component name for better debugging.
void subscribe(std::uint32_t componentId, EventType type)
Subscribe component to specific event types.
Event structure for inter-component communication.
std::vector< std::uint8_t > data
Serialized event data.
static void log(const std::string &message, const LogLevel &logLevel)
This file contains common definitions and constants.
constexpr Entity INVALID_ENTITY
@ WAITING_FOR_PLAYERS
Waiting for players to join before starting.
@ COMPLETED
Level successfully completed (all waves cleared)
@ IN_PROGRESS
Game is actively running.
@ LOOSE
Game over (all players dead)
constexpr float SPRITE_HEIGHT
constexpr float SPRITE_WIDTH
constexpr float BROADCAST_INTERVAL
constexpr float WORLD_MARGIN
constexpr float SCREEN_WIDTH
constexpr float SCREEN_HEIGHT
static constexpr std::uint32_t GAME_LOGIC
static constexpr std::uint32_t NETWORK_SERVER
WORLD_STATE packet payload.
std::uint16_t entityCount
std::vector< EntityState > entities