"""Copy original current TradeRoute textures/materials, preserving sRGB and source bytes."""
import gzip
import hashlib
import io
import json
import struct
from pathlib import Path
from PIL import Image
import pefile
source=Path('artifacts/galaxy-query-research/power-outer-sources/material')
destination=Path('XFEEDToolBox.Core/Rendering')
proof=Path('artifacts/galaxy-query-research/current-trade');proof.mkdir(parents=True,exist_ok=True)
image=Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe').read_bytes()
image_hash='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
if hashlib.sha256(image).hexdigest()!=image_hash:raise ValueError('Pinned original image changed')
pe=pefile.PE(data=image,fast_load=True)
if struct.unpack('<I',pe.get_data(0x4E2E500+96*4,4))[0]!=72:raise ValueError('Original trade texture is not DXGI72/BC1_UNORM_SRGB')
metadata=json.loads((source/'original-materials.json').read_text())
body=(source/(metadata['resource']+'.stream0')).read_bytes()
if hashlib.sha256(body).hexdigest()!=metadata['frozenSha256']:raise ValueError('Original material bundle changed')
materials=[next(m for m in metadata['materials'] if m['name']==name) for name in ('traderoute','traderoutehotspot')]
if [m['shaderClass'] for m in materials]!=['RouteInstances','RouteHotspotInstances']:raise ValueError('Original trade shader class changed')
textures=[]
for key,name,width,height,size in (
('route','traderoute.pdiffuse_alphatexture',512,512,131072),
('trail','traderoute.photspottrailtexture',64,4,512),
('hotspot','traderoutehotspot.pdiffuse_alphatexture',512,512,131072)):
item=next(t for t in metadata['textures'] if t['name']==name)
if (item['sourceFormat'],item['width'],item['height'],item['depth'],item['array'],item['mips'],item['gpuBytes'])!=(96,width,height,1,1,1,size):
raise ValueError('Original trade texture layout changed')
payload=body[item['gpuOffset']:item['gpuOffset']+size]
resource='original-current-trade-'+key+'.bc1.gz'
(destination/resource).write_bytes(gzip.compress(payload,compresslevel=9,mtime=0))
textures.append(dict(key=key,resource=resource,source=item,format='BC1_UNorm_SRgb',nativeFormat=72,
payloadBytes=len(payload),payloadSha256=hashlib.sha256(payload).hexdigest()))
# Inspection decoding only: remove GPU row padding; retain original pixels.
pitch=item['mipLayout'][0]['rowPitch'];row_bytes=((width+3)//4)*8
tight=b''.join(payload[row*pitch:row*pitch+row_bytes] for row in range((height+3)//4))
dds=(b'DDS '+struct.pack('<7I',124,0x81007,height,width,len(tight),0,1)+bytes(44)
+struct.pack('<8I',32,4,int.from_bytes(b'DXT1','little'),0,0,0,0,0)+struct.pack('<5I',0x1000,0,0,0,0)+tight)
Image.open(io.BytesIO(dds)).convert('RGBA').save(proof/('original-'+key+'-atlas.png'))
state={};exec(Path('research/Extract-OriginalGalaxyAppearance.py').read_text().split('tables={}')[0],state)
frozen=state['b'];at=state['at'];references=state['references'];root=(423,14672)
if hashlib.sha256(frozen).hexdigest()!='5135b3d55e5239b3d11f79a76adeda954eb78be5101b6a516fd25df257affa77':raise ValueError('Original configuration changed')
configuration={}
for key,offset,kind,expected in (
('routeAtlasColumns',0xB8,'I',16),('routeAtlasRows',0xBC,'I',13),('hotspotAtlasColumns',0xC0,'I',4),('hotspotAtlasRows',0xC4,'I',4),
('segmentDistance',0xC8,'f',3),('segmentCountOffset',0xD0,'I',2),('innerRange',0xD4,'f',25)):
value=struct.unpack_from('<'+kind,frozen,at((root[0],root[1]+offset)))[0]
if value!=expected:raise ValueError('Original trade configuration field changed')
configuration[key]=value
configuration['animationTimeScale']=struct.unpack_from('<f',frozen,at((root[0],root[1]+0xCC)))[0]
configuration['outerFadeRange']=struct.unpack('<f',pe.get_data(0x4E328E0,4))[0]
configuration['amountScale']=struct.unpack('<f',pe.get_data(0x515503C,4))[0]
configuration['amountBase']=struct.unpack('<f',pe.get_data(0x5110C40,4))[0]
labels=[state['string'](references[root[0],root[1]+offset]) for offset in (0xA0,0xA8,0xB0)]
if labels!=['GalaxyMapResources','TradeRoute','TradeRouteHotspot']:raise ValueError('Original trade material labels changed')
effects=json.loads((proof/'effects/original-trade-effects.json').read_text())
shaders=[dict(archive=a['name'],**shader) for a in effects['archives'] for shader in a['selected']]
if len(shaders)!=4:raise ValueError('Original trade effects are incomplete')
for shader in shaders:
if hashlib.sha256((proof/'effects'/(shader['name']+'.dxbc')).read_bytes()).hexdigest()!=shader['sha256']:raise ValueError('Original trade DXBC changed')
result=dict(imageSha256=image_hash,sourceResource=metadata['resource'],sourceArchiveSha256=metadata['sourceArchiveSha256'],
frozenSha256=metadata['frozenSha256'],configurationResource=state['key'],configurationSha256=hashlib.sha256(frozen).hexdigest(),
configurationRoot=root,configuration=configuration,labels=labels,materials=materials,textures=textures,shaders=shaders,
instanceBytes=44,sourceVertexColour='White RGB with original per-route fade alpha; category is atlas index',
sourceGeometry=dict(routeVertices=50,routeIndices=192,hotspotVertices=4,hotspotIndices=6,
routeMeshFunction='0x3C08CA0',hotspotMeshFunction='0x3C09790',routeWriter='0x3C05BA0',hotspotWriter='0x3C05320'),
sourceAnimation=dict(callback='0x3AB9B00',update='0x3C074B0',deltaScale=struct.unpack('<f',pe.get_data(0x511201C,4))[0],
timer0=[struct.unpack('<f',pe.get_data(address,4))[0] for address in (0x5538948,0x553894C,0x5538950,0x5538954)],
timer1=struct.unpack('<f',pe.get_data(0x5538958,4))[0],operation='float32 per-frame increment and fraction'),
gameProcessAccess=False,gameCalls=0,fullOriginalTradeRestored=False,
remainingLimits=['Original live cell-load fade and absolute animation phase','Original normal decode constants','Complete original shared output/exposure/LUT/bloom','Live/pixel-parity acceptance'])
(destination/'original-current-trade.json').write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
print(json.dumps({t['key']:dict(bytes=t['payloadBytes'],sha256=t['payloadSha256']) for t in textures},indent=2))
"""Copy original current TradeRoute textures/materials, preserving sRGB and source bytes."""
import gzip
import hashlib
import io
import json
import struct
from pathlib import Path
from PIL import Image
import pefile
source=Path('artifacts/galaxy-query-research/power-outer-sources/material')
destination=Path('XFEEDToolBox.Core/Rendering')
proof=Path('artifacts/galaxy-query-research/current-trade');proof.mkdir(parents=True,exist_ok=True)
image=Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe').read_bytes()
image_hash='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
if hashlib.sha256(image).hexdigest()!=image_hash:raise ValueError('Pinned original image changed')
pe=pefile.PE(data=image,fast_load=True)
if struct.unpack('<I',pe.get_data(0x4E2E500+96*4,4))[0]!=72:raise ValueError('Original trade texture is not DXGI72/BC1_UNORM_SRGB')
metadata=json.loads((source/'original-materials.json').read_text())
body=(source/(metadata['resource']+'.stream0')).read_bytes()
if hashlib.sha256(body).hexdigest()!=metadata['frozenSha256']:raise ValueError('Original material bundle changed')
materials=[next(m for m in metadata['materials'] if m['name']==name) for name in ('traderoute','traderoutehotspot')]
if [m['shaderClass'] for m in materials]!=['RouteInstances','RouteHotspotInstances']:raise ValueError('Original trade shader class changed')
textures=[]
for key,name,width,height,size in (
('route','traderoute.pdiffuse_alphatexture',512,512,131072),
('trail','traderoute.photspottrailtexture',64,4,512),
('hotspot','traderoutehotspot.pdiffuse_alphatexture',512,512,131072)):
item=next(t for t in metadata['textures'] if t['name']==name)
if (item['sourceFormat'],item['width'],item['height'],item['depth'],item['array'],item['mips'],item['gpuBytes'])!=(96,width,height,1,1,1,size):
raise ValueError('Original trade texture layout changed')
payload=body[item['gpuOffset']:item['gpuOffset']+size]
resource='original-current-trade-'+key+'.bc1.gz'
(destination/resource).write_bytes(gzip.compress(payload,compresslevel=9,mtime=0))
textures.append(dict(key=key,resource=resource,source=item,format='BC1_UNorm_SRgb',nativeFormat=72,
payloadBytes=len(payload),payloadSha256=hashlib.sha256(payload).hexdigest()))
# Inspection decoding only: remove GPU row padding; retain original pixels.
pitch=item['mipLayout'][0]['rowPitch'];row_bytes=((width+3)//4)*8
tight=b''.join(payload[row*pitch:row*pitch+row_bytes] for row in range((height+3)//4))
dds=(b'DDS '+struct.pack('<7I',124,0x81007,height,width,len(tight),0,1)+bytes(44)
+struct.pack('<8I',32,4,int.from_bytes(b'DXT1','little'),0,0,0,0,0)+struct.pack('<5I',0x1000,0,0,0,0)+tight)
Image.open(io.BytesIO(dds)).convert('RGBA').save(proof/('original-'+key+'-atlas.png'))
state={};exec(Path('research/Extract-OriginalGalaxyAppearance.py').read_text().split('tables={}')[0],state)
frozen=state['b'];at=state['at'];references=state['references'];root=(423,14672)
if hashlib.sha256(frozen).hexdigest()!='5135b3d55e5239b3d11f79a76adeda954eb78be5101b6a516fd25df257affa77':raise ValueError('Original configuration changed')
configuration={}
for key,offset,kind,expected in (
('routeAtlasColumns',0xB8,'I',16),('routeAtlasRows',0xBC,'I',13),('hotspotAtlasColumns',0xC0,'I',4),('hotspotAtlasRows',0xC4,'I',4),
('segmentDistance',0xC8,'f',3),('segmentCountOffset',0xD0,'I',2),('innerRange',0xD4,'f',25)):
value=struct.unpack_from('<'+kind,frozen,at((root[0],root[1]+offset)))[0]
if value!=expected:raise ValueError('Original trade configuration field changed')
configuration[key]=value
configuration['animationTimeScale']=struct.unpack_from('<f',frozen,at((root[0],root[1]+0xCC)))[0]
configuration['outerFadeRange']=struct.unpack('<f',pe.get_data(0x4E328E0,4))[0]
configuration['amountScale']=struct.unpack('<f',pe.get_data(0x515503C,4))[0]
configuration['amountBase']=struct.unpack('<f',pe.get_data(0x5110C40,4))[0]
labels=[state['string'](references[root[0],root[1]+offset]) for offset in (0xA0,0xA8,0xB0)]
if labels!=['GalaxyMapResources','TradeRoute','TradeRouteHotspot']:raise ValueError('Original trade material labels changed')
effects=json.loads((proof/'effects/original-trade-effects.json').read_text())
shaders=[dict(archive=a['name'],**shader) for a in effects['archives'] for shader in a['selected']]
if len(shaders)!=4:raise ValueError('Original trade effects are incomplete')
for shader in shaders:
if hashlib.sha256((proof/'effects'/(shader['name']+'.dxbc')).read_bytes()).hexdigest()!=shader['sha256']:raise ValueError('Original trade DXBC changed')
result=dict(imageSha256=image_hash,sourceResource=metadata['resource'],sourceArchiveSha256=metadata['sourceArchiveSha256'],
frozenSha256=metadata['frozenSha256'],configurationResource=state['key'],configurationSha256=hashlib.sha256(frozen).hexdigest(),
configurationRoot=root,configuration=configuration,labels=labels,materials=materials,textures=textures,shaders=shaders,
instanceBytes=44,sourceVertexColour='White RGB with original per-route fade alpha; category is atlas index',
sourceGeometry=dict(routeVertices=50,routeIndices=192,hotspotVertices=4,hotspotIndices=6,
routeMeshFunction='0x3C08CA0',hotspotMeshFunction='0x3C09790',routeWriter='0x3C05BA0',hotspotWriter='0x3C05320'),
sourceAnimation=dict(callback='0x3AB9B00',update='0x3C074B0',deltaScale=struct.unpack('<f',pe.get_data(0x511201C,4))[0],
timer0=[struct.unpack('<f',pe.get_data(address,4))[0] for address in (0x5538948,0x553894C,0x5538950,0x5538954)],
timer1=struct.unpack('<f',pe.get_data(0x5538958,4))[0],operation='float32 per-frame increment and fraction'),
gameProcessAccess=False,gameCalls=0,fullOriginalTradeRestored=False,
remainingLimits=['Original live cell-load fade and absolute animation phase','Original normal decode constants','Complete original shared output/exposure/LUT/bloom','Live/pixel-parity acceptance'])
(destination/'original-current-trade.json').write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
print(json.dumps({t['key']:dict(bytes=t['payloadBytes'],sha256=t['payloadSha256']) for t in textures},indent=2))