extract_scene_trs.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import argparse
  2. import sys
  3. import json
  4. from pathlib import Path
  5. # Add parent directories to the Python path to find utils and parsers
  6. source_path = Path(__file__).parent.parent
  7. sys.path.append(str(source_path / 'utils'))
  8. sys.path.append(str(source_path / 'parsers'))
  9. from file_utils import find_files_by_extension
  10. from json_utils import write_json
  11. from config_utils import load_config
  12. from trs_processor import TRSSceneProcessor
  13. def generate_guid_mappers(input_dir, output_dir, indent=None, shrink=False, ignored_folders=None):
  14. """
  15. Finds all .meta files and generates JSON files mapping GUIDs to asset paths.
  16. This is a necessary setup step to allow the TRS processor to find prefab files.
  17. """
  18. assets_dir = input_dir / "Assets"
  19. if not assets_dir.is_dir():
  20. print(f"Error: 'Assets' directory not found in '{input_dir}'", file=sys.stderr)
  21. return None
  22. print("--> Finding all .meta files for GUID mapping...")
  23. meta_files = find_files_by_extension(str(assets_dir), '.meta', ignored_folders=ignored_folders, project_root=input_dir)
  24. print(f"--> Found {len(meta_files)} .meta files.")
  25. guid_map = {}
  26. print("--> Parsing .meta files and mapping GUIDs to asset paths...")
  27. for meta_file_path_str in meta_files:
  28. meta_file_path = Path(meta_file_path_str)
  29. asset_file_path = Path(meta_file_path_str.rsplit('.meta', 1)[0])
  30. if not asset_file_path.is_file():
  31. continue
  32. guid = None
  33. try:
  34. with open(meta_file_path, 'r', encoding='utf-8') as f:
  35. for line in f:
  36. if line.strip().startswith('guid:'):
  37. guid = line.strip().split(':')[1].strip()
  38. break
  39. except Exception as e:
  40. print(f"Warning: Could not read or parse guid from {meta_file_path}. {e}", file=sys.stderr)
  41. continue
  42. if guid:
  43. # Use the full, resolved path for the guid_map value
  44. guid_map[guid] = asset_file_path.resolve().as_posix()
  45. print("--> GUID mapping complete.")
  46. return guid_map
  47. def main():
  48. """
  49. Main function to run the TRS-only data extraction for scenes.
  50. """
  51. parser = argparse.ArgumentParser(
  52. description="Generates a simplified JSON representation of scene hierarchies with only TRS data."
  53. )
  54. parser.add_argument(
  55. "--input",
  56. type=str,
  57. required=True,
  58. help="The root directory of the target Unity project."
  59. )
  60. parser.add_argument(
  61. "--output",
  62. type=str,
  63. required=True,
  64. help="The directory where the generated JSON files will be saved."
  65. )
  66. args = parser.parse_args()
  67. # --- Load Configuration ---
  68. config = load_config()
  69. ignored_folders = config.get('ignored_folders', [])
  70. shrink_json = config.get('shrink_json', False)
  71. indent_level = config.get('indentation_level', 4)
  72. input_dir = Path(args.input).resolve()
  73. output_dir = Path(args.output).resolve()
  74. if not input_dir.is_dir():
  75. print(f"Error: Input path '{input_dir}' is not a valid directory.", file=sys.stderr)
  76. sys.exit(1)
  77. # --- Setup Output Directory ---
  78. try:
  79. output_dir.mkdir(parents=True, exist_ok=True)
  80. print(f"Output will be saved to: {output_dir}")
  81. except OSError as e:
  82. print(f"Error: Could not create output directory '{output_dir}'. {e}", file=sys.stderr)
  83. sys.exit(1)
  84. assets_dir = input_dir / "Assets"
  85. if not assets_dir.is_dir():
  86. print(f"Warning: 'Assets' directory not found in '{input_dir}'. Skipping all processing.", file=sys.stderr)
  87. return
  88. print("\n--- Running Scene TRS Extraction ---")
  89. # --- Task 1: Generate GUID Map (for prefab lookups) ---
  90. print("\n[1/2] Generating GUID Mappers...")
  91. guid_map = generate_guid_mappers(
  92. input_dir,
  93. output_dir, # Not saving mappers, just using the map in memory
  94. ignored_folders=ignored_folders
  95. )
  96. if guid_map is None:
  97. print("Error: Failed to generate GUID map. Aborting.", file=sys.stderr)
  98. sys.exit(1)
  99. print("--> GUID Mapper generation complete.")
  100. # --- Task 2: Find and Process Scene Files ---
  101. print("\n[2/2] Parsing Scene Hierarchies for TRS data...")
  102. scene_files = find_files_by_extension(str(assets_dir), '.unity', ignored_folders=ignored_folders, project_root=input_dir)
  103. if not scene_files:
  104. print("--> No scene files found to process.")
  105. return
  106. print(f"--> Found {len(scene_files)} scene file(s) to process.")
  107. total_files = len(scene_files)
  108. for i, file_path_str in enumerate(scene_files):
  109. file_path = Path(file_path_str)
  110. output_json_path = output_dir / f"{file_path.stem}.json"
  111. try:
  112. print(f"\n--- Processing {file_path.name} ({i+1}/{total_files}) ---")
  113. processor = TRSSceneProcessor(guid_map)
  114. print(f" -> Loading and parsing file...")
  115. if not processor.load_documents(file_path):
  116. print(f"Warning: Could not load or parse {file_path.name}. Skipping.", file=sys.stderr)
  117. continue
  118. print(f" -> Building hierarchy and extracting TRS data...")
  119. hierarchy = processor.process()
  120. # The hierarchy is the list of root objects, which will be the top-level JSON array.
  121. write_json(hierarchy, output_json_path, indent=indent_level, shrink=shrink_json)
  122. print(f"--> Successfully processed TRS hierarchy for {file_path.name} -> {output_json_path}")
  123. except Exception as e:
  124. print(f"Error processing TRS hierarchy for {file_path.name}: {e}", file=sys.stderr)
  125. print("\nScene TRS extraction complete.")
  126. if __name__ == "__main__":
  127. main()