pub const MAX_MIRROR_ENTITIES: usize = 65536;
#[derive(Debug, Default)]
pub struct ClientMirror {
pub positions: Vec<[f32; 3]>,
pub rotations: Vec<[f32; 4]>,
pub entity_count: usize,
pub tick: u64,
pub(crate) pending_despawns: Vec<usize>,
}
impl ClientMirror {
pub fn new() -> Self {
Self::default()
}
pub fn apply_snapshot(&mut self, positions: Vec<[f32; 3]>, rotations: Vec<[f32; 4]>) {
let cap = positions.len().min(MAX_MIRROR_ENTITIES);
self.entity_count = cap;
self.positions = positions;
self.positions.truncate(cap);
self.rotations = rotations;
self.rotations.truncate(cap);
}
pub fn advance_tick(&mut self) {
self.tick += 1;
}
pub(crate) fn queue_despawn(&mut self, slot: usize) {
self.pending_despawns.push(slot);
}
pub(crate) fn flush_despawns(&mut self) {
self.pending_despawns.sort_unstable();
self.pending_despawns.dedup();
for &slot in self.pending_despawns.iter().rev() {
if slot < self.positions.len() {
self.positions.swap_remove(slot);
self.rotations.swap_remove(slot);
}
}
self.entity_count = self.positions.len();
self.pending_despawns.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_mirror() {
let m = ClientMirror::new();
assert_eq!(m.entity_count, 0);
assert_eq!(m.tick, 0);
}
#[test]
fn apply_snapshot() {
let mut m = ClientMirror::new();
m.apply_snapshot(vec![[1.0, 2.0, 3.0]], vec![[0.0, 0.0, 0.0, 1.0]]);
assert_eq!(m.entity_count, 1);
}
#[test]
fn snapshot_respects_cap() {
let mut m = ClientMirror::new();
let big: Vec<[f32; 3]> = (0..MAX_MIRROR_ENTITIES + 100).map(|i| [i as f32, 0.0, 0.0]).collect();
let rots: Vec<[f32; 4]> = vec![[0.0, 0.0, 0.0, 1.0]; big.len()];
m.apply_snapshot(big, rots);
assert_eq!(m.entity_count, MAX_MIRROR_ENTITIES);
assert_eq!(m.positions.len(), MAX_MIRROR_ENTITIES);
}
#[test]
fn deferred_despawn_reverse_order() {
let mut m = ClientMirror::new();
m.positions = vec![[0.0; 3]; 5];
m.rotations = vec![[0.0, 0.0, 0.0, 1.0]; 5];
m.entity_count = 5;
m.queue_despawn(1);
m.queue_despawn(3);
m.flush_despawns();
assert_eq!(m.entity_count, 3);
}
}