use crate::{
game::{ControllerState, GameTickPacket},
init_with_options, InitOptions,
};
use std::{env, error::Error, path::PathBuf};
pub trait Bot {
fn set_player_index(&mut self, index: usize);
fn tick(&mut self, packet: &GameTickPacket) -> ControllerState;
}
#[allow(deprecated)]
pub fn run_bot<B: Bot>(mut bot: B) -> Result<(), Box<dyn Error>> {
let args = parse_framework_args()
.map_err(|_| Box::<dyn Error>::from("could not parse framework arguments"))?
.ok_or_else(|| Box::<dyn Error>::from("not launched by framework"))?;
let player_index = args.player_index;
let rlbot = init_with_options(args.into())?;
bot.set_player_index(player_index as usize);
let mut packets = rlbot.packeteer();
loop {
let packet = packets.next()?;
let input = bot.tick(&packet);
rlbot.update_player_input(player_index, &input)?;
}
}
pub fn parse_framework_args() -> Result<Option<FrameworkArgs>, ()> {
parse_framework_command_line(env::args().skip(1))
}
fn parse_framework_command_line(
mut args: impl Iterator<Item = String>,
) -> Result<Option<FrameworkArgs>, ()> {
if args.next().as_ref().map(|s| &s[..]) != Some("--rlbot-version") {
return Ok(None); }
let rlbot_version = args.next().ok_or(())?;
if args.next().as_ref().map(|s| &s[..]) != Some("--rlbot-dll-directory") {
return Err(());
}
let rlbot_dll_directory = PathBuf::from(args.next().ok_or(())?);
if args.next().as_ref().map(|s| &s[..]) != Some("--player-index") {
return Err(());
}
let player_index = args.next().ok_or(())?.parse().map_err(|_| ())?;
Ok(Some(FrameworkArgs {
rlbot_version,
rlbot_dll_directory,
player_index,
_non_exhaustive: (),
}))
}
pub struct FrameworkArgs {
pub rlbot_version: String,
pub rlbot_dll_directory: PathBuf,
pub player_index: i32,
_non_exhaustive: (),
}
impl From<FrameworkArgs> for InitOptions {
fn from(args: FrameworkArgs) -> Self {
Self::new().rlbot_dll_directory(args.rlbot_dll_directory)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn pfcl(ss: Vec<&str>) -> Result<Option<FrameworkArgs>, ()> {
parse_framework_command_line(ss.into_iter().map(str::to_string))
}
#[test]
fn parse_framework_args() {
let args = pfcl(vec![
"--rlbot-version",
"1.8.1",
"--rlbot-dll-directory",
"/tmp",
"--player-index",
"0",
])
.unwrap()
.unwrap();
assert_eq!(args.rlbot_version, "1.8.1");
assert_eq!(args.rlbot_dll_directory.to_str().unwrap(), "/tmp");
assert_eq!(args.player_index, 0);
}
#[test]
fn parse_empty_command_line() {
let args = pfcl(vec![]).unwrap();
assert!(args.is_none());
}
#[test]
fn parse_non_matching_command_line() {
let args = pfcl(vec!["--unrelated-argument"]).unwrap();
assert!(args.is_none());
}
#[test]
fn parse_error() {
let args = pfcl(vec!["--rlbot-version"]);
assert!(args.is_err());
let args = pfcl(vec!["--rlbot-version", "1.8.1"]);
assert!(args.is_err());
}
}