echo_netcode/
echo_netcode.rs

1use renetcode2::{
2    ClientAuthentication, ConnectToken, NetcodeClient, NetcodeServer, ServerAuthentication, ServerConfig, ServerResult, ServerSocketConfig,
3    NETCODE_KEY_BYTES, NETCODE_MAX_PACKET_BYTES, NETCODE_USER_DATA_BYTES,
4};
5use std::time::Duration;
6use std::{collections::HashMap, thread};
7use std::{
8    net::{SocketAddr, UdpSocket},
9    time::Instant,
10};
11use std::{
12    sync::mpsc::{self, Receiver, TryRecvError},
13    time::{SystemTime, UNIX_EPOCH},
14};
15
16// Unique id used for a version of your game
17const PROTOCOL_ID: u64 = 123456789;
18
19// Helper struct to pass an username in user data inside the ConnectToken
20struct Username(String);
21
22impl Username {
23    fn to_netcode_user_data(&self) -> [u8; NETCODE_USER_DATA_BYTES] {
24        let mut user_data = [0u8; NETCODE_USER_DATA_BYTES];
25        if self.0.len() > NETCODE_USER_DATA_BYTES - 8 {
26            panic!("Username is too big");
27        }
28        user_data[0..8].copy_from_slice(&(self.0.len() as u64).to_le_bytes());
29        user_data[8..self.0.len() + 8].copy_from_slice(self.0.as_bytes());
30
31        user_data
32    }
33
34    fn from_user_data(user_data: &[u8; NETCODE_USER_DATA_BYTES]) -> Self {
35        let mut buffer = [0u8; 8];
36        buffer.copy_from_slice(&user_data[0..8]);
37        let mut len = u64::from_le_bytes(buffer) as usize;
38        len = len.min(NETCODE_USER_DATA_BYTES - 8);
39        let data = user_data[8..len + 8].to_vec();
40        let username = String::from_utf8(data).unwrap();
41        Self(username)
42    }
43}
44
45fn main() {
46    println!("Usage: server [SERVER_PORT] or client [SERVER_PORT] [USER_NAME]");
47    let args: Vec<String> = std::env::args().collect();
48    let private_key = b"an example very very secret key."; // 32-bytes
49
50    let exec_type = &args[1];
51    match exec_type.as_str() {
52        "client" => {
53            let socket_id = 0;
54            let server_addr: SocketAddr = format!("127.0.0.1:{}", args[2]).parse().unwrap();
55            let username = Username(args[3].clone());
56            let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
57            println!("Stating connecting at {:?} with username {}", now, username.0,);
58            let client_id = now.as_millis() as u64;
59            let connect_token = ConnectToken::generate(
60                now,
61                PROTOCOL_ID,
62                300,
63                client_id,
64                15,
65                socket_id,
66                vec![server_addr],
67                Some(&username.to_netcode_user_data()),
68                private_key,
69            )
70            .unwrap();
71            let auth = ClientAuthentication::Secure { connect_token };
72            client(auth);
73        }
74        "server" => {
75            let server_addr: SocketAddr = format!("127.0.0.1:{}", args[2]).parse().unwrap();
76            server(server_addr, *private_key);
77        }
78        _ => {
79            println!("Invalid argument, first one must be \"client\" or \"server\".");
80        }
81    }
82}
83
84fn handle_server_result(
85    server_result: ServerResult,
86    socket: &UdpSocket,
87    received_messages: &mut Vec<String>,
88    usernames: &mut HashMap<u64, String>,
89) {
90    match server_result {
91        ServerResult::Payload { client_id, payload } => {
92            let text = String::from_utf8(payload.to_vec()).unwrap();
93            let username = usernames.get(&client_id).unwrap();
94            println!("Client {} ({}) sent message {:?}.", username, client_id, text);
95            let text = format!("{}: {}", username, text);
96            received_messages.push(text);
97        }
98        ServerResult::ConnectionAccepted { payload, addr, .. } | ServerResult::PacketToSend { payload, addr, .. } => {
99            socket.send_to(payload, addr).unwrap();
100        }
101        ServerResult::ClientConnected {
102            client_id,
103            user_data,
104            payload,
105            addr,
106            ..
107        } => {
108            let username = Username::from_user_data(&user_data);
109            println!("Client {} with id {} connected.", username.0, client_id);
110            usernames.insert(client_id, username.0);
111            socket.send_to(payload, addr).unwrap();
112        }
113        ServerResult::ClientDisconnected {
114            client_id, addr, payload, ..
115        } => {
116            println!("Client {} disconnected.", client_id);
117            usernames.remove_entry(&client_id);
118            if let Some(payload) = payload {
119                socket.send_to(payload, addr).unwrap();
120            }
121        }
122        ServerResult::ConnectionDenied { .. } => {}
123        ServerResult::Error { .. } => {}
124        ServerResult::None => {}
125    }
126}
127
128fn server(addr: SocketAddr, private_key: [u8; NETCODE_KEY_BYTES]) {
129    let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
130    let config = ServerConfig {
131        current_time,
132        max_clients: 16,
133        protocol_id: PROTOCOL_ID,
134        sockets: vec![ServerSocketConfig::new(vec![addr])],
135        authentication: ServerAuthentication::Secure { private_key },
136    };
137    let mut server: NetcodeServer = NetcodeServer::new(config);
138    let udp_socket = UdpSocket::bind(addr).unwrap();
139    udp_socket.set_nonblocking(true).unwrap();
140    let mut received_messages = vec![];
141    let mut last_updated = Instant::now();
142    let mut buffer = [0u8; NETCODE_MAX_PACKET_BYTES];
143    let mut usernames: HashMap<u64, String> = HashMap::new();
144    loop {
145        server.update(Instant::now() - last_updated);
146        received_messages.clear();
147
148        loop {
149            match udp_socket.recv_from(&mut buffer) {
150                Ok((len, addr)) => {
151                    // println!("Received decrypted message {:?} from {}.", &buffer[..len], addr);
152                    let server_result = server.process_packet(0, addr, &mut buffer[..len]);
153                    handle_server_result(server_result, &udp_socket, &mut received_messages, &mut usernames);
154                }
155                Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break,
156                Err(e) => panic!("Socket error: {}", e),
157            };
158        }
159
160        for text in received_messages.iter() {
161            for client_id in server.clients_id().iter() {
162                let (_, addr, payload) = server.generate_payload_packet(*client_id, text.as_bytes()).unwrap();
163                udp_socket.send_to(payload, addr).unwrap();
164            }
165        }
166
167        for client_id in server.clients_id().into_iter() {
168            let server_result = server.update_client(client_id);
169            handle_server_result(server_result, &udp_socket, &mut received_messages, &mut usernames);
170        }
171
172        last_updated = Instant::now();
173        thread::sleep(Duration::from_millis(50));
174    }
175}
176
177fn client(authentication: ClientAuthentication) {
178    let udp_socket = UdpSocket::bind("127.0.0.1:0").unwrap();
179    udp_socket.set_nonblocking(true).unwrap();
180    let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
181    let mut client = NetcodeClient::new(now, authentication).unwrap();
182    let stdin_channel = spawn_stdin_channel();
183    let mut buffer = [0u8; NETCODE_MAX_PACKET_BYTES];
184
185    let mut last_updated = Instant::now();
186    loop {
187        if let Some(err) = client.disconnect_reason() {
188            panic!("Client error: {:?}", err);
189        }
190
191        match stdin_channel.try_recv() {
192            Ok(text) => {
193                if client.is_connected() {
194                    let (addr, payload) = client.generate_payload_packet(text.as_bytes()).unwrap();
195                    udp_socket.send_to(payload, addr).unwrap();
196                } else {
197                    println!("Client is not yet connected");
198                }
199            }
200            Err(TryRecvError::Empty) => {}
201            Err(TryRecvError::Disconnected) => panic!("Stdin channel disconnected"),
202        }
203
204        loop {
205            match udp_socket.recv_from(&mut buffer) {
206                Ok((len, addr)) => {
207                    if addr != client.server_addr() {
208                        // Ignore packets that are not from the server
209                        continue;
210                    }
211                    // println!("Received decrypted message {:?} from server {}", &buffer[..len], addr);
212                    if let Some(payload) = client.process_packet(&mut buffer[..len]) {
213                        let text = String::from_utf8(payload.to_vec()).unwrap();
214                        println!("Received message from server: {}", text);
215                    }
216                }
217                Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break,
218                Err(e) => panic!("Socket error: {}", e),
219            };
220        }
221
222        if let Some((packet, addr)) = client.update(Instant::now() - last_updated) {
223            udp_socket.send_to(packet, addr).unwrap();
224        }
225        last_updated = Instant::now();
226        thread::sleep(Duration::from_millis(50));
227    }
228}
229
230fn spawn_stdin_channel() -> Receiver<String> {
231    let (tx, rx) = mpsc::channel::<String>();
232    thread::spawn(move || loop {
233        let mut buffer = String::new();
234        std::io::stdin().read_line(&mut buffer).unwrap();
235        tx.send(buffer.trim_end().to_string()).unwrap();
236    });
237    rx
238}