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
|
use std::collections::HashMap;
use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*};
use bevy_quinnet::{
server::{DisconnectionEvent, QuinnetServerPlugin, Server, ServerConfigurationData},
ClientId,
};
use chat_protocol::{ClientMessage, ServerMessage};
#[path = "../chat_protocol/lib.rs"] // Because we can't have a shared lib between Cargo examples
mod chat_protocol;
#[derive(Debug, Clone, Default)]
struct Users {
names: HashMap<ClientId, String>,
}
fn handle_client_messages(mut server: ResMut<Server>, mut users: ResMut<Users>) {
while let Ok(Some(message)) = server.receive_message::<ClientMessage>() {
// Retrieve the assigned ClientId.
let client_id = message.1;
match message.0 {
ClientMessage::Join { name } => {
if users.names.contains_key(&client_id) {
warn!(
"Received a Join from an already connected client: {}",
client_id
)
} else {
info!("{} connected", name);
users.names.insert(client_id, name.clone());
// Initialize this client with existing state
server
.send_message(
client_id,
ServerMessage::InitClient {
client_id: client_id,
usernames: users.names.clone(),
},
)
.unwrap();
// Broadcast the connection event
server
.send_group_message(
users.names.keys().into_iter(),
ServerMessage::ClientConnected {
client_id: client_id,
username: name,
},
)
.unwrap();
}
}
ClientMessage::Disconnect {} => {
// We tell the server to disconnect this user
server.disconnect_client(client_id);
handle_disconnect(&mut server, &mut users, client_id);
}
ClientMessage::ChatMessage { message } => {
info!(
"Chat message | {:?}: {}",
users.names.get(&client_id),
message
);
server
.send_group_message(
users.names.keys().into_iter(),
ServerMessage::ChatMessage {
client_id: client_id,
message: message,
},
)
.unwrap();
}
}
}
}
fn handle_server_events(
mut disconnections: EventReader<DisconnectionEvent>,
mut server: ResMut<Server>,
mut users: ResMut<Users>,
) {
// The server signals us about users that disconnected (connection lost)
for client in disconnections.iter() {
handle_disconnect(&mut server, &mut users, client.id);
}
}
/// Shared disconnection behaviour, whether the client lost connection or asked to disconnect
fn handle_disconnect(server: &mut ResMut<Server>, users: &mut ResMut<Users>, client_id: ClientId) {
// Remove this user
if let Some(username) = users.names.remove(&client_id) {
// Broadcast its deconnection
server
.send_group_message(
users.names.keys().into_iter(),
ServerMessage::ClientDisconnected {
client_id: client_id,
},
)
.unwrap();
info!("{} disconnected", username);
} else {
warn!(
"Received a Disconnect from an unknown or disconnected client: {}",
client_id
)
}
}
fn main() {
App::new()
.add_plugin(ScheduleRunnerPlugin::default())
.add_plugin(LogPlugin::default())
.add_plugin(QuinnetServerPlugin::default())
.insert_resource(ServerConfigurationData::new(
"127.0.0.1".to_string(),
6000,
"0.0.0.0".to_string(),
))
.insert_resource(Users::default())
.add_system(handle_client_messages)
.add_system(handle_server_events)
.run();
}
|