Resolve original HUD fonts through native VLT font-manager mappings

This commit is contained in:
chazmm committed 2026-09-08 16:33:14 +01:00
1 parent 1c768a3e6c
commit 3c2860e376
2 files changed
+51 -12

No files matched your search

+41 -6
View File
@@ -8,16 +8,50 @@ import argparse
import hashlib
import json
import sys
import struct
from vendor.skate3_ui.project import extract_project
from vendor.skate3_ui.scene_graph import AssetCache, SceneFlattener
from vendor.skate3_ui.actions import Actions
from asset_pipeline.vlt import hash64
def prepare(game: Path, output: Path):
def font_mapping(collections: Path, cache: AssetCache) -> dict:
"""FontManager82808AE8 table; APT-name lookup82809208, load82809308.
Resolve the authored FileName, never infer family aliases from metrics.
"""
data = json.loads(collections.read_text(encoding='utf-8'))
result = {}
for row in data['collections']:
if row['class'] != 'Hash_FECFBCAF356518C4':
continue
def field(name):
return row['fields'].get(name, row['fields'].get(f'Hash_{hash64(name):016X}'))
apt_name = row['fields']['Hash_340832CCFD9FDEB4']['data']
filename = field('FileName')['data']
matches = [r for r in cache.manifest['bundles']
if 'font' in r and Path(r['name']).name == filename]
if not matches:
continue # The debug font is not a packaged front-end bitmap bank.
if len(matches) != 1 or apt_name in result:
raise ValueError(f'Ambiguous native font record: {apt_name}')
scale = {name: struct.unpack('>f',bytes.fromhex(field(name)['data']))[0]
for name in ('ScaleX','ScaleY','OffsetX','OffsetY')}
target = matches[0]['font']['family']
provenance = {'class': row['class'], 'key': row['key'],
'source_sha256': row['sha256'], 'file_name':filename,
'native_layout':scale}
cache.add_font_alias(apt_name,target,provenance)
result[apt_name] = provenance
return result
def prepare(game: Path, output: Path, collections: Path):
extract_project(game, output, prefixes=("data/fe/source/screens/hud2/",
"data/fe/source/controls/"), update=True)
cache = AssetCache(output)
mappings = font_mapping(collections,cache)
name = "data/fe/source/screens/hud2/trickdisplay2"
bundle = cache.load_bundle(name)
apt_path = output / "raw" / (name + ".apt")
@@ -42,17 +76,16 @@ def prepare(game: Path, output: Path):
elif c['type_name'] == 'font':
family = c['font']['name']
asset = cache.font_asset(family)
# Preserve this explicit source limitation. Preview.18 inferred a
# metric alias in HighlightText; that is not proof of retail HUD
# glyph/raster substitution. Never silently substitute a font.
fonts[family] = asset
result = {
'format': 'skate3-scoring-hud', 'version': 1,
'source': {'bundle': name,
'apt_sha256': hashlib.sha256(apt_path.read_bytes()).hexdigest(),
'const_sha256': hashlib.sha256(const_path.read_bytes()).hexdigest()},
'const_sha256': hashlib.sha256(const_path.read_bytes()).hexdigest(),
'collections_sha256': hashlib.sha256(collections.read_bytes()).hexdigest()},
'characters': list(bundle['characters'].values()),
'shapes': shapes, 'fonts': fonts, 'actions': blocks,
'font_mappings':mappings,
'unresolved_fonts': [family for family, asset in fonts.items() if asset is None],
}
target = output / 'runtime' / 'trickdisplay.json'
@@ -68,5 +101,7 @@ if __name__ == '__main__':
p = argparse.ArgumentParser(description=__doc__)
p.add_argument('--game', type=Path, required=True)
p.add_argument('--output', type=Path, required=True)
p.add_argument('--collections', type=Path, required=True,
help='Owned private/stock/skater-collections.json')
args = p.parse_args()
prepare(args.game.resolve(), args.output.resolve())
prepare(args.game.resolve(), args.output.resolve(), args.collections.resolve())