Skip to content

Commit feed6fa

Browse files
committed
the lobby is waaaaaay cleaner, but it's also the only thing that works
1 parent 0331e66 commit feed6fa

File tree

7 files changed

+551
-212
lines changed

7 files changed

+551
-212
lines changed

Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ edition = "2021"
88
[dependencies]
99
rand = "0.8.5"
1010
rocket = { version = "0.5.0", features = ["secrets", "json"] }
11+
thiserror = "1.0.51"

src/common.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
pub use crate::PlayerWrapper;
2+
use crate::{
3+
game::{Game, Lobby, Player, Room},
4+
lobby,
5+
};
6+
use std::{
7+
collections::HashMap,
8+
marker::PhantomData,
9+
sync::{Arc, Mutex, MutexGuard},
10+
};
11+
12+
macro_rules! make_event {
13+
($message:expr) => {{
14+
let __msg = $message;
15+
Event::json(&__msg).event(__msg.name())
16+
}};
17+
}
18+
19+
pub(crate) use make_event;
20+
21+
pub struct GlobalState {
22+
pub lobbys: Mutex<HashMap<String, Protected<lobby::Player, Lobby<lobby::Player>>>>,
23+
pub games: Mutex<HashMap<String, Protected<crate::PlayerWrapper, Game<crate::PlayerWrapper>>>>,
24+
}
25+
26+
impl GlobalState {
27+
pub fn new() -> Self {
28+
Self {
29+
lobbys: Mutex::new(HashMap::new()),
30+
games: Mutex::new(HashMap::new()),
31+
}
32+
}
33+
}
34+
35+
pub struct Protected<PLAYER: Player, ROOM: Room<PLAYER>>(Arc<Mutex<ROOM>>, PhantomData<PLAYER>);
36+
37+
impl<PLAYER: Player, ROOM: Room<PLAYER>> Protected<PLAYER, ROOM> {
38+
pub fn new(content: ROOM) -> Self {
39+
Self(Arc::new(Mutex::new(content)), PhantomData)
40+
}
41+
42+
pub fn lock(&self) -> MutexGuard<ROOM> {
43+
self.0.lock().unwrap()
44+
}
45+
}
46+
47+
impl<PLAYER: Player, ROOM: Room<PLAYER>> Clone for Protected<PLAYER, ROOM> {
48+
fn clone(&self) -> Self {
49+
Self(Arc::clone(&self.0), PhantomData)
50+
}
51+
}

src/game.rs

Lines changed: 129 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rand::{
22
seq::{IteratorRandom, SliceRandom},
33
thread_rng,
44
};
5-
use rocket::serde::Serialize;
5+
use rocket::serde::{Deserialize, Serialize};
66
use std::{collections::HashMap, hash::Hash};
77

88
macro_rules! repeated_vec {
@@ -21,19 +21,116 @@ macro_rules! repeated_vec {
2121
};
2222
}
2323

24-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
24+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2525
#[serde(crate = "rocket::serde")]
2626
#[serde(rename_all = "lowercase")]
2727
pub enum Team {
2828
Sherlock,
2929
Moriarty,
3030
}
3131

