#!/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('>> 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('