23 void hashCombine(std::size_t &seed, std::size_t value)
25 seed ^= value + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
28 std::size_t hashRoomList(
const std::list<net::RoomInfo>& rooms)
31 for (
const auto& room : rooms) {
32 hashCombine(seed, std::hash<uint32_t>{}(room.roomId));
33 hashCombine(seed, std::hash<uint32_t>{}(room.currentPlayers));
34 hashCombine(seed, std::hash<uint32_t>{}(room.maxPlayers));
35 hashCombine(seed, std::hash<uint8_t>{}(room.inGame));
36 hashCombine(seed, std::hash<float>{}(room.difficulty));
37 hashCombine(seed, std::hash<float>{}(room.speed));
38 hashCombine(seed, std::hash<uint32_t>{}(room.duration));
39 hashCombine(seed, std::hash<uint32_t>{}(room.seed));
40 hashCombine(seed, std::hash<uint32_t>{}(room.levelId));
41 hashCombine(seed, std::hash<std::string>{}(std::string(room.roomName)));
56 std::function<
void(
GameState)> changeState)
57 : _uiRegistry(UiRegistry),
59 _translationManager(translationManager),
61 _uiFactory(uiFactory),
62 _changeState(changeState)
84 auto &buttons = buttonsOpt.value().get();
85 if (!buttons.has(entity)) {
88 auto &button = buttons[entity];
89 std::copy(std::begin(style.idleColor), std::end(style.idleColor),
90 std::begin(button.idleColor));
91 std::copy(std::begin(style.hoverColor), std::end(style.hoverColor),
92 std::begin(button.hoverColor));
93 std::copy(std::begin(style.pressedColor), std::end(style.pressedColor),
94 std::begin(button.pressedColor));
97 auto formatFloat = [](
float value) -> std::string {
98 std::ostringstream oss;
99 oss << std::fixed << std::setprecision(1) << value;
178 "assets/fonts/title.ttf",
188 "assets/fonts/title.ttf",
198 "Rooms available: " + std::to_string(rooms.size()),
199 "assets/fonts/main.ttf",
205 const float topY = 150.0f;
206 const float topX = 180.0f;
207 const float topBtnW = 200.0f;
208 const float topBtnH = 50.0f;
209 const float topGap = 20.0f;
221 styleButton(refreshButton, secondaryStyle);
225 {topX + topBtnW + topGap, topY},
232 styleButton(createRoomButton, primaryStyle);
236 {topX + (topBtnW + topGap) * 2.0f, topY},
243 styleButton(backButton, secondaryStyle);
245 const float panelX = 140.0f;
246 const float panelY = 220.0f;
247 const float panelW = 1000.0f;
248 const float panelH = 420.0f;
257 styleButton(listPanel, panelStyle);
261 {panelX + 20.0f, panelY + 12.0f},
263 "assets/fonts/main.ttf",
271 {panelX + panelW - 250.0f, panelY + 12.0f},
273 "assets/fonts/main.ttf",
279 float y = panelY + 40.0f;
282 for (
const auto& room : rooms) {
287 const float rowY = y +
static_cast<float>(shown) * 64.0f;
290 {panelX + 20.0f, rowY},
291 {panelW - 40.0f, 56.0f},
295 styleButton(rowBg, (shown % 2 == 0) ? rowStyleA : rowStyleB);
297 std::string roomName = std::string(room.roomName);
298 if (roomName.empty()) {
299 roomName =
"Room " + std::to_string(room.roomId);
302 std::string line1 = roomName +
" • " +
303 std::to_string(room.currentPlayers) +
"/" +
304 std::to_string(room.maxPlayers) +
" players";
306 std::string line2 =
"Difficulty " + formatFloat(room.difficulty) +
307 " • Speed " + formatFloat(room.speed) +
308 " • Level " + std::to_string(room.levelId);
312 {panelX + 40.0f, rowY + 8.0f},
314 "assets/fonts/main.ttf",
322 {panelX + 40.0f, rowY + 32.0f},
324 "assets/fonts/main.ttf",
330 const float joinW = 110.0f;
331 const float specW = 110.0f;
332 const float actionY = rowY + 10.0f;
333 const float joinX = panelX + panelW - 250.0f;
334 const float specX = joinX + joinW + 10.0f;
343 log::info(
"Attempting to join Room ID {}", room.roomId);
347 styleButton(joinButton, joinStyle);
356 log::info(
"Attempting to spectate Room ID {}", room.roomId);
360 styleButton(specButton, specStyle);
365 {panelX + panelW - 360.0f, rowY + 18.0f},
367 "assets/fonts/main.ttf",
380 {panelX + 40.0f, panelY + 80.0f},
381 "No rooms found. Create one or refresh.",
382 "assets/fonts/main.ttf",
404 const std::size_t newHash = hashRoomList(rooms);
System to handle network-related operations on the client side.
State getState(void) const
Get the current state of the client.
void tryJoinRoom(uint32_t roomId, bool asSpectator=false)
Send a request to join an existing room on the server.
void requestListRooms(void)
Send a request to have the list of available rooms from the server.
std::list< net::RoomInfo > getAvailableRooms(void) const
Get a list of available rooms from the server.
Manages game settings and preferences.
Manages game translations for all UI elements.
Factory class for creating UI components in the ECS registry.
static ecs::Entity createText(ecs::Registry ®istry, const position &position, const std::string &content, const std::string &fontPath, unsigned int fontSize, const std::uint8_t zIndex=0, const color &textColor={255, 255, 255})
static ecs::Entity createButton(ecs::Registry ®istry, const position &position, const size &size, const std::string &label, std::function< void()> onClick=nullptr)
Create a button UI component.
NetworkSyncSystem & _network
Reference to the client network.
uint32_t _uiSelectedRoomId
Currently selected room ID in the UI.
ecs::Registry & _uiRegistry
Reference to the ECS registry.
ChangeStateFn _changeState
Function to change the game state.
bool _uiBuilt
Tracks if the UI has been built at least once.
void update(float dt) override
Update the scene state.
void onExit(void) override
Called when the scene is exited.
graphics::UiFactory & _uiFactory
UI Factory for creating UI components.
std::size_t _roomsHash
Hash of the last room list displayed.
void onEnter(void) override
Called when the scene is entered.
void handleEvent(const sf::Event &event) override
Handle an incoming event.
LobbyScene(ecs::Registry &UiRegistry, Settings &settings, TranslationManager &translationManager, NetworkSyncSystem &network, graphics::UiFactory &uiFactory, std::function< void(GameState)> changeState)
Constructor for LobbyScene.
Represents an entity in the ECS (Entity-Component-System) architecture.
void clear(void) noexcept
auto get(this const Self &self) -> std::expected< std::reference_wrapper< ConstLike< Self, SparseArray< T > > >, rtp::Error >
@ RoomWaiting
Room waiting state.
@ CreateRoom
Create room state.
@ Playing
In-game playing state.
void info(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an informational message.