/* 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 anyhow::Result; use clap::Parser; use hurrycurry_bot::{BotAlgo, PacketSink, algos::ALGO_CONSTRUCTORS}; use hurrycurry_game_core::{Game, network::sync::Network}; use hurrycurry_protocol::{Character, PacketC, PacketS, PlayerClass, PlayerID}; use log::warn; use std::{thread::sleep, time::Duration}; #[derive(Parser)] struct Args { /// Bot player name, algo name by default #[arg(short, long)] username: Option, /// Character color #[arg(long, default_value_t = 0)] character_color: i32, /// Character headwear #[arg(long, default_value_t = 0)] character_headwear: i32, /// Character hairstyle #[arg(long, default_value_t = 0)] character_hairstyle: i32, algo: String, /// Websocket address of the server address: String, } pub struct BotDriver { pub interacting: bool, id: PlayerID, state: Box, } fn main() -> Result<()> { env_logger::init_from_env("LOG"); rustls::crypto::ring::default_provider() .install_default() .unwrap(); let args = Args::parse(); let mut network = Network::connect(&args.address)?; let mut game = Game::default(); network.queue_out.push_back(PacketS::Join { name: format!("{}-bot", args.username.clone().unwrap_or(args.algo.clone())), character: Character { color: args.character_color, hairstyle: args.character_hairstyle, headwear: args.character_headwear, }, class: PlayerClass::Bot, id: None, position: None, }); let mut bots = Vec::new(); loop { let dt = 1. / 50.; network.poll()?; while let Some(packet) = network.queue_in.pop_front() { match &packet { PacketC::Joined { id } => bots.push(BotDriver { id: *id, interacting: false, state: ALGO_CONSTRUCTORS .iter() .find(|(n, _)| n == &args.algo) .map(|(_, c)| c(*id)) .unwrap_or_else(|| panic!("unknown algo {:?}", args.algo)), }), PacketC::ServerMessage { message, error: true, } => { warn!("server error message: {message:?}"); } _ => (), } game.apply_packet(packet); } bots.retain_mut(|b| { b.state .tick(PacketSink::new(&mut network.queue_out), &game, dt); if b.state.is_finished() { network.queue_out.push_back(PacketS::Leave { player: b.id }); return false; } true }); sleep(Duration::from_secs_f32(dt)); } }