|
@@ -1,66 +1,40 @@
|
|
import argparse
|
|
import argparse
|
|
import sys
|
|
import sys
|
|
-import json
|
|
|
|
-import shutil
|
|
|
|
|
|
+import subprocess
|
|
from pathlib import Path
|
|
from pathlib import Path
|
|
|
|
|
|
-# Add the utils directory to the Python path
|
|
|
|
-utils_path = Path(__file__).parent / 'utils'
|
|
|
|
-sys.path.append(str(utils_path))
|
|
|
|
-
|
|
|
|
-from file_utils import find_files_by_extension
|
|
|
|
-from deep_parser import parse_scene_or_prefab
|
|
|
|
-from json_utils import write_json
|
|
|
|
-from yaml_utils import load_unity_yaml, convert_to_plain_python_types
|
|
|
|
-from hierarchy_utils import HierarchyParser
|
|
|
|
-
|
|
|
|
-def copy_scripts(assets_dir, output_assets_dir):
|
|
|
|
- """
|
|
|
|
- Copies all C# scripts (.cs) to the target directory.
|
|
|
|
- """
|
|
|
|
- print("\n--- Starting Script Handling ---")
|
|
|
|
- cs_files = find_files_by_extension(str(assets_dir), '.cs')
|
|
|
|
- print(f"Found {len(cs_files)} C# script files to copy.")
|
|
|
|
-
|
|
|
|
- for script_path_str in cs_files:
|
|
|
|
- script_path = Path(script_path_str)
|
|
|
|
- relative_path = script_path.relative_to(assets_dir)
|
|
|
|
- destination_path = output_assets_dir / relative_path
|
|
|
|
-
|
|
|
|
- destination_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
-
|
|
|
|
- try:
|
|
|
|
- shutil.copy(script_path, destination_path)
|
|
|
|
- except IOError as e:
|
|
|
|
- print(f"Error copying {script_path} to {destination_path}: {e}", file=sys.stderr)
|
|
|
|
|
|
+def run_subprocess(script_name, input_dir, output_dir, indent=None):
|
|
|
|
+ """Helper function to run a parser subprocess."""
|
|
|
|
+ script_path = Path(__file__).parent / "parsers" / script_name
|
|
|
|
+ command = [
|
|
|
|
+ sys.executable,
|
|
|
|
+ str(script_path),
|
|
|
|
+ "--input",
|
|
|
|
+ str(input_dir),
|
|
|
|
+ "--output",
|
|
|
|
+ str(output_dir)
|
|
|
|
+ ]
|
|
|
|
+ if indent is not None:
|
|
|
|
+ command.extend(["--indent", str(indent)])
|
|
|
|
|
|
- print("Script copying complete.")
|
|
|
|
|
|
+ try:
|
|
|
|
+ subprocess.run(command, check=True, text=True, capture_output=True)
|
|
|
|
+ except subprocess.CalledProcessError as e:
|
|
|
|
+ print(f"--- ERROR in {script_name} ---")
|
|
|
|
+ print(e.stdout)
|
|
|
|
+ print(e.stderr)
|
|
|
|
+ print(f"--- End of Error ---")
|
|
|
|
|
|
def main():
|
|
def main():
|
|
"""
|
|
"""
|
|
- Main function to run the low-level data extraction process.
|
|
|
|
|
|
+ Main function to orchestrate the low-level data extraction pipeline.
|
|
"""
|
|
"""
|
|
parser = argparse.ArgumentParser(
|
|
parser = argparse.ArgumentParser(
|
|
- description="Generates a deeply detailed, per-GameObject breakdown of scenes and prefabs."
|
|
|
|
- )
|
|
|
|
- parser.add_argument(
|
|
|
|
- "--input",
|
|
|
|
- type=str,
|
|
|
|
- required=True,
|
|
|
|
- help="The root directory of the target Unity project."
|
|
|
|
- )
|
|
|
|
- parser.add_argument(
|
|
|
|
- "--output",
|
|
|
|
- type=str,
|
|
|
|
- required=True,
|
|
|
|
- help="The directory where the generated output folder will be saved."
|
|
|
|
- )
|
|
|
|
- parser.add_argument(
|
|
|
|
- "--indent",
|
|
|
|
- type=int,
|
|
|
|
- default=None,
|
|
|
|
- help="Indentation level for JSON output. Defaults to None (compact)."
|
|
|
|
|
|
+ description="Orchestrates a pipeline of parsers for a detailed data breakdown."
|
|
)
|
|
)
|
|
|
|
+ parser.add_argument("--input", type=str, required=True, help="The root directory of the target Unity project.")
|
|
|
|
+ parser.add_argument("--output", type=str, required=True, help="The directory where the output folder will be saved.")
|
|
|
|
+ parser.add_argument("--indent", type=int, default=None, help="Indentation level for JSON output.")
|
|
args = parser.parse_args()
|
|
args = parser.parse_args()
|
|
|
|
|
|
input_dir = Path(args.input).resolve()
|
|
input_dir = Path(args.input).resolve()
|
|
@@ -70,131 +44,18 @@ def main():
|
|
print(f"Error: Input path '{input_dir}' is not a valid directory.", file=sys.stderr)
|
|
print(f"Error: Input path '{input_dir}' is not a valid directory.", file=sys.stderr)
|
|
sys.exit(1)
|
|
sys.exit(1)
|
|
|
|
|
|
- # Create the main output folder, named "LowLevel"
|
|
|
|
low_level_output_dir = output_dir / "LowLevel"
|
|
low_level_output_dir = output_dir / "LowLevel"
|
|
- output_assets_dir = low_level_output_dir / "Assets"
|
|
|
|
- try:
|
|
|
|
- output_assets_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
- print(f"Output will be saved to: {low_level_output_dir}")
|
|
|
|
- except OSError as e:
|
|
|
|
- print(f"Error: Could not create output directory '{low_level_output_dir}'. {e}", file=sys.stderr)
|
|
|
|
- sys.exit(1)
|
|
|
|
-
|
|
|
|
- # --- Orchestration ---
|
|
|
|
- assets_dir = input_dir / "Assets"
|
|
|
|
- if not assets_dir.is_dir():
|
|
|
|
- print(f"Error: 'Assets' directory not found in '{input_dir}'.", file=sys.stderr)
|
|
|
|
- return
|
|
|
|
-
|
|
|
|
- # --- Task 1: Copy C# Scripts ---
|
|
|
|
- copy_scripts(assets_dir, output_assets_dir)
|
|
|
|
-
|
|
|
|
- # --- Task 2: Process Scenes and Prefabs ---
|
|
|
|
- scene_files = find_files_by_extension(str(assets_dir), '.unity')
|
|
|
|
- prefab_files = find_files_by_extension(str(assets_dir), '.prefab')
|
|
|
|
- files_to_process = scene_files + prefab_files
|
|
|
|
-
|
|
|
|
- print(f"\nFound {len(files_to_process)} scene/prefab files to process.")
|
|
|
|
-
|
|
|
|
- for file_path_str in files_to_process:
|
|
|
|
- file_path = Path(file_path_str)
|
|
|
|
- print(f"\nProcessing Scene/Prefab: {file_path.name}")
|
|
|
|
-
|
|
|
|
- # --- Deep Parsing for Individual GameObjects ---
|
|
|
|
- gameobject_list = parse_scene_or_prefab(str(file_path))
|
|
|
|
-
|
|
|
|
- # Create the output subdirectory for this asset
|
|
|
|
- relative_path = file_path.relative_to(input_dir)
|
|
|
|
- asset_output_dir = low_level_output_dir / relative_path
|
|
|
|
- try:
|
|
|
|
- asset_output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
- except OSError as e:
|
|
|
|
- print(f"Error creating directory {asset_output_dir}: {e}", file=sys.stderr)
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- if gameobject_list:
|
|
|
|
- print(f"Saving {len(gameobject_list)} GameObjects to {asset_output_dir}")
|
|
|
|
- for go_data in gameobject_list:
|
|
|
|
- file_id = go_data.get('fileID')
|
|
|
|
- if file_id:
|
|
|
|
- output_json_path = asset_output_dir / f"{file_id}.json"
|
|
|
|
- try:
|
|
|
|
- write_json(go_data, output_json_path, indent=args.indent)
|
|
|
|
- except Exception as e:
|
|
|
|
- print(f"Error writing to {output_json_path}: {e}", file=sys.stderr)
|
|
|
|
- else:
|
|
|
|
- print(f"Skipped deep parsing for {file_path.name}.")
|
|
|
|
-
|
|
|
|
- # --- Hierarchy Parsing for Root Object Identification ---
|
|
|
|
- try:
|
|
|
|
- documents = load_unity_yaml(file_path)
|
|
|
|
- if not documents:
|
|
|
|
- print(f"Could not load YAML from {file_path.name} for hierarchy parsing.")
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- raw_object_map = {int(doc.anchor.value): doc for doc in documents if hasattr(doc, 'anchor') and doc.anchor is not None}
|
|
|
|
- object_map = {file_id: convert_to_plain_python_types(obj) for file_id, obj in raw_object_map.items()}
|
|
|
|
-
|
|
|
|
- parser = HierarchyParser(object_map)
|
|
|
|
- root_object_ids = parser.get_root_object_ids()
|
|
|
|
-
|
|
|
|
- root_ids_list = [file_id for file_id, _ in root_object_ids]
|
|
|
|
-
|
|
|
|
- if root_ids_list:
|
|
|
|
- roots_output_path = asset_output_dir / "root_objects.json"
|
|
|
|
- write_json(root_ids_list, roots_output_path, indent=args.indent)
|
|
|
|
- print(f"Successfully saved root object list to {roots_output_path}")
|
|
|
|
-
|
|
|
|
- except Exception as e:
|
|
|
|
- print(f"Error during hierarchy parsing for {file_path.name}: {e}", file=sys.stderr)
|
|
|
|
-
|
|
|
|
- # --- Task 3: Process .asset files ---
|
|
|
|
- asset_files = find_files_by_extension(str(assets_dir), '.asset')
|
|
|
|
- print(f"\nFound {len(asset_files)} .asset files to process.")
|
|
|
|
-
|
|
|
|
- for file_path_str in asset_files:
|
|
|
|
- file_path = Path(file_path_str)
|
|
|
|
- print(f"\nProcessing Asset: {file_path.name}")
|
|
|
|
-
|
|
|
|
- relative_path = file_path.relative_to(input_dir)
|
|
|
|
- asset_output_dir = low_level_output_dir / relative_path
|
|
|
|
- try:
|
|
|
|
- asset_output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
- except OSError as e:
|
|
|
|
- print(f"Error creating directory {asset_output_dir}: {e}", file=sys.stderr)
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- try:
|
|
|
|
- documents = load_unity_yaml(file_path)
|
|
|
|
- if not documents:
|
|
|
|
- print(f"Skipped {file_path.name} as it's empty or could not be parsed.")
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- print(f"Saving {len(documents)} objects from {file_path.name} to {asset_output_dir}")
|
|
|
|
- for doc in documents:
|
|
|
|
- if not hasattr(doc, 'anchor') or doc.anchor is None:
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- file_id = int(doc.anchor.value)
|
|
|
|
- obj_data = convert_to_plain_python_types(doc)
|
|
|
|
-
|
|
|
|
- final_obj_data = {}
|
|
|
|
- for key, value in obj_data.items():
|
|
|
|
- if isinstance(value, dict):
|
|
|
|
- new_value = value.copy()
|
|
|
|
- new_value['fileID'] = file_id
|
|
|
|
- final_obj_data[key] = new_value
|
|
|
|
- else:
|
|
|
|
- final_obj_data[key] = value
|
|
|
|
-
|
|
|
|
- output_json_path = asset_output_dir / f"{file_id}.json"
|
|
|
|
- write_json(final_obj_data, output_json_path, indent=args.indent)
|
|
|
|
-
|
|
|
|
- except Exception as e:
|
|
|
|
- print(f"Error processing asset file {file_path.name}: {e}", file=sys.stderr)
|
|
|
|
|
|
+ low_level_output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
+ print(f"Output will be saved to: {low_level_output_dir}")
|
|
|
|
|
|
|
|
+ # --- Run Extraction Pipeline ---
|
|
|
|
+ run_subprocess("copy_scripts.py", input_dir, low_level_output_dir, args.indent)
|
|
|
|
+ run_subprocess("copy_shaders.py", input_dir, low_level_output_dir, args.indent)
|
|
|
|
+ run_subprocess("parse_project_settings.py", input_dir, low_level_output_dir, args.indent)
|
|
|
|
+ run_subprocess("parse_generic_assets.py", input_dir, low_level_output_dir, args.indent)
|
|
|
|
+ run_subprocess("parse_scenes_and_prefabs.py", input_dir, low_level_output_dir, args.indent)
|
|
|
|
|
|
- print("\nLow-level extraction complete.")
|
|
|
|
|
|
+ print("\nLow-level extraction pipeline complete.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if __name__ == "__main__":
|
|
- main()
|
|
|
|
|
|
+ main()
|