nmarshall commited on
Commit
722cbae
·
1 Parent(s): 6bf0f1a

gameplay: port override command ownership

Browse files
crates/urt-gameplay/src/bin/urt-camera-world.rs CHANGED
@@ -312,7 +312,7 @@ fn run() -> Result<String, String> {
312
  let mut state = w[0];
313
  let slot = w[1] as usize;
314
  let n = w[2] as usize;
315
- let fallback = urt_gameplay::transition::View {
316
  origin: w[3..6].try_into().unwrap(),
317
  angles: w[6..9].try_into().unwrap(),
318
  };
 
312
  let mut state = w[0];
313
  let slot = w[1] as usize;
314
  let n = w[2] as usize;
315
+ let _fallback = urt_gameplay::transition::View {
316
  origin: w[3..6].try_into().unwrap(),
317
  angles: w[6..9].try_into().unwrap(),
318
  };
crates/urt-gameplay/src/bin/urt-map-commands.rs CHANGED
@@ -60,6 +60,25 @@ fn run() -> Result<String, String> {
60
  rotation_json(&effects)
61
  ))
62
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  _ => Err("unknown command".into()),
64
  }
65
  }
@@ -72,3 +91,23 @@ fn main() {
72
  }
73
  }
74
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  rotation_json(&effects)
61
  ))
62
  }
63
+ "map" => {
64
+ let mut p = 0;
65
+ let mirror = bytes(&w, &mut p)?;
66
+ let current = bytes(&w, &mut p)?;
67
+ if p + 1 != w.len() {
68
+ return Err("invalid map response input".into());
69
+ }
70
+ let r = select_map(&mirror, &current).map_err(|e| format!("{e:?}"))?;
71
+ let cmd = r
72
+ .command
73
+ .as_ref()
74
+ .map(|v| format!("\"{}\"", hex(v)))
75
+ .unwrap_or("null".into());
76
+ Ok(format!(
77
+ "{{\"mirror\":\"{}\",\"command\":{cmd},\"operations\":{}}}",
78
+ hex(&r.mirror),
79
+ map_effects_json(&r.effects)
80
+ ))
81
+ }
82
  _ => Err("unknown command".into()),
83
  }
84
  }
 
91
  }
92
  }
93
  }
94
+
95
+ fn map_effects_json(e: &[MapEffect]) -> String {
96
+ format!(
97
+ "[{}]",
98
+ e.iter()
99
+ .map(|e| match e {
100
+ MapEffect::ReadMap(v) => format!("{{\"op\":\"read-map\",\"text\":\"{}\"}}", hex(v)),
101
+ MapEffect::SetCycle(v) =>
102
+ format!("{{\"op\":\"set-cycle\",\"value\":\"{}\"}}", hex(v)),
103
+ MapEffect::ClearNext => "{\"op\":\"clear-next\"}".into(),
104
+ MapEffect::Command { mode, text } => format!(
105
+ "{{\"op\":\"command\",\"mode\":{mode},\"text\":\"{}\"}}",
106
+ hex(text)
107
+ ),
108
+ MapEffect::Fallback => "{\"op\":\"fallback\"}".into(),
109
+ })
110
+ .collect::<Vec<String>>()
111
+ .join(",")
112
+ )
113
+ }
crates/urt-gameplay/src/map_commands.rs CHANGED
@@ -94,3 +94,70 @@ mod rotation_tests {
94
  assert_eq!(s, old);
95
  }
96
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  assert_eq!(s, old);
95
  }
96
  }
