""" 骨骼动画系统插件 - 网络同步模块 提供动画状态网络同步、多人协作等功能 """ from panda3d.core import * from direct.distributed.ClockDelta import * from direct.showbase.DirectObject import DirectObject import json import hashlib class AnimationNetworkSync(DirectObject): """ 动画网络同步系统 支持多人环境中动画状态的同步 """ def __init__(self, world): self.world = world self.network_settings = { 'enable_sync': True, 'sync_interval': 0.1, # 同步间隔(秒) 'interpolation_mode': 'linear', # 插值模式 'extrapolation_limit': 0.5, # 外推限制(秒) 'compression_enabled': True, 'delta_compression': True } # 网络状态 self.is_server = False self.is_client = False self.connected = False self.network_actor_states = {} # {actor_id: state_data} self.local_actor_states = {} # {actor_id: state_data} self.actor_sync_callbacks = {} # {actor_id: callback_func} # 同步定时器 self.sync_task = None self.last_sync_time = 0 def enable_server_mode(self): """ 启用服务器模式 """ self.is_server = True self.is_client = False self.connected = True print("动画网络同步系统 - 服务器模式已启用") def enable_client_mode(self): """ 启用客户端模式 """ self.is_server = False self.is_client = True self.connected = True print("动画网络同步系统 - 客户端模式已启用") def disable_network_sync(self): """ 禁用网络同步 """ self.is_server = False self.is_client = False self.connected = False print("动画网络同步系统已禁用") def register_actor_for_sync(self, actor_id, actor, sync_callback=None): """ 注册Actor以进行网络同步 :param actor_id: Actor ID :param actor: Actor对象 :param sync_callback: 同步回调函数 """ self.local_actor_states[actor_id] = { 'actor': actor, 'last_state': self._capture_actor_state(actor), 'last_update': globalClock.getRealTime(), 'sync_callback': sync_callback } if sync_callback: self.actor_sync_callbacks[actor_id] = sync_callback print(f"Actor {actor_id} 已注册网络同步") def unregister_actor_from_sync(self, actor_id): """ 取消Actor的网络同步注册 :param actor_id: Actor ID """ if actor_id in self.local_actor_states: del self.local_actor_states[actor_id] if actor_id in self.actor_sync_callbacks: del self.actor_sync_callbacks[actor_id] if actor_id in self.network_actor_states: del self.network_actor_states[actor_id] print(f"Actor {actor_id} 已取消网络同步注册") def _capture_actor_state(self, actor): """ 捕获Actor当前状态 :param actor: Actor对象 :return: 状态数据 """ state = { 'position': actor.getPos().toTuple(), 'rotation': actor.getHpr().toTuple(), 'scale': actor.getScale().toTuple(), 'active_animations': {}, 'timestamp': globalClock.getRealTime() } # 捕获活动动画状态 for anim_name in actor.getAnimNames(): control = actor.getAnimControl(anim_name) if control and control.isPlaying(): state['active_animations'][anim_name] = { 'frame': actor.getCurrentFrame(anim_name), 'play_rate': actor.getPlayRate(anim_name), 'is_looping': control.getLoop() } return state def _apply_actor_state(self, actor, state_data): """ 应用Actor状态 :param actor: Actor对象 :param state_data: 状态数据 """ # 应用变换 if 'position' in state_data: actor.setPos(*state_data['position']) if 'rotation' in state_data: actor.setHpr(*state_data['rotation']) if 'scale' in state_data: actor.setScale(*state_data['scale']) # 应用动画状态 if 'active_animations' in state_data: for anim_name, anim_state in state_data['active_animations'].items(): if anim_name in actor.getAnimNames(): # 停止当前动画 actor.stop(anim_name) # 设置到指定帧 if 'frame' in anim_state: actor.pose(anim_name, anim_state['frame']) # 设置播放速度 if 'play_rate' in anim_state: actor.setPlayRate(anim_state['play_rate'], anim_name) # 调用自定义同步回调 actor_id = actor.getName() # 简化获取ID的方法 if actor_id in self.actor_sync_callbacks: self.actor_sync_callbacks[actor_id](actor, state_data) def send_actor_state(self, actor_id): """ 发送Actor状态(服务器模式) :param actor_id: Actor ID """ if not self.is_server or not self.connected: return if actor_id not in self.local_actor_states: return actor_state = self.local_actor_states[actor_id] actor = actor_state['actor'] current_state = self._capture_actor_state(actor) # 检查状态是否发生变化 if self._has_state_changed(actor_state['last_state'], current_state): # 发送状态更新 self._broadcast_actor_state(actor_id, current_state) # 更新最后状态 actor_state['last_state'] = current_state actor_state['last_update'] = globalClock.getRealTime() def _has_state_changed(self, old_state, new_state, threshold=0.001): """ 检查状态是否发生变化 :param old_state: 旧状态 :param new_state: 新状态 :param threshold: 变化阈值 :return: 是否发生变化 """ # 检查位置变化 if 'position' in old_state and 'position' in new_state: old_pos = Vec3(*old_state['position']) new_pos = Vec3(*new_state['position']) if (old_pos - new_pos).length() > threshold: return True # 检查旋转变化 if 'rotation' in old_state and 'rotation' in new_state: old_hpr = Vec3(*old_state['rotation']) new_hpr = Vec3(*new_state['rotation']) if (old_hpr - new_hpr).length() > threshold: return True # 检查动画状态变化 if 'active_animations' in old_state and 'active_animations' in new_state: if old_state['active_animations'] != new_state['active_animations']: return True return False def _broadcast_actor_state(self, actor_id, state_data): """ 广播Actor状态 :param actor_id: Actor ID :param state_data: 状态数据 """ # 在实际实现中,这里会通过网络发送数据 # 为简化,我们直接更新网络状态 self.network_actor_states[actor_id] = state_data print(f"广播Actor {actor_id} 状态更新") def receive_actor_state(self, actor_id, state_data): """ 接收Actor状态(客户端模式) :param actor_id: Actor ID :param state_data: 状态数据 """ if not self.is_client or not self.connected: return # 存储接收到的状态 self.network_actor_states[actor_id] = { 'state': state_data, 'receive_time': globalClock.getRealTime(), 'interpolated': False } print(f"接收Actor {actor_id} 状态更新") def update_network_sync(self, task): """ 更新网络同步 """ current_time = globalClock.getRealTime() # 检查同步间隔 if current_time - self.last_sync_time < self.network_settings['sync_interval']: return task.cont self.last_sync_time = current_time if self.is_server: # 服务器:发送本地Actor状态 for actor_id in list(self.local_actor_states.keys()): self.send_actor_state(actor_id) elif self.is_client: # 客户端:应用接收到的状态 self._apply_network_states() return task.cont def _apply_network_states(self): """ 应用网络状态 """ current_time = globalClock.getRealTime() for actor_id, state_info in self.network_actor_states.items(): state_data = state_info['state'] receive_time = state_info['receive_time'] # 查找对应的Actor actor_np = self.world.render.find(f"**/{actor_id}") if actor_np and actor_np.node(): actor = actor_np.node() if isinstance(actor, Actor): # 时间补偿插值 if self.network_settings['interpolation_mode'] == 'linear': # 简单线性插值 self._apply_actor_state(actor, state_data) else: # 直接应用状态 self._apply_actor_state(actor, state_data) def start_sync_task(self): """ 启动同步任务 """ if self.sync_task is None: self.sync_task = self.world.taskMgr.add( self.update_network_sync, "animationNetworkSyncTask", sort=40 # 确保在网络更新之后执行 ) print("动画网络同步任务已启动") def stop_sync_task(self): """ 停止同步任务 """ if self.sync_task: self.world.taskMgr.remove(self.sync_task) self.sync_task = None print("动画网络同步任务已停止") def get_network_stats(self): """ 获取网络同步统计信息 :return: 统计信息 """ return { 'is_server': self.is_server, 'is_client': self.is_client, 'connected': self.connected, 'local_actors': len(self.local_actor_states), 'network_actors': len(self.network_actor_states), 'sync_enabled': self.network_settings['enable_sync'], 'sync_interval': self.network_settings['sync_interval'] } class DistributedAnimationManager: """ 分布式动画管理器 管理网络环境中的动画同步 """ def __init__(self, world): self.world = world self.network_sync = AnimationNetworkSync(world) self.distributed_actors = {} # {actor_id: distributed_data} self.master_slave_relations = {} # {slave_actor_id: master_actor_id} def enable_distributed_mode(self, mode='server'): """ 启用分布式模式 :param mode: 模式 ('server' 或 'client') """ if mode == 'server': self.network_sync.enable_server_mode() else: self.network_sync.enable_client_mode() self.network_sync.start_sync_task() print(f"分布式动画管理器已启用 ({mode} 模式)") def disable_distributed_mode(self): """ 禁用分布式模式 """ self.network_sync.stop_sync_task() self.network_sync.disable_network_sync() print("分布式动画管理器已禁用") def create_distributed_actor(self, actor_id, model_path, anim_dict=None): """ 创建分布式Actor :param actor_id: Actor ID :param model_path: 模型路径 :param anim_dict: 动画字典 :return: Actor对象 """ from direct.actor.Actor import Actor # 创建Actor if anim_dict: actor = Actor(model_path, anim_dict) else: actor = Actor(model_path) # 添加到场景 actor.reparentTo(self.world.render) actor.setName(actor_id) # 注册网络同步 self.network_sync.register_actor_for_sync(actor_id, actor) # 存储分布式数据 self.distributed_actors[actor_id] = { 'actor': actor, 'model_path': model_path, 'anim_dict': anim_dict, 'is_distributed': True } print(f"分布式Actor已创建: {actor_id}") return actor def set_master_slave_relation(self, master_id, slave_id): """ 设置主从关系 :param master_id: 主Actor ID :param slave_id: 从Actor ID """ if master_id in self.distributed_actors and slave_id in self.distributed_actors: self.master_slave_relations[slave_id] = master_id print(f"设置主从关系: {master_id} -> {slave_id}") def sync_actor_animation(self, actor_id, anim_name, play=True, loop=False, play_rate=1.0): """ 同步Actor动画 :param actor_id: Actor ID :param anim_name: 动画名称 :param play: 是否播放 :param loop: 是否循环 :param play_rate: 播放速度 """ if actor_id not in self.distributed_actors: return actor_data = self.distributed_actors[actor_id] actor = actor_data['actor'] if play: actor.play(anim_name) if loop: actor.loop(anim_name, restart=False) actor.setPlayRate(play_rate, anim_name) else: actor.stop(anim_name) print(f"同步Actor {actor_id} 动画: {anim_name}") def get_distributed_stats(self): """ 获取分布式统计信息 :return: 统计信息 """ network_stats = self.network_sync.get_network_stats() return { 'network_stats': network_stats, 'distributed_actors': len(self.distributed_actors), 'master_slave_relations': len(self.master_slave_relations) } class AnimationStateSerializer: """ 动画状态序列化器 支持动画状态的序列化和反序列化 """ def __init__(self): self.serialization_settings = { 'compress_data': True, 'include_bone_transforms': True, 'include_animation_state': True, 'include_custom_properties': True } def serialize_actor_state(self, actor, include_animations=True): """ 序列化Actor状态 :param actor: Actor对象 :param include_animations: 是否包含动画状态 :return: 序列化数据 """ state_data = { 'name': actor.getName() if hasattr(actor, 'getName') else 'Unknown', 'position': actor.getPos().toTuple(), 'rotation': actor.getHpr().toTuple(), 'scale': actor.getScale().toTuple(), 'timestamp': globalClock.getRealTime() } if include_animations: state_data['animations'] = self._serialize_animation_state(actor) if self.serialization_settings['include_bone_transforms']: state_data['bone_transforms'] = self._serialize_bone_transforms(actor) # 计算数据校验和 state_data['checksum'] = self._calculate_checksum(state_data) return state_data def _serialize_animation_state(self, actor): """ 序列化动画状态 :param actor: Actor对象 :return: 动画状态数据 """ anim_state = { 'current_animations': [], 'animation_rates': {}, 'animation_frames': {} } for anim_name in actor.getAnimNames(): control = actor.getAnimControl(anim_name) if control and control.isPlaying(): anim_state['current_animations'].append(anim_name) anim_state['animation_rates'][anim_name] = actor.getPlayRate(anim_name) anim_state['animation_frames'][anim_name] = actor.getCurrentFrame(anim_name) return anim_state def _serialize_bone_transforms(self, actor): """ 序列化骨骼变换 :param actor: Actor对象 :return: 骨骼变换数据 """ bone_transforms = {} # 获取骨骼信息 bundle_dict = actor.getPartBundleDict() for bundle_name, bundle in bundle_dict.items(): bone_transforms[bundle_name] = self._extract_bundle_transforms(bundle) return bone_transforms def _extract_bundle_transforms(self, bundle): """ 提取绑定变换 :param bundle: PartBundle对象 :return: 变换数据 """ transforms = {} # 遍历子节点 for i in range(bundle.getNumChildren()): child = bundle.getChild(i) if hasattr(child, 'getName'): bone_name = child.getName() # 注意:这里简化处理,实际项目中需要更复杂的骨骼数据提取 transforms[bone_name] = { 'transform': 'dummy_transform_data' } return transforms def _calculate_checksum(self, data): """ 计算数据校验和 :param data: 数据 :return: 校验和 """ # 简化实现,实际项目中应使用更安全的哈希算法 data_str = json.dumps(data, sort_keys=True) return hashlib.md5(data_str.encode()).hexdigest() def deserialize_actor_state(self, actor, state_data): """ 反序列化Actor状态 :param actor: Actor对象 :param state_data: 状态数据 """ # 验证校验和 if 'checksum' in state_data: expected_checksum = state_data['checksum'] data_to_check = state_data.copy() del data_to_check['checksum'] actual_checksum = self._calculate_checksum(data_to_check) if expected_checksum != actual_checksum: print("警告: 数据校验和不匹配") # 应用变换 if 'position' in state_data: actor.setPos(*state_data['position']) if 'rotation' in state_data: actor.setHpr(*state_data['rotation']) if 'scale' in state_data: actor.setScale(*state_data['scale']) # 应用动画状态 if 'animations' in state_data: self._deserialize_animation_state(actor, state_data['animations']) def _deserialize_animation_state(self, actor, anim_state): """ 反序列化动画状态 :param actor: Actor对象 :param anim_state: 动画状态数据 """ # 停止所有当前动画 actor.stop() # 播放指定动画 for anim_name in anim_state.get('current_animations', []): if anim_name in actor.getAnimNames(): frame = anim_state.get('animation_frames', {}).get(anim_name, 0) rate = anim_state.get('animation_rates', {}).get(anim_name, 1.0) actor.pose(anim_name, frame) actor.setPlayRate(rate, anim_name) def save_state_to_file(self, actor, file_path, include_animations=True): """ 保存状态到文件 :param actor: Actor对象 :param file_path: 文件路径 :param include_animations: 是否包含动画状态 """ state_data = self.serialize_actor_state(actor, include_animations) try: with open(file_path, 'w') as f: json.dump(state_data, f, indent=2) print(f"Actor状态已保存到: {file_path}") except Exception as e: print(f"保存状态失败: {e}") def load_state_from_file(self, actor, file_path): """ 从文件加载状态 :param actor: Actor对象 :param file_path: 文件路径 """ try: with open(file_path, 'r') as f: state_data = json.load(f) self.deserialize_actor_state(actor, state_data) print(f"Actor状态已从 {file_path} 加载") except Exception as e: print(f"加载状态失败: {e}") # 使用示例 def example_network_sync_usage(world): """ 网络同步使用示例 """ print("=== 动画网络同步使用示例 ===") # 创建网络同步系统 network_sync = AnimationNetworkSync(world) # 模拟服务器模式 network_sync.enable_server_mode() # 获取网络统计 stats = network_sync.get_network_stats() print(f"网络统计: {stats}") print("网络同步示例完成") def example_distributed_usage(world): """ 分布式动画使用示例 """ print("=== 分布式动画使用示例 ===") # 创建分布式管理器 dist_manager = DistributedAnimationManager(world) # 启用服务器模式 dist_manager.enable_distributed_mode('server') # 获取分布式统计 stats = dist_manager.get_distributed_stats() print(f"分布式统计: {stats}") print("分布式动画示例完成") def example_serialization_usage(actor): """ 状态序列化使用示例 """ print("=== 动画状态序列化使用示例 ===") # 创建序列化器 serializer = AnimationStateSerializer() # 序列化Actor状态 state_data = serializer.serialize_actor_state(actor) print(f"序列化状态大小: {len(json.dumps(state_data))} 字符") # 保存到文件 serializer.save_state_to_file(actor, "actor_state.json") print("状态序列化示例完成") if __name__ == "__main__": print("动画网络同步模块加载完成")