qvm: damage protection and armor gates
Browse files- docs/ASSET_PIPELINE_TODO.md +3 -0
- 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/QVM_DAMAGE_PROTECTION.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-damage-protection.json +0 -0
- scripts/analyze_qvm_damage_protection.py +16 -0
- scripts/qvm_damage_support.py +32 -0
- scripts/test_qvm_damage_protection.py +27 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -772,3 +772,6 @@ Research progress: RE-700 [report](research/QVM_CONTACT_GATES.md); remaining nat
|
|
| 772 |
|
| 773 |
|
| 774 |
Research progress: RE-701 [report](research/RUST_MD3.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 772 |
|
| 773 |
|
| 774 |
Research progress: RE-701 [report](research/RUST_MD3.md); remaining native/content/runtime/platform scope stays open.
|
| 775 |
+
|
| 776 |
+
|
| 777 |
+
Research progress: RE-703 [report](research/QVM_DAMAGE_PROTECTION.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -1118,3 +1118,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 1118 |
|
| 1119 |
|
| 1120 |
**RE-701 — Rust original-byte MD3 asset core and cross-language validation:** A dependency-free Rust asset crate parses all619 originals with Python parity for headers, surfaces, sampled packed geometry, frame/tag float bits, UVs, triangles and shaders. [Evidence](research/RUST_MD3.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1118 |
|
| 1119 |
|
| 1120 |
**RE-701 — Rust original-byte MD3 asset core and cross-language validation:** A dependency-free Rust asset crate parses all619 originals with Python parity for headers, surfaces, sampled packed geometry, frame/tag float bits, UVs, triangles and shaders. [Evidence](research/RUST_MD3.md).
|
| 1121 |
+
|
| 1122 |
+
|
| 1123 |
+
**RE-703 — Damage protection and armor location selection:** 289594 rejects mode9 and strictly active spawn protection before location output; actual32155/32117 reclassifies head/torso using live inventory low bytes and health, excluding slot16. [Evidence](research/QVM_DAMAGE_PROTECTION.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1107,3 +1107,6 @@ Research progress: RE-701 [report](research/RUST_MD3.md); remaining native/conte
|
|
| 1107 |
|
| 1108 |
|
| 1109 |
RE-692–701 batch complete: [original models and Rust asset foundation](research/ORIGINAL_MODELS_RUST_BATCH.md). RE-702 tracks Bevy integration, native parity and downstream contact/damage; playable macOS/Linux Solari gameplay remains open.
|
|
|
|
|
|
|
|
|
|
|
|
| 1107 |
|
| 1108 |
|
| 1109 |
RE-692–701 batch complete: [original models and Rust asset foundation](research/ORIGINAL_MODELS_RUST_BATCH.md). RE-702 tracks Bevy integration, native parity and downstream contact/damage; playable macOS/Linux Solari gameplay remains open.
|
| 1110 |
+
|
| 1111 |
+
|
| 1112 |
+
Research progress: RE-703 [report](research/QVM_DAMAGE_PROTECTION.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1152,3 +1152,8 @@ Original-asset runs retain measurable source-point differences from conventional
|
|
| 1152 |
## 2026-10-21 — RE-701 Rust original-byte MD3 asset core and cross-language validation (separate task commit)
|
| 1153 |
|
| 1154 |
A dependency-free Rust asset crate parses all619 originals with Python parity for headers, surfaces, sampled packed geometry, frame/tag float bits, UVs, triangles and shaders. Ten offline Rust unit tests plus four Python corpus-parity tests cover all619 originals and malformed CLI inputs; build/CLI execute locally on macOS. Full suite: 1259 tests pass. Report regenerates byte-identically (1812358 bytes). Storage/filter, links and whitespace checks pass. No original assets/shared VM evaluator changed; the safe dependency-free Rust asset crate and offline CLI are introduced; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1152 |
## 2026-10-21 — RE-701 Rust original-byte MD3 asset core and cross-language validation (separate task commit)
|
| 1153 |
|
| 1154 |
A dependency-free Rust asset crate parses all619 originals with Python parity for headers, surfaces, sampled packed geometry, frame/tag float bits, UVs, triangles and shaders. Ten offline Rust unit tests plus four Python corpus-parity tests cover all619 originals and malformed CLI inputs; build/CLI execute locally on macOS. Full suite: 1259 tests pass. Report regenerates byte-identically (1812358 bytes). Storage/filter, links and whitespace checks pass. No original assets/shared VM evaluator changed; the safe dependency-free Rust asset crate and offline CLI are introduced; native/reference/legal/full platform scope remains open.
|
| 1155 |
+
|
| 1156 |
+
|
| 1157 |
+
## 2026-10-21 — RE-703 Damage protection and armor location selection (separate task commit)
|
| 1158 |
+
|
| 1159 |
+
289594 rejects mode9 and strictly active spawn protection before location output; actual32155/32117 reclassifies head/torso using live inventory low bytes and health, excluding slot16. 356 gate/inventory fixtures and independent boundary/notification/location oracles pass. Full suite: 1263 tests pass. Report regenerates byte-identically (653493 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
|
@@ -1150,3 +1150,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1150 |
|
| 1151 |
|
| 1152 |
- [ ] RE-702 Integrate the verified Rust MD3 core with Bevy, port original transform/geometry contracts, recover native loader/reference behavior and complete contact/damage/shared-pellet callers toward a playable macOS/Linux Solari slice. See the [next ten tasks](research/ORIGINAL_MODELS_RUST_BATCH.md#remaining-limits-and-next-ten-tasks).
|
|
|
|
|
|
|
|
|
|
|
|
| 1150 |
|
| 1151 |
|
| 1152 |
- [ ] RE-702 Integrate the verified Rust MD3 core with Bevy, port original transform/geometry contracts, recover native loader/reference behavior and complete contact/damage/shared-pellet callers toward a playable macOS/Linux Solari slice. See the [next ten tasks](research/ORIGINAL_MODELS_RUST_BATCH.md#remaining-limits-and-next-ten-tasks).
|
| 1153 |
+
|
| 1154 |
+
|
| 1155 |
+
- [x] RE-703 Damage protection and armor location selection ([report](research/QVM_DAMAGE_PROTECTION.md)).
|
docs/research/QVM_DAMAGE_PROTECTION.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Damage protection and armor location selection
|
| 2 |
+
|
| 3 |
+
RE-703. Reproduce with `python3 scripts/analyze_qvm_damage_protection.py`; check with `python3 scripts/test_qvm_damage_protection.py`. The [machine report](qvm-damage-protection.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
The source range289595–289761 uses signed millisecond arithmetic: time minus client4140 must be at least protection_seconds×1000. Mode9 returns zero first; active protection captures278003(attacker,110,targetID). Accepted inputs copy context68 to the location output. Locations1/2 resolve to1 without item22 or2 with it;3/4 resolve to3 without item17 or4 with it. Actual inventory routines require positive client208 and search exactly16 slots using the low byte. Slot16 is excluded. Clock, client presence and inventory inputs are explicit fixtures. Notification effects and damage continuation remain open.
|
| 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
|
@@ -708,3 +708,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 708 |
|
| 709 |
|
| 710 |
[RE-692–701: Original models and Rust asset foundation](ORIGINAL_MODELS_RUST_BATCH.md), with validation limits and the next ten tasks.
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
|
| 709 |
|
| 710 |
[RE-692–701: Original models and Rust asset foundation](ORIGINAL_MODELS_RUST_BATCH.md), with validation limits and the next ten tasks.
|
| 711 |
+
|
| 712 |
+
|
| 713 |
+
[RE-703: Damage protection and armor location selection](QVM_DAMAGE_PROTECTION.md). Reproduce with `python3 scripts/analyze_qvm_damage_protection.py`; check with `python3 scripts/test_qvm_damage_protection.py`.
|
docs/research/qvm-damage-protection.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_damage_protection.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Damage-factor protection gates and actual inventory-based location selection."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source
|
| 6 |
+
from qvm_damage_support import seed,run
|
| 7 |
+
from analyze_qvm import write_json
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
q,raw,h,ins=source();rows=[]
|
| 11 |
+
cases=[dict(mode=mode,now=now,location=loc,vest_slot=slot if loc in (3,4) else -1,helmet_slot=slot if loc in (1,2) else -1) for mode,now,loc,slot in itertools.product([3,9],[3999,4000,4001],range(1,15),[-1,0,15,16])]
|
| 12 |
+
cases += [dict(location=loc,client=client,health=health,vest_slot=0,helmet_slot=15) for loc,client,health in itertools.product([1,2,3,4,14],[False,True],[0,100])]
|
| 13 |
+
for a in cases:
|
| 14 |
+
_,p=run(ins,seed(raw,h,**a),289595,289762);p['input']=a;rows.append(p)
|
| 15 |
+
write_json(Path('docs/research/qvm-damage-protection.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Actual289595..289761,32155,32117. Notification278003 is captured without its effects; clock/client/inventory fixtures supplied. No health damage.'})
|
| 16 |
+
if __name__=='__main__':main()
|
scripts/qvm_damage_support.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Explicit bounded fixtures for damage-factor289594 research; no engine model."""
|
| 2 |
+
from qvm_research_support import constants
|
| 3 |
+
from qvm_trace_support import resume,captured
|
| 4 |
+
from analyze_qvm_interaction_request import inventory_check
|
| 5 |
+
from analyze_qvm_acceleration import word
|
| 6 |
+
L=0x79d00000
|
| 7 |
+
ATTACKER=L+4096
|
| 8 |
+
TARGET=L+8192
|
| 9 |
+
CLIENT=L+12288
|
| 10 |
+
CONTEXT=L+16384
|
| 11 |
+
LOCATION=L+20480
|
| 12 |
+
EXTRA=L+24576
|
| 13 |
+
|
| 14 |
+
def seed(raw,h,**x):
|
| 15 |
+
m=constants(raw,h,list(range(4068,4068+432*34,4))+list(range(32796,32856,4)))
|
| 16 |
+
m.update({L+o:0 for o in range(0,120,4)})
|
| 17 |
+
m.update({CLIENT+o:0 for o in range(0,6312,4)})
|
| 18 |
+
m.update({L+92:ATTACKER,L+96:TARGET,L+100:x.get('weapon',3),L+104:CONTEXT,L+108:LOCATION,L+112:EXTRA,LOCATION:x.get('location',3),EXTRA:word(x.get('extra',0.25)),CONTEXT+68:x.get('location',3),CONTEXT+84:word(x.get('distance',0)),TARGET:65,TARGET+520:CLIENT if x.get('client',True) else 0,TARGET+552:x.get('entity_flags',0),TARGET+836:0,CLIENT+208:x.get('health',100),CLIENT+4140:x.get('spawn',1000),CLIENT+4312:word(x.get('stamina',0)),CLIENT+220:x.get('flags',8),CLIENT+192:x.get('location_flags',16),CLIENT+4300:99,CLIENT+4304:x.get('counter',0),CLIENT+4316:77,CLIENT+144:0,CLIENT+312:x.get('held',0),CLIENT+6304:123,34992532:x.get('now',5000),34074804:x.get('protection_seconds',3),34090788:x.get('mode',3),34066516:x.get('override',0),L+20:word(x.get('factor',0.4)),L+24:x.get('wound',1),L+28:x.get('protected',0),L+32:word(x.get('ratio',0)),L+36:word(1)})
|
| 19 |
+
for item,slot in [(17,x.get('vest_slot',-1)),(22,x.get('helmet_slot',-1))]:
|
| 20 |
+
if slot>=0:m[CLIENT+376+4*slot]=0xaa0000|item
|
| 21 |
+
return m
|
| 22 |
+
|
| 23 |
+
def run(ins,m,start,stop):
|
| 24 |
+
notices=[]
|
| 25 |
+
def inventory(i,m,a):
|
| 26 |
+
m,_,v,r=inventory_check(i,m,a,(0,0,0));return m,v,r
|
| 27 |
+
before=snapshot(m)
|
| 28 |
+
m,e=resume(ins,start,stop,m,L,handlers={32155:inventory,278003:captured(278003,notices)})
|
| 29 |
+
return m,{'initial':before,'final':snapshot(m),'notices':notices,'execution':e}
|
| 30 |
+
|
| 31 |
+
def snapshot(m):
|
| 32 |
+
return {'locals':{str(o):m.get(L+o,0)&0xffffffff for o in [20,24,28,32,36,40,44,48,52,56]},'location':m[LOCATION]&0xffffffff,'extra':m[EXTRA]&0xffffffff,'client':{str(o):m[CLIENT+o]&0xffffffff for o in [192,220,4300,4304,4312,4316,6304]},'attacker_pointer':m[TARGET+836]}
|
scripts/test_qvm_damage_protection.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
class DamageProtectionTests(unittest.TestCase):
|
| 4 |
+
@classmethod
|
| 5 |
+
def setUpClass(cls):cls.ps=json.loads(Path('docs/research/qvm-damage-protection.json').read_text())['probes']
|
| 6 |
+
def test_strict_clock_and_mode_gates(self):
|
| 7 |
+
for p in self.ps:
|
| 8 |
+
a=p['input'];protected=a.get('now',5000)-1000<3000;blocked=a.get('mode',3)==9 or protected
|
| 9 |
+
self.assertEqual(p['execution']['return'],0 if blocked else None)
|
| 10 |
+
self.assertEqual(p['execution']['stop'],289641 if a.get('mode',3)==9 else 289661 if protected else 289762)
|
| 11 |
+
def test_actual_low_byte_inventory_reclassification(self):
|
| 12 |
+
for p in self.ps:
|
| 13 |
+
a=p['input'];loc=a['location'];blocked=a.get('mode',3)==9 or a.get('now',5000)-1000<3000
|
| 14 |
+
if not blocked and a.get('client',True):
|
| 15 |
+
if loc in (1,2):loc=2 if a.get('health',100)>0 and 0<=a.get('helmet_slot',-1)<16 else 1
|
| 16 |
+
if loc in (3,4):loc=4 if a.get('health',100)>0 and 0<=a.get('vest_slot',-1)<16 else 3
|
| 17 |
+
self.assertEqual(p['final']['location'],loc)
|
| 18 |
+
def test_protection_notification_arguments(self):
|
| 19 |
+
from qvm_damage_support import ATTACKER
|
| 20 |
+
for p in self.ps:
|
| 21 |
+
a=p['input'];notify=a.get('mode',3)!=9 and a.get('now',5000)-1000<3000
|
| 22 |
+
self.assertEqual(len(p['notices']),int(notify))
|
| 23 |
+
if notify:self.assertEqual(p['notices'][0]['arguments'],{'8':ATTACKER,'12':110,'16':65})
|
| 24 |
+
def test_inventory_slot_sixteen_is_excluded(self):
|
| 25 |
+
rows=[p for p in self.ps if p['input'].get('vest_slot')==16 and p['input']['location']==4 and p['execution']['return'] is None]
|
| 26 |
+
self.assertTrue(rows);self.assertTrue(all(p['final']['location']==3 for p in rows))
|
| 27 |
+
if __name__=='__main__':unittest.main()
|