use std::path::PathBuf;
use anyhow::{Context, Result};
use dotzuki_runner::{run_headless, HeadlessOptions, LoadedProject, RunnerGame, RunnerOptions};
pub struct RunArgs {
pub dir: PathBuf,
pub map: Option<String>,
pub lang: String,
pub headless: bool,
pub frames: u32,
pub screenshot: Option<PathBuf>,
pub scale: u32,
pub watch: bool,
pub fresh: bool,
pub save_file: Option<PathBuf>,
pub save: bool,
}
pub fn run(args: RunArgs) -> Result<()> {
let project = LoadedProject::load(&args.dir)
.with_context(|| format!("failed to load project {}", args.dir.display()))?;
let title = project.manifest().name.clone();
let mut game = RunnerGame::new(
project,
RunnerOptions {
map: args.map,
lang: args.lang,
watch: args.watch && !args.headless,
headless: args.headless,
fresh: args.fresh,
save_file: args.save_file.clone(),
write_saves: !args.headless || args.save,
rng_script: None,
pcm_audio: false,
},
)?;
if args.headless {
if args.watch {
eprintln!("--watch is ignored in headless mode");
}
run_headless(
&mut game,
&HeadlessOptions {
frames: args.frames,
screenshot: args.screenshot.clone(),
..HeadlessOptions::default()
},
)?;
println!("headless run complete ({} frames)", args.frames);
if args.save {
let save_path = args
.save_file
.clone()
.unwrap_or_else(|| args.dir.join(dotzuki_runner::DEFAULT_SAVE_FILE));
if !save_path.is_file() {
eprintln!(
"note: no save file was written at {} — the run reached no stable point within {} frames",
save_path.display(),
args.frames
);
}
}
return Ok(());
}
dotzuki_app::run(
dotzuki_app::GameWindowConfig {
title,
width: dotzuki_runner::SCREEN_W as u32,
height: dotzuki_runner::SCREEN_H as u32,
scale: args.scale,
resizable: true,
},
game,
)
.map_err(|e| anyhow::anyhow!("window error: {e}"))
}