"""Pin the authored Galaxy plane/core meshes and their actual renderer transforms.
This is an offline evidence export. Packed attributes other than position remain
raw until the selected model VS/input layout has been checked independently.
"""
from pathlib import Path
import hashlib,json,math,struct
import pefile
root=Path('artifacts/galaxy-query-research/power-outer-sources')
out=root/'authored-models';out.mkdir(exist_ok=True)
image=Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe')
raw=image.read_bytes();sha=hashlib.sha256(raw).hexdigest()
if sha!='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93':raise ValueError('Pinned image changed')
pe=pefile.PE(data=raw,fast_load=True);base=pe.OPTIONAL_HEADER.ImageBase
if struct.unpack('<Q',pe.get_data(0x551F2D8+0x10,8))[0]!=base+0x3A5BAF0:raise ValueError('Galaxy initializer changed')
if pe.get_data(0x551F6D8,13)!=b'MilkyWayCore\0' or pe.get_data(0x551F6E8,14)!=b'MilkyWayPlane\0':raise ValueError('Original model names changed')
constants={}
for label,rva,n in [('centre',0x551F6B8,4),('origin',0x551F6C8,4),('coreScale',0x5529C00,1),('planeScale',0x4DEC680,1),
('axisX',0x50CB0D0,4),('axisY',0x50CB0E0,4),('axisZ',0x50CB0F0,4),('signMask',0x4E32920,4)]:
data=pe.get_data(rva,n*4);constants[label]=dict(rva=hex(rva),bytes=data.hex(),values=struct.unpack('<'+'f'*n,data))
if constants['centre']['values']!=(50000.,40955.,50000.,0.) or constants['origin']['values']!=(49985.,40985.,24105.,0.):raise ValueError('Original model origin changed')
if constants['coreScale']['values']!=(40000.,) or constants['planeScale']['values']!=(100000.,):raise ValueError('Original scale changed')
scope={};exec(Path('research/Extract-GalaxyRenderMaterials.py').read_text().split('for group,entry in enumerate(buffers):')[0],scope)
b=scope['b'];materials=json.loads((root/'material/original-materials.json').read_text())
def decode_position(v):
packed=struct.unpack_from('<Q',v)[0];power=v[11]&127
if power==64:
radius=2**((packed>>48)*(16/65535))-1
return [(((packed>>shift)&65535)*(2/65535)-1)*radius for shift in (0,16,32)]
if power>19:raise ValueError('Unknown position encoding')
scale=1/((1<<(20-power))-1);bias=1<<power
return [((packed>>shift)&0x1fffff)*scale-bias for shift in (0,21,42)]
models=[]
for group,model_index,scale,axes in [(27,1,100000.,[-1,1,-1]),(28,0,40000.,[1,1,1])]:
entry=scope['buffers'][group];parts=scope['buffer_offsets'][group]
if entry[1]!=193499543 or [p['tag'] for p in parts]!=[0,1,2]:raise ValueError('Original mesh buffers changed')
name=scope['names_by_id'][entry[0]];tag,meta,gpu=[b[p['offset']:p['offset']+p['size']] for p in parts]
material_id=struct.unpack_from('<I',tag)[0];material_name=tag[4:-1].decode('ascii')
material=next(m for m in materials['materials'] if m['name']==material_name.lower() and int(m['id'],16)==material_id)
index_bytes=struct.unpack_from('<Q',meta,16)[0];vertex_bytes=struct.unpack_from('<Q',meta,32)[0]
index_count,vertex_count,unused,format_id=struct.unpack_from('<4I',meta,256)
if index_bytes!=index_count*2 or vertex_bytes!=vertex_count*40 or len(gpu)!=24+index_bytes+vertex_bytes or format_id!=8 or unused:raise ValueError('Original mesh layout changed')
indices=list(struct.unpack_from('<'+'H'*index_count,gpu,24))
if any(i>=vertex_count for i in indices):raise ValueError('Index outside original vertices')
positions=[decode_position(gpu[24+index_bytes+i*40:24+index_bytes+(i+1)*40]) for i in range(vertex_count)]
bounds=[[min(p[i] for p in positions) for i in range(3)],[max(p[i] for p in positions) for i in range(3)]]
if not all(math.isfinite(v) for p in positions for v in p):raise ValueError('Nonfinite original mesh')
mesh_file=out/(name+'.gpu');mesh_file.write_bytes(gpu)
models.append(dict(name=name,root=scope['root_by_id'][entry[0],entry[1]],bufferGroup=group,sourceParts=parts,
gpuSha256=hashlib.sha256(gpu).hexdigest(),gpuPath=str(mesh_file),indexOffset=24,indexCount=index_count,indexBytes=index_bytes,
vertexOffset=24+index_bytes,vertexCount=vertex_count,vertexBytes=vertex_bytes,vertexStride=40,vertexFormat=8,
decodedPositionBounds=bounds,positions=positions,indices=indices,materialId=hex(material_id),material=material,
originalTransform=dict(modelArrayField='0x6D0',index=model_index,scale=scale,axes=axes,worldCentre=[50000,40955,50000],
solRelativeCentre=[15,-30,25895],sourceFunction='0x3A5BAF0',helper='0x3B067D0')))
sources=[]
for relative in ['palette-resources/decompiled/solo-3a06740.c','power-outer-sources/background/solo-3a5baf0.c',
'power-outer-sources/background/solo-3a5c2d0.c','power-outer-sources/background/solo-3b067d0.c']:
path=Path('artifacts/galaxy-query-research')/relative
sources.append(dict(path=str(path),sha256=hashlib.sha256(path.read_bytes()).hexdigest()))
result=dict(gameImageSha256=sha,gameProcessAccess=False,gameCalls=0,resource='19b9e393c96329f63707aeade6a46e8cf3b71398',
archiveSha256=materials['sourceArchiveSha256'],frozenSha256=materials['frozenSha256'],
renderer=dict(constructor='0x3A06740',mainVtable='0x551F2D8',initializationSlot='0x10',initializer='0x3A5BAF0',
slotBytes=pe.get_data(0x551F2D8+0x10,8).hex(),constructorAlsoCreates='actual galaxy renderer used by the cloud passes'),
constants=constants,sourceFunctions=sources,models=models,
unclosed=['selected original packed VS/input layout for every non-position attribute',
'dynamic material override and final per-pass shader selection','frame fade/shared output and final HDR transform'],productionModelRenderingEnabled=False)
path=out/'original-authored-models.json';path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
print(json.dumps(dict(path=str(path),models=[dict(name=m['name'],vertices=m['vertexCount'],indices=m['indexCount'],bounds=m['decodedPositionBounds'],shader=m['material']['shaderClass']) for m in models])))
"""Pin the authored Galaxy plane/core meshes and their actual renderer transforms.
This is an offline evidence export. Packed attributes other than position remain
raw until the selected model VS/input layout has been checked independently.
"""
from pathlib import Path
import hashlib,json,math,struct
import pefile
root=Path('artifacts/galaxy-query-research/power-outer-sources')
out=root/'authored-models';out.mkdir(exist_ok=True)
image=Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe')
raw=image.read_bytes();sha=hashlib.sha256(raw).hexdigest()
if sha!='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93':raise ValueError('Pinned image changed')
pe=pefile.PE(data=raw,fast_load=True);base=pe.OPTIONAL_HEADER.ImageBase
if struct.unpack('<Q',pe.get_data(0x551F2D8+0x10,8))[0]!=base+0x3A5BAF0:raise ValueError('Galaxy initializer changed')
if pe.get_data(0x551F6D8,13)!=b'MilkyWayCore\0' or pe.get_data(0x551F6E8,14)!=b'MilkyWayPlane\0':raise ValueError('Original model names changed')
constants={}
for label,rva,n in [('centre',0x551F6B8,4),('origin',0x551F6C8,4),('coreScale',0x5529C00,1),('planeScale',0x4DEC680,1),
('axisX',0x50CB0D0,4),('axisY',0x50CB0E0,4),('axisZ',0x50CB0F0,4),('signMask',0x4E32920,4)]:
data=pe.get_data(rva,n*4);constants[label]=dict(rva=hex(rva),bytes=data.hex(),values=struct.unpack('<'+'f'*n,data))
if constants['centre']['values']!=(50000.,40955.,50000.,0.) or constants['origin']['values']!=(49985.,40985.,24105.,0.):raise ValueError('Original model origin changed')
if constants['coreScale']['values']!=(40000.,) or constants['planeScale']['values']!=(100000.,):raise ValueError('Original scale changed')
scope={};exec(Path('research/Extract-GalaxyRenderMaterials.py').read_text().split('for group,entry in enumerate(buffers):')[0],scope)
b=scope['b'];materials=json.loads((root/'material/original-materials.json').read_text())
def decode_position(v):
packed=struct.unpack_from('<Q',v)[0];power=v[11]&127
if power==64:
radius=2**((packed>>48)*(16/65535))-1
return [(((packed>>shift)&65535)*(2/65535)-1)*radius for shift in (0,16,32)]
if power>19:raise ValueError('Unknown position encoding')
scale=1/((1<<(20-power))-1);bias=1<<power
return [((packed>>shift)&0x1fffff)*scale-bias for shift in (0,21,42)]
models=[]
for group,model_index,scale,axes in [(27,1,100000.,[-1,1,-1]),(28,0,40000.,[1,1,1])]:
entry=scope['buffers'][group];parts=scope['buffer_offsets'][group]
if entry[1]!=193499543 or [p['tag'] for p in parts]!=[0,1,2]:raise ValueError('Original mesh buffers changed')
name=scope['names_by_id'][entry[0]];tag,meta,gpu=[b[p['offset']:p['offset']+p['size']] for p in parts]
material_id=struct.unpack_from('<I',tag)[0];material_name=tag[4:-1].decode('ascii')
material=next(m for m in materials['materials'] if m['name']==material_name.lower() and int(m['id'],16)==material_id)
index_bytes=struct.unpack_from('<Q',meta,16)[0];vertex_bytes=struct.unpack_from('<Q',meta,32)[0]
index_count,vertex_count,unused,format_id=struct.unpack_from('<4I',meta,256)
if index_bytes!=index_count*2 or vertex_bytes!=vertex_count*40 or len(gpu)!=24+index_bytes+vertex_bytes or format_id!=8 or unused:raise ValueError('Original mesh layout changed')
indices=list(struct.unpack_from('<'+'H'*index_count,gpu,24))
if any(i>=vertex_count for i in indices):raise ValueError('Index outside original vertices')
positions=[decode_position(gpu[24+index_bytes+i*40:24+index_bytes+(i+1)*40]) for i in range(vertex_count)]
bounds=[[min(p[i] for p in positions) for i in range(3)],[max(p[i] for p in positions) for i in range(3)]]
if not all(math.isfinite(v) for p in positions for v in p):raise ValueError('Nonfinite original mesh')
mesh_file=out/(name+'.gpu');mesh_file.write_bytes(gpu)
models.append(dict(name=name,root=scope['root_by_id'][entry[0],entry[1]],bufferGroup=group,sourceParts=parts,
gpuSha256=hashlib.sha256(gpu).hexdigest(),gpuPath=str(mesh_file),indexOffset=24,indexCount=index_count,indexBytes=index_bytes,
vertexOffset=24+index_bytes,vertexCount=vertex_count,vertexBytes=vertex_bytes,vertexStride=40,vertexFormat=8,
decodedPositionBounds=bounds,positions=positions,indices=indices,materialId=hex(material_id),material=material,
originalTransform=dict(modelArrayField='0x6D0',index=model_index,scale=scale,axes=axes,worldCentre=[50000,40955,50000],
solRelativeCentre=[15,-30,25895],sourceFunction='0x3A5BAF0',helper='0x3B067D0')))
sources=[]
for relative in ['palette-resources/decompiled/solo-3a06740.c','power-outer-sources/background/solo-3a5baf0.c',
'power-outer-sources/background/solo-3a5c2d0.c','power-outer-sources/background/solo-3b067d0.c']:
path=Path('artifacts/galaxy-query-research')/relative
sources.append(dict(path=str(path),sha256=hashlib.sha256(path.read_bytes()).hexdigest()))
result=dict(gameImageSha256=sha,gameProcessAccess=False,gameCalls=0,resource='19b9e393c96329f63707aeade6a46e8cf3b71398',
archiveSha256=materials['sourceArchiveSha256'],frozenSha256=materials['frozenSha256'],
renderer=dict(constructor='0x3A06740',mainVtable='0x551F2D8',initializationSlot='0x10',initializer='0x3A5BAF0',
slotBytes=pe.get_data(0x551F2D8+0x10,8).hex(),constructorAlsoCreates='actual galaxy renderer used by the cloud passes'),
constants=constants,sourceFunctions=sources,models=models,
unclosed=['selected original packed VS/input layout for every non-position attribute',
'dynamic material override and final per-pass shader selection','frame fade/shared output and final HDR transform'],productionModelRenderingEnabled=False)
path=out/'original-authored-models.json';path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
print(json.dumps(dict(path=str(path),models=[dict(name=m['name'],vertices=m['vertexCount'],indices=m['indexCount'],bounds=m['decodedPositionBounds'],shader=m['material']['shaderClass']) for m in models])))