diff options
author | metamuffin <metamuffin@disroot.org> | 2024-08-11 13:35:15 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-08-11 13:35:15 +0200 |
commit | 52d99b16534631e293a23ddbc18c4ea70b71392f (patch) | |
tree | f596887a976540ab553e69105ab192cbbb2dd753 /server/bot/src/main.rs | |
parent | 63d5a3ff37d1e3972d34ccc9e1d26c3b4bc05efb (diff) | |
download | hurrycurry-52d99b16534631e293a23ddbc18c4ea70b71392f.tar hurrycurry-52d99b16534631e293a23ddbc18c4ea70b71392f.tar.bz2 hurrycurry-52d99b16534631e293a23ddbc18c4ea70b71392f.tar.zst |
add recipes back to protocol
Diffstat (limited to 'server/bot/src/main.rs')
-rw-r--r-- | server/bot/src/main.rs | 134 |
1 files changed, 127 insertions, 7 deletions
diff --git a/server/bot/src/main.rs b/server/bot/src/main.rs index 18c4617a..864141b0 100644 --- a/server/bot/src/main.rs +++ b/server/bot/src/main.rs @@ -15,13 +15,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#![feature(isqrt)] +pub mod pathfinding; use anyhow::Result; use hurrycurry_client_lib::{network::sync::Network, Game}; -use hurrycurry_protocol::{glam::Vec2, PacketC, PacketS, PlayerID}; +use hurrycurry_protocol::{ + glam::{IVec2, Vec2}, + ItemIndex, Message, PacketC, PacketS, PlayerID, RecipeIndex, +}; +use log::{info, warn}; +use pathfinding::{find_path, Path}; use std::{thread::sleep, time::Duration}; fn main() -> Result<()> { + env_logger::init_from_env("LOG"); let mut network = Network::connect("ws://127.0.0.1")?; let mut game = Game::default(); @@ -46,11 +54,19 @@ fn main() -> Result<()> { game.apply_packet(packet); } - for b in &bots { + for b in &mut bots { + let (dir, boost, interact) = b.tick(&game); + if interact.is_some() != b.interacting { + b.interacting = interact.is_some(); + network.queue_out.push_back(PacketS::Interact { + player: b.id, + pos: interact, + }) + } network.queue_out.push_back(PacketS::Movement { player: b.id, - dir: Vec2::ONE, - boost: true, + dir, + boost, pos: None, }); } @@ -60,14 +76,118 @@ fn main() -> Result<()> { } pub struct Bot { + pub interacting: bool, + id: PlayerID, + want: Option<ItemIndex>, + take: Option<IVec2>, + put: Option<IVec2>, + path: Option<Path>, } impl Bot { pub fn new(id: PlayerID) -> Self { - Self { id } + Self { + id, + want: None, + path: None, + take: None, + put: None, + interacting: false, + } } - pub fn tick(&self, game: &Game) { - if let Some(player) = game.players.get(&self.id) {} + pub fn tick(&mut self, game: &Game) -> (Vec2, bool, Option<IVec2>) { + if let Some(player) = game.players.get(&self.id) { + let pos = player.movement.position; + + if let Some(path) = &mut self.path { + let dir = path.next_direction(pos); + if path.is_done() { + self.path = None; + } + return (dir, false, None); + } + if let Some(interact) = self.take.take() { + return (Vec2::ZERO, false, Some(interact)); + } + if let Some(item) = &player.item { + if Some(item.kind) == self.want { + if let Some(interact) = self.put.take() { + return (Vec2::ZERO, false, Some(interact)); + } + } + } + + if let Some(item) = self.want { + if let Some((path, target)) = find_item_on_map(game, pos.as_ivec2(), item) { + info!("target={target}"); + info!("path found"); + self.path = Some(path); + self.take = Some(target); + } else if let Some(recipe) = find_item_as_recipe_output(game, item) { + info!("recipe={recipe:?}"); + self.want = game.data.recipes[recipe.0].outputs().first().copied(); + info!("want={:?}", self.want) + } else { + warn!("stuck"); + } + } else { + if let Some((item, dest)) = select_demand(game) { + info!("want={item:?}"); + self.want = Some(item); + self.put = Some(dest); + } + } + } + (Vec2::ZERO, false, None) } } + +fn find_item_as_recipe_output(game: &Game, item: ItemIndex) -> Option<RecipeIndex> { + game.data + .recipes + .iter() + .enumerate() + .find(|(_, r)| r.inputs().contains(&item)) + .map(|r| RecipeIndex(r.0)) +} + +fn find_item_on_map(game: &Game, player: IVec2, item: ItemIndex) -> Option<(Path, IVec2)> { + game.tiles.iter().find_map(|(pos, tile)| { + if let Some(i) = &tile.item { + if i.kind == item { + for xo in -1..=1 { + for yo in -1..=1 { + let t = *pos + IVec2::new(xo, yo); + if let Some(path) = find_path(&game.walkable, player, t) { + return Some((path, *pos)); + } + } + } + } + } + None + }) +} + +fn select_demand(game: &Game) -> Option<(ItemIndex, IVec2)> { + game.players + .iter() + .find_map(|(_, pl)| match &pl.communicate_persist { + Some(Message::Item(item)) => { + let pos = pl.movement.position.as_ivec2(); + for xo in -1..=1 { + for yo in -1..=1 { + let t = pos + IVec2::new(xo, yo); + if let Some(tile) = game.tiles.get(&t) { + if game.data.tile_interact[tile.kind.0] { + return Some((*item, t)); + } + } + } + } + None + } + _ => None, + }) +} |