deep_parser.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import sys
  2. from pathlib import Path
  3. import ruamel.yaml
  4. # Add the utils directory to the Python path
  5. utils_path = Path(__file__).parent
  6. sys.path.append(str(utils_path))
  7. from yaml_utils import load_unity_yaml, convert_to_plain_python_types
  8. from file_utils import create_guid_to_path_map
  9. def parse_scene_or_prefab(file_path, guid_map=None, assets_dir=None):
  10. """
  11. Parses a Unity scene or prefab file and returns a flat list of
  12. GameObject dictionaries with embedded component data.
  13. """
  14. if guid_map is None or assets_dir is None:
  15. p = Path(file_path).resolve()
  16. while p.name != 'Assets' and p.parent != p:
  17. p = p.parent
  18. if p.name == 'Assets':
  19. assets_dir = str(p)
  20. else:
  21. assets_dir = str(Path(file_path).resolve().parent.parent)
  22. guid_map = create_guid_to_path_map(assets_dir)
  23. documents = load_unity_yaml(file_path)
  24. if not documents:
  25. return None
  26. raw_object_map = {int(doc.anchor.value): doc for doc in documents if hasattr(doc, 'anchor') and doc.anchor is not None}
  27. object_map = {file_id: convert_to_plain_python_types(obj) for file_id, obj in raw_object_map.items()}
  28. flat_gameobject_list = []
  29. transform_to_gameobject = {}
  30. parent_to_children_transforms = {}
  31. # First pass: Populate relationship maps
  32. for file_id, obj_data in object_map.items():
  33. if 'Transform' in obj_data:
  34. parent_id = obj_data['Transform'].get('m_Father', {}).get('fileID')
  35. if parent_id:
  36. if parent_id not in parent_to_children_transforms:
  37. parent_to_children_transforms[parent_id] = []
  38. parent_to_children_transforms[parent_id].append(file_id)
  39. for file_id, obj_data in object_map.items():
  40. if 'GameObject' in obj_data:
  41. for comp in obj_data['GameObject'].get('m_Component', []):
  42. comp_id = comp['component']['fileID']
  43. if comp_id in object_map and 'Transform' in object_map.get(comp_id, {}):
  44. transform_to_gameobject[comp_id] = file_id
  45. break
  46. # Second pass: Process each GameObject
  47. for file_id, obj_data in object_map.items():
  48. if 'GameObject' in obj_data:
  49. go_info = obj_data['GameObject']
  50. source_obj_info = go_info.get('m_CorrespondingSourceObject')
  51. if source_obj_info and source_obj_info.get('guid'):
  52. guid = source_obj_info['guid']
  53. source_prefab_path = guid_map.get(guid)
  54. if source_prefab_path:
  55. modifications = go_info.get('m_Modification')
  56. flat_gameobject_list.append({
  57. 'fileID': file_id,
  58. 'm_Name': go_info.get('m_Name'),
  59. 'isPrefab': True,
  60. 'sourcePrefabGUID': guid,
  61. 'm_Modification': modifications
  62. })
  63. continue
  64. components_data = []
  65. for comp_ref in go_info.get('m_Component', []):
  66. comp_id = comp_ref['component']['fileID']
  67. if comp_id in object_map:
  68. components_data.append(object_map[comp_id])
  69. children_ids = []
  70. my_transform_id = None
  71. for t_id, go_id in transform_to_gameobject.items():
  72. if go_id == file_id:
  73. my_transform_id = t_id
  74. break
  75. if my_transform_id in parent_to_children_transforms:
  76. child_transform_ids = parent_to_children_transforms[my_transform_id]
  77. for child_t_id in child_transform_ids:
  78. child_go_id = transform_to_gameobject.get(child_t_id)
  79. if child_go_id:
  80. children_ids.append(child_go_id)
  81. flat_gameobject_list.append({
  82. 'fileID': file_id,
  83. 'm_Name': go_info.get('m_Name'),
  84. 'm_IsActive': go_info.get('m_IsActive', 1),
  85. 'm_TagString': go_info.get('m_TagString'),
  86. 'm_Layer': go_info.get('m_Layer'),
  87. 'm_ComponentsData': components_data,
  88. 'm_Children': children_ids
  89. })
  90. return flat_gameobject_list