summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/src/game.rs26
-rw-r--r--server/src/main.rs4
-rw-r--r--server/src/protocol.rs1
-rw-r--r--server/src/state.rs25
4 files changed, 39 insertions, 17 deletions
diff --git a/server/src/game.rs b/server/src/game.rs
index 96cfa93a..599aadbd 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -28,7 +28,7 @@ use std::{
collections::{HashMap, VecDeque},
ops::Deref,
sync::Arc,
- time::Instant,
+ time::{Duration, Instant},
};
#[derive(Debug, PartialEq)]
@@ -65,7 +65,8 @@ pub struct Game {
players: HashMap<PlayerID, Player>,
packet_out: VecDeque<PacketC>,
demand: Option<DemandState>,
- points: i64,
+ pub points: i64,
+ end: Option<Instant>,
}
impl Game {
@@ -76,6 +77,7 @@ impl Game {
players: Default::default(),
tiles: Default::default(),
demand: None,
+ end: None,
points: 0,
}
}
@@ -95,7 +97,7 @@ impl Game {
}
self.demand = None;
}
- pub fn load(&mut self, gamedata: Gamedata) {
+ pub fn load(&mut self, gamedata: Gamedata, timer: Option<Duration>) {
let players = self
.players
.iter()
@@ -107,6 +109,7 @@ impl Game {
self.data = gamedata.into();
self.points = 0;
+ self.end = timer.map(|dur| Instant::now() + dur);
for (&p, (tile, item)) in &self.data.initial_map {
self.tiles.insert(
@@ -201,6 +204,7 @@ impl Game {
pub fn score(&self) -> PacketC {
PacketC::Score {
+ time_remaining: self.end.map(|t| (t - Instant::now()).as_secs_f32()),
points: self.points,
demands_failed: self.demand.as_ref().map(|d| d.failed).unwrap_or_default(),
demands_completed: self
@@ -375,6 +379,9 @@ impl Game {
}
self.packet_out.push_back({
PacketC::Score {
+ time_remaining: self
+ .end
+ .map(|t| (t - Instant::now()).as_secs_f32()),
points: self.points,
demands_failed: self
.demand
@@ -423,7 +430,8 @@ impl Game {
Ok(())
}
- pub fn tick(&mut self, dt: f32) {
+ /// Returns true if the game should end
+ pub fn tick(&mut self, dt: f32) -> bool {
if let Some(demand) = &mut self.demand {
let mut packet_out = Vec::new();
if let Err(err) = demand.tick(
@@ -436,12 +444,8 @@ impl Game {
warn!("demand tick {err}");
}
if demand.score_changed {
- self.packet_out.push_back(PacketC::Score {
- points: self.points,
- demands_failed: demand.failed,
- demands_completed: demand.completed,
- });
- demand.score_changed = false
+ demand.score_changed = false;
+ self.packet_out.push_back(self.score());
}
for (player, packet) in packet_out {
if let Err(err) = self.packet_in(player, packet) {
@@ -473,6 +477,8 @@ impl Game {
}
}
}
+
+ return self.end.map(|t| t < Instant::now()).unwrap_or_default();
}
}
diff --git a/server/src/main.rs b/server/src/main.rs
index 68927eaa..a144c704 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -90,7 +90,9 @@ async fn run() -> anyhow::Result<()> {
let mut tick = interval(Duration::from_secs_f32(dt));
loop {
tick.tick().await;
- state.write().await.tick(dt).await;
+ if let Err(e) = state.write().await.tick(dt).await {
+ warn!("tick failed: {e}");
+ }
}
});
}
diff --git a/server/src/protocol.rs b/server/src/protocol.rs
index 39bc0887..176eb31b 100644
--- a/server/src/protocol.rs
+++ b/server/src/protocol.rs
@@ -141,6 +141,7 @@ pub enum PacketC {
points: i64,
demands_failed: usize,
demands_completed: usize,
+ time_remaining: Option<f32>,
},
SetIngame {
state: bool,
diff --git a/server/src/state.rs b/server/src/state.rs
index 41ffce20..ffcc8fa2 100644
--- a/server/src/state.rs
+++ b/server/src/state.rs
@@ -1,3 +1,5 @@
+use std::time::Duration;
+
use crate::{
data::DataIndex,
game::Game,
@@ -20,6 +22,8 @@ enum Command {
Start {
#[arg(default_value = "small-default-default")]
spec: String,
+ #[arg(default_value = "300")]
+ timer: u64,
},
Effect {
name: String,
@@ -33,17 +37,26 @@ impl State {
index.reload()?;
let mut game = Game::new();
- game.load(index.generate("lobby-none-none".to_string())?);
+ game.load(index.generate("lobby-none-none".to_string())?, None);
Ok(Self { game, index, tx })
}
- pub async fn tick(&mut self, dt: f32) {
- self.game.tick(dt);
+ pub async fn tick(&mut self, dt: f32) -> anyhow::Result<()> {
+ if self.game.tick(dt) {
+ self.tx
+ .send(PacketC::ServerMessage {
+ text: format!("Game finished. You reached {} points.", self.game.points),
+ })
+ .ok();
+ self.game
+ .load(self.index.generate("lobby-none-none".to_string())?, None);
+ }
while let Some(p) = self.game.packet_out() {
debug!("-> {p:?}");
let _ = self.tx.send(p);
}
+ Ok(())
}
pub async fn packet_in(&mut self, player: PlayerID, packet: PacketS) -> Result<Vec<PacketC>> {
match &packet {
@@ -81,13 +94,13 @@ impl State {
async fn handle_command(&mut self, player: PlayerID, command: Command) -> Result<()> {
match command {
- Command::Start { spec } => {
+ Command::Start { spec, timer } => {
let data = self.index.generate(spec)?;
- self.game.load(data);
+ self.game.load(data, Some(Duration::from_secs(timer)));
}
Command::End => {
self.game
- .load(self.index.generate("lobby-none-none".to_string())?);
+ .load(self.index.generate("lobby-none-none".to_string())?, None);
}
Command::Effect { name } => {
self.tx