1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#![doc = include_str!("../README.md")]
// This cfg_attr is needed because `rustdoc::all` includes lints not supported on stable
#![cfg_attr(doc, allow(unknown_lints))]
#![deny(rustdoc::all)]

use serde::{Deserialize, Serialize};

/// ALPN used for the matchmaking protocol.
pub const MATCH_ALPN: &[u8] = b"/bones/match/0";

/// ALPN used for the direct connections between players.
pub const PLAY_ALPN: &[u8] = b"/bones/play/0";

//
// === Matchmaking Mode ===
//
// These are messages sent when first establishing a connection to the matchmaker and waiting for a
// match.
//
/// Requests that may be made in matchmaking mode
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum MatchmakerRequest {
    /// Request to have the client join matchmaking queue
    RequestMatchmaking(MatchInfo),
    /// Request to remove the client from the matchmaking queue
    StopMatchmaking(MatchInfo),
    /// Request a list of lobbies for a specific game
    ListLobbies(String),
    /// Request to create a new lobby
    CreateLobby(LobbyInfo),
    /// Request to join an existing lobby for a specific gameid, optionally providing a password
    JoinLobby(GameID, LobbyId, Option<String>),
}

/// Information about a match that is being requested
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
pub struct MatchInfo {
    /// The maximum number of players to have in a match.
    pub max_players: u32,
    /// This is an arbitrary set of bytes that must match exactly for clients to end up in the same match.
    /// This allows us to support matchmaking for different modes or game versions with the same matchmaking server.
    pub match_data: Vec<u8>,
    /// The unique identifier for the game
    pub game_id: GameID,
    /// Enables choosing how player_idx should be assigned to each player who joins the match.
    pub player_idx_assignment: PlayerIdxAssignment,
}

/// Information about a lobby
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LobbyInfo {
    /// The name of the lobby
    pub name: String,
    /// The maximum number of players allowed in the lobby
    pub max_players: u32,
    /// The hashed password for the lobby, if any
    pub password_hash: Option<String>,
    /// This is an arbitrary set of bytes that the lobby creator specifies and which other clients must read/accept (ie. settings, version number, etc.)
    pub match_data: Vec<u8>,
    /// The unique identifier for the game
    pub game_id: String,
    /// Enables choosing how player_idx should be assigned to each player who joins the match.
    pub player_idx_assignment: PlayerIdxAssignment,
}

/// Choose how player_idx should be assigned to each player who joins a match/lobby.
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq, Default)]
pub enum PlayerIdxAssignment {
    /// The players will be assigned an idx based on the order that they join the match/lobby.
    #[default]
    Ordered,
    /// The players will randomly be assigned an idx
    Random,
    /// The order specified in the Vec will be assigned to the players based on the order they join the match/lobby.
    /// Ie. If the Vec contains `0,2,1,3` then the first player will get player_idx 0, second 2, third 1, and fourth 3.
    SpecifiedOrder(Vec<usize>),
}

/// A unique identifier for a game
pub type GameID = String;

/// A unique identifier for a lobby
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
pub struct LobbyId(pub String);

/// Responses that may be returned in matchmaking mode
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum MatchmakerResponse {
    /// The connection has been accepted
    Accepted,
    /// Response that specifies updates about the current matchmaking (ie. player count updates)
    MatchmakingUpdate { player_count: u32 },
    /// The desired client count has been reached, and the match may start.
    Success {
        /// The random seed that each client should use.
        random_seed: u64,
        /// The client idx of the current client
        player_idx: u32,
        /// The number of connected clients in the match
        player_count: u32,
        /// The node ids of all players.
        player_ids: Vec<(u32, iroh::NodeAddr)>,
    },
    /// Response that specifies updates about the current lobby (ie. player count updates)
    LobbyUpdate { player_count: u32 },
    /// A list of available lobbies
    LobbiesList(Vec<LobbyListItem>),
    /// Confirmation that a lobby has been created
    LobbyCreated(LobbyId),
    /// Confirmation that a client has joined a lobby
    LobbyJoined(LobbyId),
    /// An error message
    Error(String),
}

/// Information about a lobby for the lobby list
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LobbyListItem {
    /// The unique identifier of the lobby
    pub id: LobbyId,
    /// The name of the lobby
    pub name: String,
    /// The current number of players in the lobby
    pub current_players: u32,
    /// The maximum number of players allowed in the lobby
    pub max_players: u32,
    /// Whether the lobby is password protected
    pub has_password: bool,
    /// The unique identifier for the game this lobby belongs to
    pub game_id: String,
}

/// The format of a message sent by a client to the proxy, so the proxy can send it to another client.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SendProxyMessage {
    /// The client that the message should go to.
    pub target_client: TargetClient,
    /// The message data.
    pub message: Vec<u8>,
}

/// The client to send a network message to.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum TargetClient {
    /// Send the message to all connected clients.
    All,
    /// Send the message to the client with the specified index.
    One(u8),
}

/// The format of a message forwarded by the proxy to a client.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RecvProxyMessage {
    /// The client that the message came from.
    pub from_client: u8,
    /// The message data.
    pub message: Vec<u8>,
}