gameplay: integrate queried fallback spawn selection
Browse files- crates/urt-gameplay/src/bin/urt-camera-world.rs +84 -0
- crates/urt-gameplay/src/camera_world.rs +119 -1
- docs/FINDINGS.md +3 -0
- docs/PROVISIONAL_TODO.md +3 -0
- docs/RESEARCH_LEDGER.md +5 -0
- docs/REVERSE_ENGINEERING_TODO.md +3 -0
- docs/research/README.md +3 -0
- docs/research/RUST_QUERIED_SPAWN.md +7 -0
- docs/research/rust-health-impulse.json +1 -1
- docs/research/rust-queried-spawn.json +0 -0
- scripts/analyze_rust_queried_spawn.py +19 -0
- scripts/test_rust_queried_spawn.py +9 -0
- xtask/checks.tsv +15 -0
crates/urt-gameplay/src/bin/urt-camera-world.rs
CHANGED
|
@@ -305,6 +305,65 @@ fn run() -> Result<String, String> {
|
|
| 305 |
}
|
| 306 |
}
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
"spawn-camera" => {
|
| 309 |
if w.len() < 9 || w[1] > 1 || w[2] > 1024 {
|
| 310 |
return Err("invalid camera header".into());
|
|
@@ -536,3 +595,28 @@ fn spawn_records(w: &[u32], p: &mut usize, n: usize) -> Result<Vec<SpawnEntity>,
|
|
| 536 |
}
|
| 537 |
Ok(c)
|
| 538 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
}
|
| 306 |
}
|
| 307 |
|
| 308 |
+
"queried-spawn" => {
|
| 309 |
+
if w.len() < 5 || w[4] > 1024 {
|
| 310 |
+
return Err("invalid spawn header".into());
|
| 311 |
+
}
|
| 312 |
+
let mut state = w[0];
|
| 313 |
+
let avoid = w[1..4].try_into().unwrap();
|
| 314 |
+
let n = w[4] as usize;
|
| 315 |
+
let mut p = 5;
|
| 316 |
+
let world = spawn_records(&w, &mut p, n)?;
|
| 317 |
+
let bound_words = w.get(p..p + 6).ok_or("missing query bounds")?;
|
| 318 |
+
p += 6;
|
| 319 |
+
let bounds = std::array::from_fn(|h| {
|
| 320 |
+
std::array::from_fn(|j| f32::from_bits(bound_words[h * 3 + j]))
|
| 321 |
+
});
|
| 322 |
+
let profile = *w.get(p).ok_or("missing query profile")?;
|
| 323 |
+
p += 1;
|
| 324 |
+
let mut queries = vec![];
|
| 325 |
+
let mut client_words = vec![0; 1024];
|
| 326 |
+
client_words[901] = u32::MAX;
|
| 327 |
+
let mut math = math_calls(&w, &mut p)?;
|
| 328 |
+
if p != w.len() {
|
| 329 |
+
return Err("trailing spawn words".into());
|
| 330 |
+
}
|
| 331 |
+
let r = fallback_spawn_queried(
|
| 332 |
+
&world,
|
| 333 |
+
avoid,
|
| 334 |
+
&mut state,
|
| 335 |
+
&mut math,
|
| 336 |
+
SpawnQueryWorld {
|
| 337 |
+
bounds,
|
| 338 |
+
client_words: &client_words,
|
| 339 |
+
},
|
| 340 |
+
|j, b| {
|
| 341 |
+
let indices = query_results(j, profile);
|
| 342 |
+
queries.push(query_json(j, b, &indices));
|
| 343 |
+
Ok(indices)
|
| 344 |
+
},
|
| 345 |
+
);
|
| 346 |
+
math.finish().map_err(|e| format!("{e:?}"))?;
|
| 347 |
+
let payload = match r {
|
| 348 |
+
Ok(r) => Ok(format!(
|
| 349 |
+
"{{\"result\":{},\"rng_state\":{state},\"fatal\":false,\"candidates\":{},\"distances\":{},\"origin\":{},\"angles\":{}}}",
|
| 350 |
+
r.index,
|
| 351 |
+
array(&r.candidates.iter().map(|j| *j as u32).collect::<Vec<_>>()),
|
| 352 |
+
array(&r.distances),
|
| 353 |
+
array(&r.view.origin),
|
| 354 |
+
array(&r.view.angles)
|
| 355 |
+
)),
|
| 356 |
+
Err(Error::NoSpawn) => Ok(format!(
|
| 357 |
+
"{{\"result\":-1,\"rng_state\":{state},\"fatal\":true,\"candidates\":[],\"distances\":[],\"origin\":[305419896,305419896,305419896],\"angles\":[305419896,305419896,305419896]}}"
|
| 358 |
+
)),
|
| 359 |
+
Err(e) => Err(format!("{e:?}")),
|
| 360 |
+
}?;
|
| 361 |
+
Ok(format!(
|
| 362 |
+
"{{\"queries\":[{}],\"selection\":{payload}}}",
|
| 363 |
+
queries.join(",")
|
| 364 |
+
))
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
"spawn-camera" => {
|
| 368 |
if w.len() < 9 || w[1] > 1 || w[2] > 1024 {
|
| 369 |
return Err("invalid camera header".into());
|
|
|
|
| 595 |
}
|
| 596 |
Ok(c)
|
| 597 |
}
|
| 598 |
+
|
| 599 |
+
fn query_results(j: usize, profile: u32) -> Vec<usize> {
|
| 600 |
+
match profile {
|
| 601 |
+
0 => vec![],
|
| 602 |
+
1 => vec![900],
|
| 603 |
+
2 => vec![900, 901],
|
| 604 |
+
_ => {
|
| 605 |
+
if j % 2 == 1 {
|
| 606 |
+
vec![901]
|
| 607 |
+
} else {
|
| 608 |
+
vec![900, 900]
|
| 609 |
+
}
|
| 610 |
+
}
|
| 611 |
+
}
|
| 612 |
+
}
|
| 613 |
+
fn query_json(j: usize, b: urt_gameplay::native_policy::SpawnBox, indices: &[usize]) -> String {
|
| 614 |
+
format!(
|
| 615 |
+
"{{\"index\":{j},\"mins\":{},\"maxs\":{},\"capacity\":{},\"indices\":{},\"blocked\":{}}}",
|
| 616 |
+
array(&b.mins.map(f32::to_bits)),
|
| 617 |
+
array(&b.maxs.map(f32::to_bits)),
|
| 618 |
+
b.capacity,
|
| 619 |
+
array(&indices.iter().map(|v| *v as u32).collect::<Vec<_>>()),
|
| 620 |
+
u32::from(indices.contains(&901))
|
| 621 |
+
)
|
| 622 |
+
}
|
crates/urt-gameplay/src/camera_world.rs
CHANGED
|
@@ -599,6 +599,20 @@ pub fn fallback_spawn<M: AngleMath>(
|
|
| 599 |
avoid: [u32; 3],
|
| 600 |
state: &mut u32,
|
| 601 |
math: &mut M,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
) -> Result<SpawnSelection, Error> {
|
| 603 |
bounds(world.len(), world.len(), None)?;
|
| 604 |
let mut ranked = vec![];
|
|
@@ -611,7 +625,7 @@ pub fn fallback_spawn<M: AngleMath>(
|
|
| 611 |
continue;
|
| 612 |
}
|
| 613 |
first.get_or_insert(j);
|
| 614 |
-
if
|
| 615 |
continue;
|
| 616 |
}
|
| 617 |
let mut d = [0f32; 3];
|
|
@@ -834,3 +848,107 @@ mod composed_spawn_tests {
|
|
| 834 |
assert_eq!(state, 9);
|
| 835 |
}
|
| 836 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
avoid: [u32; 3],
|
| 600 |
state: &mut u32,
|
| 601 |
math: &mut M,
|
| 602 |
+
) -> Result<SpawnSelection, Error> {
|
| 603 |
+
fallback_spawn_with_check(world, avoid, state, math, |_, e| Ok(e.blocked))
|
| 604 |
+
}
|
| 605 |
+
/// Run overlap checks only at the original class-filter boundary, interleaved
|
| 606 |
+
/// with each accepted candidate's distance evaluation.
|
| 607 |
+
pub fn fallback_spawn_with_check<
|
| 608 |
+
M: AngleMath,
|
| 609 |
+
F: FnMut(usize, &SpawnEntity) -> Result<bool, Error>,
|
| 610 |
+
>(
|
| 611 |
+
world: &[SpawnEntity],
|
| 612 |
+
avoid: [u32; 3],
|
| 613 |
+
state: &mut u32,
|
| 614 |
+
math: &mut M,
|
| 615 |
+
mut blocked: F,
|
| 616 |
) -> Result<SpawnSelection, Error> {
|
| 617 |
bounds(world.len(), world.len(), None)?;
|
| 618 |
let mut ranked = vec![];
|
|
|
|
| 625 |
continue;
|
| 626 |
}
|
| 627 |
first.get_or_insert(j);
|
| 628 |
+
if blocked(j, e)? {
|
| 629 |
continue;
|
| 630 |
}
|
| 631 |
let mut d = [0f32; 3];
|
|
|
|
| 848 |
assert_eq!(state, 9);
|
| 849 |
}
|
| 850 |
}
|
| 851 |
+
|
| 852 |
+
#[derive(Clone, Copy)]
|
| 853 |
+
pub struct SpawnQueryWorld<'a> {
|
| 854 |
+
pub bounds: [[f32; 3]; 2],
|
| 855 |
+
pub client_words: &'a [u32],
|
| 856 |
+
}
|
| 857 |
+
fn overlap_check<F: FnMut(usize, crate::native_policy::SpawnBox) -> Result<Vec<usize>, Error>>(
|
| 858 |
+
j: usize,
|
| 859 |
+
e: &SpawnEntity,
|
| 860 |
+
scene: SpawnQueryWorld<'_>,
|
| 861 |
+
query: &mut F,
|
| 862 |
+
) -> Result<bool, Error> {
|
| 863 |
+
let bounds = crate::native_policy::spawn_box(e.origin.map(f32::from_bits), scene.bounds)
|
| 864 |
+
.map_err(|_| Error::FloatDomain)?;
|
| 865 |
+
let results = query(j, bounds)?;
|
| 866 |
+
crate::native_policy::spawn_overlap(
|
| 867 |
+
&results,
|
| 868 |
+
i32::try_from(results.len()).map_err(|_| Error::InvalidCount)?,
|
| 869 |
+
scene.client_words,
|
| 870 |
+
)
|
| 871 |
+
.map_err(|_| Error::InvalidCount)
|
| 872 |
+
}
|
| 873 |
+
pub fn fallback_spawn_queried<
|
| 874 |
+
M: AngleMath,
|
| 875 |
+
F: FnMut(usize, crate::native_policy::SpawnBox) -> Result<Vec<usize>, Error>,
|
| 876 |
+
>(
|
| 877 |
+
world: &[SpawnEntity],
|
| 878 |
+
avoid: [u32; 3],
|
| 879 |
+
state: &mut u32,
|
| 880 |
+
math: &mut M,
|
| 881 |
+
scene: SpawnQueryWorld<'_>,
|
| 882 |
+
mut query: F,
|
| 883 |
+
) -> Result<SpawnSelection, Error> {
|
| 884 |
+
fallback_spawn_with_check(world, avoid, state, math, |j, e| {
|
| 885 |
+
overlap_check(j, e, scene, &mut query)
|
| 886 |
+
})
|
| 887 |
+
}
|
| 888 |
+
#[cfg(test)]
|
| 889 |
+
mod query_spawn_tests {
|
| 890 |
+
use super::*;
|
| 891 |
+
#[test]
|
| 892 |
+
fn filtered_entities_do_not_query() {
|
| 893 |
+
let e = SpawnEntity {
|
| 894 |
+
class: HashEntity {
|
| 895 |
+
in_use: 0,
|
| 896 |
+
class_present: true,
|
| 897 |
+
class_hash: (-103258081i32) as u32,
|
| 898 |
+
},
|
| 899 |
+
blocked: false,
|
| 900 |
+
origin: [0; 3],
|
| 901 |
+
angles: [0; 3],
|
| 902 |
+
};
|
| 903 |
+
let mut state = 7;
|
| 904 |
+
let mut queried = false;
|
| 905 |
+
assert_eq!(
|
| 906 |
+
fallback_spawn_queried(
|
| 907 |
+
&[e],
|
| 908 |
+
[0; 3],
|
| 909 |
+
&mut state,
|
| 910 |
+
&mut HostMath,
|
| 911 |
+
SpawnQueryWorld {
|
| 912 |
+
bounds: [[0.; 3]; 2],
|
| 913 |
+
client_words: &[]
|
| 914 |
+
},
|
| 915 |
+
|_, _| {
|
| 916 |
+
queried = true;
|
| 917 |
+
Ok(vec![])
|
| 918 |
+
}
|
| 919 |
+
),
|
| 920 |
+
Err(Error::NoSpawn)
|
| 921 |
+
);
|
| 922 |
+
assert!(!queried);
|
| 923 |
+
assert_eq!(state, 7);
|
| 924 |
+
}
|
| 925 |
+
#[test]
|
| 926 |
+
fn query_error_preserves_rng() {
|
| 927 |
+
let e = SpawnEntity {
|
| 928 |
+
class: HashEntity {
|
| 929 |
+
in_use: 1,
|
| 930 |
+
class_present: true,
|
| 931 |
+
class_hash: (-103258081i32) as u32,
|
| 932 |
+
},
|
| 933 |
+
blocked: false,
|
| 934 |
+
origin: [0; 3],
|
| 935 |
+
angles: [0; 3],
|
| 936 |
+
};
|
| 937 |
+
let mut state = 7;
|
| 938 |
+
assert_eq!(
|
| 939 |
+
fallback_spawn_queried(
|
| 940 |
+
&[e],
|
| 941 |
+
[0; 3],
|
| 942 |
+
&mut state,
|
| 943 |
+
&mut HostMath,
|
| 944 |
+
SpawnQueryWorld {
|
| 945 |
+
bounds: [[0.; 3]; 2],
|
| 946 |
+
client_words: &[]
|
| 947 |
+
},
|
| 948 |
+
|_, _| Ok(vec![0])
|
| 949 |
+
),
|
| 950 |
+
Err(Error::InvalidCount)
|
| 951 |
+
);
|
| 952 |
+
assert_eq!(state, 7);
|
| 953 |
+
}
|
| 954 |
+
}
|
docs/FINDINGS.md
CHANGED
|
@@ -1652,3 +1652,6 @@ RE-813–822 replaces the scoreboard decimal assumption with actual37914 executi
|
|
| 1652 |
|
| 1653 |
|
| 1654 |
**RE-884:** 64 actual168114/167638 compositions replace supplied telefrag booleans with original query/filter execution. Native -33 spatial result lists are supplied, including empty/nonclient/blocked/mixed/duplicate results. Class filtering determines query order; accepted candidates then consume modeled sqrt before RNG, preserving64-cap and all-blocked/no-spawn behavior. Native broadphase, math and runtime ownership remain open. [Evidence](research/QVM_QUERIED_SPAWN.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1652 |
|
| 1653 |
|
| 1654 |
**RE-884:** 64 actual168114/167638 compositions replace supplied telefrag booleans with original query/filter execution. Native -33 spatial result lists are supplied, including empty/nonclient/blocked/mixed/duplicate results. Class filtering determines query order; accepted candidates then consume modeled sqrt before RNG, preserving64-cap and all-blocked/no-spawn behavior. Native broadphase, math and runtime ownership remain open. [Evidence](research/QVM_QUERIED_SPAWN.md).
|
| 1655 |
+
|
| 1656 |
+
|
| 1657 |
+
**RE-885:** Rust matches64 original168114/167638 compositions and their ordered box query transcripts. The typed spatial-query callback runs only after class filtering and before each candidate distance. Existing boolean-based callers retain behavior. Query/domain errors preserve RNG; native broadphase/math and external callback effects remain open. [Evidence](research/RUST_QUERIED_SPAWN.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1683,3 +1683,6 @@ Next batch RE-884: integrate collision queries and recovered callbacks; recover
|
|
| 1683 |
|
| 1684 |
|
| 1685 |
RE-884: 64 actual168114/167638 compositions replace supplied telefrag booleans with original query/filter execution. Native -33 spatial result lists are supplied, including empty/nonclient/blocked/mixed/duplicate results. Class filtering determines query order; accepted candidates then consume modeled sqrt before RNG, preserving64-cap and all-blocked/no-spawn behavior. Native broadphase, math and runtime ownership remain open. Full runtime completion remains open. [Evidence](research/QVM_QUERIED_SPAWN.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1683 |
|
| 1684 |
|
| 1685 |
RE-884: 64 actual168114/167638 compositions replace supplied telefrag booleans with original query/filter execution. Native -33 spatial result lists are supplied, including empty/nonclient/blocked/mixed/duplicate results. Class filtering determines query order; accepted candidates then consume modeled sqrt before RNG, preserving64-cap and all-blocked/no-spawn behavior. Native broadphase, math and runtime ownership remain open. Full runtime completion remains open. [Evidence](research/QVM_QUERIED_SPAWN.md).
|
| 1686 |
+
|
| 1687 |
+
|
| 1688 |
+
RE-885: Rust matches64 original168114/167638 compositions and their ordered box query transcripts. The typed spatial-query callback runs only after class filtering and before each candidate distance. Existing boolean-based callers retain behavior. Query/domain errors preserve RNG; native broadphase/math and external callback effects remain open. Full runtime completion remains open. [Evidence](research/RUST_QUERIED_SPAWN.md).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -2130,3 +2130,8 @@ After the tenth commit, `cargo xtask test-full --since 40af75ff` passed with the
|
|
| 2130 |
## 2026-10-28 — RE-884 Original fallback spawn with actual overlap queries
|
| 2131 |
|
| 2132 |
64 actual168114/167638 compositions replace supplied telefrag booleans with original query/filter execution. Native -33 spatial result lists are supplied, including empty/nonclient/blocked/mixed/duplicate results. Class filtering determines query order; accepted candidates then consume modeled sqrt before RNG, preserving64-cap and all-blocked/no-spawn behavior. Native broadphase, math and runtime ownership remain open. Focused `cargo xtask test-group qvm-queried-spawn` passes (10 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2130 |
## 2026-10-28 — RE-884 Original fallback spawn with actual overlap queries
|
| 2131 |
|
| 2132 |
64 actual168114/167638 compositions replace supplied telefrag booleans with original query/filter execution. Native -33 spatial result lists are supplied, including empty/nonclient/blocked/mixed/duplicate results. Class filtering determines query order; accepted candidates then consume modeled sqrt before RNG, preserving64-cap and all-blocked/no-spawn behavior. Native broadphase, math and runtime ownership remain open. Focused `cargo xtask test-group qvm-queried-spawn` passes (10 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
|
| 2133 |
+
|
| 2134 |
+
|
| 2135 |
+
## 2026-10-28 — RE-885 Rust queried fallback spawn policy
|
| 2136 |
+
|
| 2137 |
+
Rust matches64 original168114/167638 compositions and their ordered box query transcripts. The typed spatial-query callback runs only after class filtering and before each candidate distance. Existing boolean-based callers retain behavior. Query/domain errors preserve RNG; native broadphase/math and external callback effects remain open. Focused `cargo xtask test-group rust-queried-spawn` passes (11 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1720,3 +1720,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1720 |
|
| 1721 |
|
| 1722 |
- [x] RE-884 Original fallback spawn with actual overlap queries ([evidence](research/QVM_QUERIED_SPAWN.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1720 |
|
| 1721 |
|
| 1722 |
- [x] RE-884 Original fallback spawn with actual overlap queries ([evidence](research/QVM_QUERIED_SPAWN.md)).
|
| 1723 |
+
|
| 1724 |
+
|
| 1725 |
+
- [x] RE-885 Rust queried fallback spawn policy ([evidence](research/RUST_QUERIED_SPAWN.md)).
|
docs/research/README.md
CHANGED
|
@@ -1255,3 +1255,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 1255 |
|
| 1256 |
|
| 1257 |
[RE-884: Original fallback spawn with actual overlap queries](QVM_QUERIED_SPAWN.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1255 |
|
| 1256 |
|
| 1257 |
[RE-884: Original fallback spawn with actual overlap queries](QVM_QUERIED_SPAWN.md).
|
| 1258 |
+
|
| 1259 |
+
|
| 1260 |
+
[RE-885: Rust queried fallback spawn policy](RUST_QUERIED_SPAWN.md).
|
docs/research/RUST_QUERIED_SPAWN.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Rust queried fallback spawn policy
|
| 2 |
+
|
| 3 |
+
RE-885. Reproduce with `python3 scripts/analyze_rust_queried_spawn.py`; focused validation: `cargo xtask test-group rust-queried-spawn`. [Machine report](rust-queried-spawn.json).
|
| 4 |
+
|
| 5 |
+
Rust matches64 original168114/167638 compositions and their ordered box query transcripts. The typed spatial-query callback runs only after class filtering and before each candidate distance. Existing boolean-based callers retain behavior. Query/domain errors preserve RNG; native broadphase/math and external callback effects remain open.
|
| 6 |
+
|
| 7 |
+
Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
|
docs/research/rust-health-impulse.json
CHANGED
|
@@ -2985,7 +2985,7 @@
|
|
| 2985 |
"exit_code": 2
|
| 2986 |
}
|
| 2987 |
],
|
| 2988 |
-
"rust_unit_tests":
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
|
|
|
| 2985 |
"exit_code": 2
|
| 2986 |
}
|
| 2987 |
],
|
| 2988 |
+
"rust_unit_tests": 142,
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
docs/research/rust-queried-spawn.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_rust_queried_spawn.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import hashlib,json
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from rust_camera_world_support import binary,result,invoke
|
| 5 |
+
from analyze_qvm import write_json
|
| 6 |
+
from qvm_spawn_support import entities
|
| 7 |
+
def encode(s):
|
| 8 |
+
a=s['input'];c=entities(a['count'],a['pattern']);out=[a['seed'],*a['avoid'],len(c)]
|
| 9 |
+
for e in c:out.extend([e['active'],e['name'],e['hash'],0,*e['origin'],*e['angles']])
|
| 10 |
+
out.extend([*a['bounds'],a['profile'],len(s['math'])])
|
| 11 |
+
for m in s['math']:out.extend([m['target'],m['arguments']['8'],0,m['result']])
|
| 12 |
+
return out
|
| 13 |
+
def project(s):return {'selection':{k:s[k] for k in ['result','rng_state','fatal','candidates','distances','origin','angles']},'queries':[{k:v for k,v in q.items() if k!='trace_sha256'} for q in s['queries']]}
|
| 14 |
+
|
| 15 |
+
def main():
|
| 16 |
+
b=binary();p=Path('docs/research/qvm-queried-spawn.json');data=p.read_bytes();rows=[]
|
| 17 |
+
for s in json.loads(data)['probes']:rows.append({'source':project(s),'rust':result(b,'queried-spawn',encode(s))})
|
| 18 |
+
write_json(Path('docs/research/rust-queried-spawn.json'),{'source_report':str(p),'source_report_sha256':hashlib.sha256(data).hexdigest(),'probes':rows,'limits':'Rust matches64 original168114/167638 compositions and their ordered box query transcripts. The typed spatial-query callback runs only after class filtering and before each candidate distance. Existing boolean-based callers retain behavior. Query/domain errors preserve RNG; native broadphase/math and external callback effects remain open.'})
|
| 19 |
+
if __name__=='__main__':main()
|
scripts/test_rust_queried_spawn.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib,json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
class PortTests(unittest.TestCase):
|
| 4 |
+
def test_all_original_cases(self):
|
| 5 |
+
r=json.loads(Path('docs/research/rust-queried-spawn.json').read_text());src=json.loads(Path(r['source_report']).read_text());self.assertEqual(len(r['probes']),len(src['probes']));self.assertGreater(len(r['probes']),20)
|
| 6 |
+
for p in r['probes']:self.assertEqual(p['rust'],p['source'])
|
| 7 |
+
def test_source_identity(self):
|
| 8 |
+
r=json.loads(Path('docs/research/rust-queried-spawn.json').read_text());self.assertEqual(hashlib.sha256(Path(r['source_report']).read_bytes()).hexdigest(),r['source_report_sha256'])
|
| 9 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -2612,3 +2612,18 @@ edge docs/research/qvm-queried-spawn.json scripts/test_qvm_queried_spawn.py
|
|
| 2612 |
group qvm-queried-spawn scripts/analyze_qvm_queried_spawn.py
|
| 2613 |
edge scripts/analyze_qvm_queried_spawn.py scripts/analyze_qvm_resumer_audit.py
|
| 2614 |
edge scripts/qvm_spawn_query_support.py scripts/analyze_qvm_resumer_audit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2612 |
group qvm-queried-spawn scripts/analyze_qvm_queried_spawn.py
|
| 2613 |
edge scripts/analyze_qvm_queried_spawn.py scripts/analyze_qvm_resumer_audit.py
|
| 2614 |
edge scripts/qvm_spawn_query_support.py scripts/analyze_qvm_resumer_audit.py
|
| 2615 |
+
edge Cargo.toml scripts/analyze_rust_queried_spawn.py
|
| 2616 |
+
edge Cargo.lock scripts/analyze_rust_queried_spawn.py
|
| 2617 |
+
edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_queried_spawn.py
|
| 2618 |
+
edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_queried_spawn.py
|
| 2619 |
+
edge crates/urt-gameplay/src/camera_world.rs scripts/analyze_rust_queried_spawn.py
|
| 2620 |
+
edge crates/urt-gameplay/src/bin/urt-camera-world.rs scripts/analyze_rust_queried_spawn.py
|
| 2621 |
+
edge docs/research/qvm-queried-spawn.json scripts/analyze_rust_queried_spawn.py
|
| 2622 |
+
group rust-queried-spawn scripts/analyze_rust_health_impulse.py
|
| 2623 |
+
group gameplay scripts/analyze_rust_queried_spawn.py
|
| 2624 |
+
edge crates/urt-gameplay/src/native_policy.rs scripts/analyze_rust_queried_spawn.py
|
| 2625 |
+
group rust-queried-spawn scripts/analyze_rust_spawn_fallback.py
|
| 2626 |
+
report scripts/analyze_rust_queried_spawn.py docs/research/rust-queried-spawn.json
|
| 2627 |
+
edge docs/research/rust-queried-spawn.json scripts/test_rust_queried_spawn.py
|
| 2628 |
+
group rust-queried-spawn scripts/analyze_rust_queried_spawn.py
|
| 2629 |
+
edge scripts/analyze_rust_queried_spawn.py scripts/analyze_qvm_resumer_audit.py
|