"""Scene manager node serialization operations."""

import os
import shutil
import time
import json
import aiohttp
import asyncio
import inspect
from pathlib import Path

from panda3d.core import (
    ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3,
    MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, CollisionBox,
    BitMask32, TransparencyAttrib, LColor, TransformState, RenderModeAttrib
)
from panda3d.egg import EggData, EggVertexPool
from direct.actor.Actor import Actor
from RenderPipelineFile.rpplugins.smaa.jitters import halton_seq
from scene import util

class SceneManagerSerializationMixin:
    def serializeNode(self, node):
        """序列化节点为字典数据"""
        try:
            node_data = {
                'name': node.getName(),
                'type': type(node.node()).__name__,
                'pos': (node.getX(), node.getY(), node.getZ()),
                'hpr': (node.getH(), node.getP(), node.getR()),
                'scale': (node.getSx(), node.getSy(), node.getSz()),
                'tags': {},
                'children': []
            }

            # 保存所有标签
            for tag_key in node.getTagKeys():
                node_data['tags'][tag_key] = node.getTag(tag_key)

            # 特殊处理不同类型的节点
            if hasattr(node.node(), 'getClassType'):
                node_class = node.node().getClassType().getName()
                node_data['node_class'] = node_class

            # 递归序列化子节点
            for child in node.getChildren():
                # 跳过辅助节点
                if not child.getName().startswith(('gizmo', 'selectionBox', 'grid')):
                    child_data = self.serializeNode(child)
                    if child_data:
                        node_data['children'].append(child_data)

            return node_data

        except Exception as e:
            print(f"序列化节点 {node.getName()} 失败: {e}")
            import traceback
            traceback.print_exc()
            return None

    def deserializeNode(self, node_data, parent_node):
        """从字典数据反序列化节点"""
        try:
            # 创建新节点
            node_name = node_data.get('name', 'node')
            new_node = parent_node.attachNewNode(node_name)

            # 设置变换
            pos = node_data.get('pos', (0, 0, 0))
            hpr = node_data.get('hpr', (0, 0, 0))
            scale = node_data.get('scale', (1, 1, 1))

            new_node.setPos(*pos)
            new_node.setHpr(*hpr)
            new_node.setScale(*scale)

            # 恢复标签
            for tag_key, tag_value in node_data.get('tags', {}).items():
                new_node.setTag(tag_key, tag_value)

            # 根据节点类型进行特殊处理
            node_type = node_data.get('type', '')
            node_class = node_data.get('node_class', '')

            # 特殊处理光源节点
            if 'light_type' in node_data.get('tags', {}):
                light_type = node_data['tags']['light_type']
                if light_type == 'spot_light':
                    self._recreateSpotLight(new_node)
                elif light_type == 'point_light':
                    self._recreatePointLight(new_node)

            # 递归创建子节点
            for child_data in node_data.get('children', []):
                self.deserializeNode(child_data, new_node)

            return new_node

        except Exception as e:
            print(f"反序列化节点 {node_data.get('name', 'unknown')} 失败: {e}")
            import traceback
            traceback.print_exc()
            return None

    def serializeNodeForCopy(self, node):
        """序列化节点用于复制操作，完整保存视觉属性"""
        try:
            if not node or node.isEmpty():
                return None

            node_data = {
                'name': node.getName(),
                'type': type(node.node()).__name__,
                'pos': (node.getX(), node.getY(), node.getZ()),
                'hpr': (node.getH(), node.getP(), node.getR()),
                'scale': (node.getSx(), node.getSy(), node.getSz()),
                'tags': {},
                'children': []
            }

            # 保存所有标签
            try:
                if hasattr(node, 'getTagKeys'):
                    for tag_key in node.getTagKeys():
                        node_data['tags'][tag_key] = node.getTag(tag_key)
            except Exception as e:
                print(f"获取标签时出错: {e}")

            # 保存视觉属性
            try:
                # 保存颜色属性
                if hasattr(node, 'getColor'):
                    color = node.getColor()
                    node_data['color'] = (color.getX(), color.getY(), color.getZ(), color.getW())

                # 保存材质属性
                if hasattr(node, 'getMaterial'):
                    material = node.getMaterial()
                    if material:
                        material_data = {}
                        material_data['base_color'] = (
                            material.getBaseColor().getX(),
                            material.getBaseColor().getY(),
                            material.getBaseColor().getZ(),
                            material.getBaseColor().getW()
                        )
                        material_data['ambient'] = (
                            material.getAmbient().getX(),
                            material.getAmbient().getY(),
                            material.getAmbient().getZ(),
                            material.getAmbient().getW()
                        )
                        material_data['diffuse'] = (
                            material.getDiffuse().getX(),
                            material.getDiffuse().getY(),
                            material.getDiffuse().getZ(),
                            material.getDiffuse().getW()
                        )
                        material_data['specular'] = (
                            material.getSpecular().getX(),
                            material.getSpecular().getY(),
                            material.getSpecular().getZ(),
                            material.getSpecular().getW()
                        )
                        material_data['shininess'] = material.getShininess()
                        node_data['material'] = material_data

            except Exception as e:
                print(f"保存视觉属性时出错: {e}")

            # 根据节点类型保存特定信息
            if node.hasTag("tree_item_type"):
                node_type = node.getTag("tree_item_type")
                node_data['node_type'] = node_type

                # 保存特定类型节点的额外信息
                if node_type in ["LIGHT_NODE", "SPOT_LIGHT_NODE", "POINT_LIGHT_NODE"]:
                    # 保存光源特定信息
                    rp_light = node.getPythonTag("rp_light_object")
                    if rp_light:
                        node_data['light_data'] = {
                            'energy': getattr(rp_light, 'energy', 5000),
                            'radius': getattr(rp_light, 'radius', 1000),
                            'fov': getattr(rp_light, 'fov', 70) if hasattr(rp_light, 'fov') else None,
                            'inner_radius': getattr(rp_light, 'inner_radius', 0.4) if hasattr(rp_light,
                                                                                              'inner_radius') else None,
                            'casts_shadows': getattr(rp_light, 'casts_shadows', True) if hasattr(rp_light,
                                                                                                 'casts_shadows') else True,
                            'shadow_map_resolution': getattr(rp_light, 'shadow_map_resolution', 256) if hasattr(
                                rp_light, 'shadow_map_resolution') else 256
                        }
                elif node_type in ["GUI_BUTTON", "GUI_LABEL", "GUI_ENTRY", "GUI_IMAGE",
                                   "GUI_3D_TEXT", "GUI_3D_IMAGE", "GUI_VIRTUAL_SCREEN"]:
                    # 保存GUI元素特定信息
                    node_data['gui_data'] = self._serializeGUIData(node)
                elif node_type == "IMPORTED_MODEL_NODE":
                    # 保存模型特定信息
                    node_data['model_data'] = self._serializeModelData(node)

            return node_data

        except Exception as e:
            print(f"序列化节点失败: {e}")
            import traceback
            traceback.print_exc()
            return None

    def _serializeGUIData(self, node):
        """序列化GUI元素数据"""
        try:
            gui_data = {}

            # 保存GUI相关的通用属性
            if node.hasTag("gui_type"):
                gui_data['gui_type'] = node.getTag("gui_type")

            # 保存文本内容（如果有的话）
            if node.hasTag("text"):
                gui_data['text'] = node.getTag("text")

            # 保存其他GUI相关标签
            gui_tags = ['font', 'font_size', 'text_color', 'bg_color', 'size']
            for tag in gui_tags:
                if node.hasTag(tag):
                    gui_data[tag] = node.getTag(tag)

            return gui_data
        except Exception as e:
            print(f"序列化GUI数据失败: {e}")
            return {}

    def _serializeModelTextures(self, node):
        """序列化模型纹理信息"""
        try:
            texture_data = {}
            
            # 获取节点的所有纹理阶段
            from panda3d.core import TextureStage
            texture_stages = node.findAllTextureStages()
            
            if texture_stages.getNumTextureStages() > 0:
                texture_data['textures'] = {}
                
                # 遍历所有纹理阶段
                for i in range(texture_stages.getNumTextureStages()):
                    stage = texture_stages.getTextureStage(i)
                    stage_name = stage.getName()
                    
                    # 获取该阶段的纹理
                    texture = node.getTexture(stage)
                    if texture:
                        # 保存纹理信息
                        texture_info = {
                            'stage_name': stage_name,
                            'stage_mode': stage.getMode(),
                            'stage_sort': stage.getSort(),  # 保存纹理阶段排序
                            'texture_path': texture.getFullpath().toOsSpecific() if texture.hasFullpath() else '',
                            'texture_name': texture.getName(),
                            'wrap_u': texture.getWrapU(),
                            'wrap_v': texture.getWrapV(),
                            'minfilter': texture.getMinfilter(),
                            'magfilter': texture.getMagfilter(),
                            'anisotropic_degree': texture.getAnisotropicDegree()
                        }
                        
                        # 保存颜色比例和偏移（使用安全的方法）
                        try:
                            texture_info['color_scale'] = tuple(node.getTextureScale(stage))
                        except:
                            texture_info['color_scale'] = (1.0, 1.0, 1.0, 1.0)
                            
                        try:
                            texture_info['color_offset'] = tuple(node.getTextureOffset(stage))
                        except:
                            texture_info['color_offset'] = (0.0, 0.0, 0.0, 0.0)
                        
                        texture_data['textures'][stage_name] = texture_info
                        
            return texture_data
        except Exception as e:
            print(f"序列化模型纹理时出错: {e}")
            return {}

    def _serializeModelData(self, node):
        """序列化模型数据，包括材质和纹理信息"""
        try:
            model_data = {}

            # 保存模型相关的标签
            model_tags = ['model_path', 'file', 'element_type']
            for tag in model_tags:
                if node.hasTag(tag):
                    model_data[tag] = node.getTag(tag)

            # 保存材质信息
            try:
                # 获取模型的材质信息
                if hasattr(node, 'getState'):
                    state = node.getState()
                    if state:
                        # 保存基础颜色信息（使用正确的方法）
                        from panda3d.core import ColorAttrib
                        color_attrib = state.getAttrib(ColorAttrib)
                        if color_attrib and not color_attrib.isOff():
                            color = color_attrib.getColor()
                            model_data['base_color'] = (
                                color.getX(),
                                color.getY(),
                                color.getZ(),
                                color.getW()
                            )

                        # 保存其他材质属性
                        from panda3d.core import MaterialAttrib
                        material_attrib = state.getAttrib(MaterialAttrib.getClassType())
                        if material_attrib:
                            material = material_attrib.getMaterial()
                            if material:
                                # 保存基础颜色
                                base_color = material.getBaseColor()
                                model_data['material_base_color'] = (
                                    base_color.getX(), base_color.getY(), base_color.getZ(), base_color.getW()
                                )

                                # 保存环境光颜色
                                ambient_color = material.getAmbient()
                                model_data['material_ambient_color'] = (
                                    ambient_color.getX(), ambient_color.getY(), ambient_color.getZ(),
                                    ambient_color.getW()
                                )

                                # 保存漫反射颜色
                                diffuse_color = material.getDiffuse()
                                model_data['material_diffuse_color'] = (
                                    diffuse_color.getX(), diffuse_color.getY(), diffuse_color.getZ(),
                                    diffuse_color.getW()
                                )

                                # 保存高光颜色
                                specular_color = material.getSpecular()
                                model_data['material_specular_color'] = (
                                    specular_color.getX(), specular_color.getY(), specular_color.getZ(),
                                    specular_color.getW()
                                )

                                # 保存粗糙度和金属度等参数
                                model_data['material_roughness'] = material.getRoughness()
                                model_data['material_metallic'] = material.getMetallic()
                                
                                # 保存自发光颜色
                                emission_color = material.getEmission()
                                model_data['material_emission_color'] = (
                                    emission_color.getX(), emission_color.getY(), emission_color.getZ(),
                                    emission_color.getW()
                                )
                                
                                # 保存光泽度
                                model_data['material_shininess'] = material.getShininess()
                                
                        # 保存透明度信息
                        from panda3d.core import TransparencyAttrib
                        transparency_attrib = state.getAttrib(TransparencyAttrib.getClassType())
                        if transparency_attrib:
                            model_data['transparency_mode'] = transparency_attrib.get_mode()

            except Exception as e:
                print(f"保存材质信息时出错: {e}")
                
            # 保存纹理信息
            try:
                texture_data = self._serializeModelTextures(node)
                if texture_data:
                    model_data['texture_data'] = texture_data
            except Exception as e:
                print(f"保存纹理信息时出错: {e}")

            return model_data
        except Exception as e:
            print(f"序列化模型数据失败: {e}")
            return {}

    def recreateNodeFromData(self, node_data, parent_node):
        """根据数据重建节点，并确保在场景树中显示"""
        try:
            if not node_data or not parent_node or parent_node.isEmpty():
                return None

            print(f"正在重建节点 {node_data}")
            node_type = node_data.get('node_type', '')
            original_name = node_data.get('name', 'node')

            # 生成唯一名称
            unique_name = self._generateUniqueName(original_name, parent_node)

            # 根据节点类型调用相应的重建方法
            new_node = None
            if node_type in ["LIGHT_NODE", "SPOT_LIGHT_NODE", "POINT_LIGHT_NODE"]:
                new_node = self._recreateLightFromData(node_data, parent_node, unique_name)
            elif node_type == "CESIUM_TILESET_NODE":
                new_node = self._recreateTilesetFromData(node_data, parent_node, unique_name)
            elif node_type in ["GUI_BUTTON", "GUI_LABEL", "GUI_ENTRY", "GUI_IMAGE",
                               "GUI_3DTEXT", "GUI_3DIMAGE", "GUI_VIDEO_SCREEN","GUI_2D_VIDEO_SCREEN"]:
                new_node = self._recreateGUIFromData(node_data, parent_node, unique_name)
            elif node_type == "IMPORTED_MODEL_NODE":
                new_node = self._recreateModelFromData(node_data, parent_node, unique_name)
            else:
                # 创建普通节点
                new_node = self._createBasicNodeFromData(node_data, parent_node, unique_name)

            # 如果成功创建节点，确保它在场景树中显示
            if new_node:
                # 尝试更新场景树以显示新节点
                try:
                    if hasattr(self.world, 'interface_manager') and self.world.interface_manager:
                        # 查找父节点在场景树中的对应项
                        parent_item = self._findTreeItemForNode(parent_node)
                        if parent_item:
                            # 添加新节点到场景树
                            tree_widget = self.world.interface_manager.treeWidget
                            if tree_widget:
                                tree_widget.add_node_to_tree_widget(new_node, parent_item, node_type or "NODE")
                except Exception as e:
                    print(f"添加节点到场景树时出错: {e}")

            return new_node

        except Exception as e:
            print(f"重建节点失败: {e}")
            import traceback
            traceback.print_exc()
            return None

    def _findTreeItemForNode(self, node):
        """根据节点查找对应的场景树项"""
        try:
            if hasattr(self.world, 'interface_manager') and self.world.interface_manager:
                tree_widget = self.world.interface_manager.treeWidget
                if tree_widget:
                    # 遍历场景树查找匹配的节点项
                    for i in range(tree_widget.topLevelItemCount()):
                        item = tree_widget.topLevelItem(i)
                        result = self._findTreeItemForNodeRecursive(item, node)
                        if result:
                            return result
            return None
        except Exception as e:
            print(f"查找场景树项时出错: {e}")
            return None

    def _findTreeItemForNodeRecursive(self, item, target_node):
        """递归查找场景树项"""
        try:
            # 检查当前项是否匹配
            item_node = getattr(item, 'node_path', None)
            if not item_node:
                item_node = getattr(item, 'node', None)

            if item_node and item_node == target_node:
                return item

            # 递归检查子项
            for i in range(item.childCount()):
                child_item = item.child(i)
                result = self._findTreeItemForNodeRecursive(child_item, target_node)
                if result:
                    return result

            return None
        except Exception as e:
            print(f"递归查找场景树项时出错: {e}")
            return None

    def _recreateTilesetFromData(self, node_data, parent_node, name):
        """根据数据重建Tileset"""
        try:
            tileset_url = node_data.get('tileset_url', '')
            if not tileset_url:
                return None

            # 使用现有方法加载tileset
            position = node_data.get('pos', (0, 0, 0))
            tileset_node = self.load_cesium_tileset(tileset_url, position)

            if tileset_node:
                # 设置名称
                tileset_node.setName(name)

                # 恢复其他标签
                for tag_key, tag_value in node_data.get('tags', {}).items():
                    if tag_key not in ['name']:
                        tileset_node.setTag(tag_key, str(tag_value))

            return tileset_node

        except Exception as e:
            print(f"重建Tileset失败: {e}")
            return None

    def _recreateGUIFromData(self, node_data, parent_node, name):
        """根据数据重建GUI元素"""
        try:
            gui_data = node_data.get('gui_data', {})
            #gui_type = gui_data.get('gui_type', '')
            gui_type = node_data.get("tags").get("gui_type", "")

            print(f"正在重建GUI元素: {gui_type}")
            print(f"正在重建GUI元素: {node_data}")

            # 根据GUI类型调用相应的创建方法
            new_gui_element = None

            if gui_type == "button" and hasattr(self.world, 'createGUIButton'):
                pos = node_data.get('pos', (0, 0, 0))
                text = node_data.get('tags').get('gui_text', '')
                size = node_data.get('scale', 1)
                print(pos,text,size)
                new_gui_element = self.world.createGUIButton(pos,text,size)
            elif gui_type == "label" and hasattr(self.world, 'createGUILabel'):
                pos = node_data.get('pos', (0, 0, 0))
                text = node_data.get('tags').get('gui_text', '')
                size = node_data.get('scale', 1)
                new_gui_element = self.world.createGUILabel(pos,text,size)
            elif gui_type == "entry" and hasattr(self.world, 'createGUIEntry'):
                pos = node_data.get('pos', (0, 0, 0))
                text = node_data.get('tags').get('gui_text', '')
                size = node_data.get('scale', 1)
                new_gui_element = self.world.createGUIEntry(pos,text,size)
            elif gui_type == "2d_image" and hasattr(self.world, 'createGUI2DImage'):
                pos = node_data.get('pos', (0, 0, 0))
                image_path = node_data.get('tags').get('image_path', '')
                size = node_data.get('size', 1)
                new_gui_element = self.world.createGUI2DImage(pos, image_path, size)
            elif gui_type == "3d_text" and hasattr(self.world, 'createGUI3DText'):
                print("正在创建3D文本!!!")
                pos = node_data.get('pos', (0, 0, 0))
                text = node_data.get('tags', {}).get('gui_text', '')
                scale = node_data.get('scale', 1)
                if isinstance(scale, (list, tuple)):
                    scale = scale[0] if len(scale) > 0 else 1
                print(f"正在创建3D文本: 位置={pos}, 文本={text}, 大小={scale}")
                new_gui_element = self.world.createGUI3DText(pos, text, scale)
            elif gui_type == "3d_image" and hasattr(self.world, 'createGUI3DImage'):
                pos = node_data.get('pos', (0, 0, 0))
                image_path = node_data.get('tags').get('gui_image_path', '')
                scale = node_data.get('scale', (1, 1))
                if isinstance(scale, (int, float)):
                    scale = (scale, scale)
                elif isinstance(scale, (list, tuple)) and len(scale) >= 2:
                    scale = (scale[0], scale[1])
                else:
                    scale = (1, 1)
                print(f"正在创建3D图片: 位置={pos}, 路径={image_path}, 大小={scale}")
                new_gui_element = self.world.gui_manager.createGUI3DImage(pos, image_path, scale)
            elif gui_type == "video_screen" and hasattr(self.world.gui_manager, 'createVideoScreen'):
                pos = node_data.get('pos', (0, 0, 0))
                video_path = node_data.get('tags').get('video_path', '')
                scale = node_data.get('scale', (1, 1,1))
                new_gui_element = self.world.gui_manager.createVideoScreen(pos,scale,video_path)
            elif gui_type == "2d_video_screen" and hasattr(self.world.gui_manager, 'createGUI2DVideoScreen'):
                pos = node_data.get('pos', (0, 0, 0))
                video_path = node_data.get('tags').get('video_path', '')
                scale = node_data.get('scale', (1, 1, 1))
                new_gui_element = self.world.gui_manager.createGUI2DVideoScreen(pos,scale,video_path)

            if new_gui_element:
                # 设置名称和变换
                if hasattr(new_gui_element, 'setName'):
                    new_gui_element.setName(name)

                # 设置位置、旋转、缩放
                pos = node_data.get('pos', (0, 0, 0))
                hpr = node_data.get('hpr', (0, 0, 0))
                scale = node_data.get('scale', (1, 1, 1))

                if hasattr(new_gui_element, 'setPos'):
                    new_gui_element.setPos(*pos)
                if hasattr(new_gui_element, 'setHpr'):
                    new_gui_element.setHpr(*hpr)
                if hasattr(new_gui_element, 'setScale'):
                    new_gui_element.setScale(*scale)

                # 恢复文本内容
                if 'text' in gui_data and hasattr(new_gui_element, 'setText'):
                    new_gui_element.setText(gui_data['text'])

                # 恢复其他标签
                for tag_key, tag_value in node_data.get('tags', {}).items():
                    if hasattr(new_gui_element, 'setTag') and tag_key not in ['name']:
                        new_gui_element.setTag(tag_key, str(tag_value))

                print(f"GUI元素重建成功: {name}")

            return new_gui_element

        except Exception as e:
            print(f"重建GUI元素失败: {e}")
            import traceback
            traceback.print_exc()
            return None

    def _recreateModelFromData(self, node_data, parent_node, name):
        """根据数据重建模型，保持材质"""
        try:
            model_data = node_data.get('model_data', {})
            model_path = model_data.get('model_path', model_data.get('file', ''))

            if not model_path or not os.path.exists(model_path):
                # 如果原始模型文件不存在，创建一个基本节点
                return self._createBasicNodeFromData(node_data, parent_node, name)

            # 导入模型，保持原有参数
            model = self.importModel(
                model_path,
                apply_unit_conversion=False,  # 已经处理过的模型不需要再次转换
                normalize_scales=False,  # 保持原有缩放
                auto_convert_to_glb=False  # 已经处理过的模型不需要再次转换
            )

            if model:
                # 设置名称
                model.setName(name)

                # 设置变换
                pos = node_data.get('pos', (0, 0, 0))
                hpr = node_data.get('hpr', (0, 0, 0))
                scale = node_data.get('scale', (1, 1, 1))

                model.setPos(*pos)
                model.setHpr(*hpr)
                model.setScale(*scale)

                # 恢复材质和纹理信息
                try:
                    self._restoreModelMaterial(model, model_data)
                except Exception as e:
                    print(f"恢复模型材质时出错: {e}")

                # 恢复标签
                for tag_key, tag_value in node_data.get('tags', {}).items():
                    if tag_key not in ['name']:
                        model.setTag(tag_key, str(tag_value))

                # 添加到模型列表
                if model not in self.models:
                    self.models.append(model)

            return model

        except Exception as e:
            print(f"重建模型失败: {e}")
            # 出错时创建基本节点
            return self._createBasicNodeFromData(node_data, parent_node, name)

    def _restoreModelTextures(self, model, texture_data):
        """恢复模型纹理"""
        try:
            if not texture_data or 'textures' not in texture_data:
                return
                
            from panda3d.core import TextureStage, SamplerState
            
            textures_info = texture_data['textures']
            
            # 为每个纹理阶段恢复纹理
            for stage_name, texture_info in textures_info.items():
                # 创建纹理阶段
                stage = TextureStage(stage_name)
                stage.setMode(texture_info.get('stage_mode', TextureStage.M_modulate))
                # 恢复纹理阶段排序
                stage.setSort(texture_info.get('stage_sort', 0))  # 默认为0（p3d_Texture0）
                
                # 加载纹理
                texture_path = texture_info['texture_path']
                if texture_path and os.path.exists(texture_path):
                    texture = self.world.loader.loadTexture(texture_path)
                    if texture:
                        # 设置纹理属性
                        texture.setWrapU(texture_info.get('wrap_u', SamplerState.WM_repeat))
                        texture.setWrapV(texture_info.get('wrap_v', SamplerState.WM_repeat))
                        texture.setMinfilter(texture_info.get('minfilter', SamplerState.FT_linear))
                        texture.setMagfilter(texture_info.get('magfilter', SamplerState.FT_linear))
                        texture.setAnisotropicDegree(texture_info.get('anisotropic_degree', 1))
                        
                        # 应用纹理到模型
                        model.setTexture(stage, texture, 1)  # 1 表示强制应用
                        
                        # 恢复颜色比例和偏移（使用安全的方法）
                        if 'color_scale' in texture_info:
                            try:
                                model.setTextureScale(stage, *texture_info['color_scale'])
                            except Exception as e:
                                print(f"恢复纹理比例失败: {e}")
                            
                        if 'color_offset' in texture_info:
                            try:
                                model.setTextureOffset(stage, *texture_info['color_offset'])
                            except Exception as e:
                                print(f"恢复纹理偏移失败: {e}")
                            
                        print(f"恢复纹理: {stage_name} <- {texture_path}")
                else:
                    print(f"纹理文件不存在或路径为空: {texture_path}")
                    
        except Exception as e:
            print(f"恢复模型纹理时出错: {e}")

    def _restoreModelMaterial(self, model, model_data):
        """恢复模型材质和纹理"""
        try:
            # 恢复基础颜色
            if 'base_color' in model_data:
                from panda3d.core import ColorAttrib
                base_color = model_data['base_color']
                color = (base_color[0], base_color[1], base_color[2], base_color[3])
                model.setColor(color)

            # 恢复复杂材质属性
            if any(key.startswith('material_') for key in model_data.keys()):
                from panda3d.core import Material

                # 创建新材质或获取现有材质
                material = Material()

                # 恢复基础颜色
                if 'material_base_color' in model_data:
                    base_color = model_data['material_base_color']
                    material.setBaseColor((base_color[0], base_color[1], base_color[2], base_color[3]))

                # 恢复环境光颜色
                if 'material_ambient_color' in model_data:
                    ambient_color = model_data['material_ambient_color']
                    material.setAmbient((ambient_color[0], ambient_color[1], ambient_color[2], ambient_color[3]))

                # 恢复漫反射颜色
                if 'material_diffuse_color' in model_data:
                    diffuse_color = model_data['material_diffuse_color']
                    material.setDiffuse((diffuse_color[0], diffuse_color[1], diffuse_color[2], diffuse_color[3]))

                # 恢复高光颜色
                if 'material_specular_color' in model_data:
                    specular_color = model_data['material_specular_color']
                    material.setSpecular((specular_color[0], specular_color[1], specular_color[2], specular_color[3]))
                    
                # 恢复自发光颜色
                if 'material_emission_color' in model_data:
                    emission_color = model_data['material_emission_color']
                    material.setEmission((emission_color[0], emission_color[1], emission_color[2], emission_color[3]))

                # 恢复粗糙度和金属度
                if 'material_roughness' in model_data:
                    material.setRoughness(model_data['material_roughness'])

                if 'material_metallic' in model_data:
                    material.setMetallic(model_data['material_metallic'])
                    
                # 恢复光泽度
                if 'material_shininess' in model_data:
                    material.setShininess(model_data['material_shininess'])

                # 应用材质到模型
                model.setMaterial(material)
                
            # 恢复透明度设置
            if 'transparency_mode' in model_data:
                from panda3d.core import TransparencyAttrib
                transparency_mode = model_data['transparency_mode']
                model.setTransparency(transparency_mode)
                
            # 恢复纹理信息
            if 'texture_data' in model_data:
                self._restoreModelTextures(model, model_data['texture_data'])

        except Exception as e:
            print(f"恢复材质失败: {e}")

    def _createBasicNodeFromData(self, node_data, parent_node, name):
        """创建基本节点，保持视觉属性"""
        try:
            new_node = parent_node.attachNewNode(name)

            # 设置变换
            pos = node_data.get('pos', (0, 0, 0))
            hpr = node_data.get('hpr', (0, 0, 0))
            scale = node_data.get('scale', (1, 1, 1))

            new_node.setPos(*pos)
            new_node.setHpr(*hpr)
            new_node.setScale(*scale)

            # 恢复视觉属性
            try:
                # 恢复颜色
                if 'color' in node_data:
                    color_data = node_data['color']
                    new_node.setColor(color_data[0], color_data[1], color_data[2], color_data[3])

                # 恢复材质
                if 'material' in node_data:
                    from panda3d.core import Material
                    material_data = node_data['material']
                    material = Material()

                    if 'base_color' in material_data:
                        bc = material_data['base_color']
                        material.setBaseColor((bc[0], bc[1], bc[2], bc[3]))

                    if 'ambient' in material_data:
                        ac = material_data['ambient']
                        material.setAmbient((ac[0], ac[1], ac[2], ac[3]))

                    if 'diffuse' in material_data:
                        dc = material_data['diffuse']
                        material.setDiffuse((dc[0], dc[1], dc[2], dc[3]))

                    if 'specular' in material_data:
                        sc = material_data['specular']
                        material.setSpecular((sc[0], sc[1], sc[2], sc[3]))

                    if 'shininess' in material_data:
                        material.setShininess(material_data['shininess'])

                    new_node.setMaterial(material)

            except Exception as e:
                print(f"恢复视觉属性时出错: {e}")

            # 恢复标签
            for tag_key, tag_value in node_data.get('tags', {}).items():
                if tag_key not in ['name']:
                    new_node.setTag(tag_key, str(tag_value))

            return new_node

        except Exception as e:
            print(f"创建基本节点失败: {e}")
            return None

    def _generateUniqueName(self, base_name, parent_node):
        """生成唯一节点名称"""
        try:
            # 移除可能的数字后缀
            import re
            import time
            name_base = re.sub(r'_\d+$', '', base_name)

            # 查找现有同名节点
            counter = 1
            unique_name = base_name
            while True:
                # 检查父节点下是否已存在同名子节点
                existing_node = parent_node.find(unique_name)
                if existing_node.isEmpty():
                    break
                unique_name = f"{name_base}_{counter}"
                counter += 1
                if counter > 1000:  # 防止无限循环
                    break
            
            return unique_name

        except Exception as e:
            print(f"生成唯一名称时出错: {e}")
            return f"{base_name}_{int(time.time())}"
