diff options
author | metamuffin <metamuffin@disroot.org> | 2025-09-14 23:44:20 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-09-15 01:28:10 +0200 |
commit | 4e196b83a42b9b217e3b7107b55a14cb1a005b84 (patch) | |
tree | 7e56526704c9ec5f4553778a4f080ff485018170 /server/replaytool | |
parent | 008bd3056c1340d41fd9a8af3aa8abc90d93cae4 (diff) | |
download | hurrycurry-4e196b83a42b9b217e3b7107b55a14cb1a005b84.tar hurrycurry-4e196b83a42b9b217e3b7107b55a14cb1a005b84.tar.bz2 hurrycurry-4e196b83a42b9b217e3b7107b55a14cb1a005b84.tar.zst |
replaytool render: change resolution via override.cfg
Diffstat (limited to 'server/replaytool')
-rw-r--r-- | server/replaytool/src/main.rs | 45 | ||||
-rw-r--r-- | server/replaytool/src/render.rs | 97 |
2 files changed, 85 insertions, 57 deletions
diff --git a/server/replaytool/src/main.rs b/server/replaytool/src/main.rs index a9032a61..1e5be601 100644 --- a/server/replaytool/src/main.rs +++ b/server/replaytool/src/main.rs @@ -21,7 +21,11 @@ pub mod record; pub mod render; pub mod replay; -use crate::{record::record, render::render, replay::replay}; +use crate::{ + record::record, + render::{render, RenderArgs}, + replay::replay, +}; use clap::Parser; use hurrycurry_protocol::PacketC; use log::{info, warn, LevelFilter}; @@ -45,23 +49,7 @@ enum Args { /// Starts a local server that replays previously recorded sessions Replay { input: PathBuf }, /// Runs a replay server and the client in movie mode to record that replay - Render { - /// Replay file path - input: PathBuf, - /// Output video file path passed to godot (must end in either .avi for MJPEG or .png for PNG sequence) - output: PathBuf, - #[arg(short = 'r', long, default_value = "30")] - framerate: usize, - /// Render without display server; Requires wlheadless-run and mutter - #[arg(short = 'H', long)] - headless: bool, - #[arg(long, default_value = "wayland")] - video_driver: String, - #[arg(long, default_value = "vulkan")] - rendering_driver: String, - #[arg(long, default_value = "mutter")] - headless_compositor: String, - }, + Render(#[command(flatten)] RenderArgs), } #[derive(Serialize, Deserialize)] @@ -118,25 +106,8 @@ async fn main() -> anyhow::Result<()> { replay(&ws_listener, &input).await?; } } - Args::Render { - input, - output, - framerate, - headless, - rendering_driver, - headless_compositor, - video_driver, - } => { - render( - &input, - &output, - framerate, - headless, - &rendering_driver, - &video_driver, - &headless_compositor, - ) - .await?; + Args::Render(a) => { + render(a).await?; } } Ok(()) diff --git a/server/replaytool/src/render.rs b/server/replaytool/src/render.rs index bb5e8a57..2314de79 100644 --- a/server/replaytool/src/render.rs +++ b/server/replaytool/src/render.rs @@ -17,40 +17,93 @@ */ use crate::replay::replay; -use anyhow::Result; +use anyhow::{anyhow, Result}; use log::info; -use std::path::Path; -use tokio::{net::TcpListener, process::Command}; +use rand::random; +use std::{path::PathBuf, str::FromStr}; +use tokio::{ + fs::{create_dir_all, remove_dir, remove_file, File}, + io::AsyncWriteExt, + net::TcpListener, + process::Command, +}; -pub async fn render( - input: &Path, - output: &Path, +#[derive(clap::Parser)] +pub struct RenderArgs { + /// Replay file path + input: PathBuf, + /// Output video file path passed to godot (must end in either .avi for MJPEG or .png for PNG sequence) + output: PathBuf, + #[arg(short = 'r', long, default_value = "30")] framerate: usize, + #[arg(short = 'R', long, default_value = "1280x720")] + resolution: String, + /// Render without display server; Requires wlheadless-run and mutter + #[arg(short = 'H', long)] headless: bool, - rendering_driver: &str, - video_driver: &str, - headless_compositor: &str, -) -> Result<()> { + #[arg(long, default_value = "wayland")] + video_driver: String, + #[arg(long, default_value = "vulkan")] + rendering_driver: String, + #[arg(long, default_value = "mutter")] + headless_compositor: String, + #[arg(long, default_value = "/usr/share/hurrycurry/client.pck")] + client_pck: PathBuf, +} + +pub async fn render(a: RenderArgs) -> Result<()> { let port = 27090; let ws_listener = TcpListener::bind(("127.0.0.1", port)).await?; + let cwd = PathBuf::from_str("/tmp") + .unwrap() + .join(format!("hurrycurry-render-cfg-{:016x}", random::<u64>())); + + let config = { + let (width, height) = a + .resolution + .split_once("x") + .ok_or(anyhow!("resolution malformed"))?; + format!( + r#"config_version=5 +[display] +window/size/viewport_width={width} +window/size/viewport_height={height} +"#, + ) + }; + + create_dir_all(&cwd).await?; + File::create(cwd.join("override.cfg")) + .await? + .write_all(config.as_bytes()) + .await?; + + #[cfg(unix)] + tokio::fs::symlink(&a.client_pck, cwd.join("client.pck")).await?; + #[cfg(not(unix))] + tokio::fs::copy(&a.client_pck, cwd.join("client.pck")).await?; + let mut args = Vec::new(); - if headless { + if a.headless { args.push("wlheadless-run"); - args.extend(["-c", headless_compositor]); + args.extend(["-c", &a.headless_compositor]); args.push("--"); } - if headless && video_driver == "x11" { + if a.headless && a.video_driver == "x11" { args.push("xwayland-run"); args.push("--"); } - args.push("hurrycurry-client"); - if headless { - args.extend(["--video-driver", video_driver]); - args.extend(["--rendering-driver", rendering_driver]); + args.push("godot"); + let main_pack = cwd.join("client.pck"); + let main_pack = main_pack.to_str().unwrap(); + args.extend(["--main-pack", main_pack]); + if a.headless { + args.extend(["--video-driver", &a.video_driver]); + args.extend(["--rendering-driver", &a.rendering_driver]); } - args.extend(["--write-movie", output.to_str().unwrap()]); - let fps = framerate.to_string(); + args.extend(["--write-movie", a.output.to_str().unwrap()]); + let fps = a.framerate.to_string(); args.extend(["--fixed-fps", &fps]); args.push("--print-fps"); args.push("--"); @@ -61,9 +114,13 @@ pub async fn render( let mut client = Command::new(args[0]).args(&args[1..]).spawn()?; info!("listening for websockets on {}", ws_listener.local_addr()?); - replay(&ws_listener, &input).await?; + replay(&ws_listener, &a.input).await?; client.wait().await?.exit_ok()?; + remove_file(cwd.join("override.cfg")).await?; + remove_file(cwd.join("client.pck")).await?; + remove_dir(cwd).await?; + Ok(()) } |