warden working
This commit is contained in:
parent
d3c301a3ac
commit
5d7095a06d
@ -153,15 +153,39 @@ function Info(args) {
|
||||
);
|
||||
}
|
||||
|
||||
function playerRound(id) {
|
||||
if (!instance.rounds.length) return null;
|
||||
return instance.rounds[instance.rounds.length - 1].find(r => r.player_ids.includes(id));
|
||||
}
|
||||
|
||||
function playerText(player) {
|
||||
const round = playerRound(player.id);
|
||||
if (!round) {
|
||||
return player.ready
|
||||
? 'ready'
|
||||
: '';
|
||||
}
|
||||
|
||||
if (round.finished) return 'finished';
|
||||
|
||||
return player.ready
|
||||
? 'ready'
|
||||
: '';
|
||||
}
|
||||
|
||||
function scoreBoard() {
|
||||
const players = instance.players.map((p, i) =>
|
||||
const players = instance.players.map((p, i) => {
|
||||
const pText = playerText(p);
|
||||
console.log(pText);
|
||||
return (
|
||||
<tr key={i}
|
||||
className={p.ready ? 'ready' : ''}>
|
||||
<td>{p.name}</td>
|
||||
<td>{p.score.wins} / {p.score.losses}</td>
|
||||
<td>{p.ready ? 'ready' : ''}</td>
|
||||
<td>{pText}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<table>
|
||||
|
||||
@ -26,16 +26,6 @@ pub enum Phase {
|
||||
Finish,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Copy,Serialize,Deserialize)]
|
||||
pub enum GameMode {
|
||||
Normal,
|
||||
Pvp,
|
||||
Zone3v2Attack,
|
||||
Zone2v2Caster,
|
||||
Zone3v3MeleeMiniboss,
|
||||
Zone3v3HealerBoss,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||
pub struct Game {
|
||||
pub id: Uuid,
|
||||
@ -47,7 +37,6 @@ pub struct Game {
|
||||
pub resolved: Vec<Resolution>,
|
||||
pub log: Vec<String>,
|
||||
pub instance: Option<Uuid>,
|
||||
pub mode: GameMode,
|
||||
phase_start: DateTime<Utc>,
|
||||
}
|
||||
|
||||
@ -63,7 +52,6 @@ impl Game {
|
||||
resolved: vec![],
|
||||
log: vec![],
|
||||
instance: None,
|
||||
mode: GameMode::Normal,
|
||||
phase_start: Utc::now(),
|
||||
};
|
||||
}
|
||||
@ -83,16 +71,11 @@ impl Game {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_mode(&mut self, mode: GameMode) -> &mut Game {
|
||||
self.mode = mode;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn joinable(&self) -> bool {
|
||||
self.can_start()
|
||||
}
|
||||
|
||||
pub fn player_add(&mut self, player: Player) -> Result<&mut Game, Error> {
|
||||
pub fn player_add(&mut self, mut player: Player) -> Result<&mut Game, Error> {
|
||||
if self.players.len() == self.player_num {
|
||||
return Err(err_msg("maximum number of players"));
|
||||
}
|
||||
@ -102,11 +85,12 @@ impl Game {
|
||||
}
|
||||
|
||||
if player.cryps.iter().all(|c| c.skills.len() == 0) {
|
||||
return Err(err_msg("your cryps have no skills"));
|
||||
println!("WARNING: {:?} has no skills and has forfeited {:?}", player.name, self.id);
|
||||
player.forfeit();
|
||||
}
|
||||
|
||||
let player_description = player.cryps.iter().map(|c| c.name.clone()).collect::<Vec<String>>().join(", ");
|
||||
self.log.push(format!("{:} has joined the game.", player_description));
|
||||
self.log.push(format!("{:} has joined the game. [{:?}]", player.name, player_description));
|
||||
|
||||
self.players.push(player);
|
||||
|
||||
@ -162,13 +146,19 @@ impl Game {
|
||||
self
|
||||
}
|
||||
|
||||
fn can_start(&self) -> bool {
|
||||
pub fn can_start(&self) -> bool {
|
||||
return self.players.len() == self.player_num
|
||||
&& self.players.iter().all(|t| t.cryps.len() == self.player_cryps)
|
||||
}
|
||||
|
||||
pub fn start(mut self) -> Game {
|
||||
self.log.push("Game starting...".to_string());
|
||||
|
||||
// forfeit
|
||||
if self.finished() {
|
||||
return self.finish();
|
||||
}
|
||||
|
||||
self.skill_phase_start()
|
||||
}
|
||||
|
||||
@ -190,6 +180,7 @@ impl Game {
|
||||
self.phase = Phase::Skill;
|
||||
|
||||
self.pve_add_skills();
|
||||
|
||||
if self.skill_phase_finished() {
|
||||
return self.resolve_phase_start()
|
||||
}
|
||||
@ -317,6 +308,10 @@ impl Game {
|
||||
}
|
||||
|
||||
fn player_ready(&mut self, player_id: Uuid) -> Result<&mut Game, Error> {
|
||||
if self.phase != Phase::Skill {
|
||||
return Err(err_msg("game not in skill phase"));
|
||||
}
|
||||
|
||||
self.player_by_id(player_id)?
|
||||
.set_ready(true);
|
||||
|
||||
@ -571,10 +566,12 @@ impl Game {
|
||||
}
|
||||
|
||||
pub fn upkeep(mut self) -> Game {
|
||||
if self.phase != Phase::Skill {
|
||||
panic!("{:?} game not in skill phase during upkeep", self);
|
||||
if self.phase == Phase::Finish {
|
||||
return self;
|
||||
}
|
||||
|
||||
println!("upkeep beginning: {:?} vs {:?}", self.players[0].name, self.players[1].name);
|
||||
|
||||
if !self.phase_timed_out() {
|
||||
return self;
|
||||
}
|
||||
@ -583,8 +580,10 @@ impl Game {
|
||||
if !player.ready {
|
||||
player.set_ready(true);
|
||||
player.add_warning();
|
||||
println!("upkeep: {:?} warned", player.name);
|
||||
if player.warnings >= 3 {
|
||||
player.forfeit();
|
||||
println!("upkeep: {:?} forfeited", player.name);
|
||||
self.log.push(format!("{:?} forfeited.", player.name));
|
||||
}
|
||||
}
|
||||
@ -891,8 +890,7 @@ pub fn game_instance_new(tx: &mut Transaction, players: Vec<Player>, game_id: Uu
|
||||
game
|
||||
.set_player_num(2)
|
||||
.set_player_cryps(3)
|
||||
.set_instance(instance_id)
|
||||
.set_mode(GameMode::Pvp);
|
||||
.set_instance(instance_id);
|
||||
|
||||
// create the initiators player
|
||||
for player in players {
|
||||
|
||||
@ -9,12 +9,16 @@ use failure::err_msg;
|
||||
|
||||
use std::iter;
|
||||
|
||||
// timekeeping
|
||||
use chrono::prelude::*;
|
||||
use chrono::Duration;
|
||||
|
||||
use rpc::{InstanceLobbyParams, InstanceJoinParams, InstanceReadyParams, InstanceStateParams};
|
||||
use account::Account;
|
||||
use player::{Player, player_create, player_get, player_global_update};
|
||||
use cryp::{Cryp, cryp_get};
|
||||
use mob::{instance_mobs};
|
||||
use game::{Game, Phase, game_get, game_write, game_instance_new, game_instance_join};
|
||||
use game::{Game, Phase, game_get, game_write, game_instance_new};
|
||||
use vbox::{Var};
|
||||
use rpc::{RpcResult};
|
||||
use names::{name};
|
||||
@ -29,7 +33,7 @@ enum InstancePhase {
|
||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||
struct Round {
|
||||
player_ids: Vec<Uuid>,
|
||||
game_id: Uuid,
|
||||
game_id: Option<Uuid>,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
@ -41,8 +45,10 @@ pub struct Instance {
|
||||
rounds: Vec<Vec<Round>>,
|
||||
open: bool,
|
||||
max_players: usize,
|
||||
max_rounds: usize,
|
||||
password: Option<String>,
|
||||
pub name: String,
|
||||
phase_start: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
@ -54,8 +60,10 @@ impl Instance {
|
||||
phase: InstancePhase::Lobby,
|
||||
open: true,
|
||||
max_players: 2,
|
||||
max_rounds: 16,
|
||||
name: String::new(),
|
||||
password: None,
|
||||
phase_start: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,13 +75,42 @@ impl Instance {
|
||||
phase: InstancePhase::InProgress,
|
||||
open: false,
|
||||
max_players: 0,
|
||||
max_rounds: 1,
|
||||
name: "Global Matchmaking".to_string(),
|
||||
password: None,
|
||||
phase_start: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upkeep(mut self) -> Instance {
|
||||
self
|
||||
fn phase_timed_out(&self) -> bool {
|
||||
Utc::now().signed_duration_since(self.phase_start).num_seconds() > 60
|
||||
}
|
||||
|
||||
fn timed_out_players(&self) -> Vec<Uuid> {
|
||||
self.players
|
||||
.iter()
|
||||
.filter(|p| !p.ready)
|
||||
.filter(|p| self.current_game_id(p.id).is_none())
|
||||
.map(|p| p.id)
|
||||
.collect::<Vec<Uuid>>()
|
||||
}
|
||||
|
||||
pub fn upkeep(mut self) -> (Instance, Vec<Game>) {
|
||||
if self.phase != InstancePhase::InProgress {
|
||||
return (self, vec![]);
|
||||
}
|
||||
|
||||
if !self.phase_timed_out() {
|
||||
return (self, vec![]);
|
||||
}
|
||||
|
||||
let new_games = self
|
||||
.timed_out_players()
|
||||
.iter()
|
||||
.filter_map(|p| self.player_ready(*p).unwrap())
|
||||
.collect::<Vec<Game>>();
|
||||
|
||||
(self, new_games)
|
||||
}
|
||||
|
||||
fn set_max_players(mut self, max: usize) -> Result<Instance, Error> {
|
||||
@ -94,6 +131,15 @@ impl Instance {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn set_max_rounds(mut self, rounds: usize) -> Result<Instance, Error> {
|
||||
if rounds == 0 {
|
||||
return Err(err_msg("max rounds must be nonzero"));
|
||||
}
|
||||
|
||||
self.max_rounds = rounds;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn add_bots(mut self) -> Instance {
|
||||
self.open = false;
|
||||
self.players = iter::repeat_with(|| {
|
||||
@ -118,79 +164,98 @@ impl Instance {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn player_update(mut self, player: Player, ignore_phase: bool) -> Result<Instance, Error> {
|
||||
if !ignore_phase && self.phase != InstancePhase::InProgress {
|
||||
return Err(format_err!("instance not in vbox phase ({:?})", self.phase));
|
||||
}
|
||||
|
||||
let i = self.players
|
||||
.iter()
|
||||
.position(|p| p.id == player.id)
|
||||
.ok_or(err_msg("player_id not found"))?;
|
||||
|
||||
self.players[i] = player;
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn player_ready(&mut self, player_id: Uuid) -> Result<&mut Instance, Error> {
|
||||
fn player_ready(&mut self, player_id: Uuid) -> Result<Option<Game>, Error> {
|
||||
if ![InstancePhase::InProgress, InstancePhase::Lobby].contains(&self.phase) {
|
||||
return Err(err_msg("instance not in start or vbox phase"));
|
||||
}
|
||||
|
||||
// LOBBY CHECKS
|
||||
if self.phase == InstancePhase::Lobby {
|
||||
let i = self.players
|
||||
.iter_mut()
|
||||
.position(|p| p.id == player_id)
|
||||
.ok_or(err_msg("player_id not found"))?;
|
||||
|
||||
if self.phase != InstancePhase::Lobby && self.players[i].cryps.iter().all(|c| c.skills.len() == 0) {
|
||||
return Err(err_msg("your cryps have no skills"));
|
||||
let v = !self.players[i].ready;
|
||||
self.players[i].set_ready(v);
|
||||
|
||||
match self.can_start() {
|
||||
true => {
|
||||
self.start();
|
||||
return Ok(None);
|
||||
}
|
||||
false => return Ok(None),
|
||||
};
|
||||
}
|
||||
|
||||
// GAME PHASE READY
|
||||
let i = self.players
|
||||
.iter_mut()
|
||||
.position(|p| p.id == player_id)
|
||||
.ok_or(err_msg("player_id not found"))?;
|
||||
|
||||
let v = !self.players[i].ready;
|
||||
self.players[i].set_ready(v);
|
||||
|
||||
if self.phase == InstancePhase::Lobby && self.can_start() {
|
||||
self.start();
|
||||
// start the game even if afk noobs have no skills
|
||||
if !self.phase_timed_out() && self.players[i].cryps.iter().all(|c| c.skills.len() == 0) {
|
||||
return Err(err_msg("your cryps have no skills"));
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
// create a game object if both players are ready
|
||||
// this should only happen once
|
||||
|
||||
let all_ready = self.round_ready_check(player_id);
|
||||
|
||||
if !all_ready {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
fn player_has_pve_game(&self, player_id: Uuid) -> bool {
|
||||
let opponent_id = self.current_round(player_id).player_ids
|
||||
.iter()
|
||||
.find(|p| **p != player_id)
|
||||
.expect("unable to find opponent");
|
||||
let game = self.create_round_game(player_id);
|
||||
|
||||
return self.players
|
||||
.iter()
|
||||
.find(|p| p.id == *opponent_id)
|
||||
.expect("unable to find opponent")
|
||||
.bot;
|
||||
{
|
||||
let round_num = self.rounds.len() - 1;
|
||||
let current_round = self.rounds[round_num]
|
||||
.iter_mut()
|
||||
.find(|g| g.player_ids.contains(&player_id))
|
||||
.unwrap();
|
||||
|
||||
current_round.game_id = Some(game.id);
|
||||
}
|
||||
|
||||
fn bot_vs_player_game(&self, player_id: Uuid) -> Result<Game, Error> {
|
||||
return Ok(Some(game));
|
||||
|
||||
}
|
||||
|
||||
fn round_ready_check(&mut self, player_id: Uuid) -> bool {
|
||||
let current_round = self.current_round(player_id);
|
||||
let bot_id = current_round.player_ids.iter().find(|id| **id != player_id).unwrap();
|
||||
|
||||
let plr = self.players.clone().into_iter().find(|p| p.id == player_id).unwrap();
|
||||
let bot = self.players.clone().into_iter().find(|p| p.id == *bot_id).unwrap();
|
||||
self.players
|
||||
.iter()
|
||||
.filter(|p| current_round.player_ids.contains(&p.id))
|
||||
.all(|p| p.ready)
|
||||
}
|
||||
|
||||
// maybe just embed the games in the instance
|
||||
// but seems hella inefficient
|
||||
fn create_round_game(&self, player_id: Uuid) -> Game {
|
||||
let current_round = self.current_round(player_id);
|
||||
let mut game = Game::new();
|
||||
game.id = current_round.game_id;
|
||||
|
||||
game
|
||||
.set_player_num(2)
|
||||
.set_player_cryps(3)
|
||||
.set_instance(self.id);
|
||||
|
||||
game
|
||||
.player_add(plr)?
|
||||
.player_add(bot)?;
|
||||
// create the initiators player
|
||||
for player in self.players
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|p| current_round.player_ids.contains(&p.id)) {
|
||||
game.player_add(player).unwrap();
|
||||
}
|
||||
|
||||
game = game.start();
|
||||
|
||||
Ok(game)
|
||||
assert!(game.can_start());
|
||||
return game.start();
|
||||
}
|
||||
|
||||
fn can_start(&self) -> bool {
|
||||
@ -205,119 +270,46 @@ impl Instance {
|
||||
|
||||
fn next_round(&mut self) -> &mut Instance {
|
||||
self.phase = InstancePhase::InProgress;
|
||||
self.phase_start = Utc::now();
|
||||
|
||||
if self.rounds.len() >= self.max_rounds {
|
||||
return self.finish();
|
||||
}
|
||||
|
||||
self.players.iter_mut().for_each(|p| {
|
||||
p.ready = false;
|
||||
p.set_ready(false);
|
||||
p.vbox.fill();
|
||||
});
|
||||
|
||||
self.generate_rounds();
|
||||
self.bot_vbox_phase();
|
||||
self.bot_games_phase();
|
||||
self.bot_round_actions();
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn all_ready(&self) -> bool {
|
||||
self.players.iter().all(|p| p.ready)
|
||||
fn finish(&mut self) -> &mut Instance {
|
||||
self.phase = InstancePhase::Finished;
|
||||
self
|
||||
}
|
||||
|
||||
fn game_finished(&mut self, game: &Game) -> Result<&mut Instance, Error> {
|
||||
let round_num = self.rounds.len() - 1;
|
||||
self.rounds[round_num]
|
||||
.iter_mut()
|
||||
.find(|r| r.game_id == game.id)
|
||||
.ok_or(err_msg("could not find matchup in current round"))?
|
||||
.finished = true;
|
||||
|
||||
// if you don't win, you lose
|
||||
// ties can happen if both players forfeit
|
||||
let winner_id = match game.winner() {
|
||||
Some(w) => w.id,
|
||||
None => Uuid::nil(),
|
||||
};
|
||||
|
||||
for player in game.players.iter() {
|
||||
let mut player = self.account_player(player.id)?;
|
||||
match player.id == winner_id {
|
||||
true => player.add_win(),
|
||||
false => player.add_loss(),
|
||||
};
|
||||
}
|
||||
|
||||
if self.all_games_finished() {
|
||||
self.next_round();
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn all_games_finished(&self) -> bool {
|
||||
match self.rounds.last() {
|
||||
Some(r) => r.iter().all(|g| g.finished),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn bot_vbox_phase(&mut self) -> &mut Instance {
|
||||
fn bot_round_actions(&mut self) -> &mut Instance {
|
||||
for bot in self.players.iter_mut().filter(|p| p.bot) {
|
||||
bot.vbox.fill();
|
||||
bot.autobuy();
|
||||
bot.set_ready(true);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn bot_games_phase(&mut self) -> &mut Instance {
|
||||
if self.phase != InstancePhase::InProgress {
|
||||
panic!("instance not in progress phase");
|
||||
}
|
||||
|
||||
let r = self.rounds.len() - 1;
|
||||
// println!("round num {:?}", r);
|
||||
// println!("{:?}", self.rounds[r]);
|
||||
for mut round in self.rounds[r].iter_mut() {
|
||||
if self.players
|
||||
let games = self.players
|
||||
.clone()
|
||||
.iter()
|
||||
.filter(|p| round.player_ids.contains(&p.id) && p.bot && p.ready)
|
||||
.count() == 2 {
|
||||
// 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 b = self.players.clone().into_iter().find(|p| p.id == round.player_ids[1]).unwrap();
|
||||
|
||||
// println!("{:?} vs {:?}", a.name, b.name);
|
||||
|
||||
let mut game = Game::new();
|
||||
game
|
||||
.set_player_num(2)
|
||||
.set_player_cryps(3);
|
||||
|
||||
game
|
||||
.player_add(a).unwrap()
|
||||
.player_add(b).unwrap();
|
||||
|
||||
game = game.start();
|
||||
|
||||
if !game.finished() {
|
||||
panic!("game not finished {:?}", game)
|
||||
}
|
||||
|
||||
let winner = match game.winner() {
|
||||
Some(w) => w,
|
||||
None => panic!("game has no winner {:?}", game),
|
||||
};
|
||||
|
||||
round.finished = true;
|
||||
|
||||
for player in game.players.iter() {
|
||||
let mut player = self.players.iter_mut().find(|p| p.id == player.id).unwrap();
|
||||
match player.id == winner.id {
|
||||
true => player.add_win(),
|
||||
false => player.add_loss(),
|
||||
};
|
||||
}
|
||||
.filter(|b| b.bot)
|
||||
.filter_map(|b| self.player_ready(b.id).unwrap())
|
||||
.collect::<Vec<Game>>();
|
||||
|
||||
for game in games {
|
||||
if game.finished() {
|
||||
self.game_finished(&game).unwrap();
|
||||
} else {
|
||||
println!("{:?} unfishededes", game);
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,7 +337,7 @@ impl Instance {
|
||||
.enumerate()
|
||||
.map(|(i, id)| Round {
|
||||
player_ids: vec![*id, matched_players[np - (i + 1)]],
|
||||
game_id: Uuid::new_v4(),
|
||||
game_id: None,
|
||||
finished: false,
|
||||
})
|
||||
.collect::<Vec<Round>>();
|
||||
@ -366,24 +358,59 @@ impl Instance {
|
||||
current_round
|
||||
}
|
||||
|
||||
fn current_game(&self, player_id: Uuid) -> Option<Uuid> {
|
||||
fn current_game_id(&self, player_id: Uuid) -> Option<Uuid> {
|
||||
if self.phase == InstancePhase::Lobby {
|
||||
return None;
|
||||
}
|
||||
|
||||
let current_round = self.current_round(player_id);
|
||||
|
||||
let can_start = self.players
|
||||
.iter()
|
||||
.filter(|p| current_round.player_ids.contains(&p.id))
|
||||
.all(|p| p.ready);
|
||||
if current_round.finished || current_round.game_id.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match can_start {
|
||||
true => match current_round.finished {
|
||||
true => None,
|
||||
false => Some(current_round.game_id),
|
||||
},
|
||||
false => None,
|
||||
return current_round.game_id;
|
||||
}
|
||||
|
||||
fn game_finished(&mut self, game: &Game) -> Result<&mut Instance, Error> {
|
||||
let round_num = self.rounds.len() - 1;
|
||||
self.rounds[round_num]
|
||||
.iter_mut()
|
||||
.filter(|r| r.game_id.is_some())
|
||||
.find(|r| r.game_id.unwrap() == game.id)
|
||||
.ok_or(err_msg("could not find matchup in current round"))?
|
||||
.finished = true;
|
||||
|
||||
// if you don't win, you lose
|
||||
// ties can happen if both players forfeit
|
||||
let winner_id = match game.winner() {
|
||||
Some(w) => w.id,
|
||||
None => Uuid::nil(),
|
||||
};
|
||||
|
||||
for player in game.players.iter() {
|
||||
let mut player = self.account_player(player.id)?;
|
||||
match player.id == winner_id {
|
||||
true => player.add_win(),
|
||||
false => player.add_loss(),
|
||||
};
|
||||
}
|
||||
|
||||
if self.all_games_finished() {
|
||||
self.next_round();
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn all_ready(&self) -> bool {
|
||||
self.players.iter().all(|p| p.ready)
|
||||
}
|
||||
|
||||
fn all_games_finished(&self) -> bool {
|
||||
match self.rounds.last() {
|
||||
Some(r) => r.iter().all(|g| g.finished),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,7 +426,7 @@ impl Instance {
|
||||
if self.phase == InstancePhase::Lobby {
|
||||
return Err(err_msg("game not yet started"));
|
||||
}
|
||||
if self.current_game(account).is_some() {
|
||||
if self.current_game_id(account).is_some() {
|
||||
return Err(err_msg("you cannot perform vbox actions while in a game"));
|
||||
}
|
||||
|
||||
@ -552,8 +579,7 @@ pub fn instances_need_upkeep(tx: &mut Transaction) -> Result<Vec<Instance>, Erro
|
||||
let query = "
|
||||
SELECT data, id
|
||||
FROM instances
|
||||
WHERE updated_at < now() - interval '5 seconds'
|
||||
AND id != '00000000-0000-0000-0000-000000000000';
|
||||
WHERE id != '00000000-0000-0000-0000-000000000000';
|
||||
";
|
||||
|
||||
let result = tx
|
||||
@ -636,32 +662,9 @@ pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account:
|
||||
pub fn instance_ready(params: InstanceReadyParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
|
||||
let mut instance = instance_get(tx, params.instance_id)?;
|
||||
let player_id = instance.account_player(account.id)?.id;
|
||||
instance.player_ready(player_id)?;
|
||||
|
||||
if let Some(game_id) = instance.current_game(player_id) {
|
||||
match instance.player_has_pve_game(player_id) {
|
||||
true => match game_get(tx, game_id) {
|
||||
Ok(g) => g,
|
||||
Err(_) => {
|
||||
let game = instance.bot_vs_player_game(player_id)?;
|
||||
if let Some(game) = instance.player_ready(player_id)? {
|
||||
game_write(tx, &game)?;
|
||||
game
|
||||
},
|
||||
},
|
||||
false => {
|
||||
let opponent_id = *instance
|
||||
.current_round(account.id)
|
||||
.player_ids
|
||||
.iter()
|
||||
.find(|p| **p != account.id)
|
||||
.expect("could not find opponent");
|
||||
|
||||
let a = instance.account_player(account.id)?.clone();
|
||||
let b = instance.account_player(opponent_id)?.clone();
|
||||
let players = vec![a, b];
|
||||
game_instance_new(tx, players, game_id, instance.id)?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
instance_update(tx, instance)
|
||||
@ -670,11 +673,11 @@ pub fn instance_ready(params: InstanceReadyParams, tx: &mut Transaction, account
|
||||
pub fn instance_state(params: InstanceStateParams, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
|
||||
let instance = instance_get(tx, params.instance_id)?;
|
||||
|
||||
if let Some(game_id) = instance.current_game(account.id) {
|
||||
if let Some(game_id) = instance.current_game_id(account.id) {
|
||||
let game = game_get(tx, game_id)?;
|
||||
|
||||
// return the game until it's finished
|
||||
if game.phase != Phase::Finish {
|
||||
|
||||
return Ok(RpcResult::GameState(game))
|
||||
}
|
||||
}
|
||||
@ -716,6 +719,7 @@ mod tests {
|
||||
fn instance_pve_test() {
|
||||
let mut instance = Instance::new()
|
||||
.set_max_players(16).expect("unable to set max players")
|
||||
.set_max_rounds(2).expect("max rounds failure")
|
||||
.add_bots();
|
||||
|
||||
let player_account = Uuid::new_v4();
|
||||
@ -728,21 +732,9 @@ mod tests {
|
||||
assert_eq!(instance.phase, InstancePhase::Lobby);
|
||||
instance.player_ready(player_id).unwrap();
|
||||
|
||||
assert_eq!(instance.phase, InstancePhase::InProgress);
|
||||
assert_eq!(instance.phase, InstancePhase::Finished);
|
||||
assert_eq!(instance.rounds[0].len(), 8);
|
||||
|
||||
instance.player_ready(player_id).unwrap();
|
||||
|
||||
assert!(instance.all_games_finished());
|
||||
instance.next_round();
|
||||
|
||||
instance.player_ready(player_id).unwrap();
|
||||
|
||||
instance.next_round();
|
||||
|
||||
instance.player_ready(player_id).unwrap();
|
||||
|
||||
assert_eq!(instance.rounds.len(), 3);
|
||||
assert_eq!(instance.rounds.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -784,5 +776,55 @@ mod tests {
|
||||
assert_eq!(instance.phase, InstancePhase::InProgress);
|
||||
|
||||
assert!(!instance.can_start());
|
||||
|
||||
instance.players[0].autobuy();
|
||||
instance.players[1].autobuy();
|
||||
|
||||
instance.player_ready(a_id).expect("a ready");
|
||||
let game = instance.player_ready(b_id).expect("b ready");
|
||||
|
||||
assert!(game.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instance_upkeep_test() {
|
||||
let mut instance = Instance::new()
|
||||
.set_max_players(2)
|
||||
.expect("could not create instance");
|
||||
|
||||
let player_account = Uuid::new_v4();
|
||||
let cryps = instance_mobs(player_account);
|
||||
let player = Player::new(player_account, &"a".to_string(), cryps);
|
||||
let a_id = player.id;
|
||||
|
||||
instance.add_player(player).expect("could not add player");
|
||||
assert!(!instance.can_start());
|
||||
|
||||
let player_account = Uuid::new_v4();
|
||||
let cryps = instance_mobs(player_account);
|
||||
let player = Player::new(player_account, &"b".to_string(), cryps);
|
||||
let b_id = player.id;
|
||||
instance.add_player(player).expect("could not add player");
|
||||
|
||||
instance.players[0].autobuy();
|
||||
|
||||
instance.player_ready(a_id).expect("a ready");
|
||||
instance.player_ready(b_id).expect("b ready");
|
||||
|
||||
instance.phase_start = Utc::now().checked_sub_signed(Duration::seconds(61)).unwrap();
|
||||
|
||||
let (mut instance, new_games) = instance.upkeep();
|
||||
|
||||
assert_eq!(new_games.len(), 1);
|
||||
|
||||
let game = &new_games[0];
|
||||
assert!(game.finished());
|
||||
|
||||
instance.game_finished(game).unwrap();
|
||||
|
||||
assert_eq!(instance.rounds.len(), 2);
|
||||
assert!(instance.players.iter().all(|p| !p.ready));
|
||||
|
||||
println!("{:#?}", instance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,14 +73,12 @@ impl Player {
|
||||
|
||||
pub fn add_win(&mut self) -> &mut Player {
|
||||
self.score.wins += 1;
|
||||
self.set_ready(false);
|
||||
self.vbox.balance_add(12);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_loss(&mut self) -> &mut Player {
|
||||
self.score.losses += 1;
|
||||
self.set_ready(false);
|
||||
self.vbox.balance_add(9);
|
||||
self
|
||||
}
|
||||
|
||||
@ -1,25 +1,24 @@
|
||||
use std::time::{Duration};
|
||||
use std::thread::sleep;
|
||||
|
||||
// Db Commons
|
||||
use postgres::transaction::Transaction;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use r2d2::{Pool};
|
||||
use r2d2_postgres::{PostgresConnectionManager};
|
||||
|
||||
use game::{Game, games_need_upkeep, game_update};
|
||||
use instance::{Instance, instances_need_upkeep, instance_update};
|
||||
use game::{games_need_upkeep, game_update, game_write, game_delete};
|
||||
use instance::{instances_need_upkeep, instance_update};
|
||||
use net::{Db};
|
||||
|
||||
fn fetch_games(mut tx: Transaction) -> Result<Transaction, Error> {
|
||||
let games = games_need_upkeep(&mut tx)?;
|
||||
|
||||
println!("warden: {:?} games active", games.len());
|
||||
|
||||
for mut game in games {
|
||||
game_update(&mut tx, &game.upkeep())?;
|
||||
let game = game.upkeep();
|
||||
match game_update(&mut tx, &game) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
game_delete(&mut tx, game.id)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(tx)
|
||||
@ -29,18 +28,26 @@ fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> {
|
||||
let instances = instances_need_upkeep(&mut tx)?;
|
||||
|
||||
for mut instance in instances {
|
||||
instance_update(&mut tx, instance.upkeep())?;
|
||||
let (instance, new_games) = instance.upkeep();
|
||||
println!("{:?} new games", new_games.len());
|
||||
for game in new_games {
|
||||
game_write(&mut tx, &game)?;
|
||||
}
|
||||
instance_update(&mut tx, instance)?;
|
||||
}
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
pub fn warden(db: Db) -> Result<(), Error> {
|
||||
println!("upkeep beginning");
|
||||
fetch_games(db.transaction()?)?
|
||||
.commit()?;
|
||||
|
||||
fetch_instances(db.transaction()?)?
|
||||
.commit()?;
|
||||
|
||||
println!("upkeep done");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user