"""Pin original/new DD4 range operands; offline PE reads, no game calls."""
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'))
assert hashlib.sha256(old.raw).hexdigest()=='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
assert hashlib.sha256(new.raw).hexdigest()=='ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63'
rva=0x3b46fd0;fn=old.function(rva);assert fn[0]==rva
matched=audit.match(old,new,rva,fn[1]-rva);assert matched['status']=='unique'
after=int(matched['newRva'],16)
refs=audit.references(old,new,rva,after,matched['length'])
bindings={a:b for a,b,_,_ in refs}
constants={
'one':0x4de165c,'worldMinimum':0x5169300,'worldYMaximumBase':0x55374ec,
'cellLimitMargin':0x51e6e48,'cellCoordinateScale':0x4e29758,
'debugRadiusSquared':0x551df20,'debugRangeScale':0x51daf4c,
'referenceFadeStart':0x4e340fc,'referenceFadeLength':0x515dc60,
'debugRegionX':0x523fde0,'debugRegionY':0x523fddc,'debugRegionZ':0x523fdd8,
}
rows=[]
for name,before in constants.items():
target=bindings[before]
a=old.data(before,4);b=new.data(target,4);assert a==b
rows.append(dict(name=name,oldRva=hex(before),newRva=hex(target),bytesHex=a.hex(),value=struct.unpack('<f',a)[0]))
runtime=[]
for name,before in [('debugRangeEnabled',0x5e9d38d),('cellLimitVector',0x5fdf210)]:
target=bindings[before]
runtime.append(dict(name=name,oldRva=hex(before),newRva=hex(target),value=None,
source='matching DD4 update RIP operand; runtime contents are unknown'))
result=dict(runtimeNeutral=True,gameProcessAccess=False,gameCalls=0,canInstallHooks=False,runtimeValidated=False,
oldImageSha256=hashlib.sha256(old.raw).hexdigest(),newImageSha256=hashlib.sha256(new.raw).hexdigest(),
function=dict(oldRva=hex(rva),newRva=hex(after),**{k:v for k,v in matched.items() if k not in ['newRva']}),
constants=rows,runtime=runtime,
references=[dict(oldRva=hex(a),newRva=hex(b),instructionOldRva=hex(at)) for a,b,_,at in refs],
formula=dict(worldClamp='min(max(input,worldMinimum),[163838,YMaximumBase,163838]-worldMinimum)',
cellCentre='clamp(clampedWorld,0,cellLimitVector-cellLimitMargin)',
ordinaryModifier='smallMode ? 1 : clamp((distance(rawInput,referencePosition)-fadeStart)/fadeLength,0,1)',
debugBranch='only when !smallMode && runtime debugRangeEnabled && viewMode==2 && raw input inside strict debug radius',
debugEffect='multiply ordinary modifier by debugRangeScale; original callback changes too, so ordinary descriptor cannot certify this branch'))
path=Path('artifacts/galaxy-query-research/constellations/catalogue-range-constants.json')
path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),function=result['function'],constants=rows,runtime=runtime),indent=2))
"""Pin original/new DD4 range operands; offline PE reads, no game calls."""
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'))
assert hashlib.sha256(old.raw).hexdigest()=='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
assert hashlib.sha256(new.raw).hexdigest()=='ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63'
rva=0x3b46fd0;fn=old.function(rva);assert fn[0]==rva
matched=audit.match(old,new,rva,fn[1]-rva);assert matched['status']=='unique'
after=int(matched['newRva'],16)
refs=audit.references(old,new,rva,after,matched['length'])
bindings={a:b for a,b,_,_ in refs}
constants={
'one':0x4de165c,'worldMinimum':0x5169300,'worldYMaximumBase':0x55374ec,
'cellLimitMargin':0x51e6e48,'cellCoordinateScale':0x4e29758,
'debugRadiusSquared':0x551df20,'debugRangeScale':0x51daf4c,
'referenceFadeStart':0x4e340fc,'referenceFadeLength':0x515dc60,
'debugRegionX':0x523fde0,'debugRegionY':0x523fddc,'debugRegionZ':0x523fdd8,
}
rows=[]
for name,before in constants.items():
target=bindings[before]
a=old.data(before,4);b=new.data(target,4);assert a==b
rows.append(dict(name=name,oldRva=hex(before),newRva=hex(target),bytesHex=a.hex(),value=struct.unpack('<f',a)[0]))
runtime=[]
for name,before in [('debugRangeEnabled',0x5e9d38d),('cellLimitVector',0x5fdf210)]:
target=bindings[before]
runtime.append(dict(name=name,oldRva=hex(before),newRva=hex(target),value=None,
source='matching DD4 update RIP operand; runtime contents are unknown'))
result=dict(runtimeNeutral=True,gameProcessAccess=False,gameCalls=0,canInstallHooks=False,runtimeValidated=False,
oldImageSha256=hashlib.sha256(old.raw).hexdigest(),newImageSha256=hashlib.sha256(new.raw).hexdigest(),
function=dict(oldRva=hex(rva),newRva=hex(after),**{k:v for k,v in matched.items() if k not in ['newRva']}),
constants=rows,runtime=runtime,
references=[dict(oldRva=hex(a),newRva=hex(b),instructionOldRva=hex(at)) for a,b,_,at in refs],
formula=dict(worldClamp='min(max(input,worldMinimum),[163838,YMaximumBase,163838]-worldMinimum)',
cellCentre='clamp(clampedWorld,0,cellLimitVector-cellLimitMargin)',
ordinaryModifier='smallMode ? 1 : clamp((distance(rawInput,referencePosition)-fadeStart)/fadeLength,0,1)',
debugBranch='only when !smallMode && runtime debugRangeEnabled && viewMode==2 && raw input inside strict debug radius',
debugEffect='multiply ordinary modifier by debugRangeScale; original callback changes too, so ordinary descriptor cannot certify this branch'))
path=Path('artifacts/galaxy-query-research/constellations/catalogue-range-constants.json')
path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),function=result['function'],constants=rows,runtime=runtime),indent=2))