use std::{
hash::{Hash, Hasher},
marker::PhantomData,
};
use bevy::prelude::*;
use crate::{SaveWorld, SaveWorldSystems, checksum_hasher};
#[derive(Component)]
pub struct ChecksumFlag<T> {
_phantom: PhantomData<T>,
}
impl<T> Default for ChecksumFlag<T> {
fn default() -> Self {
Self {
_phantom: default(),
}
}
}
#[derive(Component, Default, Hash)]
pub struct ChecksumPart(pub u128);
impl ChecksumPart {
pub fn from_value<T: Hash>(value: &T) -> Self {
let mut hasher = checksum_hasher();
value.hash(&mut hasher);
Self(hasher.finish() as u128)
}
}
#[derive(Resource, Default, Clone, Copy)]
pub struct Checksum(pub u128);
pub struct ChecksumPlugin;
impl ChecksumPlugin {
pub fn update(mut checksum: ResMut<Checksum>, parts: Query<&ChecksumPart>) {
let parts = parts.iter().fold(0, |a: u128, &ChecksumPart(b)| a ^ b);
trace!("Frame has checksum {:X}", parts);
*checksum = Checksum(parts);
}
}
#[cfg(test)]
mod tests {
use super::ChecksumPart;
#[test]
fn from_value_is_deterministic() {
let a = ChecksumPart::from_value(&42u32);
let b = ChecksumPart::from_value(&42u32);
assert_eq!(a.0, b.0);
}
}
impl Plugin for ChecksumPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<Checksum>().add_systems(
SaveWorld,
Self::update
.after(SaveWorldSystems::Checksum)
.before(SaveWorldSystems::Snapshot),
);
}
}