Replay check version from header
This commit is contained in:
parent
d34eb0bd33
commit
d2aded9e44
@ -135,6 +135,10 @@ impl StandaloneReplayManager {
|
||||
|
||||
thread::spawn(move || match fs::read(path) {
|
||||
Ok(mut bytes) => {
|
||||
if let Err(e) = read_header(&mut bytes) {
|
||||
return send.send(ReplayReadEvent::Error(e.to_string()));
|
||||
}
|
||||
|
||||
let cursor = Cursor::new(&mut bytes);
|
||||
let decoder = GzDecoder::new(cursor);
|
||||
|
||||
@ -665,6 +669,7 @@ impl ReplayRecorder {
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend(produce_header());
|
||||
let encoder = GzEncoder::new(&mut bytes, Compression::default());
|
||||
match ciborium::into_writer(&replay, encoder) {
|
||||
Ok(_) => match fs::write(path, bytes) {
|
||||
@ -928,3 +933,102 @@ pub struct ReplayTriggerableState {
|
||||
active: Option<u16>,
|
||||
active_for: f64,
|
||||
}
|
||||
|
||||
const GAME_NAME: &str = "skullball";
|
||||
const MAJOR: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_MAJOR"), 10) {
|
||||
Ok(res) => res,
|
||||
Err(_) => 0,
|
||||
};
|
||||
const MINOR: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_MINOR"), 10) {
|
||||
Ok(res) => res,
|
||||
Err(_) => 0,
|
||||
};
|
||||
const PATCH: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_PATCH"), 10) {
|
||||
Ok(res) => res,
|
||||
Err(_) => 0,
|
||||
};
|
||||
const VERSION: Version = Version {
|
||||
major: MAJOR,
|
||||
minor: MINOR,
|
||||
patch: PATCH,
|
||||
};
|
||||
|
||||
fn produce_header() -> Vec<u8> {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
bytes.extend(GAME_NAME.as_bytes());
|
||||
bytes.push(MAJOR);
|
||||
bytes.push(MINOR);
|
||||
bytes.push(PATCH);
|
||||
bytes
|
||||
}
|
||||
|
||||
fn read_header(bytes: &mut Vec<u8>) -> Result<(), HeaderReadError> {
|
||||
if bytes.len() < (GAME_NAME.len() + 3) {
|
||||
return Err(HeaderReadError::ReadIncomplete);
|
||||
}
|
||||
|
||||
let mut name_bytes = Vec::with_capacity(GAME_NAME.len());
|
||||
for _ in 0..GAME_NAME.len() {
|
||||
name_bytes.push(bytes.remove(0));
|
||||
}
|
||||
let name = String::from_utf8(name_bytes).map_err(|_| HeaderReadError::InvalidTitle)?;
|
||||
if name != GAME_NAME {
|
||||
return Err(HeaderReadError::InvalidTitle);
|
||||
}
|
||||
|
||||
let major = bytes.remove(0);
|
||||
let minor = bytes.remove(0);
|
||||
let patch = bytes.remove(0);
|
||||
let version = Version {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
};
|
||||
if version != VERSION {
|
||||
return Err(HeaderReadError::InvalidVersion(version));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub enum HeaderReadError {
|
||||
ReadIncomplete,
|
||||
InvalidTitle,
|
||||
InvalidVersion(Version),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for HeaderReadError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
HeaderReadError::ReadIncomplete => {
|
||||
write!(f, "Header read incomplete, invalid replay file")
|
||||
}
|
||||
HeaderReadError::InvalidTitle => {
|
||||
write!(f, "Invalid title in header, invalid replay file")
|
||||
}
|
||||
HeaderReadError::InvalidVersion(version) => write!(
|
||||
f,
|
||||
"Replay game version mismatch: {} != {}",
|
||||
version, VERSION
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd, Eq)]
|
||||
pub struct Version {
|
||||
pub major: u8,
|
||||
pub minor: u8,
|
||||
pub patch: u8,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Version {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.major, f)?;
|
||||
write!(f, ".")?;
|
||||
std::fmt::Display::fmt(&self.minor, f)?;
|
||||
write!(f, ".")?;
|
||||
std::fmt::Display::fmt(&self.patch, f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user