panel public release

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 01:26:41 -07:00
commit 295eb22826
2165 changed files with 301492 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env python3
"""Remap 7DTD decoration.7dt / multiblocks.7dt block ids from a world's NATIVE
table to the cluster CANONICAL table, BY NAME. Preserves all non-id bits.
7dt format (little-endian, no trailing bytes):
[0] u8 version (=6)
[1:5] u32 count
then count * 17-byte records; block id = u16 @ record offset +12,
low 15 bits (& 0x7FFF) = id, high bit + bytes +14/+16 = rotation/placement.
Rewrite rule: new = (orig & ~0x7FFF) | (canon_id & 0x7FFF).
"""
import sys, struct
sys.path.insert(0, '/home/refuge/nimcanon/tool')
from nimtool import read_nim # -> (records[list of (id,flag,name)], version)
REC = 17; HDR = 5; IDOFF = 12
def load_id2name(path):
if path.endswith('.nim'):
recs, _ = read_nim(path)
return {i: n for i, _, n in recs}
d = {}
for line in open(path, encoding='utf-8', errors='replace'):
line = line.rstrip('\n')
if not line: continue
p = line.split('\t')
if len(p) >= 2 and p[0].isdigit():
d[int(p[0])] = p[1]
return d
def load_name2id(path):
recs, _ = read_nim(path)
return {n: i for i, _, n in recs}
def canon_idset(path):
recs, _ = read_nim(path)
return {i for i, _, n in recs}
def decode_ids(b):
ver = b[0]; count = struct.unpack_from('<I', b, 1)[0]
assert len(b) == HDR + REC*count, f"BAD LEN {len(b)} != {HDR+REC*count} (ver={ver} count={count})"
out = []
for r in range(count):
pos = HDR + r*REC + IDOFF
orig = struct.unpack_from('<H', b, pos)[0]
out.append((pos, orig, orig & 0x7FFF, orig & 0x8000))
return ver, count, out
def analyze(native, canon, infile):
b = open(infile, 'rb').read()
n2 = load_id2name(native); c2 = load_name2id(canon)
ver, count, recs = decode_ids(b)
from collections import Counter
dist = Counter(r[2] for r in recs)
unmap_id = sorted(i for i in dist if i not in n2)
nm_for = {i: n2.get(i) for i in dist}
unmap_name = sorted(set(nm_for[i] for i in dist if nm_for[i] is not None and nm_for[i] not in c2))
inst_unmap_id = sum(dist[i] for i in unmap_id)
inst_unmap_nm = sum(dist[i] for i in dist if nm_for[i] in (None,) or (nm_for[i] is not None and nm_for[i] not in c2))
print(f" file={infile.split('/')[-1]} ver={ver} count={count} distinct_ids={len(dist)}")
print(f" distinct ids NOT in native table: {len(unmap_id)} (instances {inst_unmap_id}/{count} = {100*inst_unmap_id/count:.1f}%)")
if unmap_id[:8]: print(f" e.g. {unmap_id[:8]}")
print(f" distinct names NOT in canon: {len(unmap_name)}")
if unmap_name[:8]: print(f" e.g. {unmap_name[:8]}")
nchg = sum(dist[i] for i in dist if i in n2 and n2[i] in c2 and (c2[n2[i]] & 0x7FFF) != i)
print(f" instances whose canon id DIFFERS from native (would be rewritten): {nchg} ({100*nchg/count:.1f}%)")
ok = (len(unmap_id) == 0 and len(unmap_name) == 0)
print(f" >>> FULLY REMAPPABLE: {ok}")
return ok
def decodecheck(table, infile):
b = open(infile, 'rb').read(); ids = canon_idset(table) if table.endswith('.nim') else set(load_id2name(table))
ver, count, recs = decode_ids(b)
from collections import Counter
dist = Counter(r[2] for r in recs)
miss = sum(dist[i] for i in dist if i not in ids)
print(f" {infile.split('/')[-1]} vs {table.split('/')[-1]}: {count} instances, {len(dist)} distinct ids, MISSING-in-table {miss} ({100*miss/count:.1f}%) [clean world should be ~0%]")
def apply(native, canon, infile, outfile):
src = open(infile, 'rb').read(); b = bytearray(src)
n2 = load_id2name(native); c2 = load_name2id(canon); cset = canon_idset(canon)
ver, count, recs = decode_ids(b)
changed = 0; bad = []
for (pos, orig, bid, high) in recs:
name = n2.get(bid)
if name is None: bad.append(('noid', bid)); continue
cid = c2.get(name)
if cid is None: bad.append(('noname', name)); continue
new = high | (cid & 0x7FFF)
if new != orig:
struct.pack_into('<H', b, pos, new); changed += 1
if bad:
print(f" !! {len(bad)} unmappable records, ABORT (e.g. {bad[:5]})"); return False
open(outfile, 'wb').write(b)
# self-verify byte safety: same length, only +12/+13 differ, all new ids in canon
assert len(b) == len(src), "LENGTH CHANGED"
diffbytes = [k for k in range(len(src)) if src[k] != b[k]]
badpos = [k for k in diffbytes if (k - HDR) % REC not in (IDOFF, IDOFF+1)]
ver2, count2, recs2 = decode_ids(bytes(b))
unresolved = sum(1 for (_,o,bid,_) in recs2 if bid not in cset)
print(f" wrote {outfile.split('/')[-1]}: count={count}(unchanged) len={len(b)}(unchanged) records_rewritten={changed}")
print(f" byte-diff outside id field: {len(badpos)} (MUST be 0) ids unresolved in canon after remap: {unresolved} (MUST be 0)")
return len(badpos) == 0 and unresolved == 0
if __name__ == '__main__':
cmd = sys.argv[1]
if cmd == 'analyze': analyze(sys.argv[2], sys.argv[3], sys.argv[4])
elif cmd == 'decodecheck': decodecheck(sys.argv[2], sys.argv[3])
elif cmd == 'apply': sys.exit(0 if apply(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) else 1)