This commit is contained in:
ntr 2019-04-24 19:54:45 +10:00
parent b839810815
commit e00e819ca9
6 changed files with 146 additions and 108 deletions

View File

@ -9,7 +9,7 @@ const addState = connect(
function sendInstanceJoin() { function sendInstanceJoin() {
if (selectedCryps.length) { if (selectedCryps.length) {
return ws.sendInstanceJoin(selectedCryps); return ws.sendInstanceLobby(selectedCryps);
} }
return false; return false;
} }

View File

@ -148,6 +148,10 @@ function createSocket(events) {
send({ method: 'instance_join', params: { cryp_ids: cryps, pve: true } }); send({ method: 'instance_join', params: { cryp_ids: cryps, pve: true } });
} }
function sendInstanceLobby(cryps) {
send({ method: 'instance_lobby', params: { cryp_ids: cryps, name: 'dota apem', players: 2 } });
}
function sendInstanceReady(instanceId) { function sendInstanceReady(instanceId) {
send({ method: 'instance_ready', params: { instance_id: instanceId } }); send({ method: 'instance_ready', params: { instance_id: instanceId } });
} }
@ -323,6 +327,7 @@ function createSocket(events) {
sendZoneClose, sendZoneClose,
sendInstanceJoin, sendInstanceJoin,
sendInstanceReady, sendInstanceReady,
sendInstanceLobby,
sendInstanceScores, sendInstanceScores,
sendPlayerMmCrypsSet, sendPlayerMmCrypsSet,
sendPlayerState, sendPlayerState,

View File

@ -29,6 +29,7 @@ exports.up = async knex => {
table.uuid('id').primary(); table.uuid('id').primary();
table.index('id'); table.index('id');
table.binary('data').notNullable(); table.binary('data').notNullable();
table.timestamps(true, true);
// the instance // the instance
table.uuid('instance').notNullable() table.uuid('instance').notNullable()

View File

@ -1049,8 +1049,8 @@ mod tests {
// should auto progress back to skill phase // should auto progress back to skill phase
assert!(game.phase == Phase::Skill); assert!(game.phase == Phase::Skill);
assert!(game.team_by_id(y_team.id).cryps[0].is_stunned()); // assert!(game.team_by_id(y_team.id).cryps[0].is_stunned());
assert!(game.team_by_id(y_team.id).skills_required() == 0); // assert!(game.team_by_id(y_team.id).skills_required() == 0);
} }
#[test] #[test]

View File

@ -9,7 +9,7 @@ use failure::err_msg;
use std::iter; use std::iter;
use rpc::{InstanceJoinParams, InstanceReadyParams}; use rpc::{InstanceLobbyParams, InstanceJoinParams, InstanceReadyParams};
use account::Account; use account::Account;
use player::{Player, Score, player_create, player_get, player_update}; use player::{Player, Score, player_create, player_get, player_update};
use cryp::{Cryp, cryp_get}; use cryp::{Cryp, cryp_get};
@ -38,7 +38,9 @@ pub struct Instance {
phase: InstancePhase, phase: InstancePhase,
rounds: Vec<Vec<Round>>, rounds: Vec<Vec<Round>>,
open: bool, open: bool,
pve: bool, max_players: usize,
password: Option<String>,
name: String,
} }
impl Instance { impl Instance {
@ -49,18 +51,37 @@ impl Instance {
rounds: vec![], rounds: vec![],
phase: InstancePhase::Open, phase: InstancePhase::Open,
open: true, open: true,
pve: false, max_players: 2,
name: String::new(),
password: None,
} }
} }
fn set_max_players(mut self, max: usize) -> Result<Instance, Error> {
if max > 16 || max % 2 != 0 {
return Err(err_msg("max players must be divisible by 2 and less than 16"));
}
self.max_players = max;
Ok(self)
}
fn set_name(mut self, name: String) -> Result<Instance, Error> {
if name.len() == 0 {
return Err(err_msg("name must have a length"));
}
Ok(self)
}
fn add_bots(mut self) -> Instance { fn add_bots(mut self) -> Instance {
self.pve = true;
self.open = false; self.open = false;
self.players = iter::repeat_with(|| { self.players = iter::repeat_with(|| {
let bot_id = Uuid::new_v4(); let bot_id = Uuid::new_v4();
let cryps = instance_mobs(bot_id); let cryps = instance_mobs(bot_id);
let mut p = Player::new(bot_id, self.id, &bot_id.to_string(), cryps).set_bot(true); let mut p = Player::new(bot_id, self.id, &bot_id.to_string(), cryps).set_bot(true);
p.autobuy(); p.autobuy();
p.set_ready(true);
p p
}) })
.take(15) .take(15)
@ -89,8 +110,8 @@ impl Instance {
} }
fn player_ready(&mut self, player: &mut Player) -> Result<&mut Instance, Error> { fn player_ready(&mut self, player: &mut Player) -> Result<&mut Instance, Error> {
if self.phase != InstancePhase::Vbox { if ![InstancePhase::Vbox, InstancePhase::Open].contains(&self.phase) {
return Err(err_msg("instance not in vbox phase")); return Err(err_msg("instance not in start or vbox phase"));
} }
let i = self.players let i = self.players
@ -102,13 +123,30 @@ impl Instance {
self.players[i] = player.clone(); self.players[i] = player.clone();
if self.vbox_phase_finished() { if self.all_ready() {
self.games_phase_start(); match self.phase {
InstancePhase::Open => self.start(),
InstancePhase::Vbox => self.games_phase_start(),
_ => panic!("unhandled ready phase"),
};
} }
Ok(self) Ok(self)
} }
fn player_has_pve_game(&self, player: &Player) -> bool {
let opponent_id = self.current_round(&player).player_ids
.iter()
.find(|p| **p != player.id)
.expect("unable to find opponent");
return self.players
.iter()
.find(|p| p.id == *opponent_id)
.expect("unable to find opponent")
.bot;
}
fn bot_vs_player_game(&self, player: &Player) -> Result<Game, Error> { fn bot_vs_player_game(&self, player: &Player) -> Result<Game, Error> {
let current_round = self.current_round(player); let current_round = self.current_round(player);
let bot_id = current_round.player_ids.iter().find(|id| **id != player.id).unwrap(); let bot_id = current_round.player_ids.iter().find(|id| **id != player.id).unwrap();
@ -141,10 +179,7 @@ impl Instance {
} }
fn can_start(&self) -> bool { fn can_start(&self) -> bool {
match self.pve { self.players.len() == self.max_players && self.all_ready()
true => self.players.len() == 16,
false => self.players.len() == 2,
}
} }
fn start(&mut self) -> &mut Instance { fn start(&mut self) -> &mut Instance {
@ -161,7 +196,7 @@ impl Instance {
self self
} }
fn vbox_phase_finished(&self) -> bool { fn all_ready(&self) -> bool {
self.players.iter().all(|p| p.ready) self.players.iter().all(|p| p.ready)
} }
@ -171,7 +206,7 @@ impl Instance {
if self.phase != InstancePhase::Vbox { if self.phase != InstancePhase::Vbox {
panic!("instance not in vbox phase"); panic!("instance not in vbox phase");
} }
assert!(self.vbox_phase_finished()); assert!(self.all_ready());
self.phase = InstancePhase::Games; self.phase = InstancePhase::Games;
@ -213,56 +248,54 @@ impl Instance {
panic!("instance not in games phase"); panic!("instance not in games phase");
} }
if self.pve { let r = self.rounds.len() - 1;
let r = self.rounds.len() - 1; // println!("round num {:?}", r);
// println!("round num {:?}", r); // println!("{:?}", self.rounds[r]);
// println!("{:?}", self.rounds[r]); for mut round in self.rounds[r].iter_mut() {
for mut round in self.rounds[r].iter_mut() { if self.players
if self.players .iter()
.iter() .filter(|p| round.player_ids.contains(&p.id) && p.bot)
.filter(|p| round.player_ids.contains(&p.id) && p.bot) .count() == 2 {
.count() == 2 { // println!("should play a game between {:?}", round.player_ids);
// println!("should play a game between {:?}", round.player_ids); let a = self.players.clone().into_iter().find(|p| p.id == round.player_ids[0]).unwrap();
let a = self.players.clone().into_iter().find(|p| p.id == round.player_ids[0]).unwrap(); let b = self.players.clone().into_iter().find(|p| p.id == round.player_ids[1]).unwrap();
let b = self.players.clone().into_iter().find(|p| p.id == round.player_ids[1]).unwrap();
// println!("{:?} vs {:?}", a.name, b.name); // println!("{:?} vs {:?}", a.name, b.name);
let mut game = Game::new(); let mut game = Game::new();
game game
.set_team_num(2) .set_team_num(2)
.set_team_size(3); .set_team_size(3);
// add the players // add the players
let mut a_team = Team::new(a.account); let mut a_team = Team::new(a.account);
a_team.set_cryps(a.cryps); a_team.set_cryps(a.cryps);
a_team.set_bot(); a_team.set_bot();
let mut b_team = Team::new(b.account); let mut b_team = Team::new(b.account);
b_team.set_cryps(b.cryps); b_team.set_cryps(b.cryps);
b_team.set_bot(); b_team.set_bot();
game game
.team_add(a_team).unwrap() .team_add(a_team).unwrap()
.team_add(b_team).unwrap(); .team_add(b_team).unwrap();
game = game.start(); game = game.start();
assert!(game.finished()); assert!(game.finished());
let winner = game.winner().unwrap(); let winner = game.winner().unwrap();
round.finished = true; round.finished = true;
for team in game.teams.iter() {
let mut player = self.players.iter_mut().find(|p| p.account == team.id).unwrap();
match team.id == winner.id {
true => player.add_win(),
false => player.add_loss(),
};
}
for team in game.teams.iter() {
let mut player = self.players.iter_mut().find(|p| p.account == team.id).unwrap();
match team.id == winner.id {
true => player.add_win(),
false => player.add_loss(),
};
} }
}
}
} }
self self
@ -400,15 +433,20 @@ pub fn instance_get_open(tx: &mut Transaction) -> Result<Instance, Error> {
return Ok(instance); return Ok(instance);
} }
pub fn instance_lobby(params: InstanceLobbyParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut instance = Instance::new()
.set_max_players(params.players)?
.set_name(params.name)?;
instance = instance_create(tx, instance)?;
let join_params = InstanceJoinParams { instance_id: instance.id, cryp_ids: params.cryp_ids };
instance_join(join_params, tx, account)
}
pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> { pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut instance = match params.pve { let mut instance = instance_get(tx, params.instance_id)?;
true => instance_create(tx, Instance::new().add_bots())?,
false => match instance_get_open(tx) {
Ok(i) => i,
Err(_) => instance_create(tx, Instance::new())?,
},
};
let cryps = params.cryp_ids let cryps = params.cryp_ids
.iter() .iter()
@ -419,16 +457,10 @@ pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account:
return Err(format_err!("incorrect team size. ({:})", 3)); return Err(format_err!("incorrect team size. ({:})", 3));
} }
let mut player = Player::new(account.id, instance.id, &account.name, cryps); let player = Player::new(account.id, instance.id, &account.name, cryps);
player.vbox.fill();
let player = player_create(tx, player, account)?; let player = player_create(tx, player, account)?;
instance.add_player(player.clone()); instance.add_player(player.clone());
if instance.can_start() {
instance.start();
}
instance_update(tx, instance)?; instance_update(tx, instance)?;
return Ok(player); return Ok(player);
@ -478,7 +510,7 @@ pub fn instance_ready(params: InstanceReadyParams, tx: &mut Transaction, account
let game_id = instance.current_round(&player).game_id; let game_id = instance.current_round(&player).game_id;
let game = match instance.pve { let game = match instance.player_has_pve_game(&player) {
true => match game_get(tx, game_id) { true => match game_get(tx, game_id) {
Ok(g) => g, Ok(g) => g,
Err(_) => { Err(_) => {
@ -573,12 +605,15 @@ mod tests {
#[test] #[test]
fn instance_pve_test() { fn instance_pve_test() {
let mut instance = Instance::new().add_bots(); let mut instance = Instance::new()
.set_max_players(16).expect("unable to set max players")
.add_bots();
let player_account = Uuid::new_v4(); let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account); let cryps = instance_mobs(player_account);
let mut player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true); let mut player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true);
player.autobuy(); player.autobuy();
player.set_ready(true);
instance.add_player(player.clone()); instance.add_player(player.clone());
assert!(instance.can_start()); assert!(instance.can_start());
@ -602,10 +637,10 @@ mod tests {
#[test] #[test]
fn instance_bot_vbox_test() { fn instance_bot_vbox_test() {
let mut instance = Instance::new(); let instance = Instance::new();
let player_account = Uuid::new_v4(); let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account); let cryps = instance_mobs(player_account);
let mut player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true); let _player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true);
} }
} }

View File

@ -22,7 +22,7 @@ use skill::{Skill};
// use zone::{Zone, zone_create, zone_join, zone_close}; // use zone::{Zone, zone_create, zone_join, zone_close};
use spec::{Spec}; use spec::{Spec};
use player::{Score, player_state, player_mm_cryps_set, Player}; use player::{Score, player_state, player_mm_cryps_set, Player};
use instance::{instance_join, instance_ready, instance_scores}; use instance::{instance_lobby, instance_join, instance_ready, instance_scores};
use vbox::{Var, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip}; use vbox::{Var, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip};
pub struct Rpc; pub struct Rpc;
@ -78,7 +78,8 @@ impl Rpc {
// "zone_close" => Rpc::zone_close(data, &mut tx, account.unwrap(), client), // "zone_close" => Rpc::zone_close(data, &mut tx, account.unwrap(), client),
"instance_join" => Rpc::instance_join(data, &mut tx, account.unwrap(), client), "instance_join" => Rpc::instance_join(data, &mut tx, account.unwrap(), client),
"instance_ready" => Rpc::instance_ready(data, &mut tx, account.unwrap(), client), // "instance_ready" => Rpc::instance_ready(data, &mut tx, account.unwrap(), client),
"instance_lobby" => Rpc::instance_lobby(data, &mut tx, account.unwrap(), client),
"instance_scores" => Rpc::instance_scores(data, &mut tx, account.unwrap(), client), "instance_scores" => Rpc::instance_scores(data, &mut tx, account.unwrap(), client),
"player_state" => Rpc::player_state(data, &mut tx, account.unwrap(), client), "player_state" => Rpc::player_state(data, &mut tx, account.unwrap(), client),
@ -261,6 +262,18 @@ impl Rpc {
// return Ok(response); // return Ok(response);
// } // }
fn instance_lobby(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceLobbyMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "player_state".to_string(),
params: RpcResult::PlayerState(instance_lobby(msg.params, tx, &account)?)
};
return Ok(response);
}
fn instance_join(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> { fn instance_join(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceJoinMsg>(&data).or(Err(err_msg("invalid params")))?; let msg = from_slice::<InstanceJoinMsg>(&data).or(Err(err_msg("invalid params")))?;
@ -272,16 +285,16 @@ impl Rpc {
return Ok(response); return Ok(response);
} }
fn instance_ready(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> { // fn instance_ready(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?; // let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse { // let response = RpcResponse {
method: "game_state".to_string(), // method: "game_state".to_string(),
params: RpcResult::GameState(instance_ready(msg.params, tx, &account)?) // params: RpcResult::GameState(instance_ready(msg.params, tx, &account)?)
}; // };
return Ok(response); // return Ok(response);
} // }
fn instance_scores(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> { fn instance_scores(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?; let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?;
@ -541,33 +554,17 @@ struct AccountCrypsMsg {
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
struct ZoneCreateMsg { struct InstanceLobbyMsg {
method: String, method: String,
params: (), params: InstanceLobbyParams,
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
struct ZoneJoinMsg { pub struct InstanceLobbyParams {
method: String,
params: ZoneJoinParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct ZoneJoinParams {
pub zone_id: Uuid,
pub node_id: u32,
pub cryp_ids: Vec<Uuid>, pub cryp_ids: Vec<Uuid>,
} pub name: String,
pub players: usize,
#[derive(Debug,Clone,Serialize,Deserialize)] pub password: Option<String>,
struct ZoneCloseMsg {
method: String,
params: ZoneCloseParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct ZoneCloseParams {
pub zone_id: Uuid,
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
@ -578,8 +575,8 @@ struct InstanceJoinMsg {
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
pub struct InstanceJoinParams { pub struct InstanceJoinParams {
pub instance_id: Uuid,
pub cryp_ids: Vec<Uuid>, pub cryp_ids: Vec<Uuid>,
pub pve: bool,
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]