echo/
echo.rs

1use renetcode::{
2    ClientAuthentication, ConnectToken, NetcodeClient, NetcodeServer, ServerAuthentication, ServerConfig, ServerResult, NETCODE_KEY_BYTES,
3    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 server_addr: SocketAddr = format!("127.0.0.1:{}", args[2]).parse().unwrap();
54            let username = Username(args[3].clone());
55            let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
56            println!("Stating connecting at {:?} with username {}", now, username.0,);
57            let client_id = now.as_millis() as u64;
58            let connect_token = ConnectToken::generate(
59                now,
60                PROTOCOL_ID,
61                300,
62                client_id,
63                15,
64                vec![server_addr],
65                Some(&username.to_netcode_user_data()),
66                private_key,
67            )
68            .unwrap();
69            let auth = ClientAuthentication::Secure { connect_token };
70            client(auth);
71        }
72        "server" => {
73            let server_addr: SocketAddr = format!("127.0.0.1:{}", args[2]).parse().unwrap();
74            server(server_addr, *private_key);
75        }
76        _ => {
77            println!("Invalid argument, first one must be \"client\" or \"server\".");
78        }
79    }
80}
81
82fn handle_server_result(
83    server_result: ServerResult,
84    socket: &UdpSocket,
85    received_messages: &mut Vec<String>,
86    usernames: &mut HashMap<u64, String>,
87) {
88    match server_result {
89        ServerResult::Payload { client_id, payload } => {
90            let text = String::from_utf8(payload.to_vec()).unwrap();
91            let username = usernames.get(&client_id).unwrap();
92            println!("Client {} ({}) sent message {:?}.", username, client_id, text);
93            let text = format!("{}: {}", username, text);
94            received_messages.push(text);
95        }
96        ServerResult::PacketToSend { payload, addr } => {
97            socket.send_to(payload, addr).unwrap();
98        }
99        ServerResult::ClientConnected {
100            client_id,
101            user_data,
102            payload,
103            addr,
104        } => {
105            let username = Username::from_user_data(&user_data);
106            println!("Client {} with id {} connected.", username.0, client_id);
107            usernames.insert(client_id, username.0);
108            socket.send_to(payload, addr).unwrap();
109        }
110        ServerResult::ClientDisconnected { client_id, addr, payload } => {
111            println!("Client {} disconnected.", client_id);
112            usernames.remove_entry(&client_id);
113            if let Some(payload) = payload {
114                socket.send_to(payload, addr).unwrap();
115            }
116        }
117        ServerResult::None => {}
118    }
119}
120
121fn server(addr: SocketAddr, private_key: [u8; NETCODE_KEY_BYTES]) {
122    let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
123    let config = ServerConfig {
124        current_time,
125        max_clients: 16,
126        protocol_id: PROTOCOL_ID,
127        public_addresses: vec![addr],
128        authentication: ServerAuthentication::Secure { private_key },
129    };
130    let mut server: NetcodeServer = NetcodeServer::new(config);
131    let udp_socket = UdpSocket::bind(addr).unwrap();
132    udp_socket.set_nonblocking(true).unwrap();
133    let mut received_messages = vec![];
134    let mut last_updated = Instant::now();
135    let mut buffer = [0u8; NETCODE_MAX_PACKET_BYTES];
136    let mut usernames: HashMap<u64, String> = HashMap::new();
137    loop {
138        server.update(Instant::now() - last_updated);
139        received_messages.clear();
140
141        loop {
142            match udp_socket.recv_from(&mut buffer) {
143                Ok((len, addr)) => {
144                    // println!("Received decrypted message {:?} from {}.", &buffer[..len], addr);
145                    let server_result = server.process_packet(addr, &mut buffer[..len]);
146                    handle_server_result(server_result, &udp_socket, &mut received_messages, &mut usernames);
147                }
148                Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break,
149                Err(e) => panic!("Socket error: {}", e),
150            };
151        }
152
153        for text in received_messages.iter() {
154            for client_id in server.clients_id().iter() {
155                let (addr, payload) = server.generate_payload_packet(*client_id, text.as_bytes()).unwrap();
156                udp_socket.send_to(payload, addr).unwrap();
157            }
158        }
159
160        for client_id in server.clients_id().into_iter() {
161            let server_result = server.update_client(client_id);
162            handle_server_result(server_result, &udp_socket, &mut received_messages, &mut usernames);
163        }
164
165        last_updated = Instant::now();
166        thread::sleep(Duration::from_millis(50));
167    }
168}
169
170fn client(authentication: ClientAuthentication) {
171    let udp_socket = UdpSocket::bind("127.0.0.1:0").unwrap();
172    udp_socket.set_nonblocking(true).unwrap();
173    let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
174    let mut client = NetcodeClient::new(now, authentication).unwrap();
175    let stdin_channel = spawn_stdin_channel();
176    let mut buffer = [0u8; NETCODE_MAX_PACKET_BYTES];
177
178    let mut last_updated = Instant::now();
179    loop {
180        if let Some(err) = client.disconnect_reason() {
181            panic!("Client error: {:?}", err);
182        }
183
184        match stdin_channel.try_recv() {
185            Ok(text) => {
186                if client.is_connected() {
187                    let (addr, payload) = client.generate_payload_packet(text.as_bytes()).unwrap();
188                    udp_socket.send_to(payload, addr).unwrap();
189                } else {
190                    println!("Client is not yet connected");
191                }
192            }
193            Err(TryRecvError::Empty) => {}
194            Err(TryRecvError::Disconnected) => panic!("Stdin channel disconnected"),
195        }
196
197        loop {
198            match udp_socket.recv_from(&mut buffer) {
199                Ok((len, addr)) => {
200                    if addr != client.server_addr() {
201                        // Ignore packets that are not from the server
202                        continue;
203                    }
204                    // println!("Received decrypted message {:?} from server {}", &buffer[..len], addr);
205                    if let Some(payload) = client.process_packet(&mut buffer[..len]) {
206                        let text = String::from_utf8(payload.to_vec()).unwrap();
207                        println!("Received message from server: {}", text);
208                    }
209                }
210                Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break,
211                Err(e) => panic!("Socket error: {}", e),
212            };
213        }
214
215        if let Some((packet, addr)) = client.update(Instant::now() - last_updated) {
216            udp_socket.send_to(packet, addr).unwrap();
217        }
218        last_updated = Instant::now();
219        thread::sleep(Duration::from_millis(50));
220    }
221}
222
223fn spawn_stdin_channel() -> Receiver<String> {
224    let (tx, rx) = mpsc::channel::<String>();
225    thread::spawn(move || loop {
226        let mut buffer = String::new();
227        std::io::stdin().read_line(&mut buffer).unwrap();
228        tx.send(buffer.trim_end().to_string()).unwrap();
229    });
230    rx
231}