"""Pinned original territory constants and verified current RIP bindings only."""
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'))
previous=json.loads(Path('artifacts/galaxy-query-research/power-outer-sources/compatibility.json').read_text())
rows=[];refs=[]
for before in (0x3B27690,0x3B28170,0x3B27100,0x3B27F60,0x3AF6A80):
row=next((r for r in previous['functions'] if int(r['oldRva'],16)==before),None)
if row is None:
span=old.function(before);row=audit.match(old,new,before,span[1]-before)
if row['status']!='unique':raise ValueError('Territory body changed')
rows.append(dict(old=hex(before),new=row['newRva'],bytes=row['length'],status=row['status']))
refs.extend(audit.references(old,new,before,int(row['newRva'],16),row['length']))
fields={}
for before,name in ((0x5FDB275,'overrideColourAlpha'),(0x5FDB277,'overrideGeometry'),(0x5E9D3DC,'overrideOpacity'),(0x5E9D3E0,'overrideRadiusMultiplier'),(0x4DF0DD0,'maximumMinimumThreshold')):
candidates={r[1] for r in refs if r[0]==before}
if len(candidates)!=1:raise ValueError('Unclosed exact original global '+hex(before))
after=candidates.pop();row=dict(oldRva=hex(before),newRva=hex(after))
if 'override' not in name or name in ('overrideOpacity','overrideRadiusMultiplier'):
row['oldStaticFloat']=struct.unpack('<f',old.data(before,4))[0]
row['newStaticFloat']=struct.unpack('<f',new.data(after,4))[0]
fields[name]=row
conversion=[]
for before in (0x3AC40B0,0x6CC950):
span=old.function(before);row=audit.match(old,new,before,span[1]-before)
if row['status']!='unique':raise ValueError('Original dual-colour conversion changed')
conversion.append(dict(oldRva=hex(before),newRva=row['newRva'],bytes=row['length'],status=row['status']))
if before==0x3AC40B0:conversion_refs=audit.references(old,new,before,int(row['newRva'],16),row['length'])
conversion_constants={}
for getter,constant,name in ((0x6CC880,0x50FF9C0,'gamma'),(0x6CC890,0x4E3203C,'offset')):
target={r[1] for r in conversion_refs if r[0]==getter}
if len(target)!=1:raise ValueError('Dual conversion parameter getter changed')
after=target.pop();length=next(i.address+i.size-old.base-getter for i in old.instructions(getter,64) if i.mnemonic=='ret')
raw,mask,*_=audit.signature(old,getter,length);actual=new.data(after,length)
if any(a!=b for a,b,keep in zip(raw,actual,mask) if keep):raise ValueError('Conversion parameter getter body changed')
constants={r[1] for r in audit.references(old,new,getter,after,length) if r[0]==constant}
if len(constants)!=1:raise ValueError('Conversion exact float binding changed')
new_constant=constants.pop();before_value=struct.unpack('<f',old.data(constant,4))[0];after_value=struct.unpack('<f',new.data(new_constant,4))[0]
if before_value!=after_value:raise ValueError('Original conversion constant changed')
conversion_constants[name]=dict(oldGetter=hex(getter),newGetter=hex(after),oldConstant=hex(constant),newConstant=hex(new_constant),value=after_value)
config=json.loads(Path('artifacts/galaxy-query-research/palette-resources/original-appearance.json').read_text())
out=dict(oldImageSha256=hashlib.sha256(old.raw).hexdigest(),newImageSha256=hashlib.sha256(new.raw).hexdigest(),
runtimeNeutral=True,gameCalls=0,functions=rows,fields=fields,sourceResource=config['sourceResource'],sourceSha256=config['sourceSha256'],
baseSize=config['defaultSize'],minimumFactor=config['unknownFields']['0x11c'],maximumFactor=config['unknownFields']['0x120'],
geometryRadiusMultiplier=config['unknownFields']['0x12c'],geometryOpacityMultiplier=config['unknownFields']['0x130'],
pointDistanceDivisor=config['unknownFields']['0x134'],pointDistanceMaximum=config['unknownFields']['0x138'],
colourConversionFunctions=conversion,colourConversionConstants=conversion_constants)
path=Path('artifacts/galaxy-query-research/power-outer-sources/territory-constants.json');path.write_text(json.dumps(out,indent=2)+'\n')
print(json.dumps(out,indent=2))
"""Pinned original territory constants and verified current RIP bindings only."""
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'))
previous=json.loads(Path('artifacts/galaxy-query-research/power-outer-sources/compatibility.json').read_text())
rows=[];refs=[]
for before in (0x3B27690,0x3B28170,0x3B27100,0x3B27F60,0x3AF6A80):
row=next((r for r in previous['functions'] if int(r['oldRva'],16)==before),None)
if row is None:
span=old.function(before);row=audit.match(old,new,before,span[1]-before)
if row['status']!='unique':raise ValueError('Territory body changed')
rows.append(dict(old=hex(before),new=row['newRva'],bytes=row['length'],status=row['status']))
refs.extend(audit.references(old,new,before,int(row['newRva'],16),row['length']))
fields={}
for before,name in ((0x5FDB275,'overrideColourAlpha'),(0x5FDB277,'overrideGeometry'),(0x5E9D3DC,'overrideOpacity'),(0x5E9D3E0,'overrideRadiusMultiplier'),(0x4DF0DD0,'maximumMinimumThreshold')):
candidates={r[1] for r in refs if r[0]==before}
if len(candidates)!=1:raise ValueError('Unclosed exact original global '+hex(before))
after=candidates.pop();row=dict(oldRva=hex(before),newRva=hex(after))
if 'override' not in name or name in ('overrideOpacity','overrideRadiusMultiplier'):
row['oldStaticFloat']=struct.unpack('<f',old.data(before,4))[0]
row['newStaticFloat']=struct.unpack('<f',new.data(after,4))[0]
fields[name]=row
conversion=[]
for before in (0x3AC40B0,0x6CC950):
span=old.function(before);row=audit.match(old,new,before,span[1]-before)
if row['status']!='unique':raise ValueError('Original dual-colour conversion changed')
conversion.append(dict(oldRva=hex(before),newRva=row['newRva'],bytes=row['length'],status=row['status']))
if before==0x3AC40B0:conversion_refs=audit.references(old,new,before,int(row['newRva'],16),row['length'])
conversion_constants={}
for getter,constant,name in ((0x6CC880,0x50FF9C0,'gamma'),(0x6CC890,0x4E3203C,'offset')):
target={r[1] for r in conversion_refs if r[0]==getter}
if len(target)!=1:raise ValueError('Dual conversion parameter getter changed')
after=target.pop();length=next(i.address+i.size-old.base-getter for i in old.instructions(getter,64) if i.mnemonic=='ret')
raw,mask,*_=audit.signature(old,getter,length);actual=new.data(after,length)
if any(a!=b for a,b,keep in zip(raw,actual,mask) if keep):raise ValueError('Conversion parameter getter body changed')
constants={r[1] for r in audit.references(old,new,getter,after,length) if r[0]==constant}
if len(constants)!=1:raise ValueError('Conversion exact float binding changed')
new_constant=constants.pop();before_value=struct.unpack('<f',old.data(constant,4))[0];after_value=struct.unpack('<f',new.data(new_constant,4))[0]
if before_value!=after_value:raise ValueError('Original conversion constant changed')
conversion_constants[name]=dict(oldGetter=hex(getter),newGetter=hex(after),oldConstant=hex(constant),newConstant=hex(new_constant),value=after_value)
config=json.loads(Path('artifacts/galaxy-query-research/palette-resources/original-appearance.json').read_text())
out=dict(oldImageSha256=hashlib.sha256(old.raw).hexdigest(),newImageSha256=hashlib.sha256(new.raw).hexdigest(),
runtimeNeutral=True,gameCalls=0,functions=rows,fields=fields,sourceResource=config['sourceResource'],sourceSha256=config['sourceSha256'],
baseSize=config['defaultSize'],minimumFactor=config['unknownFields']['0x11c'],maximumFactor=config['unknownFields']['0x120'],
geometryRadiusMultiplier=config['unknownFields']['0x12c'],geometryOpacityMultiplier=config['unknownFields']['0x130'],
pointDistanceDivisor=config['unknownFields']['0x134'],pointDistanceMaximum=config['unknownFields']['0x138'],
colourConversionFunctions=conversion,colourConversionConstants=conversion_constants)
path=Path('artifacts/galaxy-query-research/power-outer-sources/territory-constants.json');path.write_text(json.dumps(out,indent=2)+'\n')
print(json.dumps(out,indent=2))