aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-08-13 16:03:19 +0200
committermetamuffin <metamuffin@disroot.org>2024-08-13 16:03:38 +0200
commit8d83fcef94ce1558a2c0e29e8be6c966c7e10a5b (patch)
treef674b2ea255a5d80ef7ee320e313a02a9a72bc4b /server
parent0f94e292bde8b9614aa48a6ba87f1a8d927b8133 (diff)
downloadhurrycurry-8d83fcef94ce1558a2c0e29e8be6c966c7e10a5b.tar
hurrycurry-8d83fcef94ce1558a2c0e29e8be6c966c7e10a5b.tar.bz2
hurrycurry-8d83fcef94ce1558a2c0e29e8be6c966c7e10a5b.tar.zst
trying to reimplement customers
Diffstat (limited to 'server')
-rw-r--r--server/bot/src/algos/customer.rs368
-rw-r--r--server/bot/src/lib.rs5
-rw-r--r--server/protocol/src/lib.rs9
-rw-r--r--server/src/data/mod.rs11
4 files changed, 213 insertions, 180 deletions
diff --git a/server/bot/src/algos/customer.rs b/server/bot/src/algos/customer.rs
index 167fc0d7..69712ba8 100644
--- a/server/bot/src/algos/customer.rs
+++ b/server/bot/src/algos/customer.rs
@@ -15,8 +15,14 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::{pathfinding::Path, BotAlgo, BotInput};
-use hurrycurry_protocol::{glam::IVec2, DemandIndex};
+use crate::{
+ pathfinding::{find_path, Path},
+ BotAlgo, BotInput,
+};
+use hurrycurry_client_lib::Game;
+use hurrycurry_protocol::{glam::IVec2, DemandIndex, Message, PacketS, PlayerID};
+use log::info;
+use rand::random;
#[derive(Debug, Clone)]
pub enum Customer {
@@ -48,172 +54,198 @@ impl Default for Customer {
}
impl BotAlgo for Customer {
- fn tick(
- &mut self,
- me: hurrycurry_protocol::PlayerID,
- game: &hurrycurry_client_lib::Game,
- dt: f32,
- ) -> BotInput {
+ fn tick(&mut self, me: PlayerID, game: &Game, dt: f32) -> BotInput {
let _ = (me, game, dt);
- BotInput::default()
- // let Some(playerdata) = game.players.get_mut(&player) else {
- // return BotInput::default();
- // };
- // match state {
- // let chair = self.select_chair().ok_or(anyhow!("no free chair found"))?;
- // let from = game.data.customer_spawn.as_ivec2();
- // let path = find_path(&game.walkable, from, chair)
- // .ok_or(anyhow!("no path from {from} to {chair}"))?;
- // info!("{id:?} -> entering");
-
- // CustomerState::Entering { path, chair } => {
- // playerdata
- // .movement
- // .input(path.next_direction(playerdata.position()), false);
- // if path.is_done() {
- // let demand = DemandIndex(random::<u32>() as usize % self.demands.len());
- // self.cpackets.push_back(PacketS::Communicate {
- // message: Some(Message::Item(self.demands[demand.0].from)),
- // persist: true,
- // player,
- // });
- // info!("{player:?} -> waiting");
- // *state = CustomerState::Waiting {
- // chair: *chair,
- // timeout: 90. + random::<f32>() * 60.,
- // demand,
- // };
- // }
- // }
- // CustomerState::Waiting {
- // chair,
- // demand,
- // timeout,
- // } => {
- // playerdata
- // .movement
- // .input((chair.as_vec2() + 0.5) - playerdata.position(), false);
- // *timeout -= dt;
- // if *timeout <= 0. {
- // self.cpackets.push_back(PacketS::Communicate {
- // message: None,
- // persist: true,
- // player,
- // });
- // self.cpackets.push_back(PacketS::Communicate {
- // message: Some(Message::Effect("angry".to_string())),
- // persist: false,
- // player,
- // });
- // let path = find_path(
- // &game.walkable,
- // playerdata.position().as_ivec2(),
- // game.data.customer_spawn.as_ivec2(),
- // )
- // .expect("no path to exit");
- // *self.chairs.get_mut(chair).unwrap() = true;
- // game.score.demands_failed += 1;
- // game.score.points -= 1;
- // game.score_changed = true;
- // info!("{player:?} -> exiting");
- // *state = CustomerState::Exiting { path }
- // } else {
- // let demand_data = &self.demands[demand.0];
- // let demand_pos = [IVec2::NEG_X, IVec2::NEG_Y, IVec2::X, IVec2::Y]
- // .into_iter()
- // .find_map(|off| {
- // let pos = *chair + off;
- // if game
- // .tiles
- // .get(&pos)
- // .map(|t| {
- // t.item
- // .as_ref()
- // .map(|i| i.kind == demand_data.from)
- // .unwrap_or_default()
- // })
- // .unwrap_or_default()
- // {
- // Some(pos)
- // } else {
- // None
- // }
- // });
- // if let Some(pos) = demand_pos {
- // self.cpackets.push_back(PacketS::Communicate {
- // persist: true,
- // message: None,
- // player,
- // });
- // self.cpackets.push_back(PacketS::Communicate {
- // message: Some(Message::Effect("satisfied".to_string())),
- // persist: false,
- // player,
- // });
- // self.cpackets.push_back(PacketS::Interact {
- // pos: Some(pos),
- // player,
- // });
- // self.cpackets
- // .push_back(PacketS::Interact { pos: None, player });
- // info!("{player:?} -> eating");
- // *state = CustomerState::Eating {
- // demand: *demand,
- // target: pos,
- // progress: 0.,
- // chair: *chair,
- // }
- // }
- // }
- // }
- // CustomerState::Eating {
- // demand,
- // target,
- // progress,
- // chair,
- // } => {
- // playerdata
- // .movement
- // .input((chair.as_vec2() + 0.5) - playerdata.position(), false);
- // let demand = &self.demands[demand.0];
- // *progress += dt / demand.duration;
- // if *progress >= 1. {
- // self.cpackets.push_back(PacketS::ReplaceHand {
- // player,
- // item: demand.to,
- // });
- // if demand.to.is_some() {
- // self.cpackets.push_back(PacketS::Interact {
- // player,
- // pos: Some(*target),
- // });
- // self.cpackets
- // .push_back(PacketS::Interact { player, pos: None });
- // }
- // let path = find_path(
- // &game.walkable,
- // playerdata.position().as_ivec2(),
- // game.data.customer_spawn.as_ivec2(),
- // )
- // .ok_or(anyhow!("no path to exit"))?;
- // *self.chairs.get_mut(chair).unwrap() = true;
- // game.score.demands_completed += 1;
- // game.score.points += demand.points;
- // game.score_changed = true;
- // info!("{player:?} -> exiting");
- // *state = CustomerState::Exiting { path }
- // }
- // }
- // CustomerState::Exiting { path } => {
- // playerdata
- // .movement
- // .input(path.next_direction(playerdata.position()), false);
- // if path.is_done() {
- // info!("{player:?} -> leave");
- // self.cpackets.push_back(PacketS::Leave { player });
- // customers_to_remove.push(player);
- // }
- // }
- // }
+ let Some(playerdata) = game.players.get_mut(&me) else {
+ return BotInput::default();
+ };
+ let pos = playerdata.movement.position;
+ match self {
+ Customer::New => {
+ if let Some((chair, _)) = game
+ .tiles
+ .iter()
+ .find(|(_, t)| game.data.tile_name(t.kind) == "chair")
+ {
+ if let Some(path) = find_path(&game.walkable, pos.as_ivec2(), *chair) {
+ info!("{me:?} -> entering");
+ *self = Customer::Entering {
+ path,
+ chair: *chair,
+ };
+ }
+ }
+ BotInput::default()
+ }
+ Customer::Entering { path, chair } => {
+ let direction = path.next_direction(pos);
+ if path.is_done() {
+ let demand = DemandIndex(random::<u32>() as usize % game.data.demands.len());
+ info!("{me:?} -> waiting");
+ *self = Customer::Waiting {
+ chair: *chair,
+ timeout: 90. + random::<f32>() * 60.,
+ demand,
+ };
+ BotInput {
+ extra: vec![PacketS::Communicate {
+ message: Some(Message::Item(game.data.demands[demand.0].input)),
+ persist: true,
+ player: me,
+ }],
+ ..Default::default()
+ }
+ } else {
+ BotInput {
+ direction,
+ ..Default::default()
+ }
+ }
+ }
+ Customer::Waiting {
+ chair,
+ demand,
+ timeout,
+ } => {
+ playerdata
+ .movement
+ .input((chair.as_vec2() + 0.5) - pos, false);
+ *timeout -= dt;
+ if *timeout <= 0. {
+ let path = find_path(
+ &game.walkable,
+ pos.as_ivec2(),
+ pos.as_ivec2(),
+ // game.data.customer_spawn.as_ivec2(),
+ )
+ .expect("no path to exit");
+ // *self.chairs.get_mut(chair).unwrap() = true;
+ // game.score.demands_failed += 1;
+ // game.score.points -= 1;
+ // game.score_changed = true;
+ info!("{me:?} -> exiting");
+ *self = Customer::Exiting { path };
+ BotInput {
+ extra: vec![
+ PacketS::Communicate {
+ message: None,
+ persist: true,
+ player: me,
+ },
+ PacketS::Communicate {
+ message: Some(Message::Effect("angry".to_string())),
+ persist: false,
+ player: me,
+ },
+ ],
+ ..Default::default()
+ }
+ } else {
+ let demand_data = &game.data.demands[demand.0];
+ let demand_pos = [IVec2::NEG_X, IVec2::NEG_Y, IVec2::X, IVec2::Y]
+ .into_iter()
+ .find_map(|off| {
+ let pos = *chair + off;
+ if game
+ .tiles
+ .get(&pos)
+ .map(|t| {
+ t.item
+ .as_ref()
+ .map(|i| i.kind == demand_data.input)
+ .unwrap_or_default()
+ })
+ .unwrap_or_default()
+ {
+ Some(pos)
+ } else {
+ None
+ }
+ });
+ if let Some(pos) = demand_pos {
+ info!("{me:?} -> eating");
+ *self = Customer::Eating {
+ demand: *demand,
+ target: pos,
+ progress: 0.,
+ chair: *chair,
+ };
+ BotInput {
+ extra: vec![
+ PacketS::Communicate {
+ persist: true,
+ message: None,
+ player: me,
+ },
+ PacketS::Communicate {
+ message: Some(Message::Effect("satisfied".to_string())),
+ persist: false,
+ player: me,
+ },
+ PacketS::Interact {
+ pos: Some(pos),
+ player: me,
+ },
+ PacketS::Interact {
+ pos: None,
+ player: me,
+ },
+ ],
+ ..Default::default()
+ }
+ } else {
+ BotInput::default()
+ }
+ }
+ }
+ Customer::Eating {
+ demand,
+ target,
+ progress,
+ chair,
+ } => {
+ playerdata
+ .movement
+ .input((chair.as_vec2() + 0.5) - playerdata.position(), false);
+ let demand = &game.data.demands[demand.0];
+ *progress += dt / demand.duration;
+ if *progress >= 1. {
+ self.cpackets.push_back(PacketS::ReplaceHand {
+ player,
+ item: demand.to,
+ });
+ if demand.to.is_some() {
+ self.cpackets.push_back(PacketS::Interact {
+ player,
+ pos: Some(*target),
+ });
+ self.cpackets
+ .push_back(PacketS::Interact { player, pos: None });
+ }
+ let path = find_path(
+ &game.walkable,
+ playerdata.position().as_ivec2(),
+ game.data.customer_spawn.as_ivec2(),
+ )
+ .ok_or(anyhow!("no path to exit"))?;
+ *self.chairs.get_mut(chair).unwrap() = true;
+ game.score.demands_completed += 1;
+ game.score.points += demand.points;
+ game.score_changed = true;
+ info!("{player:?} -> exiting");
+ *state = Customer::Exiting { path }
+ }
+ }
+ Customer::Exiting { path } => {
+ playerdata
+ .movement
+ .input(path.next_direction(playerdata.position()), false);
+ if path.is_done() {
+ info!("{player:?} -> leave");
+ self.cpackets.push_back(PacketS::Leave { player });
+ customers_to_remove.push(player);
+ }
+ }
+ }
}
}
diff --git a/server/bot/src/lib.rs b/server/bot/src/lib.rs
index 543a1062..b2334333 100644
--- a/server/bot/src/lib.rs
+++ b/server/bot/src/lib.rs
@@ -22,15 +22,16 @@ pub mod pathfinding;
use hurrycurry_client_lib::Game;
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
- PlayerID,
+ PacketS, PlayerID,
};
-#[derive(Default, Clone, Copy)]
+#[derive(Default, Clone)]
pub struct BotInput {
pub direction: Vec2,
pub boost: bool,
pub interact: Option<IVec2>,
pub leave: bool,
+ pub extra: Vec<PacketS>,
}
pub type DynBotAlgo = Box<dyn BotAlgo + Send + Sync + 'static>;
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index 695d45cf..80d94192 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -69,6 +69,14 @@ pub struct MapMetadata {
difficulty: i32,
}
+#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
+pub struct Demand {
+ pub input: ItemIndex,
+ pub output: Option<ItemIndex>,
+ pub duration: f32,
+ pub points: i64,
+}
+
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, Default)]
#[rustfmt::skip]
pub struct Gamedata {
@@ -79,6 +87,7 @@ pub struct Gamedata {
pub tile_interact: Vec<bool>,
pub maps: HashMap<String, MapMetadata>,
pub recipes: Vec<Recipe>,
+ pub demands: Vec<Demand>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
diff --git a/server/src/data/mod.rs b/server/src/data/mod.rs
index 6555fbc4..f7f184d2 100644
--- a/server/src/data/mod.rs
+++ b/server/src/data/mod.rs
@@ -92,18 +92,9 @@ pub struct DemandDecl {
points: i64,
}
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Demand {
- pub from: ItemIndex,
- pub to: Option<ItemIndex>,
- pub duration: f32,
- pub points: i64,
-}
-
#[derive(Debug,Clone, Default)]
#[rustfmt::skip]
pub struct Serverdata {
- pub demands: Vec<Demand>,
pub spec: String,
pub initial_map: HashMap<IVec2, (TileIndex, Option<ItemIndex>)>,
pub chef_spawn: Vec2,
@@ -301,11 +292,11 @@ pub fn build_data(
tile_interact,
recipes,
item_names,
+ demands,
tile_names,
},
Serverdata {
spec,
- demands,
initial_map,
chef_spawn,
customer_spawn,