convert_scene.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import yaml
  2. import json
  3. import re
  4. import sys
  5. import argparse
  6. import os
  7. # Regex to capture the type ID and anchor ID from the document separator
  8. header_pattern = re.compile(r"--- !u!(\d+) &(\S+)")
  9. # Regex to find and remove the tags for the parser
  10. tag_remover_pattern = re.compile(r"!u!\d+\s")
  11. def convert_unity_yaml_to_json(yaml_content):
  12. """
  13. Parses a Unity YAML file string, preserving fileID references, and returns a JSON string.
  14. """
  15. json_data = []
  16. # First, find all the original headers
  17. headers = header_pattern.findall(yaml_content)
  18. # Next, remove the problematic tags from the content so the parser doesn't fail
  19. sanitized_content = tag_remover_pattern.sub("", yaml_content)
  20. # HACK: Unity sometimes generates invalid YAML with an empty key.
  21. # We'll correct this before parsing.
  22. lines = sanitized_content.split('\n')
  23. corrected_lines = []
  24. for line in lines:
  25. if line.strip().startswith(':') and 'Any' in line:
  26. corrected_lines.append(line.replace(':', 'key_for_any:'))
  27. else:
  28. corrected_lines.append(line)
  29. corrected_content = "\n".join(corrected_lines)
  30. # Use the standard SafeLoader, as the tags are now gone
  31. documents = list(yaml.safe_load_all(corrected_content))
  32. # The first document is the file info, which we can often skip if it's empty
  33. if documents and isinstance(documents[0], str) and 'YAML' in documents[0]:
  34. documents.pop(0)
  35. if len(headers) != len(documents):
  36. print(f"Warning: Mismatch between headers found ({len(headers)}) and documents parsed ({len(documents)}).", file=sys.stderr)
  37. for i, doc in enumerate(documents):
  38. if i < len(headers):
  39. type_id, anchor_id = headers[i]
  40. structured_doc = {
  41. 'type_id': type_id,
  42. 'anchor_id': anchor_id,
  43. 'data': doc
  44. }
  45. json_data.append(structured_doc)
  46. else:
  47. # Append any extra docs without headers (should be rare in Unity files)
  48. json_data.append({'data': doc})
  49. # Use compact encoding for the final JSON
  50. return json.dumps(json_data)
  51. def main():
  52. parser = argparse.ArgumentParser(description='Convert Unity YAML assets to JSON.')
  53. parser.add_argument('input_path', type=str, help='Absolute path to the input Unity asset file.')
  54. parser.add_argument('output_path', type=str, help='Absolute path for the output JSON file.')
  55. args = parser.parse_args()
  56. input_path = args.input_path
  57. output_path = args.output_path
  58. try:
  59. # Ensure the output directory exists
  60. output_dir = os.path.dirname(output_path)
  61. if not os.path.exists(output_dir):
  62. os.makedirs(output_dir)
  63. with open(input_path, 'r') as f:
  64. content = f.read()
  65. json_output = convert_unity_yaml_to_json(content)
  66. with open(output_path, 'w') as f:
  67. f.write(json_output)
  68. print(f"Successfully converted '{input_path}' to '{output_path}'")
  69. except Exception as e:
  70. print(f"An error occurred: {e}", file=sys.stderr)
  71. sys.exit(1)
  72. if __name__ == "__main__":
  73. main()