""" 高级骨骼动画系统 - 网络同步模块 提供动画状态网络同步、多人协作等功能 """ import json import hashlib from typing import Dict, List, Optional, Any, Callable from dataclasses import dataclass, field from enum import Enum from panda3d.core import * from direct.distributed.ClockDelta import globalClockDelta from direct.showbase.DirectObject import DirectObject # 定义常量 NETWORK_SETTINGS = { 'enable_sync': True, 'sync_interval': 0.1, # 同步间隔(秒) 'interpolation_mode': 'linear', # 插值模式 'extrapolation_limit': 0.5, # 外推限制(秒) 'compression_enabled': True, 'delta_compression': True } # 枚举定义 class NetworkMode(Enum): """网络模式枚举""" DISABLED = 0 SERVER = 1 CLIENT = 2 PEER_TO_PEER = 3 class SyncMode(Enum): """同步模式枚举""" STATE_SYNC = 0 # 状态同步 INPUT_SYNC = 1 # 输入同步 INTERPOLATION = 2 # 插值同步 @dataclass class NetworkActorState: """网络Actor状态数据类""" actor_id: str position: Tuple[float, float, float] rotation: Tuple[float, float, float] scale: Tuple[float, float, float] active_animations: Dict[str, Dict[str, Any]] timestamp: float network_id: str = "" checksum: str = "" @dataclass class NetworkSyncConfig: """网络同步配置数据类""" mode: NetworkMode = NetworkMode.DISABLED sync_mode: SyncMode = SyncMode.STATE_SYNC sync_interval: float = 0.1 interpolation_mode: str = 'linear' enable_compression: bool = True max_buffer_size: int = 100 update_rate: int = 20 # 每秒更新次数 class NetworkSyncBuffer: """网络同步缓冲区""" def __init__(self, max_size: int = 100): self.max_size = max_size self.buffer: List[NetworkActorState] = [] self.last_processed_time = 0.0 def add_state(self, state: NetworkActorState) -> None: """添加状态到缓冲区""" self.buffer.append(state) # 保持缓冲区大小 if len(self.buffer) > self.max_size: self.buffer.pop(0) def get_interpolated_state(self, target_time: float) -> Optional[NetworkActorState]: """ 获取插值状态 :param target_time: 目标时间 :return: 插值状态 """ if len(self.buffer) < 2: return self.buffer[-1] if self.buffer else None # 找到时间范围内的两个状态 prev_state = None next_state = None for state in self.buffer: if state.timestamp <= target_time: prev_state = state else: next_state = state break if not prev_state or not next_state: return self.buffer[-1] if self.buffer else None # 计算插值因子 time_range = next_state.timestamp - prev_state.timestamp if time_range <= 0: return prev_state t = (target_time - prev_state.timestamp) / time_range # 执行线性插值 interpolated_pos = tuple( prev_state.position[i] + t * (next_state.position[i] - prev_state.position[i]) for i in range(3) ) interpolated_rot = tuple( prev_state.rotation[i] + t * (next_state.rotation[i] - prev_state.rotation[i]) for i in range(3) ) interpolated_scale = tuple( prev_state.scale[i] + t * (next_state.scale[i] - prev_state.scale[i]) for i in range(3) ) # 创建插值状态 interpolated_state = NetworkActorState( actor_id=prev_state.actor_id, position=interpolated_pos, rotation=interpolated_rot, scale=interpolated_scale, active_animations=prev_state.active_animations, # 简化处理 timestamp=target_time, network_id=prev_state.network_id ) return interpolated_state def clear(self) -> None: """清空缓冲区""" self.buffer.clear() class AnimationNetworkSync(DirectObject): """ 动画网络同步系统 支持多人环境中动画状态的同步 """ def __init__(self, world, core_system): """ 初始化网络同步系统 :param world: 世界对象 :param core_system: 核心动画系统 """ super().__init__() self.world = world self.core_system = core_system self.config = NetworkSyncConfig() self.network_states: Dict[str, NetworkActorState] = {} self.state_buffers: Dict[str, NetworkSyncBuffer] = {} self.sync_callbacks: Dict[str, List[Callable]] = {} self.is_connected = False self.last_sync_time = 0.0 self.sync_task = None self.network_id_counter = 0 print("动画网络同步系统初始化完成") def set_network_mode(self, mode: NetworkMode) -> None: """ 设置网络模式 :param mode: 网络模式 """ self.config.mode = mode if mode != NetworkMode.DISABLED: self.is_connected = True self.start_sync_task() else: self.is_connected = False self.stop_sync_task() print(f"网络模式设置为: {mode.name}") def set_sync_mode(self, mode: SyncMode) -> None: """ 设置同步模式 :param mode: 同步模式 """ self.config.sync_mode = mode print(f"同步模式设置为: {mode.name}") def configure_sync(self, sync_interval: float = 0.1, interpolation_mode: str = 'linear', enable_compression: bool = True) -> None: """ 配置同步参数 :param sync_interval: 同步间隔 :param interpolation_mode: 插值模式 :param enable_compression: 是否启用压缩 """ self.config.sync_interval = sync_interval self.config.interpolation_mode = interpolation_mode self.config.enable_compression = enable_compression print(f"同步配置更新: 间隔={sync_interval}s, 插值={interpolation_mode}, 压缩={enable_compression}") def register_actor_for_sync(self, actor_id: str, network_id: Optional[str] = None) -> str: """ 注册Actor以进行网络同步 :param actor_id: Actor ID :param network_id: 网络ID,如果为None则自动生成 :return: 网络ID """ if network_id is None: network_id = f"net_{self.network_id_counter}" self.network_id_counter += 1 # 初始化状态缓冲区 self.state_buffers[actor_id] = NetworkSyncBuffer(self.config.max_buffer_size) print(f"Actor {actor_id} 已注册网络同步 (网络ID: {network_id})") return network_id def unregister_actor_from_sync(self, actor_id: str) -> None: """ 取消Actor的网络同步注册 :param actor_id: Actor ID """ if actor_id in self.state_buffers: self.state_buffers[actor_id].clear() del self.state_buffers[actor_id] if actor_id in self.network_states: del self.network_states[actor_id] print(f"Actor {actor_id} 已取消网络同步注册") def _capture_actor_state(self, actor_id: str) -> Optional[NetworkActorState]: """ 捕获Actor当前状态 :param actor_id: Actor ID :return: 状态数据 """ actor_info = self.core_system.actors.get(actor_id) if not actor_info: return None actor = actor_info.actor # 获取基本变换 position = actor.getPos().toTuple() rotation = actor.getHpr().toTuple() scale = actor.getScale().toTuple() # 获取活动动画状态 active_animations = {} for anim_name in actor_info.active_animations: if anim_name in actor_info.animations: anim_info = actor_info.animations[anim_name] control = actor.getAnimControl(anim_name) if anim_name in actor.getAnimNames() else None active_animations[anim_name] = { 'frame': anim_info.current_frame, 'play_rate': anim_info.play_rate, 'loop': anim_info.loop, 'state': anim_info.state.name, 'blend_weight': anim_info.blend_weight } # 创建状态对象 state = NetworkActorState( actor_id=actor_id, position=position, rotation=rotation, scale=scale, active_animations=active_animations, timestamp=globalClock.getRealTime() ) # 计算校验和 state.checksum = self._calculate_checksum(state) return state def _calculate_checksum(self, state: NetworkActorState) -> str: """ 计算状态校验和 :param state: 状态数据 :return: 校验和 """ # 创建用于校验的数据 checksum_data = { 'position': state.position, 'rotation': state.rotation, 'scale': state.scale, 'active_animations': state.active_animations, 'timestamp': state.timestamp } # 生成JSON字符串并计算MD5 data_str = json.dumps(checksum_data, sort_keys=True) return hashlib.md5(data_str.encode()).hexdigest() def _validate_checksum(self, state: NetworkActorState) -> bool: """ 验证状态校验和 :param state: 状态数据 :return: 是否有效 """ expected_checksum = state.checksum state.checksum = "" # 临时清空校验和 actual_checksum = self._calculate_checksum(state) state.checksum = expected_checksum # 恢复校验和 return expected_checksum == actual_checksum def send_actor_state(self, actor_id: str) -> None: """ 发送Actor状态(服务器模式) :param actor_id: Actor ID """ if not self.is_connected or self.config.mode != NetworkMode.SERVER: return # 捕获当前状态 state = self._capture_actor_state(actor_id) if not state: return # 发送状态(在实际实现中,这里会通过网络发送) self._broadcast_actor_state(state) def _broadcast_actor_state(self, state: NetworkActorState) -> None: """ 广播Actor状态 :param state: 状态数据 """ # 在实际实现中,这里会通过网络发送数据 # 为简化,我们直接更新本地网络状态 self.network_states[state.actor_id] = state # 添加到缓冲区用于插值 if state.actor_id in self.state_buffers: self.state_buffers[state.actor_id].add_state(state) print(f"广播Actor {state.actor_id} 状态更新 (时间: {state.timestamp:.3f})") def receive_actor_state(self, state_data: Dict[str, Any]) -> None: """ 接收Actor状态(客户端模式) :param state_data: 状态数据 """ if not self.is_connected or self.config.mode != NetworkMode.CLIENT: return # 反序列化状态 state = NetworkActorState( actor_id=state_data['actor_id'], position=tuple(state_data['position']), rotation=tuple(state_data['rotation']), scale=tuple(state_data['scale']), active_animations=state_data['active_animations'], timestamp=state_data['timestamp'], network_id=state_data.get('network_id', ''), checksum=state_data.get('checksum', '') ) # 验证校验和 if not self._validate_checksum(state): print(f"警告: Actor {state.actor_id} 状态校验和不匹配,丢弃数据") return # 存储接收到的状态 self.network_states[state.actor_id] = state # 添加到缓冲区用于插值 if state.actor_id in self.state_buffers: self.state_buffers[state.actor_id].add_state(state) print(f"接收Actor {state.actor_id} 状态更新 (时间: {state.timestamp:.3f})") def _apply_actor_state(self, actor_id: str, state: NetworkActorState) -> None: """ 应用Actor状态 :param actor_id: Actor ID :param state: 状态数据 """ actor_info = self.core_system.actors.get(actor_id) if not actor_info: return actor = actor_info.actor # 应用变换 actor.setPos(*state.position) actor.setHpr(*state.rotation) actor.setScale(*state.scale) # 应用动画状态 for anim_name, anim_state in state.active_animations.items(): if anim_name in actor.getAnimNames(): # 设置动画帧 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) # 恢复播放状态 if anim_state.get('state') in ['PLAYING', 'LOOPING']: if anim_state.get('loop', False): actor.loop(anim_name, restart=False) else: actor.play(anim_name) print(f"应用Actor {actor_id} 网络状态 (时间: {state.timestamp:.3f})") def _apply_interpolated_state(self, actor_id: str, target_time: float) -> None: """ 应用插值状态 :param actor_id: Actor ID :param target_time: 目标时间 """ if actor_id not in self.state_buffers: return # 获取插值状态 interpolated_state = self.state_buffers[actor_id].get_interpolated_state(target_time) if interpolated_state: self._apply_actor_state(actor_id, interpolated_state) def update_network_sync(self, task) -> int: """ 更新网络同步 :param task: 任务对象 """ current_time = globalClock.getRealTime() # 检查同步间隔 if current_time - self.last_sync_time < self.config.sync_interval: return task.cont self.last_sync_time = current_time if self.config.mode == NetworkMode.SERVER: # 服务器:发送本地Actor状态 for actor_id in self.core_system.actors.keys(): self.send_actor_state(actor_id) elif self.config.mode == NetworkMode.CLIENT: # 客户端:应用接收到的状态 current_network_time = globalClock.getRealTime() # 根据同步模式应用状态 if self.config.sync_mode == SyncMode.INTERPOLATION: # 使用插值 for actor_id in self.network_states.keys(): self._apply_interpolated_state(actor_id, current_network_time) else: # 直接应用最新状态 for actor_id, state in self.network_states.items(): self._apply_actor_state(actor_id, state) return task.cont def start_sync_task(self) -> None: """ 启动同步任务 """ 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) -> None: """ 停止同步任务 """ if self.sync_task: self.world.taskMgr.remove(self.sync_task) self.sync_task = None print("动画网络同步任务已停止") def get_network_stats(self) -> Dict[str, Any]: """ 获取网络同步统计信息 :return: 统计信息 """ return { 'mode': self.config.mode.name, 'sync_mode': self.config.sync_mode.name, 'connected': self.is_connected, 'sync_interval': self.config.sync_interval, 'interpolation_mode': self.config.interpolation_mode, 'compression_enabled': self.config.enable_compression, 'network_actors': len(self.network_states), 'buffered_states': sum(len(buffer.buffer) for buffer in self.state_buffers.values()) } def add_sync_callback(self, actor_id: str, callback: Callable) -> None: """ 添加同步回调 :param actor_id: Actor ID :param callback: 回调函数 """ if actor_id not in self.sync_callbacks: self.sync_callbacks[actor_id] = [] self.sync_callbacks[actor_id].append(callback) def remove_sync_callback(self, actor_id: str, callback: Callable) -> None: """ 移除同步回调 :param actor_id: Actor ID :param callback: 回调函数 """ if actor_id in self.sync_callbacks and callback in self.sync_callbacks[actor_id]: self.sync_callbacks[actor_id].remove(callback) def _trigger_sync_callbacks(self, actor_id: str, state: NetworkActorState) -> None: """ 触发同步回调 :param actor_id: Actor ID :param state: 状态数据 """ if actor_id in self.sync_callbacks: for callback in self.sync_callbacks[actor_id]: try: callback(actor_id, state) except Exception as e: print(f"执行同步回调失败: {e}") # 使用示例和测试代码 def example_network_sync_usage(world, core_system): """ 网络同步使用示例 """ print("=== 动画网络同步使用示例 ===") # 创建网络同步系统 network_sync = AnimationNetworkSync(world, core_system) # 设置为服务器模式 network_sync.set_network_mode(NetworkMode.SERVER) network_sync.set_sync_mode(SyncMode.STATE_SYNC) network_sync.configure_sync(sync_interval=0.05, interpolation_mode='linear') # 获取网络统计 stats = network_sync.get_network_stats() print(f"网络统计: {stats}") print("网络同步示例完成") return network_sync if __name__ == "__main__": print("动画网络同步模块加载完成")