1use std::collections::BTreeMap;
26
27use crate::varint;
28use crate::{ComponentId, EntityId};
29
30pub const VERSION: u8 = 1;
31pub const FLAG_FULL: u8 = 1;
32
33pub mod mask {
35 pub const X: u8 = 1;
36 pub const Y: u8 = 2;
37 pub const Z: u8 = 4;
38 pub const COMPONENTS: u8 = 8;
39}
40
41pub fn quantize(value: f32, precision: f32) -> i64 {
43 if !value.is_finite() {
44 return 0;
45 }
46 let q = (value as f64 / precision as f64).round();
47 q.clamp(i64::MIN as f64, i64::MAX as f64) as i64
48}
49
50pub fn quantize3(pos: [f32; 3], precision: f32) -> [i64; 3] {
51 pos.map(|v| quantize(v, precision))
52}
53
54pub type ComponentChange<'a> = (ComponentId, Option<&'a [u8]>);
56
57pub fn encode_update_body(delta: [i64; 3], components: &[ComponentChange<'_>]) -> Vec<u8> {
60 let mut body = Vec::with_capacity(8);
61 encode_update_body_into(&mut body, delta, components);
62 body
63}
64
65pub fn encode_update_body_into(
67 body: &mut Vec<u8>,
68 delta: [i64; 3],
69 components: &[ComponentChange<'_>],
70) {
71 let mut m = 0u8;
72 for (i, bit) in [mask::X, mask::Y, mask::Z].into_iter().enumerate() {
73 if delta[i] != 0 {
74 m |= bit;
75 }
76 }
77 if !components.is_empty() {
78 m |= mask::COMPONENTS;
79 }
80 body.push(m);
81 for d in delta {
82 if d != 0 {
83 varint::write_i64(body, d);
84 }
85 }
86 if !components.is_empty() {
87 write_components(body, components.iter().copied());
88 }
89}
90
91fn write_components<'a>(
92 out: &mut Vec<u8>,
93 components: impl ExactSizeIterator<Item = ComponentChange<'a>>,
94) {
95 varint::write_u64(out, components.len() as u64);
96 for (id, bytes) in components {
97 out.push(id);
98 match bytes {
99 Some(b) => {
100 varint::write_u64(out, b.len() as u64 + 1);
101 out.extend_from_slice(b);
102 }
103 None => varint::write_u64(out, 0),
104 }
105 }
106}
107
108#[derive(Debug)]
111pub struct FrameBuilder {
112 full: bool,
113 precision: f32,
114 despawns: Vec<EntityId>,
115 spawns: Vec<u8>,
116 spawn_count: u64,
117 last_spawn: Option<EntityId>,
118 updates: Vec<u8>,
119 update_count: u64,
120 last_update: Option<EntityId>,
121}
122
123impl FrameBuilder {
124 pub fn new(full: bool, precision: f32) -> Self {
125 Self {
126 full,
127 precision,
128 despawns: Vec::new(),
129 spawns: Vec::new(),
130 spawn_count: 0,
131 last_spawn: None,
132 updates: Vec::new(),
133 update_count: 0,
134 last_update: None,
135 }
136 }
137
138 pub fn despawn(&mut self, id: EntityId) {
139 self.despawns.push(id);
140 }
141
142 pub fn spawn<'a>(
144 &mut self,
145 id: EntityId,
146 q: [i64; 3],
147 components: impl ExactSizeIterator<Item = (ComponentId, &'a [u8])>,
148 ) {
149 write_delta_id(&mut self.spawns, &mut self.last_spawn, id);
150 for v in q {
151 varint::write_i64(&mut self.spawns, v);
152 }
153 write_components(&mut self.spawns, components.map(|(c, b)| (c, Some(b))));
154 self.spawn_count += 1;
155 }
156
157 pub fn update(&mut self, id: EntityId, body: &[u8]) {
160 write_delta_id(&mut self.updates, &mut self.last_update, id);
161 self.updates.extend_from_slice(body);
162 self.update_count += 1;
163 }
164
165 pub fn is_empty(&self) -> bool {
166 !self.full && self.despawns.is_empty() && self.spawn_count == 0 && self.update_count == 0
167 }
168
169 pub fn finish(mut self) -> Vec<u8> {
171 self.despawns.sort_unstable();
172 self.despawns.dedup();
173 let mut out = Vec::with_capacity(16 + self.spawns.len() + self.updates.len());
174 out.push(VERSION);
175 out.push(if self.full { FLAG_FULL } else { 0 });
176 out.extend_from_slice(&self.precision.to_le_bytes());
177 varint::write_u64(&mut out, self.despawns.len() as u64);
178 let mut last = None;
179 for id in &self.despawns {
180 write_delta_id(&mut out, &mut last, *id);
181 }
182 varint::write_u64(&mut out, self.spawn_count);
183 out.extend_from_slice(&self.spawns);
184 varint::write_u64(&mut out, self.update_count);
185 out.extend_from_slice(&self.updates);
186 out
187 }
188}
189
190fn write_delta_id(out: &mut Vec<u8>, last: &mut Option<EntityId>, id: EntityId) {
191 match *last {
192 Some(prev) => {
193 debug_assert!(id > prev, "ids must ascend");
194 varint::write_u64(out, id.wrapping_sub(prev));
195 }
196 None => varint::write_u64(out, id),
197 }
198 *last = Some(id);
199}
200
201#[derive(Debug, Clone, PartialEq, Eq)]
207pub struct DecodeError(pub String);
208
209impl std::fmt::Display for DecodeError {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 f.write_str(&self.0)
212 }
213}
214
215impl std::error::Error for DecodeError {}
216
217#[derive(Debug, Clone, Default, PartialEq)]
219pub struct ReplicaEntity {
220 pub q: [i64; 3],
222 pub components: BTreeMap<ComponentId, Vec<u8>>,
223}
224
225impl ReplicaEntity {
226 pub fn pos(&self, precision: f32) -> [f32; 3] {
227 self.q.map(|v| (v as f64 * precision as f64) as f32)
228 }
229}
230
231#[derive(Debug, Clone, Default, PartialEq, Eq)]
233pub struct FrameSummary {
234 pub full: bool,
235 pub spawned: Vec<EntityId>,
236 pub updated: Vec<EntityId>,
237 pub despawned: Vec<EntityId>,
238}
239
240#[derive(Debug, Clone, Default, PartialEq)]
242pub struct ReplicaTable {
243 pub entities: BTreeMap<EntityId, ReplicaEntity>,
244 pub precision: f32,
245 pub spawn_ticks: BTreeMap<EntityId, u64>,
249 pub datagram_frames: BTreeMap<EntityId, u64>,
251 pub stream_tick: u64,
255}
256
257const MAX_COUNT: u64 = 1 << 24;
260
261impl ReplicaTable {
262 pub fn new() -> Self {
263 Self::default()
264 }
265
266 pub fn pos(&self, id: EntityId) -> Option<[f32; 3]> {
267 self.entities.get(&id).map(|e| e.pos(self.precision))
268 }
269
270 pub fn apply(&mut self, frame: &[u8]) -> Result<FrameSummary, DecodeError> {
273 self.apply_inner(frame, None)
274 }
275
276 pub fn apply_stream(&mut self, frame: &[u8], tick: u64) -> Result<FrameSummary, DecodeError> {
283 self.apply_inner(frame, Some(tick))
284 }
285
286 fn apply_inner(
287 &mut self,
288 frame: &[u8],
289 tick: Option<u64>,
290 ) -> Result<FrameSummary, DecodeError> {
291 let err = |m: &str| DecodeError(m.to_string());
292 let mut b = frame;
293 let take = |b: &mut &[u8], n: usize| -> Result<Vec<u8>, DecodeError> {
294 if b.len() < n {
295 return Err(DecodeError("frame ends early".into()));
296 }
297 let (head, rest) = b.split_at(n);
298 *b = rest;
299 Ok(head.to_vec())
300 };
301 let head = take(&mut b, 6)?;
302 if head[0] != VERSION {
303 return Err(DecodeError(format!("replication version {}", head[0])));
304 }
305 let full = head[1] & FLAG_FULL != 0;
306 let precision = f32::from_le_bytes(head[2..6].try_into().unwrap());
307 if !(precision.is_finite() && precision > 0.0) {
308 return Err(err("bad precision"));
309 }
310 if full {
311 self.entities.clear();
312 self.datagram_frames.clear();
313 self.spawn_ticks.clear();
314 }
315 self.precision = precision;
316 let mut summary = FrameSummary {
317 full,
318 ..FrameSummary::default()
319 };
320 let count = |b: &mut &[u8]| -> Result<u64, DecodeError> {
321 let n = varint::read_u64(b).ok_or_else(|| err("bad count"))?;
322 if n > MAX_COUNT {
323 return Err(err("count too large"));
324 }
325 Ok(n)
326 };
327 let next_id =
328 |b: &mut &[u8], last: &mut Option<EntityId>| -> Result<EntityId, DecodeError> {
329 let v = varint::read_u64(b).ok_or_else(|| err("bad id"))?;
330 let id = match *last {
331 Some(prev) => prev
332 .checked_add(v)
333 .filter(|_| v > 0)
334 .ok_or_else(|| err("ids do not ascend"))?,
335 None => v,
336 };
337 *last = Some(id);
338 Ok(id)
339 };
340
341 let n = count(&mut b)?;
342 let mut last = None;
343 for _ in 0..n {
344 let id = next_id(&mut b, &mut last)?;
345 self.entities.remove(&id);
346 self.datagram_frames.remove(&id);
347 self.spawn_ticks.remove(&id);
348 summary.despawned.push(id);
349 }
350
351 let n = count(&mut b)?;
352 let mut last = None;
353 for _ in 0..n {
354 let id = next_id(&mut b, &mut last)?;
355 let mut q = [0i64; 3];
356 for v in &mut q {
357 *v = varint::read_i64(&mut b).ok_or_else(|| err("bad position"))?;
358 }
359 let mut entity = ReplicaEntity {
360 q,
361 components: BTreeMap::new(),
362 };
363 read_components(&mut b, &mut entity.components)?;
364 self.entities.insert(id, entity);
365 self.datagram_frames.remove(&id);
366 match tick {
367 Some(t) => self.spawn_ticks.insert(id, t),
368 None => self.spawn_ticks.remove(&id),
369 };
370 summary.spawned.push(id);
371 }
372
373 let n = count(&mut b)?;
374 let mut last = None;
375 for _ in 0..n {
376 let id = next_id(&mut b, &mut last)?;
377 let (&m, rest) = b.split_first().ok_or_else(|| err("frame ends early"))?;
378 b = rest;
379 let entity = self
380 .entities
381 .get_mut(&id)
382 .ok_or_else(|| DecodeError(format!("update for unknown entity {id}")))?;
383 for (i, bit) in [mask::X, mask::Y, mask::Z].into_iter().enumerate() {
384 if m & bit != 0 {
385 let d = varint::read_i64(&mut b).ok_or_else(|| err("bad delta"))?;
386 entity.q[i] = entity.q[i].wrapping_add(d);
387 }
388 }
389 if m & mask::COMPONENTS != 0 {
390 read_components(&mut b, &mut entity.components)?;
391 }
392 summary.updated.push(id);
393 }
394 if !b.is_empty() {
395 return Err(err("trailing bytes"));
396 }
397 if let Some(t) = tick {
398 self.stream_tick = t;
399 }
400 Ok(summary)
401 }
402}
403
404fn read_components(
405 b: &mut &[u8],
406 into: &mut BTreeMap<ComponentId, Vec<u8>>,
407) -> Result<(), DecodeError> {
408 let err = |m: &str| DecodeError(m.to_string());
409 let n = varint::read_u64(b).ok_or_else(|| err("bad component count"))?;
410 if n > 256 {
411 return Err(err("more than 256 components"));
412 }
413 for _ in 0..n {
414 let (&id, rest) = b.split_first().ok_or_else(|| err("frame ends early"))?;
415 *b = rest;
416 let len = varint::read_u64(b).ok_or_else(|| err("bad component length"))?;
417 if len == 0 {
418 into.remove(&id);
419 continue;
420 }
421 let len = usize::try_from(len - 1).map_err(|_| err("component too large"))?;
422 if b.len() < len {
423 return Err(err("component runs past the end"));
424 }
425 let (value, rest) = b.split_at(len);
426 *b = rest;
427 into.insert(id, value.to_vec());
428 }
429 Ok(())
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435
436 #[test]
437 fn spawn_update_despawn_round_trip() {
438 let p = 0.1;
439 let mut f = FrameBuilder::new(true, p);
440 f.spawn(
441 3,
442 quantize3([1.0, 2.0, 0.0], p),
443 [(1u8, &b"hp"[..])].into_iter(),
444 );
445 f.spawn(10, quantize3([-5.0, 0.0, 0.0], p), std::iter::empty());
446 let mut t = ReplicaTable::new();
447 let s = t.apply(&f.finish()).unwrap();
448 assert!(s.full);
449 assert_eq!(s.spawned, vec![3, 10]);
450 assert_eq!(t.pos(3), Some([1.0, 2.0, 0.0]));
451 assert_eq!(t.entities[&3].components[&1], b"hp");
452
453 let mut f = FrameBuilder::new(false, p);
454 f.update(
455 3,
456 &encode_update_body([5, 0, 0], &[(1, None), (2, Some(b"new"))]),
457 );
458 f.update(10, &encode_update_body([0, -20, 0], &[]));
459 f.despawn(99);
460 let s = t.apply(&f.finish()).unwrap();
461 assert_eq!(s.updated, vec![3, 10]);
462 let pos3 = t.pos(3).unwrap();
463 assert!((pos3[0] - 1.5).abs() < 1e-6);
464 assert!(!t.entities[&3].components.contains_key(&1));
465 assert_eq!(t.entities[&3].components[&2], b"new");
466 assert_eq!(t.pos(10), Some([-5.0, -2.0, 0.0]));
467
468 let mut f = FrameBuilder::new(false, p);
469 f.despawn(10);
470 t.apply(&f.finish()).unwrap();
471 assert!(!t.entities.contains_key(&10));
472 }
473
474 #[test]
475 fn an_unchanged_entity_update_is_two_bytes_plus_the_id() {
476 let body = encode_update_body([3, -2, 0], &[]);
477 assert_eq!(body.len(), 3); }
479
480 #[test]
481 fn hostile_frames_are_refused_without_panicking() {
482 let mut t = ReplicaTable::new();
483 assert!(t.apply(&[]).is_err());
484 assert!(t.apply(&[2, 0, 0, 0, 0x80, 0x3f]).is_err()); assert!(t.apply(&[1, 0, 0, 0, 0, 0]).is_err()); let head = |extra: &[u8]| {
487 let mut v = vec![1, 0];
488 v.extend_from_slice(&1.0f32.to_le_bytes());
489 v.extend_from_slice(extra);
490 v
491 };
492 assert!(t.apply(&head(&[0xff, 0xff, 0xff, 0xff, 0x0f])).is_err());
494 assert!(t.apply(&head(&[0, 0, 1, 7, 0])).is_err());
496 assert!(t.apply(&head(&[2, 5, 0, 0, 0])).is_err());
498 assert!(t.apply(&head(&[0, 0, 0, 9])).is_err());
500 assert!(t.apply(&head(&[0, 1, 1, 0, 0, 0, 1, 4, 50, 1])).is_err());
502 }
503
504 #[test]
505 fn quantize_handles_bad_values() {
506 assert_eq!(quantize(f32::NAN, 0.1), 0);
507 assert_eq!(quantize(f32::INFINITY, 0.1), 0);
508 assert_eq!(quantize(f32::MAX, 1e-30), i64::MAX);
509 assert_eq!(quantize(-0.04, 0.1), 0);
510 assert_eq!(quantize(0.26, 0.1), 3);
511 }
512}