team04_server/lobby/state/
clients.rs1use std::collections::HashMap;
2
3use uuid::Uuid;
4
5use crate::{log::uuid_human_hash::uuid_human_hash, server::Connection};
6
7use super::players::Player;
8
9#[derive(Debug)]
10pub struct Clients {
11 pub players: Players,
12 pub spectators: Spectators,
13}
14impl Clients {
15 pub fn new(players: Players, spectators: Spectators) -> Self {
16 Self {
17 players,
18 spectators,
19 }
20 }
21 pub fn new_empty() -> Self {
22 Self {
23 players: Players::new_empty(),
24 spectators: Spectators::new_empty(),
25 }
26 }
27}
28
29#[derive(Debug)]
34pub struct Players(HashMap<PlayerId, Player>);
35impl Players {
36 pub fn new(players: HashMap<PlayerId, Player>) -> Self {
37 Self(players)
38 }
39 pub fn new_empty() -> Self {
40 Self(HashMap::new())
41 }
42 pub(crate) fn add(&mut self, id: PlayerId, player: Player) {
44 self.0.insert(id, player);
45 }
46 pub(crate) fn remove(&mut self, player_id: PlayerId) -> Option<Player> {
48 self.0.remove(&player_id)
49 }
50}
51
52#[derive(Debug)]
53pub struct Spectators(Vec<Spectator>);
54impl Spectators {
55 pub fn new(spectators: Vec<Spectator>) -> Self {
56 Self(spectators)
57 }
58 pub fn new_empty() -> Self {
59 Self(Vec::new())
60 }
61 pub(crate) fn add(&mut self, spectator: Spectator) {
62 self.0.push(spectator);
63 }
64 pub(crate) fn remove_by_name(&mut self, name: &str) -> Option<Spectator> {
65 self.iter()
66 .position(|spectator| spectator.name == name)
67 .map(|i| self.0.remove(i))
68 }
69}
70
71#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
72pub struct PlayerId(Uuid);
73
74impl PlayerId {
75 pub fn new(uuid: Uuid) -> Self {
76 Self(uuid)
77 }
78 pub fn random() -> Self {
79 Self(Uuid::new_v4())
80 }
81 pub fn uuid(&self) -> &Uuid {
82 &self.0
83 }
84}
85
86#[derive(Debug)]
87pub struct Spectator {
88 name: String,
89 pub(crate) con: Connection,
90}
91impl Spectator {
92 pub fn new(name: String, con: Connection) -> Self {
93 Self { name, con }
94 }
95 pub fn name(&self) -> &str {
96 &self.name
97 }
98}
99
100#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
101pub struct ReconnectToken(Uuid);
102
103impl ReconnectToken {
104 pub fn new(uuid: Uuid) -> Self {
105 Self(uuid)
106 }
107 pub fn random() -> Self {
108 Self(Uuid::new_v4())
109 }
110 pub fn uuid(&self) -> &Uuid {
111 &self.0
112 }
113}
114
115impl Players {
116 pub fn len(&self) -> usize {
117 self.0.len()
118 }
119 pub fn contains(&self, id: &PlayerId) -> bool {
120 self.0.contains_key(id)
121 }
122 pub fn get(&self, id: &PlayerId) -> Option<&Player> {
123 self.0.get(id)
124 }
125 pub fn get_mut(&mut self, id: &PlayerId) -> Option<&mut Player> {
126 self.0.get_mut(id)
127 }
128 pub fn iter_all(&self) -> std::collections::hash_map::Iter<PlayerId, Player> {
129 self.0.iter()
130 }
131 pub fn iter_all_mut(&mut self) -> std::collections::hash_map::IterMut<PlayerId, Player> {
132 self.0.iter_mut()
133 }
134 pub fn players_all(&self) -> std::collections::hash_map::Values<PlayerId, Player> {
135 self.0.values()
136 }
137 pub fn players_all_mut(&mut self) -> std::collections::hash_map::ValuesMut<PlayerId, Player> {
138 self.0.values_mut()
139 }
140 pub fn iter_alive(&self) -> impl Iterator<Item = (&PlayerId, &Player)> {
141 self.iter_all().filter(|(_, p)| p.lives > 0)
142 }
143 pub fn iter_alive_mut(&mut self) -> impl Iterator<Item = (&PlayerId, &mut Player)> {
144 self.iter_all_mut().filter(|(_, p)| p.lives > 0)
145 }
146 pub fn players_alive(&self) -> impl Iterator<Item = &Player> {
147 self.players_all().filter(|p| p.lives > 0)
148 }
149 pub fn players_alive_mut(&mut self) -> impl Iterator<Item = &mut Player> {
150 self.players_all_mut().filter(|p| p.lives > 0)
151 }
152 pub fn ids(&self) -> std::collections::hash_map::Keys<PlayerId, Player> {
153 self.0.keys()
154 }
155}
156
157impl Spectators {
158 pub fn len(&self) -> usize {
159 self.0.len()
160 }
161 pub fn iter(&self) -> std::slice::Iter<Spectator> {
162 self.0.iter()
163 }
164 pub fn iter_mut(&mut self) -> std::slice::IterMut<Spectator> {
165 self.0.iter_mut()
166 }
167}
168
169impl Clients {
170 pub async fn broadcast_message(&mut self, message: &str) {
171 self.players.broadcast_message(message).await;
172 self.spectators.broadcast_message(message).await;
173 }
174}
175
176impl Players {
177 pub async fn broadcast_message(&mut self, message: &str) {
178 for player in self.players_all_mut() {
179 player.send_message(message).await;
180 }
181 }
182}
183
184impl Spectators {
185 pub async fn broadcast_message(&mut self, message: &str) {
186 for spectator in self.iter_mut() {
187 spectator.send_message(message).await.ok();
188 }
189 }
190}
191
192impl Spectator {
193 pub async fn send_message(
194 &mut self,
195 message: &str,
196 ) -> Result<(), tokio_tungstenite::tungstenite::Error> {
197 self.con.send(message).await
198 }
199}
200
201impl std::fmt::Display for PlayerId {
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 write!(f, "{} ({})", uuid_human_hash(&self.0), self.0)
204 }
205}
206
207#[cfg(test)]
208mod test {
209 use crate::{
210 lobby::state::{
211 clients::{PlayerId, Players},
212 players::Player,
213 },
214 messages::client_role::PlayerRole,
215 server::Connection,
216 };
217
218 use super::{Spectator, Spectators};
219
220 #[test]
221 fn remove_player_by_id() {
222 let johnny = PlayerId::random();
223 let mut players = Players::new(
224 [
225 (
226 PlayerId::random(),
227 Player::new("jimmy".to_owned(), PlayerRole::Player, Connection::fake().0),
228 ),
229 (
230 johnny,
231 Player::new(
232 "johnny".to_owned(),
233 PlayerRole::Player,
234 Connection::fake().0,
235 ),
236 ),
237 ]
238 .into_iter()
239 .collect(),
240 );
241 assert_eq!(players.len(), 2);
242 players.add(
243 PlayerId::random(),
244 Player::new("jenny".to_owned(), PlayerRole::Player, Connection::fake().0),
245 );
246 assert!(players.players_all().any(|player| player.name() == "jenny"));
247 assert!(players.remove(PlayerId::random()).is_none());
248 assert_eq!(players.len(), 3);
249 assert!(players.remove(johnny).is_some());
250 assert_eq!(players.len(), 2);
251 assert!(!players.iter_all().any(|(id, _)| *id == johnny));
252 }
253
254 #[test]
255 fn remove_spectator_by_name() {
256 let mut spectators = Spectators::new_empty();
257 spectators.add(Spectator::new(
258 "Spectator #1".to_owned(),
259 Connection::fake().0,
260 ));
261 spectators.add(Spectator::new("john".to_owned(), Connection::fake().0));
262 assert!(spectators.iter().any(|spec| spec.name() == "john"));
263 assert_eq!(spectators.len(), 2);
264 assert!(spectators.remove_by_name("John").is_none());
265 assert!(spectators.iter().any(|spec| spec.name() == "john"));
266 assert_eq!(spectators.len(), 2);
267 assert!(spectators.remove_by_name("john").is_some());
268 assert!(!spectators.iter().any(|spec| spec.name() == "john"));
269 assert_eq!(spectators.len(), 1);
270 }
271}