nmarshall commited on
Commit
c52db3b
·
1 Parent(s): ddd93d5

qvm: hitscan spread parameters

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -505,3 +505,6 @@ Research progress: RE-607 [report](research/QVM_ALLOCATED_EVENT.md); remaining n
505
 
506
 
507
  Research progress: RE-608 [report](research/QVM_ALLOCATED_GRENADE.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
505
 
506
 
507
  Research progress: RE-608 [report](research/QVM_ALLOCATED_GRENADE.md); remaining native/content/runtime/platform scope stays open.
508
+
509
+
510
+ Research progress: RE-609 [report](research/QVM_SPREAD_PARAMETERS.md); remaining native/content/runtime/platform scope stays open.
docs/FINDINGS.md CHANGED
@@ -863,3 +863,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
863
 
864
 
865
  **RE-608 — Grenade constructor with actual entity allocation:** 285971 now composes recovered277165/277125 before grenade descriptor and inherited velocity writes, preserving slot identity and in-use fields. [Evidence](research/QVM_ALLOCATED_GRENADE.md).
 
 
 
 
863
 
864
 
865
  **RE-608 — Grenade constructor with actual entity allocation:** 285971 now composes recovered277165/277125 before grenade descriptor and inherited velocity writes, preserving slot identity and in-use fields. [Evidence](research/QVM_ALLOCATED_GRENADE.md).
866
+
867
+
868
+ **RE-609 — Shared hitscan spread parameter calculation:** 290493 reads current packed slot/mode and weapon table stride432/mode stride52 to calculate base, counter-scaled and modifier-adjusted spread terms. [Evidence](research/QVM_SPREAD_PARAMETERS.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -825,3 +825,6 @@ Research progress: RE-607 [report](research/QVM_ALLOCATED_EVENT.md); remaining n
825
 
826
 
827
  Research progress: RE-608 [report](research/QVM_ALLOCATED_GRENADE.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
825
 
826
 
827
  Research progress: RE-608 [report](research/QVM_ALLOCATED_GRENADE.md); remaining native/content/runtime/platform scope stays open.
828
+
829
+
830
+ Research progress: RE-609 [report](research/QVM_SPREAD_PARAMETERS.md); remaining native/content/runtime/platform scope stays open.
docs/RESEARCH_LEDGER.md CHANGED
@@ -727,3 +727,8 @@ Full-pool retry relaxes the recent-free guard; source count1022 enters diagnosti
727
  ## 2026-10-20 — RE-608 Grenade constructor with actual entity allocation (separate task commit)
728
 
729
  285971 now composes recovered277165/277125 before grenade descriptor and inherited velocity writes, preserving slot identity and in-use fields. Eight mode/reuse/ground-query combinations compare all220 record words to an independent grenade oracle. Existing supplied-allocation reports remain unchanged. Full suite: 935 tests pass. Report regenerates byte-identically (372396 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
 
 
 
 
 
 
727
  ## 2026-10-20 — RE-608 Grenade constructor with actual entity allocation (separate task commit)
728
 
729
  285971 now composes recovered277165/277125 before grenade descriptor and inherited velocity writes, preserving slot identity and in-use fields. Eight mode/reuse/ground-query combinations compare all220 record words to an independent grenade oracle. Existing supplied-allocation reports remain unchanged. Full suite: 935 tests pass. Report regenerates byte-identically (372396 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
730
+
731
+
732
+ ## 2026-10-20 — RE-609 Shared hitscan spread parameter calculation (separate task commit)
733
+
734
+ 290493 reads current packed slot/mode and weapon table stride432/mode stride52 to calculate base, counter-scaled and modifier-adjusted spread terms. 144 weapon/mode/flag/ground/modifier/counter fixtures match an independent source-order f32 oracle for eight locals and the velocity copy. Full suite: 938 tests pass. Report regenerates byte-identically (150821 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
@@ -868,3 +868,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
868
 
869
 
870
  - [x] RE-608 Grenade constructor with actual entity allocation ([report](research/QVM_ALLOCATED_GRENADE.md)).
 
 
 
 
868
 
869
 
870
  - [x] RE-608 Grenade constructor with actual entity allocation ([report](research/QVM_ALLOCATED_GRENADE.md)).
871
+
872
+
873
+ - [x] RE-609 Shared hitscan spread parameter calculation ([report](research/QVM_SPREAD_PARAMETERS.md)).
docs/research/QVM_SPREAD_PARAMETERS.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Shared hitscan spread parameter calculation
2
+
3
+ RE-609. Reproduce with `python3 scripts/analyze_qvm_spread_parameters.py`; check with `python3 scripts/test_qvm_spread_parameters.py`. The [machine report](qvm-spread-parameters.json) retains source identity and bounded fixtures.
4
+
5
+ Actual290494–290806 copies PS32 velocity and selects the current slot from PS144, with low-byte ID and bits16–23 mode. Table base4244+ID×432+mode×52 supplies offsets16/20/32/36/40. The prefix converts degrees by file literal1016003125, conditionally zeroes local56 when PS216==0, scales it under PS12 bit1 by0.75 grounded or1.25 airborne, and applies the PS4296 modifier. Counter×table40 is capped before its modifier. Locals40/88 are distinct scaled counter terms; field semantics remain offset-based. Independent f32 formulas reproduce all144 fixtures, including counter zero and a high value that exercises the cap. No random samples, endpoint, collision or damage execute here.
6
+
7
+ 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
@@ -426,3 +426,6 @@ The extension collector adds five focused tests for native tail calls, command-r
426
 
427
 
428
  [RE-608: Grenade constructor with actual entity allocation](QVM_ALLOCATED_GRENADE.md). Reproduce with `python3 scripts/analyze_qvm_allocated_grenade.py`; check with `python3 scripts/test_qvm_allocated_grenade.py`.
 
 
 
 
426
 
427
 
428
  [RE-608: Grenade constructor with actual entity allocation](QVM_ALLOCATED_GRENADE.md). Reproduce with `python3 scripts/analyze_qvm_allocated_grenade.py`; check with `python3 scripts/test_qvm_allocated_grenade.py`.
429
+
430
+
431
+ [RE-609: Shared hitscan spread parameter calculation](QVM_SPREAD_PARAMETERS.md). Reproduce with `python3 scripts/analyze_qvm_spread_parameters.py`; check with `python3 scripts/test_qvm_spread_parameters.py`.
docs/research/qvm-spread-parameters.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_spread_parameters.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Actual290493 parameter prefix, preserving source f32 operation order."""
3
+ import itertools
4
+ from pathlib import Path
5
+ from qvm_research_support import source,execute
6
+ from qvm_server_fire_support import seed,ENTITY
7
+ from analyze_qvm_acceleration import PS
8
+ from analyze_qvm_slide_prefix import vec
9
+ from analyze_qvm import write_json
10
+ LOCAL=0x79400000
11
+ OFFSETS=[36,64,56,48,68,80,40,88]
12
+
13
+ def parameters(ins,m):
14
+ m=dict(m);m[LOCAL+216]=ENTITY;slot=m[PS+144];packed=m[PS+312+4*slot];ident=packed&255;mode=(packed>>16)&255;address=4244+ident*432+mode*52
15
+ initial={'slot':slot,'packed':packed,'id':ident,'mode':mode,'flags12':m[PS+12],'ground':m[PS+68],'counter216':m[PS+216],'modifier4296':m[PS+4296],'velocity':vec(m,PS+32),'table_address':address,'table':{str(o):m[address+o]&0xffffffff for o in [16,20,32,36,40]}}
16
+ m,_,r=execute(ins,290494,290807,m,(0,0,0),LOCAL)
17
+ return m,{'initial':initial,'execution':r,'locals':{str(o):m[LOCAL+o]&0xffffffff for o in OFFSETS},'velocity_copy':vec(m,LOCAL+12)}
18
+
19
+ def main():
20
+ q,raw,h,ins=source();rows=[]
21
+ for ident,mode,flags,ground,modifier,counter in itertools.product([2,14,22],[0,1],[0,1],[0,1023],[0,1],[0,10,100000]):
22
+ m=seed(raw,h,ident);m[PS+144]=0;m[PS+312]=ident|(mode<<16);m[PS+12]=flags;m[PS+68]=ground;m[PS+4296]=modifier;m[PS+216]=counter;rows.append(parameters(ins,m)[1])
23
+ write_json(Path('docs/research/qvm-spread-parameters.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Actual290494–290806 only. File-backed weapon/mode table. Field names remain offsets where semantics unverified; speed normalization, PRNG, endpoint, trace and damage remain later boundaries.'})
24
+ if __name__=='__main__':main()
scripts/test_qvm_spread_parameters.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest
2
+ from pathlib import Path
3
+ from test_qvm_ground import word,n,f
4
+
5
+ def expected(p):
6
+ a=p['initial'];t={int(k):n(v) for k,v in a['table'].items()};rad=n(1016003125);base=f(rad*t[16]) if a['counter216'] else 0.0
7
+ if a['flags12']&1:base=f(base*n(1067450368 if a['ground']==1023 else 1061158912))
8
+ if a['modifier4296']:base=f(base*n(1058642330))
9
+ counter=min(f(f(float(a['counter216']))*t[40]),n(1189765120))
10
+ if a['modifier4296']:counter=f(counter*n(1063675494))
11
+ x=f(rad*t[36]);y=f(rad*t[32])
12
+ if a['modifier4296']:x=f(x*n(1061997773));y=f(y*n(1061997773))
13
+ return {'36':a['id'],'64':a['mode'],'56':word(base),'48':word(counter),'68':word(x),'80':word(y),'40':word(f(counter*n(940298085))),'88':word(f(float(a['counter216'])*n(940298085)))}
14
+ class SpreadParameterTests(unittest.TestCase):
15
+ @classmethod
16
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-spread-parameters.json').read_text())
17
+ def test_independent_scalar_oracle(self):
18
+ self.assertEqual(len(self.r['probes']),144)
19
+ for p in self.r['probes']:self.assertEqual(p['locals'],expected(p))
20
+ def test_layout_and_velocity_copy(self):
21
+ for p in self.r['probes']:
22
+ a=p['initial'];self.assertEqual(a['table_address'],4244+432*a['id']+52*a['mode']);self.assertEqual(p['velocity_copy'],a['velocity']);self.assertEqual(p['execution']['calls'],[])
23
+ def test_zero_counter_base(self):
24
+ for p in self.r['probes']:
25
+ if p['initial']['counter216']==0:self.assertEqual(p['locals']['56'],0);self.assertEqual(p['locals']['40'],0)
26
+ if __name__=='__main__':unittest.main()