re: who references a .prt decides whether it ships -- menu named, in-game embedded

Censused the whole 135 unresolved set instead of chasing the five.
Cross-tab over all 376 .prt names: referenced by tables.pak AND
resolves 241; neither 100; referenced but absent 35; resolves WITHOUT
being referenced by tables.pak -- ZERO.

So resolving implies a tables.pak reference, 0 counterexamples of 376.
tables.pak holds the menu screen configs and every part it names ships
as <lang3>\<name>.prt.  The 100 names that appear only inside the
GP_MAIN_GAME_*2D.pak bundles never ship as entries -- the in-flight HUD
is authored into the bundles, not loaded by name.  The five pgmsg_*.prt
were never a special case; the split is menu = named + shipped,
in-game = embedded.

It is not a prefix rule: 6 of the 135 pg* names do resolve (pgloading,
pgloading2, pgmsg_scr, pgpause, pgpause_ttrl, pgpbase), because
tables.pak names them.

The 35-name residual is one coherent family -- pgmenu_btn*/item*/pad,
pgfacewin*, pgtextwin, phinfo1-3, 02d, 02d_scr, psview_release: the
in-game pause menu and squadron-order overlay, named by a menu config
but drawn from the in-game bundles.  Consistent with the split, not
separately proved.

Artefact +44 lines / 0 deletions; the other six regenerate
byte-identical.
This commit is contained in:
Sylpheed RE agent
2026-08-27 14:13:41 +00:00
parent 94065d40ec
commit e4000d9cb5
4 changed files with 119 additions and 2 deletions

View File

@@ -18,13 +18,14 @@ PRE = ['', 'Stage\\', 'stage\\', 'message\\', 'language\\', '2d\\', 'ui\\', 'prt
def main():
H = collections.defaultdict(set)
names = set()
ref = collections.defaultdict(set)
rat = collections.defaultdict(set)
for pk in sorted(glob.glob('/work/sylph_extract/**/*.pak', recursive=True)):
base = os.path.basename(pk)
for h, b in pak_entries(pk):
H[h].add(base)
for m in re.finditer(rb'[A-Za-z0-9_]{3,40}\.prt', b):
names.add(m.group(0).decode())
names.add(m.group(0).decode()); ref[m.group(0).decode()].add(base)
if b[:4] == b'RATC':
for m in re.finditer(rb'[A-Za-z0-9_]{3,40}_sub\.rat', b):
rat[m.group(0).decode()].add(base)
@@ -50,6 +51,23 @@ def main():
ok = [p or '<bare>' for p in PRE if U.name_hash(p + n) in H]
print(" %-20s resolves under: %s" % (n, ok if ok else 'NOTHING'))
res = {n: any(U.name_hash(p + n) in H for p in PRE) for n in names}
tab = lambda n: 'tables.pak' in ref[n]
ct = collections.Counter((tab(n), res[n]) for n in names)
print("\n## WHO REFERENCES a part decides whether it ships as an entry")
print(" cross-tab (referenced by tables.pak?, resolves as an entry?):")
for k in sorted(ct, key=lambda x: -ct[x]):
print(" tables=%-5s resolves=%-5s %3d" % (k[0], k[1], ct[k]))
print(" => resolving IMPLIES referenced by tables.pak: %d counterexamples of %d"
% (ct[(False, True)], len(names)))
bad = sorted(n for n in names if tab(n) and not res[n])
print(" the %d referenced-but-absent parts:" % len(bad))
for n in bad:
print(" %s" % n)
pg = [n for n in names if n.startswith('pg')]
print(" pg* parts: %d, of which %d resolve: %s"
% (len(pg), sum(1 for n in pg if res[n]), sorted(n for n in pg if res[n])))
print("\n## `<stem>_sub.rat` sub-bundles inside RATC")
print(" distinct _sub.rat names: %d" % len(rat))
for k in sorted(rat):