"""Verify RootGalaxyMap's authored economy RGB vector and actual consumers, offline."""
import argparse,hashlib,json,math,struct
from pathlib import Path
import pefile
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--verify',action='store_true')
args=parser.parse_args()
root=Path('artifacts/galaxy-query-research/palette-resources')
image=Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe').read_bytes()
image_sha=hashlib.sha256(image).hexdigest()
assert image_sha=='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
pe=pefile.PE(data=image,fast_load=True);base=pe.OPTIONAL_HEADER.ImageBase
pe.parse_data_directories(directories=[3])
scope={};exec(Path('research/Extract-OriginalGalaxyAppearance.py').read_text().split('# Federation row')[0],scope)
f=scope['f'];b=scope['b'];at=scope['at'];refs=scope['references'];roots=scope['roots'];string=scope['string']
assert hashlib.sha256(f).hexdigest()=='20339ca4f57ea23dc8002e04d8a04bed45d64345d87e4c3f6ae4cc3fc071ca60'
assert hashlib.sha256(b).hexdigest()=='5135b3d55e5239b3d11f79a76adeda954eb78be5101b6a516fd25df257affa77'
name='RootGalaxyMap';name_hash=5381
for value in name.lower().encode():name_hash=(name_hash*33+value)&0xffffffff
assert name_hash==0x6e6841cd
record=struct.unpack_from('<5I',f,0xd4648)
assert record==(name_hash,10,647,590,3168)
entity=roots[647][2:];vector=refs[entity[0],entity[1]+0x10]
assert struct.unpack_from('<I',b,at(entity)+0x18)[0]==309
assert refs[vector[0],vector[1]+94*8]==(590,3168)
assert pe.get_data(0x4de07a0,14)==b'RootGalaxyMap\0'
# The name registration installs this actual factory vtable, whose +8
# allocates with the same class allocator and invokes3AD0370.
for rva,raw in {0x1f5715:'488d0584b0be04',0x1f57c1:'488d0dc8dcd005e84392fbff',
0x1f1441:'488d0d781fd105',0x1f146c:'e8ffee8d03'}.items():
assert pe.get_data(rva,len(bytes.fromhex(raw)))==bytes.fromhex(raw)
assert struct.unpack('<Q',pe.get_data(0x4de0ca0+8,8))[0]-base==0x1f1430
assert struct.unpack('<Q',pe.get_data(0x552a410+0x60,8))[0]-base==0x3b379a0
assert struct.unpack('<Q',pe.get_data(0x552a5d0+0x20,8))[0]-base==0x978af0
ctor=(root/'decompiled/solo-3ad0370.c').read_text()
activate=(root/'solo-3b379a0.c').read_text()
register=(root/'decompiled/solo-1aea10.c').read_text()
assert 'param_1[10] = param_3;' in ctor and 'param_1[0xc] = &UNK_14552a5d0;' in ctor
assert '*param_1 = &UNK_144de0ca0;' in register
assert 'puVar11 = *(undefined8 **)(*(longlong *)(param_1 + 0x48) + 0x20)' in activate
assert 'puVar11 = puVar11 + 3' in activate and 'func_0x000143c42860' in activate
assert 'iStack_f4 = 0x3f800000;' in Path('artifacts/galaxy-query-research/filter-enums/decompiled/solo-3ac41d0.c').read_text()
config=(590,3168);pointer=refs[config[0],config[1]+0x20]
count=struct.unpack_from('<I',b,at(config)+0x28)[0]
assert pointer==(338,4624) and count==11
names=['None','Extraction','Refinery','Industrial','Agri','Terraforming','HighTech','Colony','Service','Tourism','Military']
enum=json.loads((root/'code-tables.json').read_text())['enumerations']['economy']
ids={row['name']:row['value'] for row in enum};rows=[]
for index,expected in enumerate(names):
p=(pointer[0],pointer[1]+24*index);label=string(refs[p]);assert label==expected
rgb=struct.unpack_from('<3f',b,at(p)+8);assert all(math.isfinite(v) for v in rgb)
rows.append(dict(name=label,nativeId=ids[label],key='agriculture' if label=='Agri' else label.lower(),
rgb=list(rgb),sourcePointer=list(p),sourceBytes=b[at(p):at(p)+24].hex()))
sources=[root/'decompiled/solo-1f47a0.c',root/'decompiled/solo-1aea10.c',root/'decompiled/solo-3ad0370.c',
root/'solo-3b379a0.c',root/'solo-978af0.c',root/'solo-3b136a0.c',
Path('artifacts/galaxy-query-research/filter-enums/decompiled/solo-3ac41d0.c')]
functions=[]
for rva in [0x1f47a0,0x1aea10,0x1f1430,0x3ad0370,0x3b379a0,0x3b136a0,0x3ac41d0]:
entry=next(e.struct for e in pe.DIRECTORY_ENTRY_EXCEPTION if e.struct.BeginAddress==rva)
body=pe.get_data(rva,entry.EndAddress-rva)
functions.append(dict(rva=hex(rva),bytes=len(body),sha256=hashlib.sha256(body).hexdigest()))
result=dict(imageSha256=image_sha,resourceSha256='29a90189d0bb238c88d09dcc0f15ff751ea29aa208b1a90894ef3b47f8942e5f',
fresSha256=hashlib.sha256(f).hexdigest(),frozenSha256=hashlib.sha256(b).hexdigest(),gameProcessAccess=False,gameCalls=0,
binding=dict(name=name,hash=hex(name_hash),recordOffset='0xd4648',record=list(record),rootOrdinal=647,
componentIndex=94,configuration=list(config),vectorField='0x20',vector=list(pointer),count=count,
nativeRegistration='0x1f47a0',nativeNameHelper='0x1aea10',factoryVtable='0x4de0ca0',factory='0x1f1430',constructor='0x3ad0370'),
runtimeMap=dict(baseOffset='0x198',recordBytes=32,key='native economy enum',rgbOffsets=['0x10','0x14','0x18'],
publishedInterfaceOffset='0x60',publishedVtable='0x552a5d0',tableGetter='0x978af0',colourGetter='0x3b136a0'),
rows=rows,sourceColourAlpha=1,functions=functions,sources=[dict(path=str(p).replace('\\','/'),sha256=hashlib.sha256(p.read_bytes()).hexdigest()) for p in sources],
remainingLimits=['Only the11 authored original rows; other enum values have no asserted original palette colour',
'Pinned original configuration defaults, not proof of current runtime overrides or same-state live rendering'])
target=root/'original-economy-colours.json';text=json.dumps(result,indent=2)+'\n'
if args.verify:
assert target.read_text()==text,'Economy evidence changed; inspect before regenerating'
else:target.write_text(text)
print(json.dumps(dict(verified=True,name=name,rows=len(rows),keys=[r['key'] for r in rows])))
"""Verify RootGalaxyMap's authored economy RGB vector and actual consumers, offline."""
import argparse,hashlib,json,math,struct
from pathlib import Path
import pefile
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--verify',action='store_true')
args=parser.parse_args()
root=Path('artifacts/galaxy-query-research/palette-resources')
image=Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe').read_bytes()
image_sha=hashlib.sha256(image).hexdigest()
assert image_sha=='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
pe=pefile.PE(data=image,fast_load=True);base=pe.OPTIONAL_HEADER.ImageBase
pe.parse_data_directories(directories=[3])
scope={};exec(Path('research/Extract-OriginalGalaxyAppearance.py').read_text().split('# Federation row')[0],scope)
f=scope['f'];b=scope['b'];at=scope['at'];refs=scope['references'];roots=scope['roots'];string=scope['string']
assert hashlib.sha256(f).hexdigest()=='20339ca4f57ea23dc8002e04d8a04bed45d64345d87e4c3f6ae4cc3fc071ca60'
assert hashlib.sha256(b).hexdigest()=='5135b3d55e5239b3d11f79a76adeda954eb78be5101b6a516fd25df257affa77'
name='RootGalaxyMap';name_hash=5381
for value in name.lower().encode():name_hash=(name_hash*33+value)&0xffffffff
assert name_hash==0x6e6841cd
record=struct.unpack_from('<5I',f,0xd4648)
assert record==(name_hash,10,647,590,3168)
entity=roots[647][2:];vector=refs[entity[0],entity[1]+0x10]
assert struct.unpack_from('<I',b,at(entity)+0x18)[0]==309
assert refs[vector[0],vector[1]+94*8]==(590,3168)
assert pe.get_data(0x4de07a0,14)==b'RootGalaxyMap\0'
# The name registration installs this actual factory vtable, whose +8
# allocates with the same class allocator and invokes3AD0370.
for rva,raw in {0x1f5715:'488d0584b0be04',0x1f57c1:'488d0dc8dcd005e84392fbff',
0x1f1441:'488d0d781fd105',0x1f146c:'e8ffee8d03'}.items():
assert pe.get_data(rva,len(bytes.fromhex(raw)))==bytes.fromhex(raw)
assert struct.unpack('<Q',pe.get_data(0x4de0ca0+8,8))[0]-base==0x1f1430
assert struct.unpack('<Q',pe.get_data(0x552a410+0x60,8))[0]-base==0x3b379a0
assert struct.unpack('<Q',pe.get_data(0x552a5d0+0x20,8))[0]-base==0x978af0
ctor=(root/'decompiled/solo-3ad0370.c').read_text()
activate=(root/'solo-3b379a0.c').read_text()
register=(root/'decompiled/solo-1aea10.c').read_text()
assert 'param_1[10] = param_3;' in ctor and 'param_1[0xc] = &UNK_14552a5d0;' in ctor
assert '*param_1 = &UNK_144de0ca0;' in register
assert 'puVar11 = *(undefined8 **)(*(longlong *)(param_1 + 0x48) + 0x20)' in activate
assert 'puVar11 = puVar11 + 3' in activate and 'func_0x000143c42860' in activate
assert 'iStack_f4 = 0x3f800000;' in Path('artifacts/galaxy-query-research/filter-enums/decompiled/solo-3ac41d0.c').read_text()
config=(590,3168);pointer=refs[config[0],config[1]+0x20]
count=struct.unpack_from('<I',b,at(config)+0x28)[0]
assert pointer==(338,4624) and count==11
names=['None','Extraction','Refinery','Industrial','Agri','Terraforming','HighTech','Colony','Service','Tourism','Military']
enum=json.loads((root/'code-tables.json').read_text())['enumerations']['economy']
ids={row['name']:row['value'] for row in enum};rows=[]
for index,expected in enumerate(names):
p=(pointer[0],pointer[1]+24*index);label=string(refs[p]);assert label==expected
rgb=struct.unpack_from('<3f',b,at(p)+8);assert all(math.isfinite(v) for v in rgb)
rows.append(dict(name=label,nativeId=ids[label],key='agriculture' if label=='Agri' else label.lower(),
rgb=list(rgb),sourcePointer=list(p),sourceBytes=b[at(p):at(p)+24].hex()))
sources=[root/'decompiled/solo-1f47a0.c',root/'decompiled/solo-1aea10.c',root/'decompiled/solo-3ad0370.c',
root/'solo-3b379a0.c',root/'solo-978af0.c',root/'solo-3b136a0.c',
Path('artifacts/galaxy-query-research/filter-enums/decompiled/solo-3ac41d0.c')]
functions=[]
for rva in [0x1f47a0,0x1aea10,0x1f1430,0x3ad0370,0x3b379a0,0x3b136a0,0x3ac41d0]:
entry=next(e.struct for e in pe.DIRECTORY_ENTRY_EXCEPTION if e.struct.BeginAddress==rva)
body=pe.get_data(rva,entry.EndAddress-rva)
functions.append(dict(rva=hex(rva),bytes=len(body),sha256=hashlib.sha256(body).hexdigest()))
result=dict(imageSha256=image_sha,resourceSha256='29a90189d0bb238c88d09dcc0f15ff751ea29aa208b1a90894ef3b47f8942e5f',
fresSha256=hashlib.sha256(f).hexdigest(),frozenSha256=hashlib.sha256(b).hexdigest(),gameProcessAccess=False,gameCalls=0,
binding=dict(name=name,hash=hex(name_hash),recordOffset='0xd4648',record=list(record),rootOrdinal=647,
componentIndex=94,configuration=list(config),vectorField='0x20',vector=list(pointer),count=count,
nativeRegistration='0x1f47a0',nativeNameHelper='0x1aea10',factoryVtable='0x4de0ca0',factory='0x1f1430',constructor='0x3ad0370'),
runtimeMap=dict(baseOffset='0x198',recordBytes=32,key='native economy enum',rgbOffsets=['0x10','0x14','0x18'],
publishedInterfaceOffset='0x60',publishedVtable='0x552a5d0',tableGetter='0x978af0',colourGetter='0x3b136a0'),
rows=rows,sourceColourAlpha=1,functions=functions,sources=[dict(path=str(p).replace('\\','/'),sha256=hashlib.sha256(p.read_bytes()).hexdigest()) for p in sources],
remainingLimits=['Only the11 authored original rows; other enum values have no asserted original palette colour',
'Pinned original configuration defaults, not proof of current runtime overrides or same-state live rendering'])
target=root/'original-economy-colours.json';text=json.dumps(result,indent=2)+'\n'
if args.verify:
assert target.read_text()==text,'Economy evidence changed; inspect before regenerating'
else:target.write_text(text)
print(json.dumps(dict(verified=True,name=name,rows=len(rows),keys=[r['key'] for r in rows])))