625 lines
22 KiB
Python
625 lines
22 KiB
Python
"""
|
||
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("动画网络同步模块加载完成") |