refactor(replay): move recorder into separate module

This commit is contained in:
Ryan 2025-03-10 21:54:57 -04:00
parent c15ea64bd3
commit c19af70274
5 changed files with 92 additions and 92 deletions

View File

@ -4,7 +4,7 @@ use crate::{
http::serve,
lua::{client, direction::Direction, player::Player, vec3::Vec3},
particle,
replay::Recorder,
replay::recorder::Recorder,
};
use anyhow::Context;
use azalea::{

View File

@ -24,7 +24,7 @@ use commands::{CommandSource, register};
use futures::lock::Mutex;
use futures_locks::RwLock;
use mlua::{Function, Lua, Table};
use replay::{Recorder, plugin::RecordPlugin};
use replay::{plugin::RecordPlugin, recorder::Recorder};
use std::{
collections::HashMap,
env,

View File

@ -1,89 +1,2 @@
pub mod plugin;
use crate::build_info;
use anyhow::Result;
use azalea::{
buf::AzaleaWriteVar,
prelude::Resource,
protocol::packets::{PROTOCOL_VERSION, ProtocolPacket, VERSION_NAME},
};
use serde_json::json;
use smallvec::SmallVec;
use std::{
fs::File,
io::Write,
time::{Instant, SystemTime, UNIX_EPOCH},
};
use zip::{ZipWriter, write::SimpleFileOptions};
#[derive(Resource)]
pub struct Recorder {
zip_writer: ZipWriter<File>,
start: Instant,
server: String,
ignore_compression: bool,
}
impl Recorder {
pub fn new(path: String, server: String, ignore_compression: bool) -> Result<Self> {
let mut zip_writer = ZipWriter::new(
File::options()
.write(true)
.create(true)
.truncate(true)
.open(path)?,
);
zip_writer.start_file("recording.tmcpr", SimpleFileOptions::default())?;
Ok(Self {
zip_writer,
start: Instant::now(),
server,
ignore_compression,
})
}
pub fn finish(mut self) -> Result<()> {
let elapsed = self.start.elapsed();
self.zip_writer
.start_file("metaData.json", SimpleFileOptions::default())?;
self.zip_writer.write_all(
json!({
"singleplayer": false,
"serverName": self.server,
"duration": elapsed.as_millis(),
"date": (SystemTime::now().duration_since(UNIX_EPOCH)? - elapsed).as_millis(),
"mcversion": VERSION_NAME,
"fileFormat": "MCPR",
"fileFormatVersion": 14,
"protocol": PROTOCOL_VERSION,
"generator": format!("errornowatcher {}", build_info::version_formatted()),
})
.to_string()
.as_bytes(),
)?;
self.zip_writer.finish()?;
Ok(())
}
fn get_timestamp(&self) -> Result<[u8; 4]> {
Ok(TryInto::<u32>::try_into(self.start.elapsed().as_millis())?.to_be_bytes())
}
fn save_raw_packet(&mut self, raw_packet: &[u8]) -> Result<()> {
let mut data = Vec::with_capacity(raw_packet.len() + 8);
data.extend(self.get_timestamp()?);
data.extend(&TryInto::<u32>::try_into(raw_packet.len())?.to_be_bytes());
data.extend(raw_packet);
self.zip_writer.write_all(&data)?;
Ok(())
}
fn save_packet<T: ProtocolPacket>(&mut self, packet: &T) -> Result<()> {
let mut raw_packet = SmallVec::<[u8; 256]>::new();
packet.id().azalea_write_var(&mut raw_packet)?;
packet.write(&mut raw_packet)?;
self.save_raw_packet(&raw_packet)
}
}
pub mod recorder;

View File

@ -1,4 +1,4 @@
use super::Recorder;
use super::recorder::Recorder;
use azalea::{
ecs::{event::EventReader, system::Query},
packet_handling::{
@ -36,7 +36,7 @@ fn record_login_packets(
) {
if let Some(mut recorder) = recorder {
for event in events.read() {
if recorder.ignore_compression
if recorder.should_ignore_compression
&& let ClientboundLoginPacket::LoginCompression(_) = *event.packet
{
continue;

87
src/replay/recorder.rs Normal file
View File

@ -0,0 +1,87 @@
use crate::build_info;
use anyhow::Result;
use azalea::{
buf::AzaleaWriteVar,
prelude::Resource,
protocol::packets::{PROTOCOL_VERSION, ProtocolPacket, VERSION_NAME},
};
use serde_json::json;
use smallvec::SmallVec;
use std::{
fs::File,
io::Write,
time::{Instant, SystemTime, UNIX_EPOCH},
};
use zip::{ZipWriter, write::SimpleFileOptions};
#[derive(Resource)]
pub struct Recorder {
zip_writer: ZipWriter<File>,
start: Instant,
server: String,
pub should_ignore_compression: bool,
}
impl Recorder {
pub fn new(path: String, server: String, should_ignore_compression: bool) -> Result<Self> {
let mut zip_writer = ZipWriter::new(
File::options()
.write(true)
.create(true)
.truncate(true)
.open(path)?,
);
zip_writer.start_file("recording.tmcpr", SimpleFileOptions::default())?;
Ok(Self {
zip_writer,
start: Instant::now(),
server,
should_ignore_compression,
})
}
pub fn finish(mut self) -> Result<()> {
let elapsed = self.start.elapsed();
self.zip_writer
.start_file("metaData.json", SimpleFileOptions::default())?;
self.zip_writer.write_all(
json!({
"singleplayer": false,
"serverName": self.server,
"duration": elapsed.as_millis(),
"date": (SystemTime::now().duration_since(UNIX_EPOCH)? - elapsed).as_millis(),
"mcversion": VERSION_NAME,
"fileFormat": "MCPR",
"fileFormatVersion": 14,
"protocol": PROTOCOL_VERSION,
"generator": format!("errornowatcher {}", build_info::version_formatted()),
})
.to_string()
.as_bytes(),
)?;
self.zip_writer.finish()?;
Ok(())
}
fn get_timestamp(&self) -> Result<[u8; 4]> {
Ok(TryInto::<u32>::try_into(self.start.elapsed().as_millis())?.to_be_bytes())
}
pub fn save_raw_packet(&mut self, raw_packet: &[u8]) -> Result<()> {
let mut data = Vec::with_capacity(raw_packet.len() + 8);
data.extend(self.get_timestamp()?);
data.extend(&TryInto::<u32>::try_into(raw_packet.len())?.to_be_bytes());
data.extend(raw_packet);
self.zip_writer.write_all(&data)?;
Ok(())
}
pub fn save_packet<T: ProtocolPacket>(&mut self, packet: &T) -> Result<()> {
let mut raw_packet = SmallVec::<[u8; 256]>::new();
packet.id().azalea_write_var(&mut raw_packet)?;
packet.write(&mut raw_packet)?;
self.save_raw_packet(&raw_packet)
}
}