extract_mid_level.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import argparse
  2. import sys
  3. import json
  4. import shutil
  5. from pathlib import Path
  6. # Add the utils directory to the Python path
  7. utils_path = Path(__file__).parent / 'utils'
  8. sys.path.append(str(utils_path))
  9. from file_utils import replicate_directory_structure, find_files_by_extension, create_guid_to_path_map
  10. from json_utils import write_json
  11. from config_utils import load_config
  12. from scene_processor import UnitySceneProcessor
  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. """
  17. print("\n--- Starting GUID Mapper Generation ---")
  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
  22. meta_files = find_files_by_extension(str(assets_dir), '.meta', ignored_folders=ignored_folders, project_root=input_dir)
  23. print(f"Found {len(meta_files)} .meta files to process.")
  24. asset_type_map = {
  25. '.prefab': 'prefabs', '.unity': 'scenes', '.mat': 'materials',
  26. '.cs': 'scripts', '.png': 'textures', '.jpg': 'textures',
  27. '.jpeg': 'textures', '.asset': 'scriptable_objects',
  28. }
  29. guid_maps = {value: {} for value in asset_type_map.values()}
  30. guid_maps['others'] = {}
  31. for meta_file_path_str in meta_files:
  32. meta_file_path = Path(meta_file_path_str)
  33. asset_file_path = Path(meta_file_path_str.rsplit('.meta', 1)[0])
  34. if not asset_file_path.is_file():
  35. continue
  36. guid = None
  37. try:
  38. with open(meta_file_path, 'r', encoding='utf-8') as f:
  39. for line in f:
  40. if line.strip().startswith('guid:'):
  41. guid = line.strip().split(':')[1].strip()
  42. break
  43. except Exception as e:
  44. print(f"Warning: Could not read or parse guid from {meta_file_path}. {e}", file=sys.stderr)
  45. continue
  46. if guid:
  47. asset_ext = asset_file_path.suffix.lower()
  48. asset_type = asset_type_map.get(asset_ext, 'others')
  49. # Use the full path from the project root for the guid_map value
  50. full_asset_path = input_dir / asset_file_path
  51. guid_maps[asset_type][guid] = full_asset_path.as_posix()
  52. mappers_dir = output_dir / "GuidMappers"
  53. try:
  54. mappers_dir.mkdir(parents=True, exist_ok=True)
  55. for asset_type, guid_map in guid_maps.items():
  56. if guid_map:
  57. output_path = mappers_dir / f"{asset_type}.json"
  58. # For the output JSON, we still want the project-relative path
  59. relative_guid_map = {g: Path(p).relative_to(input_dir).as_posix() for g, p in guid_map.items()}
  60. write_json(relative_guid_map, output_path, indent=indent, shrink=shrink)
  61. print(f"Successfully created GUID mappers in {mappers_dir}")
  62. except OSError as e:
  63. print(f"Error: Could not create GUID mapper directory or files. {e}", file=sys.stderr)
  64. # Return the map with full paths for the processor
  65. full_path_guid_map = {}
  66. for asset_type in guid_maps:
  67. full_path_guid_map.update(guid_maps[asset_type])
  68. return full_path_guid_map
  69. def main():
  70. """
  71. Main function to run the mid-level data extraction process.
  72. This script generates a virtual file structure and detailed GUID mappers.
  73. """
  74. parser = argparse.ArgumentParser(
  75. description="Generates a virtual representation of the project's structure and GUID maps."
  76. )
  77. parser.add_argument(
  78. "--input",
  79. type=str,
  80. required=True,
  81. help="The root directory of the target Unity project."
  82. )
  83. parser.add_argument(
  84. "--output",
  85. type=str,
  86. required=True,
  87. help="The directory where the generated output folder will be saved."
  88. )
  89. args = parser.parse_args()
  90. # --- Load Configuration ---
  91. config = load_config()
  92. ignored_folders = config.get('ignored_folders', [])
  93. shrink_json = config.get('shrink_json', False)
  94. indent_level = config.get('indentation_level', 4)
  95. input_dir = Path(args.input).resolve()
  96. output_dir = Path(args.output).resolve()
  97. if not input_dir.is_dir():
  98. print(f"Error: Input path '{input_dir}' is not a valid directory.", file=sys.stderr)
  99. sys.exit(1)
  100. # --- Setup Output Directories ---
  101. mid_level_output_dir = output_dir / "MidLevel"
  102. output_assets_dir = mid_level_output_dir / "Assets"
  103. try:
  104. output_assets_dir.mkdir(parents=True, exist_ok=True)
  105. print(f"Output will be saved to: {mid_level_output_dir}")
  106. except OSError as e:
  107. print(f"Error: Could not create output directory '{mid_level_output_dir}'. {e}", file=sys.stderr)
  108. sys.exit(1)
  109. assets_dir = input_dir / "Assets"
  110. if not assets_dir.is_dir():
  111. print(f"Warning: 'Assets' directory not found in '{input_dir}'. Skipping all processing.", file=sys.stderr)
  112. return
  113. # --- Task 1: Replicate 'Assets' directory structure ---
  114. print(f"\n--- Replicating 'Assets' directory structure ---")
  115. replicate_directory_structure(str(assets_dir), str(output_assets_dir), ignored_folders=ignored_folders, project_root=input_dir)
  116. print("Directory structure replication complete.")
  117. # --- Task 2: Generate GUID Map and Mappers ---
  118. guid_map = generate_guid_mappers(
  119. input_dir,
  120. mid_level_output_dir,
  121. indent=indent_level,
  122. shrink=shrink_json,
  123. ignored_folders=ignored_folders
  124. )
  125. # --- Task 3: Orchestrate Scene and Prefab Parsing for Hierarchy ---
  126. print("\n--- Starting Scene/Prefab Hierarchy Parsing ---")
  127. scene_files = find_files_by_extension(str(assets_dir), '.unity', ignored_folders=ignored_folders, project_root=input_dir)
  128. prefab_files = find_files_by_extension(str(assets_dir), '.prefab', ignored_folders=ignored_folders, project_root=input_dir)
  129. files_to_process = scene_files + prefab_files
  130. print(f"Found {len(files_to_process)} scene/prefab files to process for hierarchy.")
  131. for file_path_str in files_to_process:
  132. file_path = Path(file_path_str)
  133. relative_path = file_path.relative_to(assets_dir)
  134. output_json_path = (output_assets_dir / relative_path).with_suffix('.json')
  135. try:
  136. print(f"\n--- Processing Hierarchy for: {file_path.name} ---")
  137. # Use the sophisticated processor for building the visual tree
  138. processor = UnitySceneProcessor(guid_map)
  139. hierarchy = processor.process_file(file_path)
  140. output_json_path.parent.mkdir(parents=True, exist_ok=True)
  141. write_json(hierarchy, output_json_path, indent=indent_level, shrink=shrink_json)
  142. print(f"Successfully processed hierarchy for {file_path.name} -> {output_json_path}")
  143. except Exception as e:
  144. print(f"Error processing hierarchy for {file_path.name}: {e}", file=sys.stderr)
  145. print("\nMid-level extraction complete.")
  146. if __name__ == "__main__":
  147. main()