nmarshall commited on
Commit
19bbb42
·
1 Parent(s): c33cd79

qvm: reload requests

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -379,3 +379,6 @@ Research progress: RE-561 [report](research/QVM_WATER_EVENTS.md); remaining nati
379
 
380
 
381
  Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
379
 
380
 
381
  Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining native/content/runtime/platform scope stays open.
382
+
383
+
384
+ Research progress: RE-563 [report](research/QVM_RELOAD_REQUEST.md); remaining native/content/runtime/platform scope stays open.
docs/FINDINGS.md CHANGED
@@ -737,3 +737,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
737
 
738
 
739
  **RE-562 — Torso selector priority and weapon class dispatch:** 49117 first rejects nonzero weapon state, then prioritizes legs25 over button8192/16384, then selects torso requests from a file-backed class jump table and tag22/25 exceptions. [Evidence](research/QVM_TORSO_SELECTOR.md).
 
 
 
 
737
 
738
 
739
  **RE-562 — Torso selector priority and weapon class dispatch:** 49117 first rejects nonzero weapon state, then prioritizes legs25 over button8192/16384, then selects torso requests from a file-backed class jump table and tag22/25 exceptions. [Evidence](research/QVM_TORSO_SELECTOR.md).
740
+
741
+
742
+ **RE-563 — Reload request gates and timer animation event effects:** 49652 gates reload on button32, packed magazine/reserve bytes and state flags, sets state bit8 and a configured timer, requests torso56/57 and emits event3 without transferring ammunition. [Evidence](research/QVM_RELOAD_REQUEST.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -691,3 +691,6 @@ Research progress: RE-561 [report](research/QVM_WATER_EVENTS.md); remaining nati
691
 
692
 
693
  Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
691
 
692
 
693
  Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining native/content/runtime/platform scope stays open.
694
+
695
+
696
+ Research progress: RE-563 [report](research/QVM_RELOAD_REQUEST.md); remaining native/content/runtime/platform scope stays open.
docs/RESEARCH_LEDGER.md CHANGED
@@ -511,3 +511,8 @@ RE-549–558 each has its own code/tests/report/documentation commit. All759 tes
511
  ## 2026-10-19 — RE-562 Torso selector priority and weapon class dispatch (separate task commit)
512
 
513
  49117 first rejects nonzero weapon state, then prioritizes legs25 over button8192/16384, then selects torso requests from a file-backed class jump table and tag22/25 exceptions. 93 probes cover initialized weapon IDs0..27, timer gates, classes−1..7, tag exceptions, toggle-bit aliases and priority conflicts with independent request/animation oracles. Full suite: 771 tests pass. Report regenerates byte-identically (545687 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
 
 
 
 
 
 
511
  ## 2026-10-19 — RE-562 Torso selector priority and weapon class dispatch (separate task commit)
512
 
513
  49117 first rejects nonzero weapon state, then prioritizes legs25 over button8192/16384, then selects torso requests from a file-backed class jump table and tag22/25 exceptions. 93 probes cover initialized weapon IDs0..27, timer gates, classes−1..7, tag exceptions, toggle-bit aliases and priority conflicts with independent request/animation oracles. Full suite: 771 tests pass. Report regenerates byte-identically (545687 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
514
+
515
+
516
+ ## 2026-10-19 — RE-563 Reload request gates and timer animation event effects (separate task commit)
517
+
518
+ 49652 gates reload on button32, packed magazine/reserve bytes and state flags, sets state bit8 and a configured timer, requests torso56/57 and emits event3 without transferring ammunition. 108 probes independently check special IDs14/23, capacity equality, reserve, weapon states, action argument, timer overrides, timed animation and queue writes. Full suite: 775 tests pass. Report regenerates byte-identically (501354 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -731,3 +731,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
731
 
732
 
733
  - [x] RE-562 Torso selector priority and weapon class dispatch ([report](research/QVM_TORSO_SELECTOR.md)).
 
 
 
 
731
 
732
 
733
  - [x] RE-562 Torso selector priority and weapon class dispatch ([report](research/QVM_TORSO_SELECTOR.md)).
734
+
735
+
736
+ - [x] RE-563 Reload request gates and timer animation event effects ([report](research/QVM_RELOAD_REQUEST.md)).
docs/research/QVM_RELOAD_REQUEST.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Reload request gates and timer animation event effects
2
+
3
+ RE-563. Reproduce with `python3 scripts/analyze_qvm_reload_request.py`; check with `python3 scripts/test_qvm_reload_request.py`. The [machine report](qvm-reload-request.json) retains source identity and bounded fixtures.
4
+
5
+ Complete49652 runs to49916 with actual timed torso39552 and event39238 children. Selected weapon is the low byte of PS312+4×PS144; magazine is bits8..15 and reserve bits24..31. Button32, positive ID, magazine unequal to configured capacity, nonzero reserve, no PS12 bit8, no PS220 bits1024/8 and PS148 unequal2 are required. IDs14/23 additionally reject a nonempty magazine with nonzero PS148. Capacity is an equality test: an explicitly supplied over-capacity magazine still passes this predicate.
6
+
7
+ Accepted requests set state bit8 and replace PS44 with record4056+432×id, adding4060+432×id only when argument8 is nonzero. An existing positive weapon timer does not gate this function. Class4+ requests timed torso57, otherwise56, followed by event3. Timed-animation durations are supplied records, default321, with0/−1 fixtures. Kind3 blocks the torso animation child but the duration store still occurs. The body does not change packed ammunition or inventory.
8
+
9
+ 108 finite fixtures cover initialized records and marked synthetic overrides. Remaining work: actual reload completion/ammo transfer, full weapon state machine, animation asset matching, source-order caller interference and live configuration validation.
10
+
11
+ No original executable/full QVM/native collision/physics/rendering executes. Native responses and legal input domains are supplied or unverified where stated; full runtime/macOS/Linux Rust/Bevy/Solari gameplay remains open.
docs/research/README.md CHANGED
@@ -292,3 +292,6 @@ The extension collector adds five focused tests for native tail calls, command-r
292
 
293
 
294
  [RE-562: Torso selector priority and weapon class dispatch](QVM_TORSO_SELECTOR.md). Reproduce with `python3 scripts/analyze_qvm_torso_selector.py`; check with `python3 scripts/test_qvm_torso_selector.py`.
 
 
 
 
292
 
293
 
294
  [RE-562: Torso selector priority and weapon class dispatch](QVM_TORSO_SELECTOR.md). Reproduce with `python3 scripts/analyze_qvm_torso_selector.py`; check with `python3 scripts/test_qvm_torso_selector.py`.
295
+
296
+
297
+ [RE-563: Reload request gates and timer animation event effects](QVM_RELOAD_REQUEST.md). Reproduce with `python3 scripts/analyze_qvm_reload_request.py`; check with `python3 scripts/test_qvm_reload_request.py`.
docs/research/qvm-reload-request.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_reload_request.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Complete49652 reload request gates, packed bytes and timed animation/event."""
3
+ import itertools
4
+ from pathlib import Path
5
+ from qvm_research_support import source,execute
6
+ from qvm_suffix_support import seed,state,handlers,weapon_config,weapon_words
7
+ from analyze_qvm_acceleration import PS,FRAME
8
+ from analyze_qvm_animation_contacts import TABLE
9
+ from analyze_qvm import write_json
10
+ LOCAL=0x6d000000
11
+
12
+ def reload(ins,m,arg=1,cmd=(0,0,0)):
13
+ m=dict(m);before=state(m);ident=before['packed']&255;cfg=weapon_words(m,ident);m[LOCAL+48]=arg;duration=m[TABLE+m[FRAME+248]*2560+(57 if cfg['class']>=4 else 56)*32+28]
14
+ m,c,r=execute(ins,49653,49916,m,cmd,LOCAL,handlers())
15
+ return m,{'initial':before,'argument':arg,'buttons':m[FRAME+20],'kind':m[PS+4],'config':cfg,'supplied_animation_duration':duration,'execution':r,'final':state(m)}
16
+
17
+ def main():
18
+ q,raw,h,ins=source();rows=[]
19
+ for ident,arg,ws in itertools.product([0,1,14,22,23,27],[0,1],[0,1,2]):
20
+ cap=weapon_words(weapon_config({},raw,h),ident)['capacity']
21
+ for mag in sorted(set([0,1,cap])):
22
+ m=weapon_config(seed(raw,h),raw,h);m.update({PS+312:ident|(mag<<8)|(4<<24),FRAME+20:32,PS+148:ws,PS+44:99});rows.append(reload(ins,m,arg)[1])
23
+ for changes in [{FRAME+20:0},{PS+312:1|(1<<8)},{PS+12:8},{PS+220:8},{PS+220:1024},{PS+220:512},{PS+4:3},{PS+80:100},{PS+312:1|(6<<8)|(255<<24)},{4060+432:123},{TABLE+56*32+28:0},{TABLE+56*32+28:-1}]:
24
+ m=weapon_config(seed(raw,h),raw,h);m.update({PS+312:1|(1<<8)|(4<<24),FRAME+20:32,PS+44:99});m.update(changes);p=reload(ins,m)[1];p['supplied_changes']={str(k):v for k,v in changes.items()};rows.append(p)
25
+ write_json(Path('docs/research/qvm-reload-request.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Complete finite49652 with actual39552/39338/39238/29913; initialized weapon records and supplied animation duration321 except marked overrides. No actual ammo transfer, full weapon state machine or native animation playback.'})
26
+ if __name__=='__main__':main()
scripts/test_qvm_reload_request.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest,copy
2
+ from pathlib import Path
3
+ from test_qvm_water_events import enqueue
4
+
5
+ def allowed(p):
6
+ a=p['initial'];packed=a['packed'];ident=packed&255;mag=(packed>>8)&255;reserve=packed>>24
7
+ return bool(p['buttons']&32) and not (ident in [14,23] and mag>0 and a['weapon_state']!=0) and ident>0 and mag!=p['config']['capacity'] and reserve!=0 and not a['flags']&8 and not a['state220']&(1024|8) and a['weapon_state']!=2
8
+ class ReloadRequestTests(unittest.TestCase):
9
+ @classmethod
10
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-reload-request.json').read_text())
11
+ def test_packed_gates_and_source_request_order(self):
12
+ self.assertEqual(len(self.r['probes']),108)
13
+ for p in self.r['probes']:
14
+ active=allowed(p);self.assertEqual([c['target'] for c in p['execution']['calls']],[39552,39238] if active else []);self.assertEqual([c['args']['8'] for c in p['execution']['calls']],[(57 if p['config']['class']>=4 else 56),3] if active else [])
15
+ def test_exact_timer_state_animation_and_queue(self):
16
+ for p in self.r['probes']:
17
+ a=copy.deepcopy(p['initial'])
18
+ if allowed(p):
19
+ a['state220']|=8;a['weapon_timer']=(p['config']['reload']+(p['config']['reload_extra'] if p['argument'] else 0))&0xffffffff;a['torso_timer']=p['supplied_animation_duration']&0xffffffff
20
+ if p['kind']<3:a['torso']=((a['torso']&128)^128)|(57 if p['config']['class']>=4 else 56)
21
+ a['queue']=enqueue(a['queue'],[3])
22
+ self.assertEqual(p['final'],a)
23
+ def test_capacity_is_equality_not_less_than_and_no_ammo_transfer(self):
24
+ self.assertTrue(any((p['initial']['packed']>>8)&255>p['config']['capacity'] and allowed(p) for p in self.r['probes']))
25
+ for p in self.r['probes']:self.assertEqual(p['final']['packed'],p['initial']['packed']);self.assertEqual(p['final']['inventory'],p['initial']['inventory'])
26
+ def test_existing_timer_does_not_gate_reload(self):
27
+ active=[p for p in self.r['probes'] if allowed(p)];self.assertTrue(active);self.assertTrue(any(p['initial']['weapon_timer']==99 and p['final']['weapon_timer']!=99 for p in active));self.assertTrue(any(p['config']['reload_extra']==123 and p['final']['weapon_timer']==523 for p in active))
28
+ if __name__=='__main__':unittest.main()