ralpha-assets/RalphaData/scripts/generate_catalogue.py

134 lines
4.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Generate catalogue.json from UE5 Content folder.
This script scans the Content/Ralpha/Assets directory and generates
a machine-readable catalogue with metadata for each asset.
Usage:
python generate_catalogue.py [--project-path /path/to/RalphaProject]
Or run as UE5 commandlet:
UE4Editor-Cmd.exe RalphaProject.uproject -run=PythonScript -script=generate_catalogue.py
"""
import os
import json
import argparse
from pathlib import Path
from datetime import datetime
def find_uassets(content_path: Path) -> list:
"""Find all .uasset files in the Content folder."""
assets = []
for uasset in content_path.rglob("*.uasset"):
# Skip engine-generated files
if "Developers" in str(uasset) or "__External" in str(uasset):
continue
assets.append(uasset)
return assets
def parse_asset_path(uasset_path: Path, content_path: Path) -> dict:
"""Parse a .uasset path into catalogue metadata."""
relative = uasset_path.relative_to(content_path)
parts = relative.parts
# Generate ID from path
asset_id = "_".join(parts).replace(".uasset", "").lower()
asset_id = asset_id.replace(" ", "_").replace("-", "_")
# Extract category from folder structure
if len(parts) > 2:
category = "/".join(parts[1:-1]) # Skip 'Ralpha' prefix
else:
category = "Uncategorized"
# Display name from filename
name = parts[-1].replace(".uasset", "").replace("_", " ").title()
return {
"id": asset_id,
"name": name,
"category": category,
"tags": extract_tags(name, category),
"path": f"/Game/{'/'.join(parts)}".replace(".uasset", ""),
"thumbnail": f"thumbnails/{asset_id}.png",
"dimensions": None, # Would need UE5 API to extract
"pivot": "bottom_center",
"lods": 0,
"has_collision": False,
"materials": [],
"variants": []
}
def extract_tags(name: str, category: str) -> list:
"""Extract search tags from name and category."""
tags = []
# Add words from name
for word in name.lower().split():
if len(word) > 2:
tags.append(word)
# Add category parts
for part in category.split("/"):
tags.append(part.lower())
return list(set(tags))
def generate_catalogue(project_path: Path) -> dict:
"""Generate the full catalogue from project content."""
content_path = project_path / "Content"
if not content_path.exists():
raise FileNotFoundError(f"Content path not found: {content_path}")
assets = find_uassets(content_path)
catalogue = {
"version": "1.0.0",
"generated": datetime.utcnow().isoformat() + "Z",
"asset_count": len(assets),
"assets": []
}
for uasset in sorted(assets):
asset_data = parse_asset_path(uasset, content_path)
catalogue["assets"].append(asset_data)
return catalogue
def main():
parser = argparse.ArgumentParser(description="Generate Ralpha asset catalogue")
parser.add_argument("--project-path", type=Path,
default=Path(__file__).parent.parent.parent,
help="Path to UE5 project root")
parser.add_argument("--output", type=Path,
default=None,
help="Output path for catalogue.json")
args = parser.parse_args()
if args.output is None:
args.output = args.project_path / "RalphaData" / "catalogue.json"
print(f"Scanning project: {args.project_path}")
try:
catalogue = generate_catalogue(args.project_path)
with open(args.output, "w") as f:
json.dump(catalogue, f, indent=2)
print(f"Generated catalogue with {catalogue['asset_count']} assets")
print(f"Saved to: {args.output}")
except FileNotFoundError as e:
print(f"Error: {e}")
print("Make sure you're running from the project root or specify --project-path")
return 1
return 0
if __name__ == "__main__":
exit(main())