#ifndef MATCHMAKING_H #define MATCHMAKING_H #include #include #include #include #include "dCommonVars.h" #include "eMatchUpdate.h" /** * Activity lobbies of every world, kept by the chat server (docs/Matchmaking.md). Players on different instances of a * zone who join the same activity wait in the same lobby and are sent to the same activity instance. * * Only the state machine: no network, no game data. What it does is handed back as MatchUpdates to send to clients * and Matches to start; ChatMatchmaking sends them. */ namespace Matchmaking { // What the world read from the activity (CDClient Activities, with the world's own overrides) struct ActivitySettings { int32_t activityID{}; uint32_t instanceMapID{}; int32_t minTeams{}; int32_t maxTeams{}; int32_t minTeamSize{}; int32_t maxTeamSize{}; float waitTime{}; // seconds float startDelay{}; // seconds // How many players a lobby holds: the team size, or the number of teams when every team is one player uint32_t Capacity() const; // How many players a lobby needs before its countdown runs uint32_t Minimum() const; }; // A game message MatchUpdate for one client struct Update { LWOOBJID to{}; eMatchUpdate type{}; std::string data; // name-value text }; // A lobby whose countdown ran out: these players go to one new instance of the activity's zone struct Match { ActivitySettings settings; std::vector players; // in the order they joined }; struct LobbyPlayer { LWOOBJID id{}; std::string name; std::string choices; // the client's name-value text, shown to the others with the player bool ready{}; }; struct Lobby { ActivitySettings settings; std::vector players; float timer{}; // seconds left bool counting{}; // the lobby reached its minimum and everyone was told the countdown }; class Lobbies { public: // A player joins the activity: they go into the first lobby of it with room, or a new one. // Returns false when they are already waiting for this activity (nothing changes). bool Join(LWOOBJID player, const std::string& name, const std::string& choices, const ActivitySettings& settings, std::vector& out); // The player leaves the lobby they are in. Returns false when they are in none. bool Leave(LWOOBJID player, std::vector& out); // The player is ready (or not). Returns false when they are in no lobby. bool SetReady(LWOOBJID player, bool ready, std::vector& out); // Runs the countdowns; returns the lobbies that start now (they are removed) std::vector Tick(float deltaTime, std::vector& out); bool IsWaiting(LWOOBJID player) const { return Find(player) != nullptr; } const Lobby* Find(LWOOBJID player) const; const std::map& GetLobbies() const { return m_Lobbies; } void Clear() { m_Lobbies.clear(); } private: Lobby* FindMutable(LWOOBJID player); static void Broadcast(const Lobby& lobby, eMatchUpdate type, const std::string& data, std::vector& out); // In the order they were made, so a joining player fills the oldest lobby first std::map m_Lobbies; uint64_t m_NextLobbyID = 1; }; // The name-value texts of the updates, as live sent them std::string PlayerText(LWOOBJID player); std::string PlayerAddedText(const LobbyPlayer& player); std::string TimeText(float seconds); } #endif // MATCHMAKING_H