Browse Source

Add more helper features for the game server

new_protocol
ThePerkinrex 5 years ago
parent
commit
234f101a65
No known key found for this signature in database GPG Key ID: 1F45A7C4BFB41607
  1. 14
      server/src/db.rs
  2. 3
      server/src/games/mod.rs
  3. 25
      server/src/games/run.rs
  4. 1
      server/src/games/run/functions.rs
  5. 5
      server/src/server.rs
  6. 10
      server/src/server/connection.rs
  7. 18
      server/src/server/lobby.rs
  8. 27
      server/src/server/votes.rs

14
server/src/db.rs

@ -82,6 +82,20 @@ impl Db {
.and_then(|r| r.map(|r| r.get(0)).collect()) .and_then(|r| r.map(|r| r.get(0)).collect())
.unwrap() .unwrap()
} }
// FIXME: return Results intead of crashing
pub fn get_uuids_in_lobby_where_user_is(&mut self, uuid: Uuid) -> Vec<Uuid> {
let mut prepared = self.conn.prepare_cached("SELECT UUID FROM Users WHERE UUID in (SELECT UserId FROM UsersInLobbies WHERE LobbyId = (SELECT LobbyId FROM UsersInLobbies WHERE UserId = ?))").unwrap();
prepared
.query(params![uuid.as_bytes().to_vec()])
.and_then(|r| {
r.map(|r| r.get::<_, Vec<u8>>(0))
.map(|x| Ok(Uuid::from_slice(&x).unwrap()))
.collect()
})
.unwrap()
}
// FIXME: return Results intead of crashing // FIXME: return Results intead of crashing
pub fn create_lobby(&mut self, public: bool) -> u32 { pub fn create_lobby(&mut self, public: bool) -> u32 {
let id = rand::random(); let id = rand::random();

3
server/src/games/mod.rs

@ -4,6 +4,7 @@ mod config;
mod run; mod run;
pub use run::{CardId, CardIdx, PileKind, RunningGame}; pub use run::{CardId, CardIdx, PileKind, RunningGame};
use uuid::Uuid;
#[derive(Clone)] #[derive(Clone)]
pub struct Game { pub struct Game {
@ -44,7 +45,7 @@ impl Game {
// self.authors.clone() // self.authors.clone()
// } // }
pub fn run(&self, players: u32) -> run::RunningGame { pub fn run(&self, players: &[Uuid]) -> run::RunningGame {
// let ast = rhai::Engine::new().compile_file(self.folder.join(&self.conf.script)).unwrap(); // let ast = rhai::Engine::new().compile_file(self.folder.join(&self.conf.script)).unwrap();
run::RunningGame::new( run::RunningGame::new(
self.name.clone(), self.name.clone(),

25
server/src/games/run.rs

@ -2,6 +2,7 @@ use rhai::{
serde::{from_dynamic, to_dynamic}, serde::{from_dynamic, to_dynamic},
Dynamic, Func, AST, Dynamic, Func, AST,
}; };
use uuid::Uuid;
use std::collections::HashMap; use std::collections::HashMap;
@ -22,6 +23,7 @@ pub struct RunningGame {
functions: Functions, functions: Functions,
current_player: Player, current_player: Player,
data: HashMap<String, serde_json::Value>, data: HashMap<String, serde_json::Value>,
players: HashMap<Uuid, u32>,
} }
// TODO add errors // TODO add errors
@ -40,30 +42,45 @@ impl RunningGame {
Ok((ast, fns)) Ok((ast, fns))
} }
pub fn new(name: String, ast: AST, fns: &[String], conf: &Config, players: u32) -> Self { pub fn new(
name: String,
ast: AST,
fns: &[String],
conf: &Config,
current_players: &[Uuid],
) -> Self {
// log::info!("Fns: {:?}", fns); // log::info!("Fns: {:?}", fns);
let functions = Functions::new(fns, ast.clone(), &name); let functions = Functions::new(fns, ast.clone(), &name);
let engine = setup_engine(); let engine = setup_engine();
let setup = Func::<(Dynamic,), Dynamic>::create_from_ast(engine, ast, "setup"); let setup = Func::<(Dynamic,), Dynamic>::create_from_ast(engine, ast, "setup");
let piles = conf.piles.clone(); let piles = conf.piles.clone();
let player_piles = vec![conf.player_piles.clone(); players as usize]; let player_piles = vec![conf.player_piles.clone(); current_players.len()];
let Data { let Data {
piles, piles,
player_piles, player_piles,
players: _, players: _,
other, other,
} = from_dynamic( } = from_dynamic(
&setup(to_dynamic(Data::new(piles, player_piles, players)).unwrap()).unwrap(), &setup(
to_dynamic(Data::new(piles, player_piles, current_players.len() as u32)).unwrap(),
)
.unwrap(),
) )
.unwrap(); .unwrap();
let mut players = HashMap::new();
for (i, player) in current_players.iter().enumerate() {
players.insert(player.clone(), i as u32);
}
log::info!("PLayers in game {}: {:?}", name, players);
Self { Self {
name, name,
piles, piles,
player_piles, player_piles,
functions, functions,
current_player: Player::new(0, players), current_player: Player::new(0, current_players.len() as u32),
data: other, data: other,
players,
} }
// Self {setup: Box::new(Func::<(Vec<Pile>, Vec<Vec<Pile>>), ()>::create_from_ast(engine, ast, "setup"))} // Self {setup: Box::new(Func::<(Vec<Pile>, Vec<Vec<Pile>>), ()>::create_from_ast(engine, ast, "setup"))}
} }

1
server/src/games/run/functions.rs

@ -52,6 +52,7 @@ impl Functions {
pub fn turn_end(&self, d: Dynamic, p: Player) -> RhaiResult<rhai::Array> { pub fn turn_end(&self, d: Dynamic, p: Player) -> RhaiResult<rhai::Array> {
self.engine self.engine
.call_fn(&mut Scope::new(), &self.ast, "turn_end", (d, p)) .call_fn(&mut Scope::new(), &self.ast, "turn_end", (d, p))
// TODO Check if the game has ended (With variable in the scope)
} }
pub fn on_click( pub fn on_click(

5
server/src/server.rs

@ -24,14 +24,15 @@ pub async fn start(
let properties = Arc::new(properties); let properties = Arc::new(properties);
let games = Arc::new(games); let games = Arc::new(games);
let voting = votes::VotingSystem::new(pool.clone().await); let voting = votes::VotingSystem::new(pool.clone().await);
let running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame)>>>> = Default::default();
let connection = ConnectionService { let connection = ConnectionService {
conn: RwLock::new(pool.clone().await), conn: RwLock::new(pool.clone().await),
properties: properties.clone(), properties: properties.clone(),
games: games.clone(), games: games.clone(),
voting: voting.clone(), voting: voting.clone(),
running_games: running_games.clone(),
}; };
let running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame)>>>> = Default::default(); let lobby = LobbyService::new(pool.clone().await, voting, games, running_games.clone());
let lobby = LobbyService::new(pool.clone().await, voting, running_games.clone());
let game = GameService::new(pool, running_games); let game = GameService::new(pool, running_games);
Server::builder() Server::builder()

10
server/src/server/connection.rs

@ -4,7 +4,7 @@ use log::info;
use tokio::sync::{mpsc, RwLock}; use tokio::sync::{mpsc, RwLock};
use std::sync::Arc; use std::{collections::HashMap, sync::Arc};
use super::grpc::common::Name; use super::grpc::common::Name;
use super::grpc::connection_service::connection_server::Connection; use super::grpc::connection_service::connection_server::Connection;
@ -16,12 +16,13 @@ use super::votes;
use super::client_id; use super::client_id;
use crate::db; use crate::{db, games::RunningGame};
pub struct ConnectionService { pub struct ConnectionService {
pub conn: RwLock<db::DbClient>, pub conn: RwLock<db::DbClient>,
pub properties: Arc<crate::server_properties::ServerProperties>, pub properties: Arc<crate::server_properties::ServerProperties>,
pub games: Arc<Vec<crate::games::Game>>, pub games: Arc<Vec<crate::games::Game>>,
pub running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame)>>>>,
pub voting: votes::VotingSystem, pub voting: votes::VotingSystem,
} }
@ -46,6 +47,11 @@ impl Connection for ConnectionService {
client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"),
})?; })?;
let lobby = request.get_ref().code; let lobby = request.get_ref().code;
if self.running_games.read().await.contains_key(&lobby) {
return Err(Status::permission_denied(
"Can't join a lobby where a game is running",
));
}
let mut conn = self.conn.write().await; let mut conn = self.conn.write().await;
conn.join_lobby(uuid, lobby).await; conn.join_lobby(uuid, lobby).await;
self.voting.updated_users(&lobby).await; self.voting.updated_users(&lobby).await;

18
server/src/server/lobby.rs

@ -18,7 +18,7 @@ use crate::{db, games::RunningGame};
pub struct LobbyService { pub struct LobbyService {
conn: RwLock<db::DbClient>, conn: RwLock<db::DbClient>,
// games: Arc<Vec<crate::games::Game>>, games: Arc<Vec<crate::games::Game>>,
voting: votes::VotingSystem, voting: votes::VotingSystem,
running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame)>>>>, running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame)>>>>,
} }
@ -27,12 +27,14 @@ impl LobbyService {
pub fn new( pub fn new(
conn: db::DbClient, conn: db::DbClient,
voting: votes::VotingSystem, voting: votes::VotingSystem,
games: Arc<Vec<crate::games::Game>>,
running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame)>>>>, running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame)>>>>,
) -> Self { ) -> Self {
Self { Self {
conn: RwLock::new(conn), conn: RwLock::new(conn),
voting, voting,
running_games, running_games,
games,
} }
} }
} }
@ -54,15 +56,15 @@ impl Lobby for LobbyService {
client_id::Error::NotSet => Status::failed_precondition("client_id must be set"), client_id::Error::NotSet => Status::failed_precondition("client_id must be set"),
client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"),
})?; })?;
let finished = self.voting.ready(uuid).await; if let Some(Some(winner)) = self.voting.ready(uuid).await {
if let Some(finished) = finished { let mut conn = self.conn.write().await;
let user_count = self let lobby = conn.get_lobby_for_user(uuid).await.unwrap();
.conn let user_count = conn.get_uuids_in_lobby_where_user_is(uuid).await;
let game = self.games[winner as usize].run(&user_count);
self.running_games
.write() .write()
.await .await
.get_users_in_lobby_where_user_is(uuid) .insert(lobby, RwLock::new((winner, game)));
.await
.len();
} }
Ok(Response::new(())) Ok(Response::new(()))
} }

