no time control for practice
This commit is contained in:
parent
39501c167a
commit
1070d3482a
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
mobile info page
|
mobile info page
|
||||||
|
|
||||||
|
mnml tv
|
||||||
|
|
||||||
rework scatter
|
rework scatter
|
||||||
hatred maybe
|
hatred maybe
|
||||||
|
|
||||||
|
|||||||
@ -333,11 +333,11 @@
|
|||||||
height: 2px;
|
height: 2px;
|
||||||
transform-origin: center;
|
transform-origin: center;
|
||||||
background-color: whitesmoke;
|
background-color: whitesmoke;
|
||||||
animation: equipping-skill 2s infinite ease alternate;
|
animation: equipping-skill 2s infinite ease-out alternate;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.equipping::after, .equip-spec::after {
|
.equipping::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
@ -346,7 +346,7 @@
|
|||||||
height: 2px;
|
height: 2px;
|
||||||
transform-origin: center;
|
transform-origin: center;
|
||||||
background-color: whitesmoke;
|
background-color: whitesmoke;
|
||||||
animation: equipping-skill 2s infinite ease alternate;
|
animation: equipping-skill 2s infinite ease-out alternate;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
animation-delay: 0.75s
|
animation-delay: 0.75s
|
||||||
}
|
}
|
||||||
@ -373,7 +373,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.equip-spec::after {
|
.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 {
|
.equip .specs figcaption {
|
||||||
|
|||||||
@ -108,7 +108,7 @@ function GameFooter(props) {
|
|||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const end = Date.parse(game.phase_end);
|
const end = Date.parse(game.phase_end);
|
||||||
const timerPct = ((now - zero) / (end - zero) * 100);
|
const timerPct = ((now - zero) / (end - zero) * 100);
|
||||||
const displayPct = resolution || game.phase === 'Finish'
|
const displayPct = resolution || game.phase === 'Finish' || !game.phase_end
|
||||||
? 0
|
? 0
|
||||||
: Math.min(timerPct, 100);
|
: Math.min(timerPct, 100);
|
||||||
|
|
||||||
@ -123,11 +123,13 @@ function GameFooter(props) {
|
|||||||
background: displayColour,
|
background: displayColour,
|
||||||
};
|
};
|
||||||
|
|
||||||
const timer = (
|
const timer = game.phase_end
|
||||||
|
? (
|
||||||
<div class="timer-container">
|
<div class="timer-container">
|
||||||
<div class="timer" style={timerStyles} > </div>
|
<div class="timer" style={timerStyles} > </div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer>
|
<footer>
|
||||||
|
|||||||
@ -67,7 +67,7 @@ class InstanceCreateForm extends Component {
|
|||||||
placeholder="game name"
|
placeholder="game name"
|
||||||
onInput={this.nameInput}
|
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"
|
<input id="pveSelect"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|||||||
@ -94,7 +94,9 @@ function Instance(args) {
|
|||||||
const zero = Date.parse(instance.phase_start);
|
const zero = Date.parse(instance.phase_start);
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const end = Date.parse(instance.phase_end);
|
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
|
const displayColour = player.ready
|
||||||
? 'forestgreen'
|
? 'forestgreen'
|
||||||
|
|||||||
@ -38,8 +38,8 @@ pub struct Game {
|
|||||||
pub resolved: Vec<Resolution>,
|
pub resolved: Vec<Resolution>,
|
||||||
pub instance: Option<Uuid>,
|
pub instance: Option<Uuid>,
|
||||||
time_control: TimeControl,
|
time_control: TimeControl,
|
||||||
phase_end: DateTime<Utc>,
|
|
||||||
phase_start: DateTime<Utc>,
|
phase_start: DateTime<Utc>,
|
||||||
|
phase_end: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
@ -54,13 +54,14 @@ impl Game {
|
|||||||
resolved: vec![],
|
resolved: vec![],
|
||||||
instance: None,
|
instance: None,
|
||||||
time_control: TimeControl::Standard,
|
time_control: TimeControl::Standard,
|
||||||
phase_end: Utc::now(),
|
phase_end: None,
|
||||||
phase_start: Utc::now(),
|
phase_start: Utc::now(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_time_control(&mut self, tc: TimeControl) -> &mut Game {
|
pub fn set_time_control(&mut self, tc: TimeControl) -> &mut Game {
|
||||||
self.time_control = tc;
|
self.time_control = tc;
|
||||||
|
self.phase_end = Some(tc.lobby_timeout());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,13 +160,12 @@ impl Game {
|
|||||||
|
|
||||||
fn skill_phase_start(mut self, num_resolutions: usize) -> Game {
|
fn skill_phase_start(mut self, num_resolutions: usize) -> Game {
|
||||||
let resolution_animation_ms = num_resolutions as i64 * 2500;
|
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()
|
self.phase_start = Utc::now()
|
||||||
.checked_add_signed(Duration::milliseconds(resolution_animation_ms))
|
.checked_add_signed(Duration::milliseconds(resolution_animation_ms))
|
||||||
.expect("could not set phase start");
|
.expect("could not set phase start");
|
||||||
self.phase_end = Utc::now()
|
|
||||||
.checked_add_signed(Duration::milliseconds(phase_add_time_ms as i64))
|
self.phase_end = self.time_control.game_phase_end(resolution_animation_ms);
|
||||||
.expect("could not set phase end");
|
|
||||||
|
|
||||||
for player in self.players.iter_mut() {
|
for player in self.players.iter_mut() {
|
||||||
if player.skills_required() == 0 {
|
if player.skills_required() == 0 {
|
||||||
@ -571,7 +571,10 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn phase_timed_out(&self) -> bool {
|
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 {
|
pub fn upkeep(mut self) -> Game {
|
||||||
@ -1435,7 +1438,7 @@ mod tests {
|
|||||||
fn upkeep_test() {
|
fn upkeep_test() {
|
||||||
let mut game = create_2v2_test_game();
|
let mut game = create_2v2_test_game();
|
||||||
game.players[0].set_ready(true);
|
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();
|
game = game.upkeep();
|
||||||
assert!(game.players[1].warnings == 1);
|
assert!(game.players[1].warnings == 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,7 @@ impl Round {
|
|||||||
#[derive(Debug,Clone,Copy,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Copy,Serialize,Deserialize)]
|
||||||
pub enum TimeControl {
|
pub enum TimeControl {
|
||||||
Standard,
|
Standard,
|
||||||
|
Slow,
|
||||||
Practice,
|
Practice,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,21 +53,47 @@ impl TimeControl {
|
|||||||
fn vbox_time_seconds(&self) -> i64 {
|
fn vbox_time_seconds(&self) -> i64 {
|
||||||
match self {
|
match self {
|
||||||
TimeControl::Standard => 120,
|
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 {
|
match self {
|
||||||
TimeControl::Standard => 60,
|
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)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
id: Uuid,
|
pub id: Uuid,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
players: Vec<Player>,
|
players: Vec<Player>,
|
||||||
@ -79,7 +106,7 @@ pub struct Instance {
|
|||||||
time_control: TimeControl,
|
time_control: TimeControl,
|
||||||
|
|
||||||
phase: InstancePhase,
|
phase: InstancePhase,
|
||||||
phase_end: DateTime<Utc>,
|
phase_end: Option<DateTime<Utc>>,
|
||||||
phase_start: DateTime<Utc>,
|
phase_start: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,9 +124,7 @@ impl Instance {
|
|||||||
time_control: TimeControl::Standard,
|
time_control: TimeControl::Standard,
|
||||||
password: None,
|
password: None,
|
||||||
phase_start: Utc::now(),
|
phase_start: Utc::now(),
|
||||||
phase_end: Utc::now()
|
phase_end: Some(TimeControl::Standard.lobby_timeout()),
|
||||||
.checked_add_signed(Duration::minutes(5))
|
|
||||||
.expect("could not set phase end"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,12 +141,15 @@ impl Instance {
|
|||||||
name: "Global Matchmaking".to_string(),
|
name: "Global Matchmaking".to_string(),
|
||||||
password: None,
|
password: None,
|
||||||
phase_start: Utc::now(),
|
phase_start: Utc::now(),
|
||||||
phase_end: Utc::now(),
|
phase_end: Some(TimeControl::Standard.lobby_timeout()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn phase_timed_out(&self) -> bool {
|
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> {
|
fn timed_out_players(&self) -> Vec<Uuid> {
|
||||||
@ -312,9 +340,7 @@ impl Instance {
|
|||||||
|
|
||||||
self.phase = InstancePhase::InProgress;
|
self.phase = InstancePhase::InProgress;
|
||||||
self.phase_start = Utc::now();
|
self.phase_start = Utc::now();
|
||||||
self.phase_end = Utc::now()
|
self.phase_end = self.time_control.vbox_phase_end();
|
||||||
.checked_add_signed(Duration::seconds(self.time_control.vbox_time_seconds()))
|
|
||||||
.expect("could not set phase end");
|
|
||||||
|
|
||||||
|
|
||||||
self.players.iter_mut().for_each(|p| {
|
self.players.iter_mut().for_each(|p| {
|
||||||
@ -336,7 +362,7 @@ impl Instance {
|
|||||||
|| self.rounds.len() == self.max_rounds
|
|| self.rounds.len() == self.max_rounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&mut self) -> &mut Instance {
|
pub fn finish(&mut self) -> &mut Instance {
|
||||||
self.phase = InstancePhase::Finished;
|
self.phase = InstancePhase::Finished;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -637,6 +663,37 @@ pub fn instances_need_upkeep(tx: &mut Transaction) -> Result<Vec<Instance>, Erro
|
|||||||
return Ok(list);
|
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> {
|
pub fn instance_new(params: InstanceLobbyParams, tx: &mut Transaction, account: &Account) -> Result<Instance, Error> {
|
||||||
let mut instance = match params.pve {
|
let mut instance = match params.pve {
|
||||||
true => Instance::new()
|
true => Instance::new()
|
||||||
@ -801,7 +858,7 @@ mod tests {
|
|||||||
instance.player_ready(a_id).expect("a ready");
|
instance.player_ready(a_id).expect("a ready");
|
||||||
instance.player_ready(b_id).expect("b 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();
|
let (mut instance, new_games) = instance.upkeep();
|
||||||
|
|
||||||
@ -830,7 +887,7 @@ mod tests {
|
|||||||
instance.add_player(player).expect("could not add player");
|
instance.add_player(player).expect("could not add player");
|
||||||
assert!(!instance.can_start());
|
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();
|
let (instance, _new_games) = instance.upkeep();
|
||||||
|
|
||||||
assert!(instance.finished());
|
assert!(instance.finished());
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use postgres::transaction::Transaction;
|
|||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
use game::{games_need_upkeep, game_update, game_write, game_delete};
|
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};
|
use net::{Db};
|
||||||
|
|
||||||
fn fetch_games(mut tx: Transaction) -> Result<Transaction, Error> {
|
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> {
|
fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> {
|
||||||
let instances = instances_need_upkeep(&mut tx)?;
|
for mut instance in instances_need_upkeep(&mut tx)? {
|
||||||
|
|
||||||
for mut instance in instances {
|
|
||||||
let (instance, new_games) = instance.upkeep();
|
let (instance, new_games) = instance.upkeep();
|
||||||
for game in new_games {
|
for game in new_games {
|
||||||
game_write(&mut tx, &game)?;
|
game_write(&mut tx, &game)?;
|
||||||
@ -35,6 +33,10 @@ fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> {
|
|||||||
instance_update(&mut tx, instance)?;
|
instance_update(&mut tx, instance)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for mut instance in instances_idle(&mut tx)? {
|
||||||
|
instance_delete(&mut tx, instance.id)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(tx)
|
Ok(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user