"""Extract the authored original constellation graph, without running the game.
3C41080/3C41070 return the exact galaxy-definition +110/+118 vector.
3A5ACE0 resolves each authored endpoint name through the original catalogue.
No real-world astronomy dataset or generated stellar coordinate is used here.
"""
from pathlib import Path
import argparse
import hashlib
import json
import struct
import zlib
ROOT = Path(__file__).resolve().parents[1]
KEY = 'd30f11c57448cff8ec3dd0c5c80d9868482ccadb'
SOURCE = ROOT / 'artifacts/navigation-0410-qa/resources' / (KEY + '.fres')
OUTPUT = ROOT / 'XFEEDToolBox.Core/Galaxy/original-constellations.json'
def extract():
f = SOURCE.read_bytes()
b = zlib.decompress(f[1620:])
assert hashlib.sha256(b).hexdigest() == '49a18ad1f339169391abe2a76475eea6731028b9809d7120fb32d57309196f22'
np, nr = struct.unpack_from('<I', f, 0x34)[0], struct.unpack_from('<I', f, 0x20)[0]
assert (np, nr, len(b)) == (3227, 24, 82232836)
cursor = grouped = 0
while grouped < np:
kind, count = struct.unpack_from('<HH', b, cursor)
assert kind in (2, 3, 4)
cursor += 4
grouped += count
assert grouped == np
pools = [struct.unpack_from('<8I', b, cursor + index * 32) for index in range(np)]
cursor += np * 32
roots = [struct.unpack_from('<4I', b, cursor + index * 16) for index in range(nr)]
cursor += nr * 16
start = len(b) - sum(pool[2] for pool in pools)
assert start == 13127884 and start - cursor == 814013 * 16 + 16
refs = {}
for index in range(814013):
s, o, t, v = struct.unpack_from('<4I', b, cursor + index * 16)
assert s < np and t < np and o < pools[s][2] and v < pools[t][2] and (s, o) not in refs
refs[s, o] = t, v
def at(pointer):
pool, offset = pointer
assert 0 <= pool < np and 0 <= offset < pools[pool][2]
return start + pools[pool][3] + offset
def label(pointer):
pos = at(pointer)
end = b.index(0, pos, pos + 128)
return b[pos:end].decode('ascii')
root = next(row for row in roots if row[:2] == (1765098201, 2090718614))
assert root[2:] == (2647, 4032)
rp, ro = root[2:]
vector = refs[rp, ro + 0x110]
count = struct.unpack_from('<I', b, at((rp, ro)) + 0x118)[0]
assert vector == (2561, 7680) and count == 16
groups = []
for index in range(count):
row = vector[0], vector[1] + index * 24
name = label(refs[row])
edge_pointer = refs[row[0], row[1] + 8]
edge_count = struct.unpack_from('<I', b, at(row) + 16)[0]
assert 0 < edge_count <= 64
edges = []
for edge in range(edge_count):
pair = edge_pointer[0], edge_pointer[1] + edge * 16
edges.append(dict(fromName=label(refs[pair]), toName=label(refs[pair[0], pair[1] + 8])))
groups.append(dict(name=name, edges=edges))
assert len(groups) == 16 and sum(len(group['edges']) for group in groups) == 206
assert groups[0]['name'] == 'Aries' and groups[14]['name'] == 'Orion'
return dict(sourceResource=KEY,
sourceSha256='ba4e049fd4eae066e72f29898a25d52692422e5905fc7a4a65105e44eb631ade',
fresSha256=hashlib.sha256(f).hexdigest(), frozenSha256=hashlib.sha256(b).hexdigest(),
root=list(root), sourceVector=list(vector), sourceVectorField='0x110', sourceCountField='0x118',
coordinateSource='Resolve original endpoint names using actual catalogue records; no positions are generated by this asset',
gameProcessAccess=False, generatedStellarRecords=False, groups=groups)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--verify', action='store_true')
args = parser.parse_args()
result = extract()
text = json.dumps(result, ensure_ascii=False, indent=2) + '\n'
if args.verify:
assert OUTPUT.read_text(encoding='utf-8') == text, 'Original constellation graph changed'
print('PASS:16 original groups,206 exact authored edges, frozen resource hash and pointers')
else:
OUTPUT.write_text(text, encoding='utf-8')
print(OUTPUT)
"""Extract the authored original constellation graph, without running the game.
3C41080/3C41070 return the exact galaxy-definition +110/+118 vector.
3A5ACE0 resolves each authored endpoint name through the original catalogue.
No real-world astronomy dataset or generated stellar coordinate is used here.
"""
from pathlib import Path
import argparse
import hashlib
import json
import struct
import zlib
ROOT = Path(__file__).resolve().parents[1]
KEY = 'd30f11c57448cff8ec3dd0c5c80d9868482ccadb'
SOURCE = ROOT / 'artifacts/navigation-0410-qa/resources' / (KEY + '.fres')
OUTPUT = ROOT / 'XFEEDToolBox.Core/Galaxy/original-constellations.json'
def extract():
f = SOURCE.read_bytes()
b = zlib.decompress(f[1620:])
assert hashlib.sha256(b).hexdigest() == '49a18ad1f339169391abe2a76475eea6731028b9809d7120fb32d57309196f22'
np, nr = struct.unpack_from('<I', f, 0x34)[0], struct.unpack_from('<I', f, 0x20)[0]
assert (np, nr, len(b)) == (3227, 24, 82232836)
cursor = grouped = 0
while grouped < np:
kind, count = struct.unpack_from('<HH', b, cursor)
assert kind in (2, 3, 4)
cursor += 4
grouped += count
assert grouped == np
pools = [struct.unpack_from('<8I', b, cursor + index * 32) for index in range(np)]
cursor += np * 32
roots = [struct.unpack_from('<4I', b, cursor + index * 16) for index in range(nr)]
cursor += nr * 16
start = len(b) - sum(pool[2] for pool in pools)
assert start == 13127884 and start - cursor == 814013 * 16 + 16
refs = {}
for index in range(814013):
s, o, t, v = struct.unpack_from('<4I', b, cursor + index * 16)
assert s < np and t < np and o < pools[s][2] and v < pools[t][2] and (s, o) not in refs
refs[s, o] = t, v
def at(pointer):
pool, offset = pointer
assert 0 <= pool < np and 0 <= offset < pools[pool][2]
return start + pools[pool][3] + offset
def label(pointer):
pos = at(pointer)
end = b.index(0, pos, pos + 128)
return b[pos:end].decode('ascii')
root = next(row for row in roots if row[:2] == (1765098201, 2090718614))
assert root[2:] == (2647, 4032)
rp, ro = root[2:]
vector = refs[rp, ro + 0x110]
count = struct.unpack_from('<I', b, at((rp, ro)) + 0x118)[0]
assert vector == (2561, 7680) and count == 16
groups = []
for index in range(count):
row = vector[0], vector[1] + index * 24
name = label(refs[row])
edge_pointer = refs[row[0], row[1] + 8]
edge_count = struct.unpack_from('<I', b, at(row) + 16)[0]
assert 0 < edge_count <= 64
edges = []
for edge in range(edge_count):
pair = edge_pointer[0], edge_pointer[1] + edge * 16
edges.append(dict(fromName=label(refs[pair]), toName=label(refs[pair[0], pair[1] + 8])))
groups.append(dict(name=name, edges=edges))
assert len(groups) == 16 and sum(len(group['edges']) for group in groups) == 206
assert groups[0]['name'] == 'Aries' and groups[14]['name'] == 'Orion'
return dict(sourceResource=KEY,
sourceSha256='ba4e049fd4eae066e72f29898a25d52692422e5905fc7a4a65105e44eb631ade',
fresSha256=hashlib.sha256(f).hexdigest(), frozenSha256=hashlib.sha256(b).hexdigest(),
root=list(root), sourceVector=list(vector), sourceVectorField='0x110', sourceCountField='0x118',
coordinateSource='Resolve original endpoint names using actual catalogue records; no positions are generated by this asset',
gameProcessAccess=False, generatedStellarRecords=False, groups=groups)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--verify', action='store_true')
args = parser.parse_args()
result = extract()
text = json.dumps(result, ensure_ascii=False, indent=2) + '\n'
if args.verify:
assert OUTPUT.read_text(encoding='utf-8') == text, 'Original constellation graph changed'
print('PASS:16 original groups,206 exact authored edges, frozen resource hash and pointers')
else:
OUTPUT.write_text(text, encoding='utf-8')
print(OUTPUT)