27
server/src/server/votes.rs

@ -150,7 +150,7 @@ impl VotingSystem {
} }
} }
pub async fn ready(&self, user: Uuid) -> Option<bool> { pub async fn ready(&self, user: Uuid) -> Option<Option<u32>> {
let mut conn = self.conn.write().await; let mut conn = self.conn.write().await;
if let Some(lobby) = conn.get_lobby_for_user(user).await { if let Some(lobby) = conn.get_lobby_for_user(user).await {
conn.vote_ready(user).await; conn.vote_ready(user).await;
@ -158,14 +158,37 @@ impl VotingSystem {
let status = conn.get_votes(lobby).await; let status = conn.get_votes(lobby).await;
if finished { if finished {
conn.delete_votes(lobby).await; conn.delete_votes(lobby).await;
let winner = get_winner(status.iter().map(|(_, g, _)| g));
self.change_status_with_timeout(lobby, (status, finished), Some(SystemTime::now())) self.change_status_with_timeout(lobby, (status, finished), Some(SystemTime::now()))
.await; .await;
Some(Some(winner))
} else { } else {
self.change_status(lobby, (status, finished)).await; self.change_status(lobby, (status, finished)).await;
Some(None)
} }
Some(finished)
} else { } else {
None None
} }
} }
} }
fn get_winner<'a, I: Iterator<Item = &'a u32>>(iter: I) -> u32 {
let mut count: HashMap<u32, u32> = Default::default();
for item in iter {
if let Some(e) = count.get_mut(item) {
*e += 1;
} else {
count.insert(*item, 1);
}
}
count
.into_iter()
.fold((0, 0), |(max_game, max_num), (game, num)| {
if num > max_num {
(game, num)
} else {
(max_game, max_num)
}
})
.0
}

Loading…
Cancel
Save