diff options
author | metamuffin <metamuffin@disroot.org> | 2025-09-11 23:59:43 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-09-11 23:59:43 +0200 |
commit | 732850dbde6788c7585ad0152e2ef6c17da79bfc (patch) | |
tree | 1df1d0ff5577e066752e2fbd0b1cc29f1781137f | |
parent | 2b1d79588241fc9afa3ef9ddc3b20b26b8ce2433 (diff) | |
download | hurrycurry-732850dbde6788c7585ad0152e2ef6c17da79bfc.tar hurrycurry-732850dbde6788c7585ad0152e2ef6c17da79bfc.tar.bz2 hurrycurry-732850dbde6788c7585ad0152e2ef6c17da79bfc.tar.zst |
add render subcommand to replaytool
-rw-r--r-- | server/replaytool/src/main.rs | 25 | ||||
-rw-r--r-- | server/replaytool/src/render.rs | 56 |
2 files changed, 79 insertions, 2 deletions
diff --git a/server/replaytool/src/main.rs b/server/replaytool/src/main.rs index 5ff821cc..40496786 100644 --- a/server/replaytool/src/main.rs +++ b/server/replaytool/src/main.rs @@ -15,10 +15,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#![feature(exit_status_error)] pub mod record; +pub mod render; pub mod replay; +use crate::{record::record, render::render, replay::replay}; use clap::Parser; use hurrycurry_protocol::PacketC; use log::{info, warn, LevelFilter}; @@ -29,8 +32,6 @@ use std::{ }; use tokio::{net::TcpListener, time::sleep}; -use crate::{record::record, replay::replay}; - #[derive(Parser)] enum Args { /// Connects as a spectator and saves the protocol packets for replay @@ -43,6 +44,18 @@ 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, + }, } #[derive(Serialize, Deserialize)] @@ -99,6 +112,14 @@ async fn main() -> anyhow::Result<()> { replay(&ws_listener, &input).await?; } } + Args::Render { + input, + output, + framerate, + headless, + } => { + render(&input, &output, framerate, headless).await?; + } } Ok(()) } diff --git a/server/replaytool/src/render.rs b/server/replaytool/src/render.rs new file mode 100644 index 00000000..79eb483b --- /dev/null +++ b/server/replaytool/src/render.rs @@ -0,0 +1,56 @@ +/* + Hurry Curry! - a game about cooking + Copyright (C) 2025 Hurry Curry! Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, version 3 of the License only. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +*/ + +use crate::replay::replay; +use anyhow::Result; +use log::info; +use std::path::Path; +use tokio::{net::TcpListener, process::Command}; + +pub async fn render(input: &Path, output: &Path, framerate: usize, headless: bool) -> Result<()> { + let port = 27090; + let ws_listener = TcpListener::bind(("127.0.0.1", port)).await?; + + let mut args = Vec::new(); + if headless { + args.push("wlheadless-run"); + args.extend(["-c", "mutter"]); + args.push("--"); + } + args.push("hurrycurry-client"); + if headless { + args.extend(["--video-driver", "wayland"]); + args.extend(["--rendering-driver", "vulkan"]); + } + args.extend(["--write-movie", output.to_str().unwrap()]); + let fps = framerate.to_string(); + args.extend(["--fixed-fps", &fps]); + args.push("--print-fps"); + args.push("--"); + let uri = format!("ws://127.0.0.1:{port}"); + args.push(&uri); + + 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?; + + client.wait().await?.exit_ok()?; + + Ok(()) +} |