"""Original D50 supplemental records: full paired functions, no process access."""
import hashlib,importlib.util,json,struct
from pathlib import Path
spec=importlib.util.spec_from_file_location('audit',Path(__file__).with_name('Audit-GalaxyClientCompatibility.py'))
audit=importlib.util.module_from_spec(spec);spec.loader.exec_module(audit)
old=audit.Image(Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe'))
new=audit.Image(Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe'))
hashes=[hashlib.sha256(i.raw).hexdigest() for i in (old,new)]
if hashes!=['6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93',
'ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63']:raise ValueError('D50 proof image changed')
functions=[];refs=[]
for before in [0x3A06740,0x3A26FA0,0x3A15D90,0x3A66600,0x3B346B0,0x3A25340,0x3A431C0]:
span=old.function(before)
if not span or span[0]!=before:raise ValueError('Exact D50 source function missing')
row=audit.match(old,new,before,span[1]-before)
if row['status']!='unique':raise ValueError('D50 complete source is not unique: '+hex(before))
row['oldRva']=hex(before);functions.append(row)
refs+=audit.references(old,new,before,int(row['newRva'],16),row['length'])
tables={}
for before,expected in [(0x551F2D8,0x551F2A8),(0x551F308,0x551F2D8),(0x551F408,0x551F3D8),(0x551F548,0x551F518)]:
actual={r[1] for r in refs if r[0]==before}
if actual!={expected}:raise ValueError('D50 renderer actual constructor vtable operand changed')
tables[hex(before)]=hex(expected)
slot=dict(oldVtable='0x551f408',newVtable='0x551f3d8',slot='0x80',oldRva='0x3a665f0',newRva='0x3a66550')
for im,prefix in ((old,'old'),(new,'new')):
if struct.unpack('<Q',im.data(int(slot[prefix+'Vtable'],16)+0x80,8))[0]-im.base!=int(slot[prefix+'Rva'],16):
raise ValueError('D50 Main interface update slot changed')
folder=Path('artifacts/galaxy-query-research/point-overrides');folder.mkdir(parents=True,exist_ok=True)
result=dict(runtimeNeutral=True,runtimeValidated=False,canInstallHooks=False,gameCalls=0,oldImageSha256=hashes[0],newImageSha256=hashes[1],
functions=functions,vtables=tables,slots=[slot],references=[list(map(hex,r)) for r in refs],
source=dict(typeInterface='componentbase+60',mainInterface='componentbase+58',container='componentbase+D50',
header=dict(count=8,capacity=0x10,storage=0x18),bitmapBytes='((capacity>>3)+7)&~7',rowStride=24,
row=dict(sharedObject=0,pending=8,minimumExtra=0xC,farFade=0x10),
shared=dict(state=0x20,readyState=2,id=0x28,compact=0x38,compactId=0)),
channels=dict(primarySize='style+0 from selected provider+48; stored at56B row+14, unchanged by D50 minimum',
originalExtra='style+1C from selected provider+60; stored at56B row+30',
overriddenExtra='max(style+1C,D50row+C); stored at56B row+10',
ordinaryPoint='3A25340 passes row+14 as style to3A431C0; its param4 is EyeDistanceSquared, not row+10'),
limits=['D50 minimum is NOT the ordinary point primary size. Do not max RelativeSize with it.',
'Row+10 extra downstream geometry needs its own consumer proof before use.',
'No game methods invoked; full native/live acceptance remains separate.'])
path=folder/'compatibility.json';path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),functions=len(functions),vtables=tables,slot=slot,primarySizeNotMaxed=True),indent=2))
"""Original D50 supplemental records: full paired functions, no process access."""
import hashlib,importlib.util,json,struct
from pathlib import Path
spec=importlib.util.spec_from_file_location('audit',Path(__file__).with_name('Audit-GalaxyClientCompatibility.py'))
audit=importlib.util.module_from_spec(spec);spec.loader.exec_module(audit)
old=audit.Image(Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe'))
new=audit.Image(Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe'))
hashes=[hashlib.sha256(i.raw).hexdigest() for i in (old,new)]
if hashes!=['6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93',
'ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63']:raise ValueError('D50 proof image changed')
functions=[];refs=[]
for before in [0x3A06740,0x3A26FA0,0x3A15D90,0x3A66600,0x3B346B0,0x3A25340,0x3A431C0]:
span=old.function(before)
if not span or span[0]!=before:raise ValueError('Exact D50 source function missing')
row=audit.match(old,new,before,span[1]-before)
if row['status']!='unique':raise ValueError('D50 complete source is not unique: '+hex(before))
row['oldRva']=hex(before);functions.append(row)
refs+=audit.references(old,new,before,int(row['newRva'],16),row['length'])
tables={}
for before,expected in [(0x551F2D8,0x551F2A8),(0x551F308,0x551F2D8),(0x551F408,0x551F3D8),(0x551F548,0x551F518)]:
actual={r[1] for r in refs if r[0]==before}
if actual!={expected}:raise ValueError('D50 renderer actual constructor vtable operand changed')
tables[hex(before)]=hex(expected)
slot=dict(oldVtable='0x551f408',newVtable='0x551f3d8',slot='0x80',oldRva='0x3a665f0',newRva='0x3a66550')
for im,prefix in ((old,'old'),(new,'new')):
if struct.unpack('<Q',im.data(int(slot[prefix+'Vtable'],16)+0x80,8))[0]-im.base!=int(slot[prefix+'Rva'],16):
raise ValueError('D50 Main interface update slot changed')
folder=Path('artifacts/galaxy-query-research/point-overrides');folder.mkdir(parents=True,exist_ok=True)
result=dict(runtimeNeutral=True,runtimeValidated=False,canInstallHooks=False,gameCalls=0,oldImageSha256=hashes[0],newImageSha256=hashes[1],
functions=functions,vtables=tables,slots=[slot],references=[list(map(hex,r)) for r in refs],
source=dict(typeInterface='componentbase+60',mainInterface='componentbase+58',container='componentbase+D50',
header=dict(count=8,capacity=0x10,storage=0x18),bitmapBytes='((capacity>>3)+7)&~7',rowStride=24,
row=dict(sharedObject=0,pending=8,minimumExtra=0xC,farFade=0x10),
shared=dict(state=0x20,readyState=2,id=0x28,compact=0x38,compactId=0)),
channels=dict(primarySize='style+0 from selected provider+48; stored at56B row+14, unchanged by D50 minimum',
originalExtra='style+1C from selected provider+60; stored at56B row+30',
overriddenExtra='max(style+1C,D50row+C); stored at56B row+10',
ordinaryPoint='3A25340 passes row+14 as style to3A431C0; its param4 is EyeDistanceSquared, not row+10'),
limits=['D50 minimum is NOT the ordinary point primary size. Do not max RelativeSize with it.',
'Row+10 extra downstream geometry needs its own consumer proof before use.',
'No game methods invoked; full native/live acceptance remains separate.'])
path=folder/'compatibility.json';path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),functions=len(functions),vtables=tables,slot=slot,primarySizeNotMaxed=True),indent=2))