impl run lobby without checks
parent
cb1a9050e8
commit
f1311c9086
|
|
@ -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::super::super::model::state::room::Room;
|
||||||
use super::lobby::Lobby;
|
use super::lobby::Lobby;
|
||||||
|
use super::gameevent::GameEvent;
|
||||||
|
use super::gameevent::GameEventType;
|
||||||
|
use std::thread;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
pub struct GameMaster {
|
pub struct GameMaster {
|
||||||
room: Box<dyn Room>,
|
room: Box<dyn Room>,
|
||||||
|
|
@ -21,18 +25,24 @@ impl GameMaster {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_lobby(&mut self) -> Result<String, String> {
|
fn run_lobby(&mut self) -> Result<String, String> {
|
||||||
println!(". run lobby");
|
while !self.lobby.locked {
|
||||||
loop {
|
|
||||||
let rollback = self.room.since();
|
let rollback = self.room.since();
|
||||||
let events = self.room.sync();
|
let events = self.room.sync();
|
||||||
println!(". rollback: {:?}", rollback);
|
println!("top of loop: since={:?}, events={:?}", self.room.since(), events);
|
||||||
for e in &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.lobby.eat(e.clone());
|
||||||
}
|
}
|
||||||
self.room.rollback(rollback);
|
thread::sleep(time::Duration::new(1, 0));
|
||||||
break
|
|
||||||
}
|
}
|
||||||
Err("not impl".to_string())
|
Ok("ok".to_string()) // todo: on lobby too small, return err and do not lock
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_game_setup(&mut self) -> Result<String, String> {
|
fn run_game_setup(&mut self) -> Result<String, String> {
|
||||||
|
|
@ -54,7 +64,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn new_mockroom() {
|
fn new_mockroom() {
|
||||||
let _ = GameMaster::new(Box::new(MockRoom::create()));
|
let _ = GameMaster::new(Box::new(MockRoom::create()));
|
||||||
println!("made");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -78,27 +87,33 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn run_lobby() {
|
fn run_lobby() {
|
||||||
let mut mrs = MockRooms::new();
|
let mut mrs = MockRooms::new();
|
||||||
let mut r1 = mrs.create();
|
let r1 = mrs.create();
|
||||||
let room_id = r1.room_id();
|
let room_id = r1.room_id();
|
||||||
let mut gm = GameMaster::new(r1);
|
let mut gm = GameMaster::new(r1);
|
||||||
let mut r2 = mrs.join(room_id).unwrap();
|
let mut r2 = mrs.join(room_id).unwrap();
|
||||||
r2.send(r#"{
|
r2.send(format!(r#"{{
|
||||||
"msgtype": "m.text",
|
"msgtype": "m.text",
|
||||||
"body": ""
|
"body": "{{\"GameEventType\": \"GameStart\"}}"
|
||||||
}"#);
|
}}"#)).unwrap(); // TODO mark end of new players
|
||||||
gm.run_lobby();
|
gm.run_lobby(); // todo assert is_ok
|
||||||
assert!(gm.lobby.players.len() == 1, "players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync());
|
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]
|
#[test]
|
||||||
fn run_game_setup_fail() {
|
fn run_game_setup_fail() {
|
||||||
let gm = GameMaster::new(Box::new(MockRoom::create()));
|
assert!(false, "not impl");
|
||||||
panic!("not impl");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn run_game_fail() {
|
fn run_game_fail() {
|
||||||
let gm = GameMaster::new(Box::new(MockRoom::create()));
|
assert!(false, "not impl");
|
||||||
panic!("not impl");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct Lobby {
|
pub struct Lobby {
|
||||||
pub players: HashMap<String, Player>,
|
pub players: HashMap<String, Player>,
|
||||||
locked: bool,
|
pub locked: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lobby {
|
impl Lobby {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// pub mod gamemaster;
|
pub mod gamemaster;
|
||||||
pub mod player;
|
pub mod player;
|
||||||
pub mod role;
|
pub mod role;
|
||||||
pub mod lobby;
|
pub mod lobby;
|
||||||
|
pub mod gameevent;
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ mod tests {
|
||||||
let mut r = _dummy();
|
let mut r = _dummy();
|
||||||
r.sync();
|
r.sync();
|
||||||
let mut sinces = vec![];
|
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());
|
||||||
sinces.push(r.send("0".to_string()).ok().unwrap());
|
sinces.push(r.send("0".to_string()).ok().unwrap());
|
||||||
r.sync();
|
r.sync();
|
||||||
|
|
@ -172,7 +172,7 @@ mod tests {
|
||||||
let mut r = _dummy();
|
let mut r = _dummy();
|
||||||
r.sync();
|
r.sync();
|
||||||
let mut sinces = vec![];
|
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();
|
r.sync();
|
||||||
assert!(r.since == sinces[sinces.len()-1]);
|
assert!(r.since == sinces[sinces.len()-1]);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ impl Rooms for MockRooms {
|
||||||
r.send(format!(r#"{{
|
r.send(format!(r#"{{
|
||||||
"displayname": "{}",
|
"displayname": "{}",
|
||||||
"membership": "join"
|
"membership": "join"
|
||||||
}}"#, rands()));
|
}}"#, rands())).unwrap();
|
||||||
return Ok(Box::new(r));
|
return Ok(Box::new(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue