|  | @@ -1,18 +1,16 @@
 | 
	
		
			
				|  |  |  use std::collections::BTreeMap;
 | 
	
		
			
				|  |  |  use std::sync::Arc;
 | 
	
		
			
				|  |  | -use std::borrow::Borrow;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  use rand::thread_rng;
 | 
	
		
			
				|  |  |  use rand::seq::SliceRandom;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  use actix::prelude::*;
 | 
	
		
			
				|  |  | +use log::info;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  use crate::server::server::{GameConnection, Server};
 | 
	
		
			
				|  |  |  use crate::datasource;
 | 
	
		
			
				|  |  |  use crate::game;
 | 
	
		
			
				|  |  | -use crate::websocket;
 | 
	
		
			
				|  |  | -use crate::websocket::*;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +use crate::server::protocol::*;
 | 
	
		
			
				|  |  |  use crate::server::messages::*;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(PartialEq)]
 | 
	
	
		
			
				|  | @@ -40,7 +38,7 @@ pub struct GameLobby {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl Actor for GameLobby {
 | 
	
		
			
				|  |  |      type Context = Context<Self>;
 | 
	
		
			
				|  |  | -    fn started(&mut self, ctx: &mut Self::Context) {
 | 
	
		
			
				|  |  | +    fn started(&mut self, _ctx: &mut Self::Context) {
 | 
	
		
			
				|  |  |          self.lobby_state = LobbyState::Starting;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -57,11 +55,11 @@ impl Handler<JoinRequest> for GameLobby {
 | 
	
		
			
				|  |  |                  LobbyJoined {
 | 
	
		
			
				|  |  |                      lobby: ctx.address(),
 | 
	
		
			
				|  |  |                      game_id: self.game_id.clone(),
 | 
	
		
			
				|  |  | -                    nick: jr.nick
 | 
	
		
			
				|  |  | +                    nick: jr.nick.clone()
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              self.send_game_to_all();
 | 
	
		
			
				|  |  | +            info!("Player {} joined lobby {}", jr.nick, self.game_id);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          else {
 | 
	
		
			
				|  |  |              self.waiting_players.insert(jr.nick.clone(), jr.p);
 | 
	
	
		
			
				|  | @@ -74,6 +72,7 @@ impl Handler<LeaveMsg> for GameLobby {
 | 
	
		
			
				|  |  |      fn handle(&mut self, lm: LeaveMsg, _ctx: &mut Self::Context) -> Self::Result {
 | 
	
		
			
				|  |  |          self.waiting_players.remove(&lm.0);
 | 
	
		
			
				|  |  |          self.connected_players.remove(&lm.0);
 | 
	
		
			
				|  |  | +        self.ready_players.retain(|p| p != &lm.0);
 | 
	
		
			
				|  |  |          self.game.remove_player(&lm.0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if self.connected_players.is_empty() {
 | 
	
	
		
			
				|  | @@ -88,6 +87,8 @@ impl Handler<ReadyMsg> for GameLobby {
 | 
	
		
			
				|  |  |          if !self.ready_players.contains(&rm.0) {
 | 
	
		
			
				|  |  |              self.ready_players.push(rm.0);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        self.send_playerlist_to_all();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          if self.ready_players.len() >= self.connected_players.len() {
 | 
	
		
			
				|  |  |              self.set_state(LobbyState::Creating);
 | 
	
		
			
				|  |  |              self.send_game_to_all();
 | 
	
	
		
			
				|  | @@ -95,6 +96,14 @@ impl Handler<ReadyMsg> for GameLobby {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +impl Handler<UnreadyMsg> for GameLobby {
 | 
	
		
			
				|  |  | +    type Result = ();
 | 
	
		
			
				|  |  | +    fn handle(&mut self, urm: UnreadyMsg, _ctx: &mut Self::Context) -> Self::Result {
 | 
	
		
			
				|  |  | +        self.ready_players.retain(|p| p != &urm.0);
 | 
	
		
			
				|  |  | +        self.send_playerlist_to_all();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  impl Handler<SubmitWordMsg> for GameLobby {
 | 
	
		
			
				|  |  |      type Result = ();
 | 
	
		
			
				|  |  |      fn handle(&mut self, swm: SubmitWordMsg, _ctx: &mut Self::Context) -> Self::Result {
 | 
	
	
		
			
				|  | @@ -104,6 +113,9 @@ impl Handler<SubmitWordMsg> for GameLobby {
 | 
	
		
			
				|  |  |              self.game.next_state();
 | 
	
		
			
				|  |  |              self.send_game_to_all();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        else {
 | 
	
		
			
				|  |  | +            self.send_playerlist_to_all();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -125,6 +137,9 @@ impl Handler<SubmitGuessMsg> for GameLobby {
 | 
	
		
			
				|  |  |              self.game.next_state();
 | 
	
		
			
				|  |  |              self.send_game_to_all();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        else {
 | 
	
		
			
				|  |  | +            self.send_playerlist_to_all();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -151,7 +166,6 @@ impl GameLobby {
 | 
	
		
			
				|  |  |                      self.game.player_join(nick.clone());
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  self.connected_players.append(&mut self.waiting_players);
 | 
	
		
			
				|  |  | -                self.ready_players.clear();
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  |              LobbyState::Creating => {
 | 
	
		
			
				|  |  |                  let s = &mut self.shuffler;
 | 
	
	
		
			
				|  | @@ -160,6 +174,7 @@ impl GameLobby {
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  |              _ => {}
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        self.ready_players.clear();
 | 
	
		
			
				|  |  |          self.lobby_state = new_state;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -182,6 +197,13 @@ impl GameLobby {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    pub fn send_playerlist_to_all(&self) {
 | 
	
		
			
				|  |  | +        let player_list = self.create_playerlist();
 | 
	
		
			
				|  |  | +        for (_nick, player) in &self.connected_players {
 | 
	
		
			
				|  |  | +            player.do_send(PlayerListUpdate{ player_list: player_list.clone() });
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn create_result_data(&self) -> RoundResultData {
 | 
	
		
			
				|  |  |          let (guesses, point_list) = self.game.create_results();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -212,14 +234,40 @@ impl GameLobby {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// determines if a player is ready to progress into the next game state
 | 
	
		
			
				|  |  | +    /// 
 | 
	
		
			
				|  |  | +    fn player_is_ready(&self, nick: &str) -> bool {
 | 
	
		
			
				|  |  | +        match self.lobby_state {
 | 
	
		
			
				|  |  | +            LobbyState::Starting => self.ready_players.iter().any(|p| p == nick),
 | 
	
		
			
				|  |  | +            LobbyState::Creating => self.game.get_player(nick)
 | 
	
		
			
				|  |  | +                                             .map(|p| p.has_submitted_word())
 | 
	
		
			
				|  |  | +                                             .unwrap_or(false),
 | 
	
		
			
				|  |  | +            LobbyState::Guessing => self.game.get_player(nick)
 | 
	
		
			
				|  |  | +                                             .map(|p| p.has_submitted_guess())
 | 
	
		
			
				|  |  | +                                             .unwrap_or(false),
 | 
	
		
			
				|  |  | +            LobbyState::Revealing => self.ready_players.iter().any(|p| p == nick)
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    fn create_playerlist(&self) -> Vec<PlayerData> {
 | 
	
		
			
				|  |  | +        self.game.players.iter()
 | 
	
		
			
				|  |  | +                         .map(|p|
 | 
	
		
			
				|  |  | +                             PlayerData {
 | 
	
		
			
				|  |  | +                                 nick: p.nick.clone(),
 | 
	
		
			
				|  |  | +                                 points: self.get_player_points(&p.nick),
 | 
	
		
			
				|  |  | +                                 ready: self.player_is_ready(&p.nick),
 | 
	
		
			
				|  |  | +                             })
 | 
	
		
			
				|  |  | +                         .collect::<Vec<_>>()
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn create_opaque_message(&self, nick: &str) -> GameData {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          let player = self.game.players.iter()
 | 
	
		
			
				|  |  |                          .find(|p| p.nick == nick);
 | 
	
		
			
				|  |  |          GameData {
 | 
	
		
			
				|  |  | -            players: self.game.players.iter()
 | 
	
		
			
				|  |  | -                        .map(|p| websocket::PlayerData{ nick: p.nick.clone(), points: self.get_player_points(&p.nick) })
 | 
	
		
			
				|  |  | -                        .collect::<Vec<_>>(),
 | 
	
		
			
				|  |  | +            players: self.create_playerlist(),
 | 
	
		
			
				|  |  |              state_data:
 | 
	
		
			
				|  |  |                  match self.game.state {
 | 
	
		
			
				|  |  |                      game::GameState::Starting => {
 |