""" Morphing和变形动画插件 - 网络同步模块 提供多人环境中动画状态的同步功能 """ import json import time from typing import Dict, List, Tuple, 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 # 导入核心模块 from .core import MorphingCore # 定义常量 NETWORK_SETTINGS = { 'sync_interval': 0.1, 'interpolation_buffer': 0.1, 'max_buffer_size': 100, 'enable_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 # 插值同步 class InterpolationMode(Enum): """插值模式枚举""" LINEAR = 0 # 线性插值 SPLINE = 1 # 样条插值 HERMITE = 2 # 埃尔米特插值 @dataclass class NetworkState: """网络状态数据类""" model_id: str morph_weights: Dict[str, float] # {target_name: weight} timestamp: float sequence_number: int @dataclass class StateBufferEntry: """状态缓冲区条目""" state: NetworkState received_time: float @dataclass class NetworkConfig: """网络配置数据类""" mode: NetworkMode = NetworkMode.DISABLED sync_mode: SyncMode = SyncMode.STATE_SYNC sync_interval: float = NETWORK_SETTINGS['sync_interval'] interpolation_mode: InterpolationMode = InterpolationMode.LINEAR enable_compression: bool = NETWORK_SETTINGS['enable_compression'] max_buffer_size: int = NETWORK_SETTINGS['max_buffer_size'] class AnimationNetworkSync(DirectObject): """ 动画网络同步系统 处理网络环境中的动画同步 """ def __init__(self, world, morphing_core: MorphingCore): """ 初始化动画网络同步系统 :param world: 世界对象 :param morphing_core: Morphing核心系统 """ super().__init__() self.world = world self.morphing_core = morphing_core self.config = NetworkConfig() self.network_id_map: Dict[str, str] = {} # {local_model_id: network_id} self.local_id_map: Dict[str, str] = {} # {network_id: local_model_id} self.state_buffers: Dict[str, List[StateBufferEntry]] = {} # {network_id: [StateBufferEntry]} self.sequence_numbers: Dict[str, int] = {} # {network_id: sequence_number} self.is_syncing = False self.sync_task = None self.last_sync_time = 0.0 self.network_interface = None # 网络接口(需要根据具体网络库实现) print("动画网络同步系统初始化完成") def set_network_mode(self, mode: NetworkMode) -> None: """ 设置网络模式 :param mode: 网络模式 """ self.config.mode = mode print(f"网络模式设置为: {mode.name}") def set_sync_mode(self, mode: SyncMode) -> None: """ 设置同步模式 :param mode: 同步模式 """ self.config.sync_mode = mode print(f"同步模式设置为: {mode.name}") def set_sync_interval(self, interval: float) -> None: """ 设置同步间隔 :param interval: 同步间隔(秒) """ self.config.sync_interval = interval print(f"同步间隔设置为: {interval}秒") def set_interpolation_mode(self, mode: InterpolationMode) -> None: """ 设置插值模式 :param mode: 插值模式 """ self.config.interpolation_mode = mode print(f"插值模式设置为: {mode.name}") def enable_compression(self, enabled: bool = True) -> None: """ 启用/禁用压缩 :param enabled: 是否启用 """ self.config.enable_compression = enabled print(f"压缩已{'启用' if enabled else '禁用'}") def register_model_for_sync(self, model_id: str, network_id: Optional[str] = None) -> str: """ 注册模型以进行网络同步 :param model_id: 本地模型ID :param network_id: 网络ID,如果为None则自动生成 :return: 网络ID """ if self.config.mode == NetworkMode.DISABLED: print("错误: 网络同步已禁用") return "" if model_id not in self.morphing_core.model_data: print(f"错误: 模型 {model_id} 未注册到Morphing核心系统") return "" if network_id is None: network_id = f"net_model_{len(self.network_id_map)}" # 检查ID是否已存在 if network_id in self.local_id_map: print(f"警告: 网络ID {network_id} 已存在,将被替换") old_local_id = self.local_id_map[network_id] if old_local_id in self.network_id_map: del self.network_id_map[old_local_id] # 建立映射关系 self.network_id_map[model_id] = network_id self.local_id_map[network_id] = model_id # 初始化状态缓冲区 self.state_buffers[network_id] = [] self.sequence_numbers[network_id] = 0 print(f"模型已注册网络同步: {model_id} -> {network_id}") return network_id def unregister_model_from_sync(self, model_id: str) -> bool: """ 从网络同步中注销模型 :param model_id: 本地模型ID :return: 是否成功注销 """ if model_id not in self.network_id_map: print(f"错误: 模型 {model_id} 未注册网络同步") return False network_id = self.network_id_map[model_id] # 清理相关数据 del self.network_id_map[model_id] if network_id in self.local_id_map: del self.local_id_map[network_id] if network_id in self.state_buffers: del self.state_buffers[network_id] if network_id in self.sequence_numbers: del self.sequence_numbers[network_id] print(f"模型已注销网络同步: {model_id} -> {network_id}") return True def send_model_state(self, model_id: str) -> bool: """ 发送模型状态 :param model_id: 本地模型ID :return: 是否成功发送 """ if self.config.mode not in [NetworkMode.SERVER, NetworkMode.PEER_TO_PEER]: print("错误: 当前网络模式不支持发送状态") return False if model_id not in self.network_id_map: print(f"错误: 模型 {model_id} 未注册网络同步") return False network_id = self.network_id_map[model_id] # 获取模型的当前状态 morph_weights = {} if model_id in self.morphing_core.morph_targets: for target_name, morph_target in self.morphing_core.morph_targets[model_id].items(): # 使用平均权重作为代表值 if morph_target.weights: morph_weights[target_name] = sum(morph_target.weights) / len(morph_target.weights) # 创建网络状态 state = NetworkState( model_id=network_id, morph_weights=morph_weights, timestamp=globalClockDelta.getRealNetworkTime(bits=32), sequence_number=self.sequence_numbers.get(network_id, 0) ) # 更新序列号 self.sequence_numbers[network_id] = self.sequence_numbers.get(network_id, 0) + 1 # 压缩状态数据(如果启用) state_data = self._serialize_state(state) if self.config.enable_compression: state_data = self._compress_state_data(state_data) # 发送状态数据(需要根据具体网络库实现) if self.network_interface: try: self.network_interface.send_state(network_id, state_data) print(f"模型状态已发送: {model_id} -> {network_id}") return True except Exception as e: print(f"发送模型状态时出错: {e}") return False else: # 模拟发送(用于测试) print(f"模拟发送模型状态: {model_id} -> {network_id}") print(f" 状态数据: {state_data}") return True def receive_model_state(self, network_id: str, state_data: bytes) -> bool: """ 接收模型状态 :param network_id: 网络ID :param state_data: 状态数据 :return: 是否成功接收 """ if self.config.mode not in [NetworkMode.CLIENT, NetworkMode.PEER_TO_PEER]: print("错误: 当前网络模式不支持接收状态") return False if network_id not in self.local_id_map: print(f"警告: 未知的网络ID {network_id},忽略状态数据") return False local_id = self.local_id_map[network_id] # 解压缩状态数据(如果启用) if self.config.enable_compression: state_data = self._decompress_state_data(state_data) # 反序列化状态 state = self._deserialize_state(state_data) if not state: print(f"错误: 无法反序列化状态数据") return False # 验证序列号 last_sequence = self.sequence_numbers.get(network_id, -1) if state.sequence_number <= last_sequence: print(f"警告: 过期的状态数据 (序列号: {state.sequence_number} <= {last_sequence})") return False # 更新序列号 self.sequence_numbers[network_id] = state.sequence_number # 添加到状态缓冲区 buffer_entry = StateBufferEntry( state=state, received_time=globalClock.getRealTime() ) if network_id not in self.state_buffers: self.state_buffers[network_id] = [] self.state_buffers[network_id].append(buffer_entry) # 限制缓冲区大小 if len(self.state_buffers[network_id]) > self.config.max_buffer_size: self.state_buffers[network_id].pop(0) # 应用状态(根据同步模式) if self.config.sync_mode == SyncMode.STATE_SYNC: self._apply_state_immediately(local_id, state) elif self.config.sync_mode == SyncMode.INTERPOLATION: # 插值模式下暂不立即应用,等待插值更新 pass print(f"模型状态已接收: {network_id} -> {local_id}") return True def _serialize_state(self, state: NetworkState) -> bytes: """ 序列化网络状态 :param state: 网络状态 :return: 序列化后的数据 """ state_dict = { 'model_id': state.model_id, 'morph_weights': state.morph_weights, 'timestamp': state.timestamp, 'sequence_number': state.sequence_number } return json.dumps(state_dict).encode('utf-8') def _deserialize_state(self, state_data: bytes) -> Optional[NetworkState]: """ 反序列化网络状态 :param state_data: 状态数据 :return: 网络状态对象 """ try: state_dict = json.loads(state_data.decode('utf-8')) return NetworkState( model_id=state_dict['model_id'], morph_weights=state_dict['morph_weights'], timestamp=state_dict['timestamp'], sequence_number=state_dict['sequence_number'] ) except Exception as e: print(f"反序列化状态数据时出错: {e}") return None def _compress_state_data(self, state_data: bytes) -> bytes: """ 压缩状态数据 :param state_data: 状态数据 :return: 压缩后的数据 """ # 简化实现,实际项目中可以使用zlib等压缩库 return state_data def _decompress_state_data(self, state_data: bytes) -> bytes: """ 解压缩状态数据 :param state_data: 压缩的状态数据 :return: 解压后的数据 """ # 简化实现,实际项目中需要对应解压 return state_data def _apply_state_immediately(self, model_id: str, state: NetworkState) -> None: """ 立即应用网络状态 :param model_id: 本地模型ID :param state: 网络状态 """ # 应用Morph目标权重 for target_name, weight in state.morph_weights.items(): self.morphing_core.set_morph_target_weight(model_id, target_name, weight) def _interpolate_states(self, network_id: str) -> None: """ 插值状态 :param network_id: 网络ID """ if network_id not in self.state_buffers or len(self.state_buffers[network_id]) < 2: return local_id = self.local_id_map[network_id] buffer = self.state_buffers[network_id] # 获取当前时间 current_time = globalClock.getRealTime() interpolation_time = current_time - NETWORK_SETTINGS['interpolation_buffer'] # 找到要插值的两个状态 prev_state = None next_state = None for entry in buffer: if entry.received_time <= interpolation_time: prev_state = entry.state else: next_state = entry.state break if not prev_state or not next_state: return # 计算插值因子 time_diff = next_state.timestamp - prev_state.timestamp if time_diff <= 0: return t = (interpolation_time - prev_state.timestamp) / time_diff t = max(0.0, min(1.0, t)) # 限制在0-1范围内 # 根据插值模式调整因子 if self.config.interpolation_mode == InterpolationMode.SPLINE: t = t * t * (3.0 - 2.0 * t) elif self.config.interpolation_mode == InterpolationMode.HERMITE: t = t * t * t * (t * (t * 6.0 - 15.0) + 10.0) # 插值Morph目标权重 all_targets = set(prev_state.morph_weights.keys()) | set(next_state.morph_weights.keys()) for target_name in all_targets: prev_weight = prev_state.morph_weights.get(target_name, 0.0) next_weight = next_state.morph_weights.get(target_name, 0.0) # 计算插值权重 interpolated_weight = prev_weight * (1.0 - t) + next_weight * t # 应用权重 self.morphing_core.set_morph_target_weight(local_id, target_name, interpolated_weight) def start_sync_task(self) -> None: """ 启动同步任务 """ if self.is_syncing: return self.is_syncing = True # 启动同步任务 self.sync_task = self.world.taskMgr.add( self._sync_task, "morphing_network_sync", sort=40 ) print("动画网络同步任务已启动") def stop_sync_task(self) -> None: """ 停止同步任务 """ if not self.is_syncing: return self.is_syncing = False # 停止同步任务 if self.sync_task: self.world.taskMgr.remove(self.sync_task) self.sync_task = None print("动画网络同步任务已停止") def _sync_task(self, task) -> int: """ 网络同步任务 :param task: 任务对象 :return: 任务状态 """ 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: # 服务器模式:发送所有注册模型的状态 for model_id in self.network_id_map.keys(): self.send_model_state(model_id) elif self.config.mode == NetworkMode.CLIENT: # 客户端模式:接收状态并应用插值(如果启用) if self.config.sync_mode == SyncMode.INTERPOLATION: for network_id in self.state_buffers.keys(): self._interpolate_states(network_id) elif self.config.mode == NetworkMode.PEER_TO_PEER: # 点对点模式:发送和接收状态 for model_id in self.network_id_map.keys(): self.send_model_state(model_id) if self.config.sync_mode == SyncMode.INTERPOLATION: for network_id in self.state_buffers.keys(): self._interpolate_states(network_id) return task.cont def get_network_info(self) -> Dict[str, Any]: """ 获取网络同步信息 :return: 网络信息字典 """ return { 'mode': self.config.mode.name, 'sync_mode': self.config.sync_mode.name, 'sync_interval': self.config.sync_interval, 'interpolation_mode': self.config.interpolation_mode.name, 'compression_enabled': self.config.enable_compression, 'registered_models': len(self.network_id_map), 'network_ids': list(self.network_id_map.values()), 'sync_status': 'active' if self.is_syncing else 'inactive' } def get_model_network_info(self, model_id: str) -> Optional[Dict[str, Any]]: """ 获取模型网络信息 :param model_id: 本地模型ID :return: 模型网络信息字典 """ if model_id not in self.network_id_map: print(f"错误: 模型 {model_id} 未注册网络同步") return None network_id = self.network_id_map[model_id] return { 'local_id': model_id, 'network_id': network_id, 'sequence_number': self.sequence_numbers.get(network_id, 0), 'buffer_size': len(self.state_buffers.get(network_id, [])), 'last_state': self.state_buffers.get(network_id, [])[-1].state if self.state_buffers.get(network_id) else None } def set_network_interface(self, network_interface) -> None: """ 设置网络接口 :param network_interface: 网络接口对象 """ self.network_interface = network_interface print("网络接口已设置") # 网络接口基类(需要根据具体网络库实现) class NetworkInterface: """ 网络接口基类 需要根据具体使用的网络库(如PyNetGames、Panda3D的PyClientRepository等)进行实现 """ def __init__(self): """初始化网络接口""" pass def send_state(self, network_id: str, state_data: bytes) -> bool: """ 发送状态数据 :param network_id: 网络ID :param state_data: 状态数据 :return: 是否成功发送 """ # 需要根据具体网络库实现 raise NotImplementedError("需要在子类中实现send_state方法") def receive_state(self, network_id: str) -> Optional[bytes]: """ 接收状态数据 :param network_id: 网络ID :return: 状态数据 """ # 需要根据具体网络库实现 raise NotImplementedError("需要在子类中实现receive_state方法") def connect(self, address: str, port: int) -> bool: """ 连接到服务器 :param address: 服务器地址 :param port: 服务器端口 :return: 是否成功连接 """ # 需要根据具体网络库实现 raise NotImplementedError("需要在子类中实现connect方法") def disconnect(self) -> None: """ 断开连接 """ # 需要根据具体网络库实现 raise NotImplementedError("需要在子类中实现disconnect方法") # 使用示例和测试代码 def example_network_usage(world, morphing_core): """ 动画网络同步系统使用示例 """ print("=== 动画网络同步系统使用示例 ===") # 创建网络同步系统 network_sync = AnimationNetworkSync(world, morphing_core) # 设置网络模式 network_sync.set_network_mode(NetworkMode.SERVER) # 设置同步模式 network_sync.set_sync_mode(SyncMode.STATE_SYNC) # 设置同步间隔 network_sync.set_sync_interval(0.05) # 50ms # 启用压缩 network_sync.enable_compression(True) # 启动同步任务 network_sync.start_sync_task() print("网络同步系统配置完成") print("=== 动画网络同步系统示例结束 ===\n") return network_sync if __name__ == "__main__": print("动画网络同步模块加载完成")