forked from mas-bandwidth/netcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample.rs
More file actions
143 lines (121 loc) · 5.1 KB
/
Copy pathexample.rs
File metadata and controls
143 lines (121 loc) · 5.1 KB
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
//! Sample netcode echo client + server. This is the bare minimum needed to show a full
//! working example. Creates two threads one for the server and one for the client.
//! The main thread listens for new lines and sends them to the client with a mpsc channel.
//! The client will then send the string to the server and the server will echo it back to the
//! client. Note that since this is a UDP based protocol it's expected some messages will be dropped.
//! Once done the string "exit" will cause the client to disconnect which the server will then
//! terminate when it hears the disconnect from the client.
extern crate netcode;
extern crate time;
extern crate log;
extern crate env_logger;
use netcode::{UdpServer, ServerEvent, UdpClient, ClientEvent, ClientState, NETCODE_MAX_PAYLOAD_SIZE};
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use std::io::{self, BufRead};
const MAX_CLIENTS: usize = 256; //Total number of clients we support
const PROTOCOL_ID: u64 = 0xFFDDEE; //Unique protocol id for our application.
const TOKEN_LIFETIME: usize = 15; //Our token lives 15 seconds.
const CLIENT_ID: u64 = 0xDDEEFF; //Single unique client id, you'll want to tie this into
// your user store in production.
const TICK_TIME_MS: f64 = 0.016; //Tick every 16ms
//Helper function for sleeping at a regular interval
fn sleep_for_tick(last_tick: &mut f64) -> f64 {
let now = time::precise_time_s();
let elapsed = (now - *last_tick).min(TICK_TIME_MS);
if elapsed < TICK_TIME_MS {
let sleep_ms = ((TICK_TIME_MS - elapsed) * 1000.0).floor() as u64;
thread::sleep(Duration::from_millis(sleep_ms));
}
*last_tick = now;
TICK_TIME_MS
}
fn main() {
//Uncomment the below block to turn on verbose debugging for netcode
/*
{
use env_logger::LogBuilder;
use log::LogLevelFilter;
LogBuilder::new().filter(None, LogLevelFilter::Trace).init().unwrap();
}
*/
let mut server = UdpServer::new("127.0.0.1:0", MAX_CLIENTS, PROTOCOL_ID, &netcode::generate_key()).unwrap();
let token = server.generate_token(TOKEN_LIFETIME, CLIENT_ID, None).unwrap();
let server_thread = thread::spawn(move || {
let mut last = 0.0;
loop {
let elapsed = sleep_for_tick(&mut last);
server.update(elapsed);
let mut packet = [0; NETCODE_MAX_PAYLOAD_SIZE];
while let Some(event) = server.next_event(&mut packet).unwrap() {
match event {
ServerEvent::ClientConnect(_id) => println!("Server: client connected"),
ServerEvent::ClientDisconnect(_id) => {
//Once our single client is done we should exit.
return
},
ServerEvent::Packet(id, size) => {
println!("Heard packet, echoing back");
server.send(id, &packet[..size]).unwrap();
},
ServerEvent::SentKeepAlive(_id) => {},
ServerEvent::RejectedClient => {},
ServerEvent::ReplayRejected(_id) => {},
ServerEvent::ClientSlotFull => {}
}
}
}
});
let mut client = UdpClient::new(&token).unwrap();
let (tx, rx) = mpsc::channel();
let client_thread = thread::spawn(move || {
let mut last = 0.0;
loop {
let elapsed = sleep_for_tick(&mut last);
client.update(elapsed);
let mut packet = [0; NETCODE_MAX_PAYLOAD_SIZE];
while let Some(event) = client.next_event(&mut packet).unwrap() {
match event {
ClientEvent::NewState(state) => match state {
ClientState::Disconnected => return,
s => println!("Client: new state {:?}", s)
},
ClientEvent::Packet(len) => {
println!("{}", String::from_utf8_lossy(&packet[..len]));
},
ClientEvent::SentKeepAlive => {}
}
}
let result: Option<String> = match rx.try_recv() {
Ok(v) => Some(v),
Err(mpsc::TryRecvError::Empty) => None,
Err(_) => {
client.disconnect().unwrap_or(());
None
}
};
match result {
Some(ref s) if s == "exit" => {
client.disconnect().unwrap_or(());
return
},
Some(s) => client.send(&s.into_bytes()).map(|_| ()).unwrap_or(()),
None => ()
}
}
});
//Read a line from stdin and send it to our client to process.
let stdin = io::stdin();
for line in stdin.lock().lines() {
let value = line.unwrap();
if value == "exit" {
tx.send(value).unwrap();
break;
} else {
tx.send(value).unwrap()
}
}
client_thread.join().unwrap();
server_thread.join().unwrap();
}