impl run lobby without checks
parent
cbb8bbec40
commit
6fb3feeeac
|
|
@ -0,0 +1,162 @@
|
|||
use super::super::super::model::state::event::Event;
|
||||
use json;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GameEvent {
|
||||
d: json::JsonValue,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum GameEventType {
|
||||
Null,
|
||||
GameStart,
|
||||
RoleSet,
|
||||
ElectionPend,
|
||||
ElectionSet,
|
||||
VoteSet,
|
||||
CardPend,
|
||||
CardPick,
|
||||
PolicySet,
|
||||
SpecialInspect,
|
||||
SpecialSelect,
|
||||
SpecialKill,
|
||||
SpecialPeek,
|
||||
GameStop,
|
||||
}
|
||||
|
||||
impl GameEventType {
|
||||
fn from_string(s: String) -> GameEventType {
|
||||
match s.as_ref() {
|
||||
"Null" => return GameEventType::Null,
|
||||
"GameStart" => return GameEventType::GameStart,
|
||||
"RoleSet" => return GameEventType::RoleSet,
|
||||
"ElectionPend" => return GameEventType::ElectionPend,
|
||||
"ElectionSet" => return GameEventType::ElectionSet,
|
||||
"VoteSet" => return GameEventType::VoteSet,
|
||||
"CardPend" => return GameEventType::CardPend,
|
||||
"CardPick" => return GameEventType::CardPick,
|
||||
"PolicySet" => return GameEventType::PolicySet,
|
||||
"SpecialInspect" => return GameEventType::SpecialInspect,
|
||||
"SpecialSelect" => return GameEventType::SpecialSelect,
|
||||
"SpecialKill" => return GameEventType::SpecialKill,
|
||||
"SpecialPeek" => return GameEventType::SpecialPeek,
|
||||
"GameStop" => return GameEventType::GameStop,
|
||||
_ => return GameEventType::Null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GameEvent {
|
||||
pub fn new(body: String) -> GameEvent {
|
||||
let top_level = json::parse(&body);
|
||||
if top_level.is_err() {
|
||||
return GameEvent{d: json::Null};
|
||||
}
|
||||
let top_level = top_level.unwrap();
|
||||
if !top_level["body"].is_string() {
|
||||
return GameEvent{d: json::Null};
|
||||
}
|
||||
GameEvent{
|
||||
d: json::parse(&top_level["body"].as_str().unwrap()).unwrap_or(json::Null),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> GameEventType {
|
||||
if self.d.is_null() {
|
||||
return GameEventType::Null;
|
||||
}
|
||||
if !self.d["GameEventType"].is_string() {
|
||||
return GameEventType::Null;
|
||||
}
|
||||
let s = self.d["GameEventType"].as_str().unwrap().to_string();
|
||||
GameEventType::from_string(s.to_string())
|
||||
}
|
||||
|
||||
pub fn sources(&self) -> Vec<String> {
|
||||
self.str_vec("sources")
|
||||
}
|
||||
|
||||
pub fn targets(&self) -> Vec<String> {
|
||||
self.str_vec("targets")
|
||||
}
|
||||
|
||||
pub fn params(&self) -> Vec<String> {
|
||||
self.str_vec("params")
|
||||
}
|
||||
|
||||
fn str_vec(&self, key: &str) -> Vec<String> {
|
||||
let mut out = vec![];
|
||||
if self.d[key].is_string() {
|
||||
out.push(self.d[key].as_str().unwrap().to_string());
|
||||
return out;
|
||||
}
|
||||
if self.d[key].is_array() {
|
||||
let iter = self.d[key].members();
|
||||
for i in iter {
|
||||
if !i.is_string() {
|
||||
return vec![];
|
||||
}
|
||||
out.push(i.as_str().unwrap().to_string());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new() {
|
||||
let ge = GameEvent::new("\"a\"".to_string());
|
||||
assert!(ge.d.is_null());
|
||||
|
||||
let ge = GameEvent::new("a".to_string());
|
||||
assert!(ge.d.is_null());
|
||||
assert!(ge.mode() == GameEventType::Null);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_from_string() {
|
||||
assert!(GameEventType::from_string("Null".to_string()) == GameEventType::Null);
|
||||
assert!(GameEventType::from_string("GameStart".to_string()) == GameEventType::GameStart);
|
||||
assert!(GameEventType::from_string("RoleSet".to_string()) == GameEventType::RoleSet);
|
||||
assert!(GameEventType::from_string("ElectionPend".to_string()) == GameEventType::ElectionPend);
|
||||
assert!(GameEventType::from_string("ElectionSet".to_string()) == GameEventType::ElectionSet);
|
||||
assert!(GameEventType::from_string("VoteSet".to_string()) == GameEventType::VoteSet);
|
||||
assert!(GameEventType::from_string("CardPend".to_string()) == GameEventType::CardPend);
|
||||
assert!(GameEventType::from_string("CardPick".to_string()) == GameEventType::CardPick);
|
||||
assert!(GameEventType::from_string("PolicySet".to_string()) == GameEventType::PolicySet);
|
||||
assert!(GameEventType::from_string("SpecialInspect".to_string()) == GameEventType::SpecialInspect);
|
||||
assert!(GameEventType::from_string("SpecialSelect".to_string()) == GameEventType::SpecialSelect);
|
||||
assert!(GameEventType::from_string("SpecialKill".to_string()) == GameEventType::SpecialKill);
|
||||
assert!(GameEventType::from_string("SpecialPeek".to_string()) == GameEventType::SpecialPeek);
|
||||
assert!(GameEventType::from_string("GameStop".to_string()) == GameEventType::GameStop);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sources() {
|
||||
let ge = GameEvent::new(r#"{"body": "{\"sources\": [\"a\", \"b\"]}"}"#.to_string());
|
||||
assert!(ge.sources() == vec!["a", "b"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn targets() {
|
||||
let ge = GameEvent::new(r#"{"body": "{\"targets\": [\"a\", \"b\"]}"}"#.to_string());
|
||||
assert!(ge.targets() == vec!["a", "b"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn params() {
|
||||
let ge = GameEvent::new(r#"{"body": "{\"params\": [\"a\", \"b\"]}"}"#.to_string());
|
||||
assert!(ge.params() == vec!["a", "b"]);
|
||||
|
||||
let ge = GameEvent::new(r#"{"body": "{\"params\": []}"}"#.to_string());
|
||||
assert!(ge.params().len() == 0);
|
||||
|
||||
let ge = GameEvent::new(r#"{"body": "{}"}"#.to_string());
|
||||
assert!(ge.params().len() == 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
use super::super::super::model::state::room::Room;
|
||||
use super::lobby::Lobby;
|
||||
use super::gameevent::GameEvent;
|
||||
use super::gameevent::GameEventType;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
pub struct GameMaster {
|
||||
room: Box<dyn Room>,
|
||||
|
|
@ -21,18 +25,24 @@ impl GameMaster {
|
|||
}
|
||||
|
||||
fn run_lobby(&mut self) -> Result<String, String> {
|
||||
println!(". run lobby");
|
||||
loop {
|
||||
while !self.lobby.locked {
|
||||
let rollback = self.room.since();
|
||||
let events = self.room.sync();
|
||||
println!(". rollback: {:?}", rollback);
|
||||
println!("top of loop: since={:?}, events={:?}", self.room.since(), events);
|
||||
for e in &events {
|
||||
println!("e: {:?}", e);
|
||||
let ge = GameEvent::new(e.body.clone());
|
||||
println!(" ge.mode = {:?}", ge.mode());
|
||||
if ge.mode() == GameEventType::GameStart {
|
||||
println!(" should return");
|
||||
self.room.rollback(e.since.clone());
|
||||
self.lobby.lock();
|
||||
return Ok("ok".to_string());
|
||||
}
|
||||
self.room.rollback(rollback);
|
||||
break
|
||||
self.lobby.eat(e.clone());
|
||||
}
|
||||
Err("not impl".to_string())
|
||||
thread::sleep(time::Duration::new(1, 0));
|
||||
}
|
||||
Ok("ok".to_string()) // todo: on lobby too small, return err and do not lock
|
||||
}
|
||||
|
||||
fn run_game_setup(&mut self) -> Result<String, String> {
|
||||
|
|
@ -54,7 +64,6 @@ mod tests {
|
|||
#[test]
|
||||
fn new_mockroom() {
|
||||
let _ = GameMaster::new(Box::new(MockRoom::create()));
|
||||
println!("made");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -78,27 +87,33 @@ mod tests {
|
|||
#[test]
|
||||
fn run_lobby() {
|
||||
let mut mrs = MockRooms::new();
|
||||
let mut r1 = mrs.create();
|
||||
let r1 = mrs.create();
|
||||
let room_id = r1.room_id();
|
||||
let mut gm = GameMaster::new(r1);
|
||||
let mut r2 = mrs.join(room_id).unwrap();
|
||||
r2.send(r#"{
|
||||
r2.send(format!(r#"{{
|
||||
"msgtype": "m.text",
|
||||
"body": ""
|
||||
}"#);
|
||||
gm.run_lobby();
|
||||
assert!(gm.lobby.players.len() == 1, "players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync());
|
||||
"body": "{{\"GameEventType\": \"GameStart\"}}"
|
||||
}}"#)).unwrap(); // TODO mark end of new players
|
||||
gm.run_lobby(); // todo assert is_ok
|
||||
assert!(gm.lobby.players.len() == 2, "first run_lobby players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync());
|
||||
let mut players1 = vec![];
|
||||
for k in gm.lobby.players.keys() {
|
||||
players1.push(k.clone());
|
||||
}
|
||||
gm.run_lobby(); // todo assert is_ok
|
||||
assert!(gm.lobby.players.len() == 2, "secnd run_lobby players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync());
|
||||
let players2 = gm.lobby.players.keys();
|
||||
assert!(format!("{:?}", players1) == format!("{:?}", players2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_game_setup_fail() {
|
||||
let gm = GameMaster::new(Box::new(MockRoom::create()));
|
||||
panic!("not impl");
|
||||
assert!(false, "not impl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_game_fail() {
|
||||
let gm = GameMaster::new(Box::new(MockRoom::create()));
|
||||
panic!("not impl");
|
||||
assert!(false, "not impl");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::collections::HashMap;
|
|||
|
||||
pub struct Lobby {
|
||||
pub players: HashMap<String, Player>,
|
||||
locked: bool,
|
||||
pub locked: bool,
|
||||
}
|
||||
|
||||
impl Lobby {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pub mod gamemaster;
|
||||
pub mod gamemaster;
|
||||
pub mod player;
|
||||
pub mod role;
|
||||
pub mod lobby;
|
||||
pub mod gameevent;
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ mod tests {
|
|||
let mut r = _dummy();
|
||||
r.sync();
|
||||
let mut sinces = vec![];
|
||||
for i in 0..10 {
|
||||
for _ in 0..10 {
|
||||
sinces.push(r.send("0".to_string()).ok().unwrap());
|
||||
sinces.push(r.send("0".to_string()).ok().unwrap());
|
||||
r.sync();
|
||||
|
|
@ -172,7 +172,7 @@ mod tests {
|
|||
let mut r = _dummy();
|
||||
r.sync();
|
||||
let mut sinces = vec![];
|
||||
for i in 0..10 {
|
||||
for _ in 0..10 {
|
||||
sinces.push(r.send("0".to_string()).ok().unwrap());
|
||||
r.sync();
|
||||
assert!(r.since == sinces[sinces.len()-1]);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl Rooms for MockRooms {
|
|||
r.send(format!(r#"{{
|
||||
"displayname": "{}",
|
||||
"membership": "join"
|
||||
}}"#, rands()));
|
||||
}}"#, rands())).unwrap();
|
||||
return Ok(Box::new(r));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue