-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR covers a large rework of the matchmaker and its entire flow to bones & the dev interface. In short the major changes include: #### Matchmaker: - Supports multiple games running a single matchmaker, thanks to GameID now integrated - Internal state revamped to support now both Matchmaking & newly added Lobbies - Bones <-> Matchmaker messaging flow rework to support more than just 1 "endpoint", and importantly enable long-lived connections which is a requirement for lobbies - Updated the interface for devs to interact with the matchmaker to provide a standardized/clean interface that we can scale with new features #### Matchmaking Changes: - Robustness was the main focus, so now implements a simple wait/retry protocol when the matchmaking room is full, thus avoiding previous issues with failure during lots of players starting matchmaking at once. - Implements dead connection cleaning, guaranteeing that when a match starts all player clients have active connections (are alive) and starting the match can proceed - Adds an explicit stop matchmaking search message, making the matchmaking flow more "proper/clean" and allowing us to do proper local error checking to prevent bad states without straining the matchmaker (ie. you can't create a lobby if you're in matchmaking). - A number of smaller edge case fixes/reworking internals to make things nicer to work with. ### Lobbies Changes: - They now exist, freshly implemented - The core mechanics are in place for list/create/join lobbies - Supports password-protected lobbies to make it easy for users to play with their friends Of note, this PR is already quite large and covers the majority of breaking changes to the matchmaker needed in the short term, while getting the flow of matchmaking to feel quite robust with the edge cases addressed. Lobbies still need further work to be robust, and the randomness seed/match_data pushing into the ggrs session runner hasn't been done here yet, however I feel this PR is encompassing enough as-is and would prefer to move forward with smaller/lighter PRs for the extra functionality. --------- Co-authored-by: Max Whitehead <[email protected]> Co-authored-by: Jeremias <[email protected]> Co-authored-by: Zicklag <[email protected]> Co-authored-by: Tekhnaeraav <[email protected]>
- Loading branch information
1 parent
1ecb3dd
commit 2f4e7ac
Showing
16 changed files
with
1,384 additions
and
478 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 36 additions & 76 deletions
112
framework_crates/bones_framework/src/networking/online.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,54 @@ | ||
Contains the online matchmaker. | ||
# Matchmaking | ||
|
||
## Matchmaking | ||
For online matchmaking, we use a centralized matchmaking server to connect peers to each-other and to forward the peers' network traffic. All connections utilize UDP and the QUIC protocol. | ||
|
||
For online matchmaking, we use a centralized matchmaking server to connect peers to each-other and | ||
to forward the peers' network traffic. All connections utilize UDP and the QUIC protocol. | ||
The matchmaking server is implemented in the [`bones_matchmaker`] crate. It binds to a single UDP port and listens for client connections. QUIC's multiplexing capabilities allow the server to handle any number of clients on this single port. | ||
|
||
In order to establish the peer connections we use a matchmaking server implemented in the | ||
[`bones_matchmaker`] crate. This server binds one UDP port and listens for client connections. | ||
Because QUIC supports mutliplexing connections, we are able to handle any number of clients on a | ||
single UDP port. | ||
Once a match starts, client traffic is proxied through the matchmaking server. While not true peer-to-peer networking, clients logically send messages to each other, with the server acting as an intermediary. | ||
|
||
All client traffic is proxied to other peers through the matchmaking server. In this way it is not | ||
true peer-to-peer networking, but logically, once the match starts, clients are sending messages to | ||
each-other, and the server doesn't take part in the match protocol. | ||
Pros of this approach: | ||
- Reduced connections per peer (one connection to the matchmaker only) | ||
- Client IP addresses are hidden from each other | ||
- Easier to bypass firewalls and NATs | ||
- Simplified connection process | ||
|
||
Having the matchmaker proxy client messages has the following pros and cons: | ||
Cons: | ||
- Increased server bandwidth usage | ||
- Additional network hop between peers, potentially increasing latency | ||
|
||
**Cons:** | ||
|
||
- It uses up more of the matchmaking server's bandwidth | ||
- It adds an extra network hop between peers, increasing latency. | ||
|
||
**Pros:** | ||
|
||
- It reduces the number of connections each peer needs to make. Each peer only holds one | ||
connection to the matchmaking server and nothing else. | ||
- It hides the IP addresses of clients from each-other. This is an important privacy feature. | ||
- It avoids a number of difficulties that you may run into while trying to establish true | ||
peer-to-peer connections, and makes it much easier to bypass firewalls, NATs, etc. | ||
|
||
This doesn't prevent us from supporting true peer-to-peer connections in the future, though. | ||
Similarly, another scenario we will support in the future is LAN games that you can join without | ||
needing a matchmaking server. | ||
This design doesn't preclude future support for true peer-to-peer connections or LAN games without a matchmaker. | ||
|
||
[`bones_matchmaker`]: https://github.com/fishfolk/bones/tree/main/crates/bones_matchmaker | ||
|
||
### Matchmaking Protocol | ||
|
||
> **ℹ️ Note:** This is meant as an overview and is not an exact specification of the matchmaking | ||
> protocol. | ||
#### Initial Connection | ||
|
||
When a client connects to the matchmaking server, the very first thing it will do is send a | ||
[`RequestMatch`][crate::external::bones_matchmaker_proto::MatchmakerRequest::RequestMatch] message | ||
to the server over a reliable channel. | ||
|
||
This message contains the [`MatchInfo`] that tells the server how many players the client wants to | ||
connect to for the match, along with an arbitrary byte sequence for the `match_data`. | ||
|
||
In order for players to end up in the same match as each-other, they must specify the _exact_ same | ||
`MatchInfo`, including the `match_data`. We use the `match_data` as a way to specify which game mode | ||
and parameters, etc. that the player wants to connect to, so that all the players that are connected | ||
to each-other are playing the same mode. | ||
|
||
The `match_data` also contains the game name and version. Because the matchmaker does not take part | ||
in the match protocol itself, just the matchmaking protocol, **this makes the matchmaking server | ||
game agnostic**. Different games can connect to the same matchmaking server, and they can make sure | ||
they are only connected to players playing the same game, by specifying a unique `match_data`. | ||
|
||
> **Note:** To be clear, the game implementation sets the `match_data` for players. Players are | ||
> never exposed directly to the concept of the `match_data`. | ||
## Matchmaking Protocol | ||
|
||
#### Waiting For Players | ||
### Initial Connection | ||
|
||
After the initial connection and match request, the server will send the client an | ||
[`Accepted`][crate::external::bones_matchmaker_proto::MatchmakerResponse::Accepted] message. | ||
1. The client connects to the matchmaking server. | ||
2. The client sends a [`RequestMatchmaking`][crate::external::bones_matchmaker_proto::MatchmakerRequest::RequestMatchmaking] message over a reliable channel. | ||
3. This message contains [`MatchInfo`] with: | ||
- The desired number of players | ||
- A `game_id` to identify the game | ||
- `match_data` (arbitrary bytes for game mode, parameters, etc.) | ||
- `player_idx_assignment` to specify how player ids should be assigned (ie. randomly assign a side for a pvp match) | ||
|
||
If the waiting room for that match already has the desired number of players in it, the server will | ||
then respond immediately with a | ||
[`Success`][crate::external::bones_matchmaker_proto::MatchmakerResponse::Success] message. This | ||
message comes with: | ||
Players must specify identical `MatchInfo` to be matched together. The `match_data` ensures players are connected for the same game mode and version. | ||
|
||
- a `random_seed` that can be used by all clients to generate deterministic random numbers, and | ||
- a `player_idx` that tells the client _which_ player in the match it is. This is used throughout | ||
the game to keep track of the players, and is between `0` and `player_count - 1`. | ||
### Waiting for Players | ||
|
||
#### In the Match | ||
1. The server responds with an [`Accepted`][crate::external::bones_matchmaker_proto::MatchmakerResponse::Accepted] message. | ||
2. While waiting, the server may send [`MatchmakingUpdate`][crate::external::bones_matchmaker_proto::MatchmakerResponse::MatchmakingUpdate] messages with the current player count. | ||
3. When the desired number of players is reached, the server sends a [`Success`][crate::external::bones_matchmaker_proto::MatchmakerResponse::Success] message containing: | ||
- A `random_seed` for deterministic random number generation | ||
- The client's `player_idx` | ||
- The total `player_count` | ||
- A list of `player_ids` with their network addresses | ||
|
||
Immediately after the desired number of clients have joined and the `Success` message has been sent | ||
to all players, the matchmaker goes into proxy mode for all clients in the match. | ||
### In the Match | ||
|
||
Once in proxy mode, the server listens for | ||
[`SendProxyMessage`][crate::external::bones_matchmaker_proto::SendProxyMessage]s from clients. Each | ||
message simply specifies a [`TargetClient`][crate::external::bones_matchmaker_proto::TargetClient] ( | ||
either a specific client or all of them ), and a binary message data. | ||
Once all players have received the `Success` message, the matchmaker enters proxy mode: | ||
|
||
Once it a `SendProxyMessage` it will send it to the target client, which will receive it in the form | ||
of a [`RecvProxyMessage`][crate::external::bones_matchmaker_proto::RecvProxyMessage], containing the | ||
message data, and the index of the client that sent the message. | ||
1. Clients send [`SendProxyMessage`][crate::external::bones_matchmaker_proto::SendProxyMessage]s to the server, specifying a target client (or all clients) and the message data. | ||
2. The server forwards these as [`RecvProxyMessage`][crate::external::bones_matchmaker_proto::RecvProxyMessage]s to the target client(s), including the sender's player index. | ||
|
||
The matchmaking server supports forwarding both reliable and unreliable message in this way, | ||
allowing the game to chose any kind of protocol it sees fit to synchronize the match data. | ||
The matchmaker supports both reliable and unreliable message forwarding, allowing the game to implement its preferred synchronization protocol. |
Oops, something went wrong.