134 lines
4.1 KiB
Python
Executable File
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())
|