no time control for practice

This commit is contained in:
ntr 2019-06-09 17:38:25 +10:00
parent 39501c167a
commit 1070d3482a
8 changed files with 117 additions and 40 deletions

View File

@ -31,6 +31,8 @@
mobile info page
mnml tv
rework scatter
hatred maybe

View File

@ -333,11 +333,11 @@
height: 2px;
transform-origin: center;
background-color: whitesmoke;
animation: equipping-skill 2s infinite ease alternate;
animation: equipping-skill 2s infinite ease-out alternate;
opacity: 0;
}
.equipping::after, .equip-spec::after {
.equipping::after {
content: '';
position: absolute;
bottom: 2px;
@ -346,7 +346,7 @@
height: 2px;
transform-origin: center;
background-color: whitesmoke;
animation: equipping-skill 2s infinite ease alternate;
animation: equipping-skill 2s infinite ease-out alternate;
opacity: 0;
animation-delay: 0.75s
}
@ -373,7 +373,16 @@
}
.equip-spec::after {
animation-delay: 0;
content: '';
position: absolute;
bottom: 2px;
left: 50%;
width: 100%;
height: 2px;
transform-origin: center;
background-color: whitesmoke;
animation: equipping-skill 2s infinite ease-out alternate;
opacity: 0;
}
.equip .specs figcaption {

View File

@ -108,7 +108,7 @@ function GameFooter(props) {
const now = Date.now();
const end = Date.parse(game.phase_end);
const timerPct = ((now - zero) / (end - zero) * 100);
const displayPct = resolution || game.phase === 'Finish'
const displayPct = resolution || game.phase === 'Finish' || !game.phase_end
? 0
: Math.min(timerPct, 100);
@ -123,11 +123,13 @@ function GameFooter(props) {
background: displayColour,
};
const timer = (
<div class="timer-container">
<div class="timer" style={timerStyles} >&nbsp;</div>
</div>
);
const timer = game.phase_end
? (
<div class="timer-container">
<div class="timer" style={timerStyles} >&nbsp;</div>
</div>
)
: null;
return (
<footer>

View File

@ -67,7 +67,7 @@ class InstanceCreateForm extends Component {
placeholder="game name"
onInput={this.nameInput}
/>
<label htmlFor="pveSelect">Practice Mode - Bo10, vs CPU, 2x turn time</label>
<label htmlFor="pveSelect">Practice Mode - Bo10, vs CPU, no time control</label>
<input id="pveSelect"
type="checkbox"
disabled={disabled}

View File

@ -94,7 +94,9 @@ function Instance(args) {
const zero = Date.parse(instance.phase_start);
const now = Date.now();
const end = Date.parse(instance.phase_end);
const timerPct = ((now - zero) / (end - zero) * 100);
const timerPct = instance.phase_end
? ((now - zero) / (end - zero) * 100)
: 0;
const displayColour = player.ready
? 'forestgreen'

View File

@ -38,8 +38,8 @@ pub struct Game {
pub resolved: Vec<Resolution>,
pub instance: Option<Uuid>,
time_control: TimeControl,
phase_end: DateTime<Utc>,
phase_start: DateTime<Utc>,
phase_end: Option<DateTime<Utc>>,
}
impl Game {
@ -54,13 +54,14 @@ impl Game {
resolved: vec![],
instance: None,
time_control: TimeControl::Standard,
phase_end: Utc::now(),
phase_end: None,
phase_start: Utc::now(),
};
}
pub fn set_time_control(&mut self, tc: TimeControl) -> &mut Game {
self.time_control = tc;
self.phase_end = Some(tc.lobby_timeout());
self
}
@ -159,13 +160,12 @@ impl Game {
fn skill_phase_start(mut self, num_resolutions: usize) -> Game {
let resolution_animation_ms = num_resolutions as i64 * 2500;
let phase_add_time_ms = self.time_control.game_time_seconds() * 1000 + resolution_animation_ms;
self.phase_start = Utc::now()
.checked_add_signed(Duration::milliseconds(resolution_animation_ms))
.expect("could not set phase start");
self.phase_end = Utc::now()
.checked_add_signed(Duration::milliseconds(phase_add_time_ms as i64))
.expect("could not set phase end");
self.phase_end = self.time_control.game_phase_end(resolution_animation_ms);
for player in self.players.iter_mut() {
if player.skills_required() == 0 {
@ -571,7 +571,10 @@ impl Game {
}
fn phase_timed_out(&self) -> bool {
Utc::now().signed_duration_since(self.phase_end).num_milliseconds() > 0
match self.phase_end {
Some(t) => Utc::now().signed_duration_since(t).num_milliseconds() > 0,
None => false,
}
}
pub fn upkeep(mut self) -> Game {
@ -1435,7 +1438,7 @@ mod tests {
fn upkeep_test() {
let mut game = create_2v2_test_game();
game.players[0].set_ready(true);
game.phase_end = Utc::now().checked_sub_signed(Duration::seconds(61)).unwrap();
game.phase_end = Some(Utc::now().checked_sub_signed(Duration::seconds(500)).unwrap());
game = game.upkeep();
assert!(game.players[1].warnings == 1);
}

View File

@ -45,6 +45,7 @@ impl Round {
#[derive(Debug,Clone,Copy,Serialize,Deserialize)]
pub enum TimeControl {
Standard,
Slow,
Practice,
}
@ -52,21 +53,47 @@ impl TimeControl {
fn vbox_time_seconds(&self) -> i64 {
match self {
TimeControl::Standard => 120,
TimeControl::Practice => 240,
TimeControl::Slow => 240,
TimeControl::Practice => panic!("practice vbox seconds called"),
}
}
pub fn game_time_seconds(&self) -> i64 {
fn game_time_seconds(&self) -> i64 {
match self {
TimeControl::Standard => 60,
TimeControl::Practice => 120,
TimeControl::Slow => 120,
TimeControl::Practice => panic!("practice game seconds called"),
}
}
pub fn vbox_phase_end(&self) -> Option<DateTime<Utc>> {
match self {
TimeControl::Practice => None,
_ => Some(Utc::now()
.checked_add_signed(Duration::seconds(self.vbox_time_seconds()))
.expect("could not set vbox phase end")),
}
}
pub fn lobby_timeout(&self) -> DateTime<Utc> {
Utc::now()
.checked_add_signed(Duration::minutes(5))
.expect("could not set phase end")
}
pub fn game_phase_end(&self, resolution_time_ms: i64) -> Option<DateTime<Utc>> {
match self {
TimeControl::Practice => None,
_ => Some(Utc::now()
.checked_add_signed(Duration::milliseconds(self.vbox_time_seconds() * 1000 + resolution_time_ms))
.expect("could not set game phase end")),
}
}
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Instance {
id: Uuid,
pub id: Uuid,
pub name: String,
players: Vec<Player>,
@ -79,7 +106,7 @@ pub struct Instance {
time_control: TimeControl,
phase: InstancePhase,
phase_end: DateTime<Utc>,
phase_end: Option<DateTime<Utc>>,
phase_start: DateTime<Utc>,
}
@ -97,9 +124,7 @@ impl Instance {
time_control: TimeControl::Standard,
password: None,
phase_start: Utc::now(),
phase_end: Utc::now()
.checked_add_signed(Duration::minutes(5))
.expect("could not set phase end"),
phase_end: Some(TimeControl::Standard.lobby_timeout()),
}
}
@ -116,12 +141,15 @@ impl Instance {
name: "Global Matchmaking".to_string(),
password: None,
phase_start: Utc::now(),
phase_end: Utc::now(),
phase_end: Some(TimeControl::Standard.lobby_timeout()),
}
}
fn phase_timed_out(&self) -> bool {
Utc::now().signed_duration_since(self.phase_end).num_milliseconds() > 0
match self.phase_end {
Some(t) => Utc::now().signed_duration_since(t).num_milliseconds() > 0,
None => false,
}
}
fn timed_out_players(&self) -> Vec<Uuid> {
@ -312,9 +340,7 @@ impl Instance {
self.phase = InstancePhase::InProgress;
self.phase_start = Utc::now();
self.phase_end = Utc::now()
.checked_add_signed(Duration::seconds(self.time_control.vbox_time_seconds()))
.expect("could not set phase end");
self.phase_end = self.time_control.vbox_phase_end();
self.players.iter_mut().for_each(|p| {
@ -336,7 +362,7 @@ impl Instance {
|| self.rounds.len() == self.max_rounds
}
fn finish(&mut self) -> &mut Instance {
pub fn finish(&mut self) -> &mut Instance {
self.phase = InstancePhase::Finished;
self
}
@ -637,6 +663,37 @@ pub fn instances_need_upkeep(tx: &mut Transaction) -> Result<Vec<Instance>, Erro
return Ok(list);
}
// timed out instances with no time control
pub fn instances_idle(tx: &mut Transaction) -> Result<Vec<Instance>, Error> {
let query = "
SELECT data, id
FROM instances
WHERE finished = false
AND updated_at < now() - interval '1 hour'
FOR UPDATE;
";
let result = tx
.query(query, &[])?;
let mut list = vec![];
for row in result.into_iter() {
let bytes: Vec<u8> = row.get(0);
let id = row.get(1);
match from_slice::<Instance>(&bytes) {
Ok(i) => list.push(i),
Err(_e) => {
instance_delete(tx, id)?;
}
};
}
return Ok(list);
}
pub fn instance_new(params: InstanceLobbyParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
let mut instance = match params.pve {
true => Instance::new()
@ -801,7 +858,7 @@ mod tests {
instance.player_ready(a_id).expect("a ready");
instance.player_ready(b_id).expect("b ready");
instance.phase_end = Utc::now().checked_sub_signed(Duration::seconds(61)).unwrap();
instance.phase_end = Some(Utc::now().checked_sub_signed(Duration::seconds(500)).unwrap());
let (mut instance, new_games) = instance.upkeep();
@ -830,7 +887,7 @@ mod tests {
instance.add_player(player).expect("could not add player");
assert!(!instance.can_start());
instance.phase_end = Utc::now().checked_sub_signed(Duration::minutes(61)).unwrap();
instance.phase_end = Some(Utc::now().checked_sub_signed(Duration::minutes(61)).unwrap());
let (instance, _new_games) = instance.upkeep();
assert!(instance.finished());

View File

@ -4,7 +4,7 @@ use postgres::transaction::Transaction;
use failure::Error;
use game::{games_need_upkeep, game_update, game_write, game_delete};
use instance::{instances_need_upkeep, instance_update};
use instance::{instances_need_upkeep, instances_idle, instance_update, instance_delete};
use net::{Db};
fn fetch_games(mut tx: Transaction) -> Result<Transaction, Error> {
@ -25,9 +25,7 @@ fn fetch_games(mut tx: Transaction) -> Result<Transaction, Error> {
}
fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> {
let instances = instances_need_upkeep(&mut tx)?;
for mut instance in instances {
for mut instance in instances_need_upkeep(&mut tx)? {
let (instance, new_games) = instance.upkeep();
for game in new_games {
game_write(&mut tx, &game)?;
@ -35,6 +33,10 @@ fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> {
instance_update(&mut tx, instance)?;
}
for mut instance in instances_idle(&mut tx)? {
instance_delete(&mut tx, instance.id)?;
}
Ok(tx)
}