97
+
98
+ #[derive(Clone, Debug, PartialEq, Eq)]
99
+ pub enum MapEffect {
100
+ ReadMap(Vec<u8>),
101
+ SetCycle(Vec<u8>),
102
+ ClearNext,
103
+ Command { mode: u32, text: Vec<u8> },
104
+ Fallback,
105
+ }
106
+ #[derive(Clone, Debug, PartialEq, Eq)]
107
+ pub struct MapSelection {
108
+ pub mirror: Vec<u8>,
109
+ pub command: Option<Vec<u8>>,
110
+ pub effects: Vec<MapEffect>,
111
+ }
112
+ pub fn select_map(mirror: &[u8], current: &[u8]) -> Result<MapSelection, Error> {
113
+ let old = logical(mirror)?;
114
+ if old.is_empty() {
115
+ return Ok(MapSelection {
116
+ mirror: old,
117
+ command: None,
118
+ effects: vec![MapEffect::Fallback],
119
+ });
120
+ }
121
+ let mut name = logical(current)?;
122
+ name.truncate(127);
123
+ let mut command = b"map ".to_vec();
124
+ command.extend_from_slice(&old[..old.len().min(127)]);
125
+ command.push(b'\n');
126
+ let effects = vec![
127
+ MapEffect::ReadMap(name.clone()),
128
+ MapEffect::SetCycle(name.clone()),
129
+ MapEffect::ClearNext,
130
+ MapEffect::Command {
131
+ mode: 2,
132
+ text: command.clone(),
133
+ },
134
+ ];
135
+ Ok(MapSelection {
136
+ mirror: old,
137
+ command: Some(command),
138
+ effects,
139
+ })
140
+ }
141
+ #[cfg(test)]
142
+ mod select_tests {
143
+ use super::*;
144
+ #[test]
145
+ fn mirror_gate_truncation_and_raw_command() {
146
+ let r = select_map(&[255; 128], b"current").unwrap();
147
+ assert_eq!(r.mirror, vec![255; 128]);
148
+ let mut cmd = b"map ".to_vec();
149
+ cmd.extend_from_slice(&[255; 127]);
150
+ cmd.push(b'\n');
151
+ assert_eq!(r.command, Some(cmd));
152
+ assert!(matches!(r.effects[2], MapEffect::ClearNext));
153
+ assert!(matches!(r.effects[3], MapEffect::Command { mode: 2, .. }));
154
+ }
155
+ #[test]
156
+ fn empty_gate_and_logical_nul() {
157
+ let r = select_map(b"\0tail", &[7; 4097]).unwrap();
158
+ assert_eq!(r.effects, vec![MapEffect::Fallback]);
159
+ assert_eq!(r.command, None);
160
+ assert_eq!(select_map(b"cycle", b"x\0tail").unwrap().mirror, b"cycle");
161
+ assert_eq!(select_map(&[1; 4097], b"x"), Err(Error::BytesTooLong));
162
+ }
163
+ }
docs/FINDINGS.md CHANGED
@@ -1610,3 +1610,6 @@ RE-813–822 replaces the scoreboard decimal assumption with actual37914 executi
1610
 
1611
 
1612
  **RE-870:** 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a127-byte local command buffer, requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. [Evidence](research/QVM_MAP_SELECT.md).
 
 
 
 
1610
 
1611
 
1612
  **RE-870:** 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a127-byte local command buffer, requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. [Evidence](research/QVM_MAP_SELECT.md).
