#!/usr/bin/env python3 import json import re from pathlib import Path from shared.paths import PROJECT_PATHS, SHARED_INCLUDE_DIR def get_objects_map(paths: list[Path]) -> dict[str, str]: result: dict[str, str] = {} for path in paths: for line in path.read_text().splitlines(): if match := re.match( r'^OBJ_NAME_DEFINE\((\w+),\s*"([^"]+)",\s*"([^"]+)"\)$', line.strip(), ): result[match.group(2)] = match.group(3) return result def get_strings_map(paths: list[Path]) -> dict[str, str]: result: dict[str, str] = {} for path in paths: for line in path.read_text().splitlines(): if match := re.match( r'^\w+DEFINE\((\w+),\s*"([^"]+)"\)$', line.strip() ): result[match.group(1)] = match.group(2) return result def postprocess_game_strings( content: str, object_names_map: dict[str, str], game_strings_map: dict[str, str], ) -> str: max_key_length = ( max(len(json.dumps(key)) for key in object_names_map.keys()) + 2 ) indent = " " * 8 content = re.sub( r'^( "objects": {)[\S\s]*?^( })', ' "objects": {\n' + "\n".join( f"{indent}{f'{json.dumps(key)}: '.ljust(max_key_length)}{json.dumps({'name': value})}," for key, value in object_names_map.items() ) + "\n }", content, flags=re.M | re.DOTALL, ) content = re.sub( r'^( "game_strings": {)[\S\s]*?^( })', ' "game_strings": {\n' + "\n".join( f" {json.dumps(key)}: {json.dumps(value)}," for key, value in sorted( game_strings_map.items(), key=lambda kv: kv[0] ) ) + "\n }", content, flags=re.M | re.DOTALL, ) return content def process(game: int) -> None: GAME_STRING_DEF_PATHS = [ SHARED_INCLUDE_DIR / "game/game_string.def", PROJECT_PATHS[game].src_dir / "game/game_string.def", ] OBJECT_NAMES_DEF_PATH = ( SHARED_INCLUDE_DIR / f"game/objects/names_tr{game}.def" ) object_names_map = get_objects_map([OBJECT_NAMES_DEF_PATH]) game_strings_map = get_strings_map(GAME_STRING_DEF_PATHS) assert object_names_map assert game_strings_map for path in PROJECT_PATHS[game].shipped_data_dir.rglob("*strings*.json*"): old_content = path.read_text() new_content = postprocess_game_strings( old_content, object_names_map, game_strings_map ) if new_content != old_content: path.write_text(new_content) def main() -> None: process(1) process(2) if __name__ == "__main__": main()