aboutsummaryrefslogtreecommitdiff
path: root/server/replaytool
diff options
context:
space:
mode:
Diffstat (limited to 'server/replaytool')
-rw-r--r--server/replaytool/src/main.rs45
-rw-r--r--server/replaytool/src/render.rs97
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(())
}