32+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
33+
#[serde(crate = "rocket::serde")]
34+
#[serde(rename_all = "lowercase")]
35+
pub enum Cable {
36+
Safe,
37+
Defusing,
38+
Bomb,
39+
}
40+
3241
pub trait Player {
3342
type ID: Eq + Hash + Clone + Copy;
3443

3544
fn id(&self) -> Self::ID;
45+
}
46+
47+
pub trait Room<PLAYER: Player> {
48+
fn name(&self) -> &str;
49+
fn players(&self) -> &HashMap<PLAYER::ID, PLAYER>;
50+
fn get_player(&self, id: PLAYER::ID) -> Option<&PLAYER>;
51+
fn get_player_mut(&mut self, id: PLAYER::ID) -> Option<&mut PLAYER>;
52+
}
53+
54+
pub trait WaitingPlayer: Player {
3655
fn ready(&self) -> bool;
56+
}
57+
58+
pub struct Lobby<PLAYER: WaitingPlayer> {
59+
name: String,
60+
players: HashMap<PLAYER::ID, PLAYER>,
61+
}
62+
63+
impl<PLAYER: WaitingPlayer> Lobby<PLAYER> {
64+
pub fn new(name: String) -> Self {
65+
Self {
66+
name,
67+
players: HashMap::new(),
68+
}
69+
}
70+
71+
pub fn add_player(&mut self, player: PLAYER) -> Result<(), errors::Join> {
72+
if self.players.len() >= 8 {
73+
return Err(errors::Join::GameFull);
74+
}
75+
76+
if self.players.contains_key(&player.id()) {
77+
return Err(errors::Join::AlreadyConnected);
78+
}
79+
self.players.insert(player.id(), player);
80+
81+
Ok(())
82+
}
83+
84+
pub fn remove_player(&mut self, id: PLAYER::ID) {
85+
self.players.remove(&id);
86+
}
87+
}
88+
89+
impl<PLAYER: WaitingPlayer> Room<PLAYER> for Lobby<PLAYER> {
90+
fn name(&self) -> &str {
91+
&self.name
92+
}
93+
94+
fn players(&self) -> &HashMap<PLAYER::ID, PLAYER> {
95+
&self.players
96+
}
97+
98+
fn get_player(&self, id: PLAYER::ID) -> Option<&PLAYER> {
99+
self.players.get(&id)
100+
}
101+
102+
fn get_player_mut(&mut self, id: PLAYER::ID) -> Option<&mut PLAYER> {
103+
self.players.get_mut(&id)
104+
}
105+
}
106+
107+
pub mod errors {
108+
use thiserror::Error;
109+
110+
#[derive(Error, Debug, Clone, Copy)]
111+
pub enum Join {
112+
#[error("this game is already full")]
113+
GameFull,
114+
#[error("you are already connected to this game")]
115+
AlreadyConnected,
116+
}
117+
}
118+
119+
//
120+
//
121+
//
122+
//
123+
//
124+
//
125+
//
126+
//
127+
//
128+
//
129+
//
130+
//
131+
//
132+
133+
pub trait OldPlayer: WaitingPlayer {
37134
fn connected(&self) -> bool;
38135

39136
fn team(&self) -> Team;
@@ -44,22 +141,13 @@ pub trait Player {
44141
fn cables(&self) -> &[Cable];
45142
}
46143

47-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
48-
#[serde(crate = "rocket::serde")]
49-
#[serde(rename_all = "lowercase")]
50-
pub enum Cable {
51-
Safe,
52-
Defusing,
53-
Bomb,
54-
}
55-
56144
pub enum CutOutcome {
57145
Win(Team),
58146
RoundEnd,
59147
Nothing,
60148
}
61149

62-
enum GameState<PLAYER: Player> {
150+
enum GameState<PLAYER: OldPlayer> {
63151
Lobby,
64152
Ingame {
65153
wire_cutters: PLAYER::ID,
@@ -68,57 +156,44 @@ enum GameState<PLAYER: Player> {
68156
},
69157
}
70158

71-
pub struct Game<PLAYER: Player> {
159+
pub struct Game<PLAYER: OldPlayer> {
72160
name: String,
73161
players: HashMap<PLAYER::ID, PLAYER>,
74162
state: GameState<PLAYER>,
75163
}
76164

77-
impl<PLAYER: Player> Game<PLAYER> {
78-
pub fn new(name: String) -> Self {
79-
Self {
80-
name,
81-
players: HashMap::new(),
82-
state: GameState::Lobby,
83-
}
84-
}
85-
86-
pub fn name(&self) -> &str {
165+
impl<PLAYER: Player + OldPlayer> Room<PLAYER> for Game<PLAYER> {
166+
fn name(&self) -> &str {
87167
&self.name
88168
}
89169

90-
pub const fn wire_cutters(&self) -> Option<PLAYER::ID> {
91-
if let GameState::Ingame { wire_cutters, .. } = self.state {
92-
Some(wire_cutters)
93-
} else {
94-
None
95-
}
96-
}
97-
98-
pub const fn players(&self) -> &HashMap<PLAYER::ID, PLAYER> {
170+
fn players(&self) -> &HashMap<PLAYER::ID, PLAYER> {
99171
&self.players
100172
}
101173

102-
pub fn get_player(&self, id: PLAYER::ID) -> Option<&PLAYER> {
174+
fn get_player(&self, id: PLAYER::ID) -> Option<&PLAYER> {
103175
self.players.get(&id)
104176
}
105177

106-
pub fn get_player_mut(&mut self, id: PLAYER::ID) -> Option<&mut PLAYER> {
178+
fn get_player_mut(&mut self, id: PLAYER::ID) -> Option<&mut PLAYER> {
107179
self.players.get_mut(&id)
108180
}
181+
}
109182

110-
pub fn add_player(&mut self, player: PLAYER) -> Result<(), errors::PlayerJoin> {
111-
match self.state {
112-
GameState::Lobby { .. } => {
113-
if self.players.len() >= 8 {
114-
return Err(errors::PlayerJoin::GameFull);
115-
}
116-
117-
self.players.entry(player.id()).or_insert(player);
183+
impl<PLAYER: OldPlayer> Game<PLAYER> {
184+
pub fn new(name: String) -> Self {
185+
Self {
186+
name,
187+
players: HashMap::new(),
188+
state: GameState::Lobby,
189+
}
190+
}
118191

119-
Ok(())
120-
}
121-
_ => Err(errors::PlayerJoin::GameAlreadyStarted),
192+
pub const fn wire_cutters(&self) -> Option<PLAYER::ID> {
193+
if let GameState::Ingame { wire_cutters, .. } = self.state {
194+
Some(wire_cutters)
195+
} else {
196+
None
122197
}
123198
}
124199

@@ -147,12 +222,12 @@ impl<PLAYER: Player> Game<PLAYER> {
147222
}
148223
}
149224

150-
pub fn start(&mut self) -> Result<(), errors::GameStart> {
225+
pub fn start(&mut self) -> Result<(), old_errors::GameStart> {
151226
if self.players.len() < 4 {
152-
return Err(errors::GameStart::NotEnoughPlayers);
227+
return Err(old_errors::GameStart::NotEnoughPlayers);
153228
}
154-
if !self.players.values().all(Player::ready) {
155-
return Err(errors::GameStart::NotAllPlayersReady);
229+
if !self.players.values().all(WaitingPlayer::ready) {
230+
return Err(old_errors::GameStart::NotAllPlayersReady);
156231
}
157232

158233
let mut teams = match self.players.len() {
@@ -185,18 +260,18 @@ impl<PLAYER: Player> Game<PLAYER> {
185260
&mut self,
186261
cutting: PLAYER::ID,
187262
cutted: PLAYER::ID,
188-
) -> Result<(Cable, CutOutcome), errors::Cut> {
263+
) -> Result<(Cable, CutOutcome), old_errors::Cut> {
189264
if let GameState::Ingame {
190265
wire_cutters,
191266
defusing_remaining,
192267
cutted_count,
193268
} = &mut self.state
194269
{
195270
if cutting != *wire_cutters {
196-
return Err(errors::Cut::DontHaveWireCutter);
271+
return Err(old_errors::Cut::DontHaveWireCutter);
197272
}
198273
if cutted == cutting {
199-
return Err(errors::Cut::CannotSelfCut);
274+
return Err(old_errors::Cut::CannotSelfCut);
200275
}
201276

202277
let cable = self.players.get_mut(&cutted).unwrap().cut_cable();
@@ -219,7 +294,7 @@ impl<PLAYER: Player> Game<PLAYER> {
219294
Ok((cable, CutOutcome::Nothing))
220295
}
221296
} else {
222-
Err(errors::Cut::GameNotStarted)
297+
Err(old_errors::Cut::GameNotStarted)
223298
}
224299
}
225300

@@ -244,12 +319,7 @@ impl<PLAYER: Player> Game<PLAYER> {
244319
}
245320
}
246321

247-
pub mod errors {
248-
pub enum PlayerJoin {
249-
GameFull,
250-
GameAlreadyStarted,
251-
}
252-
322+
pub mod old_errors {
253323
pub enum GameStart {
254324
NotEnoughPlayers,
255325
NotAllPlayersReady,

0 commit comments

Comments
 (0)