summaryrefslogtreecommitdiff
path: root/server/src/game.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/game.rs')
-rw-r--r--server/src/game.rs119
1 files changed, 82 insertions, 37 deletions
diff --git a/server/src/game.rs b/server/src/game.rs
index 1c50c7c2..b3b23ce0 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -20,16 +20,18 @@ use crate::{
data::Gamedata,
entity::{Entity, EntityT},
interaction::{interact, tick_slot, InteractEffect, TickEffect},
+ spatial_index::SpatialIndex,
};
use anyhow::{anyhow, bail, Result};
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
+ movement::MovementBase,
ClientGamedata, ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, RecipeIndex,
TileIndex,
};
use log::{info, warn};
use std::{
- collections::{HashMap, VecDeque},
+ collections::{HashMap, HashSet, VecDeque},
sync::Arc,
time::{Duration, Instant},
};
@@ -55,17 +57,22 @@ pub struct Tile {
pub struct Player {
pub name: String,
pub character: i32,
- pub position: Vec2,
- pub last_position_ts: Instant,
pub interacting: Option<IVec2>,
pub item: Option<Item>,
pub communicate_persist: Option<Message>,
+
+ movement: MovementBase,
+ direction: Vec2,
+ boost: bool,
+ last_position_update: Instant,
}
pub struct Game {
pub data: Arc<Gamedata>,
tiles: HashMap<IVec2, Tile>,
+ walkable: HashSet<IVec2>,
pub players: HashMap<PlayerID, Player>,
+ players_spatial_index: SpatialIndex<PlayerID>,
packet_out: VecDeque<PacketC>,
demand: Option<DemandState>,
pub points: i64,
@@ -80,9 +87,11 @@ impl Game {
packet_out: Default::default(),
players: HashMap::new(),
tiles: HashMap::new(),
+ walkable: HashSet::new(),
demand: None,
end: None,
entities: vec![],
+ players_spatial_index: SpatialIndex::default(),
points: 0,
}
}
@@ -130,15 +139,27 @@ impl Game {
}),
},
);
+ if !self.data.tile_collide[tile.0] {
+ self.walkable.insert(p);
+ }
}
for (id, (name, character)) in players {
self.players.insert(
id,
Player {
item: None,
- last_position_ts: Instant::now(),
character,
- position: self.data.chef_spawn,
+ movement: MovementBase {
+ position: self.data.chef_spawn,
+ facing: Vec2::X,
+ rotation: 0.,
+ velocity: Vec2::ZERO,
+ boosting: false,
+ stamina: 0.,
+ },
+ last_position_update: Instant::now(),
+ boost: false,
+ direction: Vec2::ZERO,
communicate_persist: None,
interacting: None,
name: name.clone(),
@@ -189,7 +210,7 @@ impl Game {
for (&id, player) in &self.players {
out.push(PacketC::AddPlayer {
id,
- position: player.position,
+ position: player.movement.position,
character: player.character,
name: player.name.clone(),
});
@@ -262,9 +283,18 @@ impl Game {
player,
Player {
item: None,
- last_position_ts: Instant::now(),
character,
- position,
+ movement: MovementBase {
+ position: self.data.chef_spawn,
+ facing: Vec2::X,
+ rotation: 0.,
+ velocity: Vec2::ZERO,
+ boosting: false,
+ stamina: 0.,
+ },
+ last_position_update: Instant::now(),
+ boost: false,
+ direction: Vec2::ZERO,
communicate_persist: None,
interacting: None,
name: name.clone(),
@@ -282,8 +312,11 @@ impl Game {
.players
.remove(&player)
.ok_or(anyhow!("player does not exist"))?;
+
+ self.players_spatial_index.remove_entry(player);
+
if let Some(item) = p.item {
- let pos = p.position.floor().as_ivec2();
+ let pos = p.movement.position.floor().as_ivec2();
if let Some(tile) = self.tiles.get_mut(&pos) {
if tile.item.is_none() {
self.packet_out.push_back(PacketC::SetItem {
@@ -297,37 +330,25 @@ impl Game {
self.packet_out
.push_back(PacketC::RemovePlayer { id: player })
}
- PacketS::Position { pos, rot, boosting } => {
- let pid = player;
+ PacketS::Movement {
+ pos,
+ boosting,
+ direction,
+ } => {
let player = self
.players
.get_mut(&player)
.ok_or(anyhow!("player does not exist"))?;
- // let dt = player.last_position_ts.elapsed().as_secs_f32();
- // let dist = pos.distance(player.position);
- // let speed = dist / dt;
- // let interact_dist = player
- // .interacting
- // .map(|p| (p.as_vec2() + Vec2::splat(0.5)).distance(player.position))
- // .unwrap_or_default();
- // let movement_ok = speed < PLAYER_SPEED_LIMIT && dist < 1. && interact_dist < 2.;
- // if movement_ok {
- player.position = pos;
- player.last_position_ts = Instant::now();
- // }
- self.packet_out.push_back(PacketC::Position {
- player: pid,
- pos: player.position,
- rot,
- boosting,
- });
- // if !movement_ok {
- // bail!(
- // "{:?} moved to quickly. speed={speed:.02} dist={dist:.02}",
- // player.name
- // )
- // }
+ player.direction = direction;
+ player.boost = boosting;
+
+ if let Some(pos) = pos {
+ let dt = player.last_position_update.elapsed();
+ player.last_position_update += dt;
+ player.movement.position +=
+ (pos - player.movement.position).clamp_length_max(dt.as_secs_f32());
+ }
}
PacketS::Collide { player, force } => {
self.packet_out
@@ -348,7 +369,7 @@ impl Game {
};
let entpos = pos.as_vec2() + Vec2::splat(0.5);
- if edge && entpos.distance(player.position) > 2. {
+ if edge && entpos.distance(player.movement.position) > 2. {
bail!("interacting too far from player");
}
@@ -364,7 +385,7 @@ impl Game {
let other_pid = if !self.data.is_tile_interactable(tile.kind) {
self.players
.iter()
- .find(|(id, p)| **id != pid && p.position.distance(entpos) < 0.7)
+ .find(|(id, p)| **id != pid && p.movement.position.distance(entpos) < 0.7)
.map(|(&id, _)| id)
} else {
None
@@ -497,6 +518,30 @@ impl Game {
}
for (&pid, player) in &mut self.players {
+ player
+ .movement
+ .update(&self.walkable, player.direction, player.boost, dt);
+
+ self.players_spatial_index
+ .update_entry(pid, player.movement.position);
+ }
+
+ self.players_spatial_index.all(|p1, pos1| {
+ self.players_spatial_index.query(pos1, 2., |p2, _pos2| {
+ if let Some([a, b]) = self.players.get_many_mut([&p1, &p2]) {
+ a.movement.collide(&mut b.movement, dt)
+ }
+ })
+ });
+
+ for (&pid, player) in &mut self.players {
+ self.packet_out.push_back(PacketC::Position {
+ player: pid,
+ pos: player.movement.position,
+ boosting: player.movement.boosting,
+ rot: player.movement.rotation,
+ });
+
if let Some(effect) = tick_slot(dt, &self.data, None, &mut player.item) {
match effect {
TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress {