/* Hurry Curry! - a game about cooking Copyright (C) 2025 Hurry Curry! Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ use super::{Entity, EntityContext}; use anyhow::Result; use hurrycurry_bot::{BotAlgo, DynBotAlgo, PacketSink}; use hurrycurry_locale::TrError; use hurrycurry_protocol::{Character, PacketS, PlayerClass, PlayerID}; use log::debug; use std::any::Any; pub type DynBotDriver = BotDriver; pub enum BotDriver { Joining { name: String, character: Character, class: PlayerClass, constructor: Option T + Send + Sync>>, }, Running { state: T, id: PlayerID, }, Left, } impl BotDriver { pub fn new( name: String, character: Character, class: PlayerClass, constructor: impl FnOnce(PlayerID) -> T + 'static + Send + Sync, ) -> Self { Self::Joining { character, class, constructor: Some(Box::new(constructor)), name, } } } impl Entity for BotDriver { fn finished(&self) -> bool { matches!(self, Self::Left) } fn tick(&mut self, c: EntityContext<'_>) -> Result<(), TrError> { match self { BotDriver::Joining { name, character, class, constructor, } => { let id = c.game.get_unused_player_id(); // TODO clashes when multiple bots join in the same tick debug!("enter {id}"); c.packet_in.push_back(PacketS::Join { name: name.to_string(), character: *character, id: Some(id), class: *class, position: None, }); *self = BotDriver::Running { state: constructor.take().unwrap()(id), id, }; Ok(()) } BotDriver::Running { state, id } => { state.tick(PacketSink::new(c.packet_in), c.game, c.dt); if state.is_finished() { debug!("leave {id}"); c.packet_in.push_back(PacketS::Leave { player: *id }); *self = BotDriver::Left } Ok(()) } BotDriver::Left => Ok(()), } } fn destructor(&mut self, c: EntityContext<'_>) { if let Self::Running { id, .. } = self { c.packet_in.push_back(PacketS::Leave { player: *id }) } } }