修复读取项目
This commit is contained in:
parent
4a25031cac
commit
da63dd4877
@ -84,12 +84,12 @@ Size=400,300
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][选择路径]
|
[Window][选择路径]
|
||||||
Pos=390,125
|
Pos=625,258
|
||||||
Size=600,500
|
Size=600,500
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][打开项目]
|
[Window][打开项目]
|
||||||
Pos=440,175
|
Pos=675,308
|
||||||
Size=500,400
|
Size=500,400
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from pathlib import Path
|
|||||||
from panda3d.core import (
|
from panda3d.core import (
|
||||||
ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3,
|
ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3,
|
||||||
MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, CollisionBox,
|
MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, CollisionBox,
|
||||||
BitMask32, TransparencyAttrib, LColor, TransformState, RenderModeAttrib
|
BitMask32, TransparencyAttrib, LColor, TransformState, RenderModeAttrib, LMatrix4f
|
||||||
)
|
)
|
||||||
from panda3d.egg import EggData, EggVertexPool
|
from panda3d.egg import EggData, EggVertexPool
|
||||||
from direct.actor.Actor import Actor
|
from direct.actor.Actor import Actor
|
||||||
@ -251,6 +251,392 @@ class SceneManagerIOMixin:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _collect_local_transform_snapshot(self, root_node):
|
||||||
|
"""采集根节点下所有子节点的局部变换快照(不含根节点自身)。"""
|
||||||
|
snapshot = {"by_index": {}, "by_name": {}}
|
||||||
|
try:
|
||||||
|
if not root_node or root_node.isEmpty():
|
||||||
|
return snapshot
|
||||||
|
|
||||||
|
def walk(node, index_path, name_path):
|
||||||
|
if index_path:
|
||||||
|
snapshot["by_index"][index_path] = {
|
||||||
|
"pos": tuple(node.getPos()),
|
||||||
|
"hpr": tuple(node.getHpr()),
|
||||||
|
"scale": tuple(node.getScale()),
|
||||||
|
}
|
||||||
|
snapshot["by_name"][name_path] = snapshot["by_index"][index_path]
|
||||||
|
|
||||||
|
name_count = {}
|
||||||
|
for child_index, child in enumerate(node.getChildren()):
|
||||||
|
child_name = child.getName() or ""
|
||||||
|
occur = name_count.get(child_name, 0)
|
||||||
|
name_count[child_name] = occur + 1
|
||||||
|
walk(
|
||||||
|
child,
|
||||||
|
index_path + (child_index,),
|
||||||
|
name_path + (f"{child_name}#{occur}",),
|
||||||
|
)
|
||||||
|
|
||||||
|
walk(root_node, tuple(), tuple())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return snapshot
|
||||||
|
|
||||||
|
def _apply_local_transform_snapshot(self, root_node, snapshot):
|
||||||
|
"""将保存的子节点局部变换回写到新导入模型。"""
|
||||||
|
try:
|
||||||
|
if (not root_node) or root_node.isEmpty() or (not snapshot):
|
||||||
|
return 0
|
||||||
|
by_index = snapshot.get("by_index", {})
|
||||||
|
by_name = snapshot.get("by_name", {})
|
||||||
|
if (not by_index) and (not by_name):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
applied_count = 0
|
||||||
|
|
||||||
|
def walk(node, index_path, name_path):
|
||||||
|
nonlocal applied_count
|
||||||
|
if index_path:
|
||||||
|
data = by_index.get(index_path) or by_name.get(name_path)
|
||||||
|
if data:
|
||||||
|
try:
|
||||||
|
node.setPos(*data["pos"])
|
||||||
|
node.setHpr(*data["hpr"])
|
||||||
|
node.setScale(*data["scale"])
|
||||||
|
applied_count += 1
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
name_count = {}
|
||||||
|
for child_index, child in enumerate(node.getChildren()):
|
||||||
|
child_name = child.getName() or ""
|
||||||
|
occur = name_count.get(child_name, 0)
|
||||||
|
name_count[child_name] = occur + 1
|
||||||
|
walk(
|
||||||
|
child,
|
||||||
|
index_path + (child_index,),
|
||||||
|
name_path + (f"{child_name}#{occur}",),
|
||||||
|
)
|
||||||
|
|
||||||
|
walk(root_node, tuple(), tuple())
|
||||||
|
return applied_count
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _matrices_close(self, a, b, eps=1e-6):
|
||||||
|
"""比较两个4x4矩阵是否近似相等。"""
|
||||||
|
try:
|
||||||
|
if (a is None) or (b is None):
|
||||||
|
return False
|
||||||
|
for r in range(4):
|
||||||
|
ra = a.get_row(r)
|
||||||
|
rb = b.get_row(r)
|
||||||
|
if (
|
||||||
|
abs(float(ra[0]) - float(rb[0])) > eps or
|
||||||
|
abs(float(ra[1]) - float(rb[1])) > eps or
|
||||||
|
abs(float(ra[2]) - float(rb[2])) > eps or
|
||||||
|
abs(float(ra[3]) - float(rb[3])) > eps
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _matrix_to_list(self, mat):
|
||||||
|
"""把 Panda3D 矩阵转为长度16的列表(行主序)。"""
|
||||||
|
values = []
|
||||||
|
try:
|
||||||
|
for r in range(4):
|
||||||
|
for c in range(4):
|
||||||
|
values.append(float(mat.getCell(r, c)))
|
||||||
|
except Exception:
|
||||||
|
values = []
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _list_to_matrix(self, values):
|
||||||
|
"""把长度16列表还原为 Panda3D 矩阵。"""
|
||||||
|
try:
|
||||||
|
if not isinstance(values, (list, tuple)) or len(values) != 16:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# LMatrix4f.identMat() 在部分绑定里是只读对象,不能 setCell。
|
||||||
|
numeric = [float(v) for v in values]
|
||||||
|
try:
|
||||||
|
return LMatrix4f(*numeric)
|
||||||
|
except Exception:
|
||||||
|
mat = LMatrix4f()
|
||||||
|
idx = 0
|
||||||
|
for r in range(4):
|
||||||
|
for c in range(4):
|
||||||
|
try:
|
||||||
|
mat.setCell(r, c, numeric[idx])
|
||||||
|
except Exception:
|
||||||
|
mat.set_cell(r, c, numeric[idx])
|
||||||
|
idx += 1
|
||||||
|
return mat
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _serialize_ssbo_subobject_transforms(self, model_root):
|
||||||
|
"""序列化当前 SSBO 模型的子物体变换(按 global_id 记录矩阵)。"""
|
||||||
|
try:
|
||||||
|
ssbo_editor = getattr(self.world, "ssbo_editor", None)
|
||||||
|
if not ssbo_editor:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
cleanup_group_proxy = getattr(ssbo_editor, "_cleanup_group_proxy", None)
|
||||||
|
if callable(cleanup_group_proxy):
|
||||||
|
cleanup_group_proxy()
|
||||||
|
|
||||||
|
controller = getattr(ssbo_editor, "controller", None)
|
||||||
|
ssbo_model = getattr(ssbo_editor, "model", None)
|
||||||
|
if not controller or not ssbo_model or ssbo_model != model_root:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
gid_mats = {}
|
||||||
|
changed_count = 0
|
||||||
|
|
||||||
|
for gid, obj_np in getattr(controller, "id_to_object_np", {}).items():
|
||||||
|
if not obj_np:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
if obj_np.is_empty():
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
if obj_np.isEmpty():
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
cur_mat = obj_np.get_mat(controller.model)
|
||||||
|
except Exception:
|
||||||
|
cur_mat = obj_np.getMat(controller.model)
|
||||||
|
|
||||||
|
base_mat = None
|
||||||
|
try:
|
||||||
|
if gid < len(controller.global_transforms):
|
||||||
|
base_mat = controller.global_transforms[gid]
|
||||||
|
except Exception:
|
||||||
|
base_mat = None
|
||||||
|
|
||||||
|
if base_mat is not None and self._matrices_close(cur_mat, base_mat):
|
||||||
|
continue
|
||||||
|
|
||||||
|
mat_values = self._matrix_to_list(cur_mat)
|
||||||
|
if not mat_values:
|
||||||
|
continue
|
||||||
|
gid_mats[str(int(gid))] = mat_values
|
||||||
|
changed_count += 1
|
||||||
|
|
||||||
|
if changed_count <= 0:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"version": 1,
|
||||||
|
"gid_mats": gid_mats,
|
||||||
|
}
|
||||||
|
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[SSBO] 序列化子物体变换失败: {e}")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _restore_ssbo_subobject_transforms(self, imported_node, saved_node):
|
||||||
|
"""把已保存的 SSBO 子物体变换恢复到当前导入模型。"""
|
||||||
|
try:
|
||||||
|
def _is_empty_np(np):
|
||||||
|
if not np:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
return np.is_empty()
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
return np.isEmpty()
|
||||||
|
except Exception:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _first_path_tag(np):
|
||||||
|
if _is_empty_np(np):
|
||||||
|
return ""
|
||||||
|
for tag_name in ("saved_model_path", "model_path", "original_path", "file"):
|
||||||
|
try:
|
||||||
|
if np.hasTag(tag_name):
|
||||||
|
value = np.getTag(tag_name).strip()
|
||||||
|
if value:
|
||||||
|
return value.replace("\\", "/").lower()
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if _is_empty_np(imported_node) or _is_empty_np(saved_node):
|
||||||
|
print("[SSBO] 子物体恢复跳过: 模型节点无效")
|
||||||
|
return 0
|
||||||
|
if not saved_node.hasTag("ssbo_gid_mats"):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
raw_text = saved_node.getTag("ssbo_gid_mats").strip()
|
||||||
|
if not raw_text:
|
||||||
|
print(f"[SSBO] 子物体恢复跳过: ssbo_gid_mats 为空 ({saved_node.getName()})")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
payload = json.loads(raw_text)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[SSBO] 子物体恢复失败: ssbo_gid_mats 非法 JSON: {e}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
gid_mats = payload.get("gid_mats", {}) if isinstance(payload, dict) else {}
|
||||||
|
if not isinstance(gid_mats, dict) or not gid_mats:
|
||||||
|
print(f"[SSBO] 子物体恢复跳过: 无 gid 数据 ({saved_node.getName()})")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
ssbo_editor = getattr(self.world, "ssbo_editor", None)
|
||||||
|
controller = getattr(ssbo_editor, "controller", None) if ssbo_editor else None
|
||||||
|
model_root = getattr(controller, "model", None) if controller else None
|
||||||
|
if not controller or _is_empty_np(model_root):
|
||||||
|
print("[SSBO] 子物体恢复跳过: controller/model 不可用")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
same_target = False
|
||||||
|
try:
|
||||||
|
same_target = (model_root == imported_node)
|
||||||
|
except Exception:
|
||||||
|
same_target = False
|
||||||
|
if not same_target:
|
||||||
|
try:
|
||||||
|
same_target = (model_root.node() == imported_node.node())
|
||||||
|
except Exception:
|
||||||
|
same_target = False
|
||||||
|
if not same_target:
|
||||||
|
model_path = _first_path_tag(model_root)
|
||||||
|
imported_path = _first_path_tag(imported_node)
|
||||||
|
if model_path and imported_path and model_path == imported_path:
|
||||||
|
same_target = True
|
||||||
|
if not same_target:
|
||||||
|
try:
|
||||||
|
same_target = (model_root.getName() == imported_node.getName())
|
||||||
|
except Exception:
|
||||||
|
same_target = False
|
||||||
|
if not same_target:
|
||||||
|
print(
|
||||||
|
f"[SSBO] 子物体恢复提示: controller/model 与导入节点句柄不一致,"
|
||||||
|
f"继续按当前 controller 应用 ({imported_node.getName()})"
|
||||||
|
)
|
||||||
|
|
||||||
|
id_to_object_np = getattr(controller, "id_to_object_np", {})
|
||||||
|
id_to_pick_np = getattr(controller, "id_to_pick_np", {})
|
||||||
|
id_to_chunk = getattr(controller, "id_to_chunk", {})
|
||||||
|
pick_model = getattr(controller, "pick_model", None)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"[SSBO] 子物体恢复准备: model={model_root.getName()} "
|
||||||
|
f"saved={saved_node.getName()} gids={len(gid_mats)} "
|
||||||
|
f"controller_objs={len(id_to_object_np)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
applied = 0
|
||||||
|
fallback_hits = 0
|
||||||
|
dirty_chunks = set()
|
||||||
|
missing_ids = []
|
||||||
|
|
||||||
|
for gid_text, mat_values in gid_mats.items():
|
||||||
|
try:
|
||||||
|
gid = int(gid_text)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
mat = self._list_to_matrix(mat_values)
|
||||||
|
if mat is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
obj_np = id_to_object_np.get(gid) if isinstance(id_to_object_np, dict) else None
|
||||||
|
if _is_empty_np(obj_np):
|
||||||
|
try:
|
||||||
|
found = model_root.find(f"**/obj_{gid}")
|
||||||
|
if not _is_empty_np(found):
|
||||||
|
obj_np = found
|
||||||
|
fallback_hits += 1
|
||||||
|
if isinstance(id_to_object_np, dict):
|
||||||
|
id_to_object_np[gid] = found
|
||||||
|
except Exception:
|
||||||
|
obj_np = None
|
||||||
|
|
||||||
|
if _is_empty_np(obj_np):
|
||||||
|
missing_ids.append(gid)
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
obj_np.set_mat(model_root, mat)
|
||||||
|
except Exception:
|
||||||
|
obj_np.setMat(model_root, mat)
|
||||||
|
|
||||||
|
pick_np = id_to_pick_np.get(gid) if isinstance(id_to_pick_np, dict) else None
|
||||||
|
if _is_empty_np(pick_np) and not _is_empty_np(pick_model):
|
||||||
|
try:
|
||||||
|
found_pick = pick_model.find(f"**/pick_{gid}")
|
||||||
|
if not _is_empty_np(found_pick):
|
||||||
|
pick_np = found_pick
|
||||||
|
if isinstance(id_to_pick_np, dict):
|
||||||
|
id_to_pick_np[gid] = found_pick
|
||||||
|
except Exception:
|
||||||
|
pick_np = None
|
||||||
|
|
||||||
|
if not _is_empty_np(pick_np):
|
||||||
|
pick_ref = pick_model if not _is_empty_np(pick_model) else model_root
|
||||||
|
try:
|
||||||
|
pick_np.set_mat(pick_ref, mat)
|
||||||
|
except Exception:
|
||||||
|
pick_np.setMat(pick_ref, mat)
|
||||||
|
|
||||||
|
chunk_mapping = id_to_chunk.get(gid) if isinstance(id_to_chunk, dict) else None
|
||||||
|
chunk_id = None
|
||||||
|
if isinstance(chunk_mapping, (tuple, list)):
|
||||||
|
chunk_id = chunk_mapping[0] if chunk_mapping else None
|
||||||
|
else:
|
||||||
|
chunk_id = chunk_mapping
|
||||||
|
|
||||||
|
if chunk_id is None:
|
||||||
|
try:
|
||||||
|
obj_parent = obj_np.getParent()
|
||||||
|
for cid, chunk_data in getattr(controller, "chunks", {}).items():
|
||||||
|
chunk_dynamic = chunk_data.get("dynamic_np")
|
||||||
|
if _is_empty_np(chunk_dynamic):
|
||||||
|
continue
|
||||||
|
if obj_parent == chunk_dynamic:
|
||||||
|
chunk_id = cid
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
chunk_id = None
|
||||||
|
|
||||||
|
if chunk_id is not None:
|
||||||
|
dirty_chunks.add(chunk_id)
|
||||||
|
applied += 1
|
||||||
|
|
||||||
|
rebuild_fn = getattr(controller, "_rebuild_static_chunk", None)
|
||||||
|
set_dynamic_fn = getattr(controller, "_set_chunk_dynamic", None)
|
||||||
|
for chunk_id in sorted(dirty_chunks):
|
||||||
|
if chunk_id not in controller.chunks:
|
||||||
|
continue
|
||||||
|
controller.chunks[chunk_id]["dirty"] = True
|
||||||
|
if callable(rebuild_fn):
|
||||||
|
rebuild_fn(chunk_id)
|
||||||
|
if callable(set_dynamic_fn):
|
||||||
|
set_dynamic_fn(chunk_id, False)
|
||||||
|
|
||||||
|
if missing_ids:
|
||||||
|
show_ids = ",".join(str(v) for v in missing_ids[:12])
|
||||||
|
if len(missing_ids) > 12:
|
||||||
|
show_ids += ",..."
|
||||||
|
print(f"[SSBO] 子物体恢复未命中 gid: {show_ids}")
|
||||||
|
print(
|
||||||
|
f"[SSBO] 子物体恢复结果: 应用 {applied}/{len(gid_mats)},"
|
||||||
|
f"fallback={fallback_hits},dirty_chunks={len(dirty_chunks)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return applied
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[SSBO] 恢复子物体变换失败: {e}")
|
||||||
|
return 0
|
||||||
|
|
||||||
def _reimport_saved_models_for_ssbo(self, scene, scene_filename, loaded_nodes):
|
def _reimport_saved_models_for_ssbo(self, scene, scene_filename, loaded_nodes):
|
||||||
"""在SSBO模式下,按保存的源模型路径重建模型根节点,避免加载烘焙后结构。"""
|
"""在SSBO模式下,按保存的源模型路径重建模型根节点,避免加载烘焙后结构。"""
|
||||||
replaced_model_names = set()
|
replaced_model_names = set()
|
||||||
@ -278,6 +664,8 @@ class SceneManagerIOMixin:
|
|||||||
print(f"[SSBO] 跳过模型 {node_name}: 无法解析源文件路径")
|
print(f"[SSBO] 跳过模型 {node_name}: 无法解析源文件路径")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
saved_snapshot = self._collect_local_transform_snapshot(saved_node)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
imported_node = runtime_import(source_path)
|
imported_node = runtime_import(source_path)
|
||||||
except Exception as import_e:
|
except Exception as import_e:
|
||||||
@ -334,6 +722,16 @@ class SceneManagerIOMixin:
|
|||||||
if saved_node.hasTag("parent_name"):
|
if saved_node.hasTag("parent_name"):
|
||||||
imported_node.setTag("parent_name", saved_node.getTag("parent_name"))
|
imported_node.setTag("parent_name", saved_node.getTag("parent_name"))
|
||||||
|
|
||||||
|
restored_ssbo_ids = self._restore_ssbo_subobject_transforms(imported_node, saved_node)
|
||||||
|
if restored_ssbo_ids > 0:
|
||||||
|
print(f"[SSBO] 已恢复模型 {node_name} 的子物体变换: {restored_ssbo_ids} 个")
|
||||||
|
|
||||||
|
restored_children = 0
|
||||||
|
if restored_ssbo_ids <= 0:
|
||||||
|
restored_children = self._apply_local_transform_snapshot(imported_node, saved_snapshot)
|
||||||
|
if restored_children > 0:
|
||||||
|
print(f"[SSBO] 已恢复模型 {node_name} 的子节点变换: {restored_children} 个")
|
||||||
|
|
||||||
loaded_nodes[node_name] = imported_node
|
loaded_nodes[node_name] = imported_node
|
||||||
replaced_model_names.add(node_name)
|
replaced_model_names.add(node_name)
|
||||||
if imported_node not in self.models:
|
if imported_node not in self.models:
|
||||||
@ -349,6 +747,13 @@ class SceneManagerIOMixin:
|
|||||||
try:
|
try:
|
||||||
print(f"\n=== 开始保存场景到: {filename} ===")
|
print(f"\n=== 开始保存场景到: {filename} ===")
|
||||||
|
|
||||||
|
# 提交 SSBO 组选择代理,避免保存时子物体仍挂在临时 proxy 下。
|
||||||
|
ssbo_editor = getattr(self.world, "ssbo_editor", None)
|
||||||
|
if ssbo_editor:
|
||||||
|
cleanup_group_proxy = getattr(ssbo_editor, "_cleanup_group_proxy", None)
|
||||||
|
if callable(cleanup_group_proxy):
|
||||||
|
cleanup_group_proxy()
|
||||||
|
|
||||||
# 确保文件路径是规范化的
|
# 确保文件路径是规范化的
|
||||||
filename = os.path.normpath(filename)
|
filename = os.path.normpath(filename)
|
||||||
|
|
||||||
@ -485,6 +890,15 @@ class SceneManagerIOMixin:
|
|||||||
if node.hasTag("can_create_actor_from_memory"):
|
if node.hasTag("can_create_actor_from_memory"):
|
||||||
node.setTag("saved_can_create_actor_from_memory", node.getTag("can_create_actor_from_memory"))
|
node.setTag("saved_can_create_actor_from_memory", node.getTag("can_create_actor_from_memory"))
|
||||||
|
|
||||||
|
# 保存 SSBO 子物体变换(仅当前受 SSBOEditor 控制的模型根)。
|
||||||
|
ssbo_subobject_payload = self._serialize_ssbo_subobject_transforms(node)
|
||||||
|
if ssbo_subobject_payload:
|
||||||
|
node.setTag("ssbo_gid_mats", ssbo_subobject_payload)
|
||||||
|
print(f"[SSBO] 保存模型 {node.getName()} 的子物体变换数据")
|
||||||
|
else:
|
||||||
|
if node.hasTag("ssbo_gid_mats"):
|
||||||
|
node.clearTag("ssbo_gid_mats")
|
||||||
|
|
||||||
if hasattr(self.world,'script_manager') and self.world.script_manager:
|
if hasattr(self.world,'script_manager') and self.world.script_manager:
|
||||||
script_manager = self.world.script_manager
|
script_manager = self.world.script_manager
|
||||||
scripts = script_manager.get_scripts_on_object(node)
|
scripts = script_manager.get_scripts_on_object(node)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user