Files
skate-3-rust-engine/crates/skate-net/tests/application.rs
T
Ethanw05andCursor e2b85b6489 Fix remote player irradiance and retail renderer updates.
Apply probe SH to online customiser characters after remote bind, restore received sun shadows, and ship Skyline driving, fullscreen, and renderer improvements on the branch.

Co-authored-by: Cursor <[email protected]>
2026-09-12 20:05:27 -06:00

134 lines
4.4 KiB
Rust

use skate_net::{
lobby::{APPLICATION, Info, MAX_APP_KEYS, Session},
packed,
};
fn info(id: u64) -> Info {
Info {
id,
map: 1,
rig: 2,
physics: 3,
appearance: 4,
}
}
fn pump(host: &mut Session, guests: &mut [Session], now: u64, loss: bool) {
for (i, g) in guests.iter_mut().enumerate() {
for (n, p) in g.service(now).into_iter().enumerate() {
if !loss || (now / 50 + n as u64) % 3 != 0 {
host.receive(i as u64 + 10, &p.data, now);
}
}
}
for (n, p) in host.service(now).into_iter().enumerate() {
assert!(p.data.len() <= packed::MTU);
if !loss || (now / 50 + n as u64) % 4 != 0 {
if let Some(g) = guests.get_mut((p.peer - 10) as usize) {
g.receive(1, &p.data, now);
}
}
}
}
#[test]
fn owner_state_recovers_loss_late_join_and_tombstones() {
let mut h = Session::new(7, info(1), None);
let mut g = vec![Session::new(7, info(2), Some(1))];
assert!(g[0].publish_application("obj", b"spawned".to_vec(), 0));
for t in (0..2000).step_by(50) {
pump(&mut h, &mut g, t, true);
}
assert_eq!(h.actors[&2].application["obj"].value, b"spawned");
g.push(Session::new(7, info(3), Some(1)));
for t in (2000..4000).step_by(50) {
pump(&mut h, &mut g, t, true);
}
assert_eq!(g[1].actors[&2].application["obj"].value, b"spawned");
g[0].publish_application("obj", vec![], 4000);
for t in (4000..6000).step_by(50) {
pump(&mut h, &mut g, t, true);
}
assert!(g[1].actors[&2].application["obj"].value.is_empty());
for p in g[0].goodbye() {
h.receive(10, &p.data, 6000);
}
// Only the second guest remains; service it without reviving the first.
for t in (6000..7000).step_by(50) {
for p in g[1].service(t) {
h.receive(11, &p.data, t);
}
for p in h.service(t) {
if p.peer == 11 {
g[1].receive(1, &p.data, t);
}
}
}
assert!(!g[1].actors.contains_key(&2));
}
fn wire(actor: u64, seq: u32, key: &str, value: &[u8]) -> Vec<u8> {
let mut b = packed::header(7, actor, APPLICATION, seq);
b.push(key.len() as u8);
b.extend(key.as_bytes());
b.extend(value);
b
}
#[test]
fn spoofed_owners_old_updates_and_oversized_records_are_rejected() {
let mut h = Session::new(7, info(1), None);
let mut g = vec![
Session::new(7, info(2), Some(1)),
Session::new(7, info(3), Some(1)),
];
for t in (0..1000).step_by(50) {
pump(&mut h, &mut g, t, false);
}
h.receive(10, &wire(3, 10, "state", b"forged"), 1000);
assert!(h.actors[&3].application.is_empty());
h.receive(10, &wire(2, 5, "state", b"new"), 1000);
h.receive(10, &wire(2, 4, "state", b"old"), 1001);
assert_eq!(h.actors[&2].application["state"].value, b"new");
h.receive(10, &wire(2, 6, "state", &vec![0; 1025]), 1002);
assert_eq!(h.actors[&2].application["state"].value, b"new");
assert!(!h.publish_application("big", vec![0; 1025], 0));
for i in 0..MAX_APP_KEYS {
assert!(h.publish_application(&format!("k{i}"), vec![1], 0));
}
assert!(!h.publish_application("overflow", vec![], 0));
assert!(h.publish_application("k0", vec![], 0));
}
#[test]
fn many_application_records_eventually_reach_every_player() {
let mut h = Session::new(7, info(1), None);
let mut g: Vec<_> = (2..=10)
.map(|id| Session::new(7, info(id), Some(1)))
.collect();
for (i, g) in g.iter_mut().enumerate() {
for k in 0..24 {
assert!(g.publish_application(&format!("object{k}"), vec![i as u8; 900], 0));
}
}
for t in (0..30000).step_by(50) {
pump(&mut h, &mut g, t, true);
}
for guest in &g {
assert_eq!(guest.actors.len(), 10);
for (&id, a) in &guest.actors {
if id != 1 {
assert_eq!(a.application.len(), 24, "peer {} actor {id}", guest.local);
}
}
}
}
#[test]
fn loopback_bursts_an_unacked_application_snapshot() {
let mut h = Session::new(7, info(1), None);
h.set_loopback(true);
let mut g = vec![Session::new(7, info(2), Some(1))];
g[0].set_loopback(true);
for k in 0..64 {
assert!(g[0].publish_application(&format!("k{k:02}"), vec![k as u8; 900], 0));
}
for t in (0..80).step_by(16) {
pump(&mut h, &mut g, t, false);
}
assert_eq!(h.actors[&2].application.len(), 64);
}