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
//! # netcode
//!
//! The `netcode` crate implements the [netcode](https://github.com/networkprotocol/netcode)
//! network protocol created by [Glenn Fiedler](https://gafferongames.com).
//!
//! `netcode` is a UDP-based protocol that provides secure, connection-based data transfer.
//!
//! Since the protocol is meant to be used to implement multiplayer games, its API is designed
//! to be used in a game loop, where the server and client are updated at a fixed rate (e.g., 60Hz).
//!
//! ## Protocol
//!
//! The three main components of the netcode protocol are:
//! * Dedicated [`Servers`](Server).
//! * [`Clients`](Client).
//! * The web backend - a service that authenticates clients and generates [`ConnectTokens`](ConnectToken).
//!   
//! The protocol does not specify how the web backend should be implemented, but it should probably be a typical HTTPS server
//! that provides a means for clients to authenticate and request connection tokens.
//!
//! The sequence of operations for a client to connect to a server is as follows:
//!
//! 1. The `Client` authenticates with the web backend service. (e.g., by OAuth or some other means)
//! 2. The authenticated `Client` requests a connection token from the web backend.
//! 3. The web backend generates a [`ConnectToken`] and sends it to the `Client`. (e.g., as a JSON response)
//! 4. The `Client` uses the token to connect to a dedicated `Server`.
//! 5. The `Server` makes sure the token is valid and allows the `Client` to connect.
//! 6. The `Client` and `Server` can now exchange encrypted and signed UDP packets.
//!
//! To learn more about the netcode protocol, see the upstream [specification](https://github.com/networkprotocol/netcode/blob/master/STANDARD.md).
//!
//! ## Server
//!
//! The netcode server is responsible for managing the state of the clients and sending/receiving packets.
//!
//! The server should run as a part of the game loop, process incoming packets and send updates to the clients.
//!
//! To create a server:
//!  * Provide the address you intend to bind to.
//!  * Provide the protocol id - a `u64` that uniquely identifies your app.
//!  * Provide a private key - a `u8` array of length 32. If you don't have one, you can generate one with `netcode::generate_key()`.
//!  * Optionally provide a [`ServerConfig`] - a struct that allows you to customize the server's behavior.
//!
//! ```
//! use std::{thread, time::{Instant, Duration}};
//! use netcode::{Server, MAX_PACKET_SIZE};
//!
//! // Create a server
//! let protocol_id = 0x11223344;
//! let private_key = netcode::generate_key(); // you can also provide your own key
//! let mut server = Server::new("127.0.0.1:12345", protocol_id, private_key).unwrap();
//!
//! // Run the server at 60Hz
//! let start = Instant::now();
//! let tick_rate = Duration::from_secs_f64(1.0 / 60.0);
//! loop {
//!     let elapsed = start.elapsed().as_secs_f64();
//!     server.update(elapsed);
//!     while let Some((packet, from)) = server.recv() {
//!        // ...
//!     }
//!     # break;
//!     thread::sleep(tick_rate);
//! }
//! ```
//!
//! ## Client
//!
//! The netcode client connects to the server and communicates using the same protocol.
//!
//! Like the server, the game client should run in a loop to process incoming data,
//! send updates to the server, and maintain a stable connection.
//!
//! To create a client:
//!  * Provide a **connect token** - a `u8` array of length 2048 serialized from a [`ConnectToken`].
//!  * Optionally provide a [`ClientConfig`] - a struct that allows you to customize the client's behavior.
//!
//! ```
//! use std::{thread, time::{Instant, Duration}};
//! use netcode::{ConnectToken, Client, MAX_PACKET_SIZE};
//!
//! // Generate a connection token for the client
//! let protocol_id = 0x11223344;
//! let private_key = netcode::generate_key(); // you can also provide your own key
//! let client_id = 123u64; // globally unique identifier for an authenticated client
//! let server_address = "127.0.0.1:12345"; // the server's public address (can also be multiple addresses)
//! let connect_token = ConnectToken::build("127.0.0.1:12345", protocol_id, client_id, private_key)
//!     .generate()
//!     .unwrap();
//!
//! // Start the client
//! let token_bytes = connect_token.try_into_bytes().unwrap();
//! let mut client = Client::new(&token_bytes).unwrap();
//! client.connect();
//!
//! // Run the client at 60Hz
//! let start = Instant::now();
//! let tick_rate = Duration::from_secs_f64(1.0 / 60.0);
//! loop {
//!     let elapsed = start.elapsed().as_secs_f64();
//!     client.try_update(elapsed).ok();
//!     if let Some(packet) = client.recv() {
//!         // ...
//!     }
//!     # break;
//!     thread::sleep(tick_rate);
//! }
//! ```

mod bytes;
mod client;
mod crypto;
mod error;
mod free_list;
mod packet;
mod replay;
mod server;
mod socket;
mod token;
mod transceiver;

#[cfg(test)]
mod simulator;

pub(crate) const MAC_BYTES: usize = 16;
pub(crate) const MAX_PKT_BUF_SIZE: usize = 1300;
pub(crate) const CONNECTION_TIMEOUT_SEC: i32 = 15;
pub(crate) const PACKET_SEND_RATE_SEC: f64 = 1.0 / 10.0;

pub use crate::client::{Client, ClientConfig, ClientState};
pub use crate::crypto::{generate_key, try_generate_key, Key};
pub use crate::error::{Error, Result};
pub use crate::server::{ClientId, ClientIndex, Server, ServerConfig};
pub use crate::token::{ConnectToken, ConnectTokenBuilder, InvalidTokenError};
pub use crate::transceiver::Transceiver;

/// The size of a private key in bytes.
pub const PRIVATE_KEY_BYTES: usize = 32;
/// The size of the user data in a connect token in bytes.
pub const USER_DATA_BYTES: usize = 256;
/// The size of the connect token in bytes.
pub const CONNECT_TOKEN_BYTES: usize = 2048;
/// The maximum size of a packet in bytes.
pub const MAX_PACKET_SIZE: usize = 1200;
/// The version of the netcode protocol implemented by this crate.
pub const NETCODE_VERSION: &[u8; 13] = b"NETCODE 1.02\0";