0407
This commit is contained in:
parent
885535031c
commit
283c891554
@ -1189,15 +1189,31 @@ class ProjectManager:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
ssbo_loaded = self._load_scene_description_via_ssbo(scene_description, project_path, asset_database)
|
ssbo_loaded = self._load_scene_description_via_ssbo(scene_description, project_path, asset_database)
|
||||||
|
use_manual_asset_import = (
|
||||||
|
not ssbo_loaded
|
||||||
|
and callable(getattr(self.world, "_import_model_with_menu_logic", None))
|
||||||
|
)
|
||||||
|
|
||||||
scene_root, keep_nodes = self._build_scene_root_from_description(
|
scene_root, keep_nodes, built_nodes = self._build_scene_root_from_description(
|
||||||
scene_description,
|
scene_description,
|
||||||
project_path,
|
project_path,
|
||||||
asset_database,
|
asset_database,
|
||||||
include_mode="all",
|
include_mode="all",
|
||||||
skip_asset_nodes=ssbo_loaded,
|
skip_asset_nodes=(ssbo_loaded or use_manual_asset_import),
|
||||||
|
return_node_map=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
manually_imported_models = []
|
||||||
|
if use_manual_asset_import:
|
||||||
|
manually_imported_models = self._load_scene_assets_via_manual_import(
|
||||||
|
scene_description,
|
||||||
|
project_path,
|
||||||
|
asset_database,
|
||||||
|
scene_root,
|
||||||
|
keep_nodes,
|
||||||
|
built_nodes,
|
||||||
|
)
|
||||||
|
|
||||||
scene_manager = getattr(self.world, "scene_manager", None)
|
scene_manager = getattr(self.world, "scene_manager", None)
|
||||||
if scene_manager:
|
if scene_manager:
|
||||||
scene_manager.models = []
|
scene_manager.models = []
|
||||||
@ -1212,6 +1228,13 @@ class ProjectManager:
|
|||||||
except Exception:
|
except Exception:
|
||||||
root_children = []
|
root_children = []
|
||||||
|
|
||||||
|
manual_model_keys = set()
|
||||||
|
for manual_model in manually_imported_models:
|
||||||
|
try:
|
||||||
|
manual_model_keys.add(id(manual_model))
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ssbo_editor = getattr(self.world, "ssbo_editor", None)
|
ssbo_editor = getattr(self.world, "ssbo_editor", None)
|
||||||
runtime_model = getattr(ssbo_editor, "model", None) if ssbo_editor else None
|
runtime_model = getattr(ssbo_editor, "model", None) if ssbo_editor else None
|
||||||
@ -1233,9 +1256,9 @@ class ProjectManager:
|
|||||||
if child.hasTag("is_model_root") or child.hasTag("asset_guid"):
|
if child.hasTag("is_model_root") or child.hasTag("asset_guid"):
|
||||||
built_model_nodes.append(child)
|
built_model_nodes.append(child)
|
||||||
try:
|
try:
|
||||||
if scene_manager and hasattr(scene_manager, "setupCollision"):
|
if scene_manager and hasattr(scene_manager, "setupCollision") and id(child) not in manual_model_keys:
|
||||||
scene_manager.setupCollision(child)
|
scene_manager.setupCollision(child)
|
||||||
if scene_manager and hasattr(scene_manager, "_processModelAnimations"):
|
if scene_manager and hasattr(scene_manager, "_processModelAnimations") and id(child) not in manual_model_keys:
|
||||||
scene_manager._processModelAnimations(child)
|
scene_manager._processModelAnimations(child)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@ -1248,7 +1271,14 @@ class ProjectManager:
|
|||||||
|
|
||||||
if scene_manager:
|
if scene_manager:
|
||||||
if not ssbo_loaded:
|
if not ssbo_loaded:
|
||||||
scene_manager.models = built_model_nodes
|
merged_models = []
|
||||||
|
for candidate in list(manually_imported_models) + built_model_nodes:
|
||||||
|
if not candidate or candidate.isEmpty():
|
||||||
|
continue
|
||||||
|
if any(existing == candidate for existing in merged_models):
|
||||||
|
continue
|
||||||
|
merged_models.append(candidate)
|
||||||
|
scene_manager.models = merged_models
|
||||||
else:
|
else:
|
||||||
merged_models = list(getattr(scene_manager, "models", []) or [])
|
merged_models = list(getattr(scene_manager, "models", []) or [])
|
||||||
for child in built_model_nodes:
|
for child in built_model_nodes:
|
||||||
@ -1352,6 +1382,83 @@ class ProjectManager:
|
|||||||
top_level_nodes.append(node)
|
top_level_nodes.append(node)
|
||||||
return top_level_nodes, node_lookup
|
return top_level_nodes, node_lookup
|
||||||
|
|
||||||
|
def _load_scene_assets_via_manual_import(
|
||||||
|
self,
|
||||||
|
scene_description,
|
||||||
|
project_path,
|
||||||
|
asset_database,
|
||||||
|
scene_root,
|
||||||
|
keep_nodes,
|
||||||
|
built_nodes,
|
||||||
|
):
|
||||||
|
import_with_menu = getattr(self.world, "_import_model_with_menu_logic", None)
|
||||||
|
if not callable(import_with_menu):
|
||||||
|
return []
|
||||||
|
|
||||||
|
top_level_nodes, node_lookup = self._iter_top_level_scene_asset_nodes(scene_description)
|
||||||
|
imported_models = []
|
||||||
|
for node in top_level_nodes:
|
||||||
|
components = dict(node.get("components", {}) or {})
|
||||||
|
model_component = dict(components.get("model", {}) or {})
|
||||||
|
imported_node_key = str(
|
||||||
|
model_component.get("imported_node_key", "")
|
||||||
|
or node.get("imported_node_key", "")
|
||||||
|
or ""
|
||||||
|
).strip()
|
||||||
|
if imported_node_key:
|
||||||
|
return []
|
||||||
|
|
||||||
|
asset_guid = str(
|
||||||
|
model_component.get("asset_guid", "")
|
||||||
|
or node.get("asset_guid", "")
|
||||||
|
or ""
|
||||||
|
).strip()
|
||||||
|
if not asset_guid:
|
||||||
|
continue
|
||||||
|
|
||||||
|
asset_record = asset_database.get_asset(asset_guid)
|
||||||
|
if not asset_record:
|
||||||
|
return []
|
||||||
|
|
||||||
|
asset_rel = str(
|
||||||
|
asset_record.get("asset_path", "")
|
||||||
|
or model_component.get("asset_path", "")
|
||||||
|
or node.get("asset_path", "")
|
||||||
|
or ""
|
||||||
|
).strip()
|
||||||
|
if not asset_rel:
|
||||||
|
return []
|
||||||
|
|
||||||
|
asset_abs = os.path.join(project_path, asset_rel.replace("/", os.sep))
|
||||||
|
if not os.path.exists(asset_abs):
|
||||||
|
return []
|
||||||
|
|
||||||
|
imported_np = import_with_menu(
|
||||||
|
asset_abs,
|
||||||
|
select_model=False,
|
||||||
|
set_origin=False,
|
||||||
|
show_info_message=False,
|
||||||
|
show_success_message=False,
|
||||||
|
)
|
||||||
|
if not imported_np or imported_np.isEmpty():
|
||||||
|
return []
|
||||||
|
|
||||||
|
parent_np = scene_root
|
||||||
|
parent_id = self._resolve_scene_description_parent(node, keep_nodes, node_lookup)
|
||||||
|
if parent_id in built_nodes:
|
||||||
|
parent_np = built_nodes[parent_id]
|
||||||
|
imported_np.reparentTo(parent_np)
|
||||||
|
self._apply_scene_description_state_to_subtree(
|
||||||
|
imported_np,
|
||||||
|
node,
|
||||||
|
project_path,
|
||||||
|
node_lookup,
|
||||||
|
apply_material_state=True,
|
||||||
|
prune_missing_children=False,
|
||||||
|
)
|
||||||
|
imported_models.append(imported_np)
|
||||||
|
return imported_models
|
||||||
|
|
||||||
def _apply_scene_description_state_to_node(self, target_np, node, project_path, apply_material_state=True):
|
def _apply_scene_description_state_to_node(self, target_np, node, project_path, apply_material_state=True):
|
||||||
if not target_np or target_np.isEmpty() or not isinstance(node, dict):
|
if not target_np or target_np.isEmpty() or not isinstance(node, dict):
|
||||||
return
|
return
|
||||||
@ -1447,9 +1554,17 @@ class ProjectManager:
|
|||||||
target_np.setTag("has_scripts", "true")
|
target_np.setTag("has_scripts", "true")
|
||||||
target_np.setTag("scripts_info", json.dumps(scripts, ensure_ascii=False))
|
target_np.setTag("scripts_info", json.dumps(scripts, ensure_ascii=False))
|
||||||
|
|
||||||
if apply_material_state:
|
if apply_material_state and self._should_restore_saved_material_state(node):
|
||||||
self._apply_saved_material_tags_to_node(target_np)
|
self._apply_saved_material_tags_to_node(target_np)
|
||||||
|
|
||||||
|
def _should_restore_saved_material_state(self, node):
|
||||||
|
if not isinstance(node, dict):
|
||||||
|
return False
|
||||||
|
tags = dict(node.get("tags", {}) or {})
|
||||||
|
if str(tags.get("scene_material_dirty", "") or "").strip().lower() == "true":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def _apply_saved_material_tags_to_node(self, target_np):
|
def _apply_saved_material_tags_to_node(self, target_np):
|
||||||
"""Rebuild runtime material state from serialized material_* tags."""
|
"""Rebuild runtime material state from serialized material_* tags."""
|
||||||
if not target_np or target_np.isEmpty():
|
if not target_np or target_np.isEmpty():
|
||||||
@ -1590,7 +1705,19 @@ class ProjectManager:
|
|||||||
|
|
||||||
runtime_children = []
|
runtime_children = []
|
||||||
try:
|
try:
|
||||||
runtime_children = [child for child in target_np.getChildren() if child and not child.isEmpty()]
|
for child in target_np.getChildren():
|
||||||
|
if not child or child.isEmpty():
|
||||||
|
continue
|
||||||
|
child_name = ""
|
||||||
|
try:
|
||||||
|
child_name = str(child.getName() or "")
|
||||||
|
except Exception:
|
||||||
|
child_name = ""
|
||||||
|
if child_name.startswith("modelCollision_"):
|
||||||
|
continue
|
||||||
|
if child_name.startswith("selectionOutline"):
|
||||||
|
continue
|
||||||
|
runtime_children.append(child)
|
||||||
except Exception:
|
except Exception:
|
||||||
runtime_children = []
|
runtime_children = []
|
||||||
|
|
||||||
@ -1619,10 +1746,17 @@ class ProjectManager:
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
runtime_children_by_key = {}
|
runtime_children_by_key = {}
|
||||||
|
runtime_children_by_name = {}
|
||||||
for runtime_index, runtime_child in enumerate(runtime_children):
|
for runtime_index, runtime_child in enumerate(runtime_children):
|
||||||
key = _runtime_imported_key(runtime_child)
|
key = _runtime_imported_key(runtime_child)
|
||||||
if key and key not in runtime_children_by_key:
|
if key and key not in runtime_children_by_key:
|
||||||
runtime_children_by_key[key] = (runtime_index, runtime_child)
|
runtime_children_by_key[key] = (runtime_index, runtime_child)
|
||||||
|
try:
|
||||||
|
runtime_name = str(runtime_child.getName() or "").strip()
|
||||||
|
except Exception:
|
||||||
|
runtime_name = ""
|
||||||
|
if runtime_name:
|
||||||
|
runtime_children_by_name.setdefault(runtime_name, []).append((runtime_index, runtime_child))
|
||||||
|
|
||||||
used_runtime_indices = set()
|
used_runtime_indices = set()
|
||||||
for child_entry in child_nodes:
|
for child_entry in child_nodes:
|
||||||
@ -1638,6 +1772,15 @@ class ProjectManager:
|
|||||||
target_runtime_index = keyed_index
|
target_runtime_index = keyed_index
|
||||||
target_runtime_child = keyed_child
|
target_runtime_child = keyed_child
|
||||||
|
|
||||||
|
if target_runtime_child is None:
|
||||||
|
entry_name = str(child_entry.get("name", "") or "").strip()
|
||||||
|
for named_index, named_child in runtime_children_by_name.get(entry_name, []):
|
||||||
|
if named_index in used_runtime_indices:
|
||||||
|
continue
|
||||||
|
target_runtime_index = named_index
|
||||||
|
target_runtime_child = named_child
|
||||||
|
break
|
||||||
|
|
||||||
if target_runtime_child is None:
|
if target_runtime_child is None:
|
||||||
child_index = _node_index(child_entry)
|
child_index = _node_index(child_entry)
|
||||||
if child_index < 0 or child_index >= len(runtime_children):
|
if child_index < 0 or child_index >= len(runtime_children):
|
||||||
@ -2148,7 +2291,7 @@ class ProjectManager:
|
|||||||
parent_id = parent_node.get("parent_id")
|
parent_id = parent_node.get("parent_id")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _build_scene_root_from_description(self, scene_description, project_path, asset_database, include_mode="all", skip_asset_nodes=False):
|
def _build_scene_root_from_description(self, scene_description, project_path, asset_database, include_mode="all", skip_asset_nodes=False, return_node_map=False):
|
||||||
nodes = list(scene_description.get("nodes", []) or [])
|
nodes = list(scene_description.get("nodes", []) or [])
|
||||||
node_lookup = {
|
node_lookup = {
|
||||||
str(node.get("node_id", "") or ""): dict(node)
|
str(node.get("node_id", "") or ""): dict(node)
|
||||||
@ -2200,6 +2343,8 @@ class ProjectManager:
|
|||||||
)
|
)
|
||||||
if rebuilt_np:
|
if rebuilt_np:
|
||||||
built_nodes[node_id] = rebuilt_np
|
built_nodes[node_id] = rebuilt_np
|
||||||
|
if return_node_map:
|
||||||
|
return scene_root, keep_nodes, built_nodes
|
||||||
return scene_root, keep_nodes
|
return scene_root, keep_nodes
|
||||||
|
|
||||||
def saveProject(self):
|
def saveProject(self):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user