1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
/*
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/>.
*/
#![feature(exit_status_error)]
pub mod record;
pub mod render;
pub mod replay;
use crate::{
record::record,
render::{render, RenderArgs},
replay::replay,
};
use clap::Parser;
use hurrycurry_protocol::PacketC;
use log::{info, warn, LevelFilter};
use serde::{Deserialize, Serialize};
use std::{
path::PathBuf,
time::{Duration, SystemTime},
};
use tokio::{net::TcpListener, time::sleep};
#[derive(Parser)]
enum Args {
/// Connects as a spectator and saves the protocol packets for replay
Record {
/// Dont stop after the first game but restart instead
#[arg(short, long)]
r#loop: bool,
url: String,
output: PathBuf,
},
/// 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(#[command(flatten)] RenderArgs),
}
#[derive(Serialize, Deserialize)]
struct Event {
ts: f64,
packet: PacketC,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
env_logger::builder()
.filter_level(LevelFilter::Info)
.parse_env("LOG")
.init();
rustls::crypto::ring::default_provider()
.install_default()
.unwrap();
let args = Args::parse();
match args {
Args::Record {
url,
output,
r#loop,
} => loop {
let out = if r#loop {
output.join(format!(
"replay-{}",
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
))
} else {
output.clone()
};
if let Err(e) = record(&out, &url).await {
warn!("recording failed: {e}");
sleep(Duration::from_secs(1)).await;
}
if r#loop {
info!("restarting...");
} else {
break;
}
},
Args::Replay { input } => {
let ws_listener = TcpListener::bind("127.0.0.1:27032").await?;
info!("listening for websockets on {}", ws_listener.local_addr()?);
loop {
replay(&ws_listener, &input).await?;
}
}
Args::Render(a) => {
render(a).await?;
}
}
Ok(())
}
|