1613
+
1614
+
1615
+ **RE-871:** Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port. [Evidence](research/RUST_MAP_SELECT.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -1635,3 +1635,6 @@ RE-869: Rust matches192 original rotation cases, preserving signed cursor wrap,
1635
 
1636
 
1637
  RE-870: 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a127-byte local command buffer, requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. Full runtime completion remains open. [Evidence](research/QVM_MAP_SELECT.md).
 
 
 
 
1635
 
1636
 
1637
  RE-870: 90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a127-byte local command buffer, requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. Full runtime completion remains open. [Evidence](research/QVM_MAP_SELECT.md).
1638
+
1639
+
1640
+ RE-871: Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port. Full runtime completion remains open. [Evidence](research/RUST_MAP_SELECT.md).
docs/RESEARCH_LEDGER.md CHANGED
@@ -2051,3 +2051,8 @@ Rust matches192 original rotation cases, preserving signed cursor wrap, enable/t
2051
  ## 2026-10-27 — RE-870 Original map command branch with recovered copy and formatter
2052
 
2053
  90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a127-byte local command buffer, requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. Focused `cargo xtask test-group map-select` passes (5 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.
 
 
 
 
 
 
2051
  ## 2026-10-27 — RE-870 Original map command branch with recovered copy and formatter
2052
 
2053
  90 original7188 cases compose actual strlen, bounded-copy wrapper and original formatter. A nonempty override mirror records current engine mapname in g_nextCycleMap, copies the override into a127-byte local command buffer, requests engine g_NextMap clear and emits mode2 map command. VM mirror bytes remain unchanged; engine/native-copy and lower effects remain supplied/captured. Focused `cargo xtask test-group map-select` passes (5 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.
2054
+
2055
+
2056
+ ## 2026-10-27 — RE-871 Rust cycle-mirror map command policy
2057
+
2058
+ Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port. Focused `cargo xtask test-group rust-map-select` passes (9 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
@@ -1672,3 +1672,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
1672
 
1673
 
1674
  - [x] RE-870 Original map command branch with recovered copy and formatter ([evidence](research/QVM_MAP_SELECT.md)).
 
 
 
 
1672
 
1673
 
1674
  - [x] RE-870 Original map command branch with recovered copy and formatter ([evidence](research/QVM_MAP_SELECT.md)).
1675
+
1676
+
1677
+ - [x] RE-871 Rust cycle-mirror map command policy ([evidence](research/RUST_MAP_SELECT.md)).
docs/research/README.md CHANGED
@@ -1208,3 +1208,6 @@ The extension collector adds five focused tests for native tail calls, command-r
1208
 
1209
 
1210
  [RE-870: Original map command branch with recovered copy and formatter](QVM_MAP_SELECT.md).
 
 
 
 
1208
 
1209
 
1210
  [RE-870: Original map command branch with recovered copy and formatter](QVM_MAP_SELECT.md).
1211
+
1212
+
1213
+ [RE-871: Rust cycle-mirror map command policy](RUST_MAP_SELECT.md).
docs/research/RUST_MAP_SELECT.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Rust cycle-mirror map command policy
2
+
3
+ RE-871. Reproduce with `python3 scripts/analyze_rust_map_select.py`; focused validation: `cargo xtask test-group rust-map-select`. [Machine report](rust-map-select.json).
4
+
5
+ Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port.
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": 125,
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": 127,
2989
  "source_report": "docs/research/qvm-health-impulse.json",
2990
  "source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
2991
  }
docs/research/rust-map-select.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_rust_map_select.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import hashlib,json
3
+ from pathlib import Path
4
+ from rust_map_commands_support import binary,result,invoke
5
+ from analyze_qvm import write_json
6
+ from rust_map_commands_support import blob
7
+ def encode(s):
8
+ a=s['input'];return [*blob(a['mirror']),*blob(a['current']),a['fallback']]
9
+ def project(s):return {k:s[k] for k in ['mirror','command','operations']}
10
+ def main():
11
+ b=binary();p=Path('docs/research/qvm-map-select.json');data=p.read_bytes();rows=[]
12
+ for s in json.loads(data)['probes']:rows.append({'source':project(s),'rust':result(b,'map',encode(s))})
13
+ write_json(Path('docs/research/rust-map-select.json'),{'source_report':str(p),'source_report_sha256':hashlib.sha256(data).hexdigest(),'probes':rows,'limits':'Rust matches90 original map-selection cases with empty/NUL mirror gates,127-byte engine-mapname truncation, raw non-UTF8 bytes, unchanged VM mirror and exact truncated-override mode2 map command text. The typed effect order matches source cvar/read/command requests. Engine callbacks, native copy and actual command dispatch remain outside the port.'})
14
+ if __name__=='__main__':main()
scripts/test_rust_map_select.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-map-select.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-map-select.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
@@ -2484,3 +2484,16 @@ report scripts/analyze_qvm_map_select.py docs/research/qvm-map-select.json
2484
  edge docs/research/qvm-map-select.json scripts/test_qvm_map_select.py
2485
  group map-select scripts/analyze_qvm_map_select.py
2486
  edge scripts/analyze_qvm_map_select.py scripts/analyze_qvm_resumer_audit.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2484
  edge docs/research/qvm-map-select.json scripts/test_qvm_map_select.py
2485
  group map-select scripts/analyze_qvm_map_select.py
2486
  edge scripts/analyze_qvm_map_select.py scripts/analyze_qvm_resumer_audit.py
2487
+ edge Cargo.toml scripts/analyze_rust_map_select.py
2488
+ edge Cargo.lock scripts/analyze_rust_map_select.py
2489
+ edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_map_select.py
2490
+ edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_map_select.py
2491
+ edge crates/urt-gameplay/src/map_commands.rs scripts/analyze_rust_map_select.py
2492
+ edge crates/urt-gameplay/src/bin/urt-map-commands.rs scripts/analyze_rust_map_select.py
2493
+ edge docs/research/qvm-map-select.json scripts/analyze_rust_map_select.py
2494
+ group rust-map-select scripts/analyze_rust_health_impulse.py
2495
+ group gameplay scripts/analyze_rust_map_select.py
2496
+ report scripts/analyze_rust_map_select.py docs/research/rust-map-select.json
2497
+ edge docs/research/rust-map-select.json scripts/test_rust_map_select.py
2498
+ group rust-map-select scripts/analyze_rust_map_select.py
2499
+ edge scripts/analyze_rust_map_select.py scripts/analyze_qvm_resumer_audit.py