#pragma once #include "distance_settings.h" #include "object_placement.h" #include "session_limits.h" #include "tick_settings.h" #include "voice_settings.h" #include #include #include #include #include namespace dingosdk { struct MultiplayerLobby { std::uint64_t id{}, owner{}; std::string name, map, code; bool password_required{}; int players = 1, capacity = multiplayer_player_limit; // A dedicated server rather than a player's lobby: joined by its code. bool dedicated{}; int ping = -1; // ms, when the server answered directly }; struct MultiplayerPlayer { std::uint64_t id{}; std::string name; bool connected{}, visible{}; std::string native_status, cosmetic_status, audio_status, ui_status; std::string route; float pose_hz{}; unsigned pose_target_tps = 20; float distance_m = -1; std::uint64_t pose_age_ms{}; float native_pose_hz{}, native_board_hz{}; float native_animation_hz{}, native_animation_ms{}, pose_apply_ms{}; std::uint64_t native_animation_skipped{}; std::string playback; unsigned prediction_ms{}; bool correcting{}; std::uint64_t epoch{}; // The player's party (0 = none), whether they lead it, and whether it is the local player's. std::uint32_t party{}; bool party_leader{}, party_member{}; }; // A party invite waiting for an answer (dedicated servers). struct MultiplayerPartyInvite { std::uint64_t from{}; std::string name; }; struct MultiplayerClientTiming { float callback_hz{}, gap_max_ms{}, work_ms{}, work_max_ms{}; // Capture/setup, receive/routing, encode/send, remote playback, diagnostics. std::array mean_ms{}, peak_ms{}; }; // The host settings last used, saved in the local profile, so the host pages // open with them. The password itself is never saved. struct MultiplayerHostPreferences { bool loaded{}, public_lobby{true}, password_required{}; int capacity = multiplayer_lobby_player_limit; unsigned tps = multiplayer_default_tps; std::string lobby_name; }; // Session text chat. A message is UTF-8 without control characters, at most // this many bytes; the log keeps the most recent lines of the session. inline constexpr std::size_t multiplayer_chat_max_bytes = 200; inline constexpr std::size_t multiplayer_chat_history = 50; struct MultiplayerChatLine { std::uint64_t sequence{}; // local arrival order, increasing within the process std::uint64_t sender{}; // Steam id; 0 for a notice from ReSkate itself std::string name, text; bool local{}; // sent by this player // The sender's role, as their nametag shows it: its colour (IM_COL32 layout, 0 = none) // and a tag shown in a box before the name ("Dev", "Admin", "Host", "Friend" or empty). std::uint32_t color{}; std::string tag; }; // A command typed into chat with a leading "/" (shown as the player types "/"). struct MultiplayerChatCommand { std::string name; // "/vote map" std::string usage; // "/vote map " std::string description; std::string argument; // what Tab completes after it: "player", "map", "time" or "" }; // What the chat overlay reads each frame: cheap to copy, unlike the full model. struct MultiplayerChat { bool available{}; // in a session that can carry chat std::uint64_t latest{}; // sequence of the newest line, 0 when empty std::vector lines; std::vector commands; // what "/" offers in this session std::vector players, maps; // what their arguments complete to }; // A player this PC's lobbies never admit, kept in the local profile. struct MultiplayerBan { std::uint64_t id{}; // SteamID64 std::string name; // as they were known when banned; may be empty std::int64_t added{}; // Unix time }; struct MultiplayerModel { VoiceModel voice; std::vector bans; unsigned tps = multiplayer_default_tps; ObjectPlacement object_placement = ObjectPlacement::everyone; // Host setting: whether guests may use noclip / No Bail (the host and server admins always may). bool guest_noclip{true}, guest_no_bail{true}, guest_boosts{true}; // Host setting: guests skate with the host's physics tuning (on a dedicated server: the // game's own). Guest: what that does here, while enforced. bool enforce_tuning{true}; std::string tuning_status; // Local display preference: the floating name label above each peer. bool nametags{true}; // Nametag style: ReSkate's own (name, distance, role colours, dots) or the game's. bool custom_nametags{true}; // Local: whether session text chat shows at all (and T opens it). bool chat_visible{true}; // Local: bad words in chat names and messages show as **** (on by default). bool chat_filter{true}; float voice_range = default_voice_range; // how far the host (or server) forwards proximity voice // In a dedicated server's session: the server is the host but not a player. // Admins it lists may change its settings, and its map through Levels. bool dedicated{}, server_admin{}; // `bans` is the dedicated server's list (for its admins) rather than this PC's. bool server_bans{}; unsigned server_ban_total{}; // For its admins: the levels (assets) the dedicated server can switch to. std::vector server_maps; MultiplayerHostPreferences saved_host; bool force_world_layers{}; std::uint64_t host_id{}; std::string local_name; std::string lobby_name; std::string object_status; MultiplayerClientTiming client_timing; MultiplayerDistances distances; bool password_required{}; int players = 1, capacity = multiplayer_player_limit; std::vector roster; // The local player's party. Players form their own, in a lobby as on a dedicated server // (`parties`: invite, leave, kick... are available in any session). std::uint32_t party{}; bool party_leader{}, party_open{}, parties{}; std::vector party_invites; // newest last bool active{}, hosting{}, connected{}, echo{}, remote_visible{}, local_ready{}; std::uint64_t local_id{}, peer_id{}, sent{}, received{}, dropped{}, pose_updates{}, board_pose_updates{}; std::size_t skater_bones{}, board_bones{}; std::string invite, map; std::string status = "Multiplayer is off."; std::string native_status; std::string cosmetic_status; std::string audio_status; std::uint64_t audio_captured{}, audio_played{}; std::string peer_name, player_ui_status; std::uint64_t player_map_updates{}; bool public_host{}, lobby_listed{}, lobby_searching{}, lobby_joining{}, lobby_searched{}; std::uint64_t public_lobby{}; // Verified public listing, never a private invitation. std::string lobby_status, browser_status = "Refresh to find public ReSkate lobbies."; std::vector lobbies; bool network_telemetry{}; unsigned prioritized_connections{}; std::uint64_t cosmetic_queue_us{}; unsigned direct_connections{}, fallback_streams{}, direct_upload_limit{}; int ping_ms{}, send_rate{}, pending_bytes{}; float outgoing_bps{}, incoming_bps{}, delivery_local = -1, delivery_remote = -1; std::uint64_t queue_us{}, skipped_updates{}, send_failures{}, invalid_messages{}, sent_bytes{}, raw_sent_bytes{}; }; inline bool multiplayer_controls_level(const MultiplayerModel& model) noexcept { // A server admin's level choice is sent to the server, which moves everyone. return model.lobby_joining || (model.active && !model.hosting && !model.echo && !model.server_admin); } } // namespace dingosdk