aboutsummaryrefslogtreecommitdiff
path: root/server/replaytool/src/render.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-09-14 23:44:20 +0200
committermetamuffin <metamuffin@disroot.org>2025-09-15 01:28:10 +0200
commit4e196b83a42b9b217e3b7107b55a14cb1a005b84 (patch)
tree7e56526704c9ec5f4553778a4f080ff485018170 /server/replaytool/src/render.rs
parent008bd3056c1340d41fd9a8af3aa8abc90d93cae4 (diff)
downloadhurrycurry-4e196b83a42b9b217e3b7107b55a14cb1a005b84.tar
hurrycurry-4e196b83a42b9b217e3b7107b55a14cb1a005b84.tar.bz2
hurrycurry-4e196b83a42b9b217e3b7107b55a14cb1a005b84.tar.zst
replaytool render: change resolution via override.cfg
Diffstat (limited to 'server/replaytool/src/render.rs')
-rw-r--r--server/replaytool/src/render.rs97
1 files changed, 77 insertions, 20 deletions
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(())
}