EG/plugins/user/network_sync/sync/object_sync.py
2025-10-30 11:46:41 +08:00

905 lines
31 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
对象同步模块
负责同步游戏对象的状态
"""
import time
from typing import Dict, Any, List, Optional
import threading
import copy
class ObjectSync:
"""
对象同步器
负责同步游戏对象的状态
"""
def __init__(self, plugin):
"""
初始化对象同步器
Args:
plugin: 网络同步插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 同步配置
self.sync_config = {
'sync_interval': 0.05, # 50ms同步间隔
'interpolation_time': 0.1, # 100ms插值时间
'extrapolation_limit': 0.2, # 200ms外推限制
'position_threshold': 0.01, # 位置变化阈值
'rotation_threshold': 0.1, # 旋转变化阈值
'scale_threshold': 0.01, # 缩放变化阈值
'enable_delta_compression': True, # 启用增量压缩
'enable_interpolation': True, # 启用插值
'enable_extrapolation': True, # 启用外推
'max_sync_distance': 100.0, # 最大同步距离
'sync_area_radius': 50.0 # 同步区域半径
}
# 同步对象管理
self.sync_objects = {} # 所有同步对象
self.local_objects = {} # 本地对象
self.remote_objects = {} # 远程对象
# 同步状态
self.sync_state = {
'last_sync_time': 0.0,
'objects_synced': 0,
'sync_operations': 0,
'interpolations': 0,
'extrapolations': 0
}
# 插值数据
self.interpolation_data = {}
# 外推数据
self.extrapolation_data = {}
# 对象历史状态(用于插值)
self.object_history = {}
# 同步统计
self.sync_stats = {
'objects_registered': 0,
'objects_synced': 0,
'sync_data_sent': 0,
'sync_data_received': 0,
'interpolations': 0,
'extrapolations': 0,
'sync_errors': 0,
'delta_compressions': 0
}
# 线程锁
self.sync_lock = threading.RLock()
# 回调函数
self.sync_callbacks = {
'object_registered': [],
'object_unregistered': [],
'sync_data_received': [],
'object_updated': [],
'sync_error': []
}
# 时间戳记录
self.last_sync_update = 0.0
self.last_interpolation_update = 0.0
print("✓ 对象同步器已创建")
def initialize(self) -> bool:
"""
初始化对象同步器
Returns:
是否初始化成功
"""
try:
self.initialized = True
print("✓ 对象同步器初始化完成")
return True
except Exception as e:
print(f"✗ 对象同步器初始化失败: {e}")
import traceback
traceback.print_exc()
return False
def enable(self) -> bool:
"""
启用对象同步器
Returns:
是否启用成功
"""
try:
if not self.initialized:
print("✗ 对象同步器未初始化")
return False
self.enabled = True
print("✓ 对象同步器已启用")
return True
except Exception as e:
print(f"✗ 对象同步器启用失败: {e}")
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用对象同步器"""
try:
self.enabled = False
print("✓ 对象同步器已禁用")
except Exception as e:
print(f"✗ 对象同步器禁用失败: {e}")
import traceback
traceback.print_exc()
def finalize(self):
"""清理对象同步器资源"""
try:
self.disable()
self.sync_objects.clear()
self.local_objects.clear()
self.remote_objects.clear()
self.interpolation_data.clear()
self.extrapolation_data.clear()
self.object_history.clear()
self.sync_callbacks.clear()
self.initialized = False
print("✓ 对象同步器资源已清理")
except Exception as e:
print(f"✗ 对象同步器资源清理失败: {e}")
import traceback
traceback.print_exc()
def update(self, dt: float):
"""
更新对象同步器状态
Args:
dt: 时间增量
"""
try:
if not self.enabled:
return
current_time = time.time()
self.last_sync_update = current_time
# 执行同步操作
if current_time - self.sync_state['last_sync_time'] >= self.sync_config['sync_interval']:
self._perform_sync()
self.sync_state['last_sync_time'] = current_time
# 更新插值和外推
self._update_interpolation(current_time)
self._update_extrapolation(current_time)
except Exception as e:
print(f"✗ 对象同步器更新失败: {e}")
import traceback
traceback.print_exc()
def _perform_sync(self):
"""执行同步操作"""
try:
# 收集需要同步的本地对象数据
sync_data = {}
with self.sync_lock:
for obj_id, obj_data in self.local_objects.items():
# 检查对象是否需要同步
if self._should_sync_object(obj_id, obj_data):
sync_data[obj_id] = obj_data.copy()
# 发送同步数据
if sync_data and self.plugin.network_manager:
success = self.plugin.network_manager.send_sync_data(sync_data)
if success:
self.sync_stats['sync_data_sent'] += 1
self.sync_stats['objects_synced'] += len(sync_data)
self.sync_state['sync_operations'] += 1
else:
self.sync_stats['sync_errors'] += 1
except Exception as e:
print(f"✗ 对象同步操作失败: {e}")
self.sync_stats['sync_errors'] += 1
def _should_sync_object(self, obj_id: str, obj_data: Dict[str, Any]) -> bool:
"""
检查对象是否需要同步
Args:
obj_id: 对象ID
obj_data: 对象数据
Returns:
是否需要同步
"""
try:
# 检查是否超出同步距离
if not self._is_in_sync_range(obj_data):
return False
# 检查是否有显著变化
if obj_id in self.sync_objects:
old_data = self.sync_objects[obj_id]
# 检查位置变化
if 'position' in obj_data and 'position' in old_data:
pos_diff = self._calculate_distance(obj_data['position'], old_data['position'])
if pos_diff > self.sync_config['position_threshold']:
return True
# 检查旋转变化
if 'rotation' in obj_data and 'rotation' in old_data:
rot_diff = self._calculate_rotation_difference(obj_data['rotation'], old_data['rotation'])
if rot_diff > self.sync_config['rotation_threshold']:
return True
# 检查缩放变化
if 'scale' in obj_data and 'scale' in old_data:
scale_diff = self._calculate_scale_difference(obj_data['scale'], old_data['scale'])
if scale_diff > self.sync_config['scale_threshold']:
return True
else:
# 新对象总是需要同步
return True
return False
except Exception as e:
print(f"✗ 对象同步检查失败: {e}")
return True # 出错时默认同步
def _is_in_sync_range(self, obj_data: Dict[str, Any]) -> bool:
"""
检查对象是否在同步范围内
Args:
obj_data: 对象数据
Returns:
是否在同步范围内
"""
try:
# 这里应该根据具体的游戏场景实现
# 简单实现:假设所有对象都在同步范围内
return True
except Exception as e:
print(f"✗ 同步范围检查失败: {e}")
return True
def _calculate_distance(self, pos1: List[float], pos2: List[float]) -> float:
"""
计算两点间距离
Args:
pos1: 位置1
pos2: 位置2
Returns:
距离
"""
try:
if len(pos1) >= 3 and len(pos2) >= 3:
dx = pos1[0] - pos2[0]
dy = pos1[1] - pos2[1]
dz = pos1[2] - pos2[2]
return (dx*dx + dy*dy + dz*dz) ** 0.5
elif len(pos1) >= 2 and len(pos2) >= 2:
dx = pos1[0] - pos2[0]
dy = pos1[1] - pos2[1]
return (dx*dx + dy*dy) ** 0.5
else:
return 0.0
except Exception as e:
print(f"✗ 距离计算失败: {e}")
return 0.0
def _calculate_rotation_difference(self, rot1: List[float], rot2: List[float]) -> float:
"""
计算旋转差异
Args:
rot1: 旋转1
rot2: 旋转2
Returns:
旋转差异
"""
try:
# 简单实现:计算欧拉角差异
diff = 0.0
for i in range(min(len(rot1), len(rot2))):
diff += abs(rot1[i] - rot2[i])
return diff
except Exception as e:
print(f"✗ 旋转差异计算失败: {e}")
return 0.0
def _calculate_scale_difference(self, scale1: List[float], scale2: List[float]) -> float:
"""
计算缩放差异
Args:
scale1: 缩放1
scale2: 缩放2
Returns:
缩放差异
"""
try:
# 简单实现:计算缩放差异
diff = 0.0
for i in range(min(len(scale1), len(scale2))):
diff += abs(scale1[i] - scale2[i])
return diff
except Exception as e:
print(f"✗ 缩放差异计算失败: {e}")
return 0.0
def _update_interpolation(self, current_time: float):
"""
更新插值
Args:
current_time: 当前时间
"""
try:
if not self.sync_config['enable_interpolation']:
return
updated_count = 0
with self.sync_lock:
for obj_id, interp_data in self.interpolation_data.items():
if self._perform_object_interpolation(obj_id, interp_data, current_time):
updated_count += 1
self.sync_stats['interpolations'] += updated_count
except Exception as e:
print(f"✗ 插值更新失败: {e}")
def _perform_object_interpolation(self, obj_id: str, interp_data: Dict[str, Any], current_time: float) -> bool:
"""
执行对象插值
Args:
obj_id: 对象ID
interp_data: 插值数据
current_time: 当前时间
Returns:
是否插值成功
"""
try:
start_time = interp_data.get('start_time', current_time)
end_time = interp_data.get('end_time', current_time)
duration = end_time - start_time
if duration > 0:
progress = (current_time - start_time) / duration
progress = max(0.0, min(1.0, progress)) # 限制在0-1之间
# 线性插值位置
if 'start_position' in interp_data and 'end_position' in interp_data:
start_pos = interp_data['start_position']
end_pos = interp_data['end_position']
current_pos = [
start_pos[i] + (end_pos[i] - start_pos[i]) * progress
for i in range(min(len(start_pos), len(end_pos)))
]
# 更新对象位置
if obj_id in self.remote_objects:
self.remote_objects[obj_id]['position'] = current_pos
# 球面插值旋转(简化为线性插值)
if 'start_rotation' in interp_data and 'end_rotation' in interp_data:
start_rot = interp_data['start_rotation']
end_rot = interp_data['end_rotation']
current_rot = [
start_rot[i] + (end_rot[i] - start_rot[i]) * progress
for i in range(min(len(start_rot), len(end_rot)))
]
# 更新对象旋转
if obj_id in self.remote_objects:
self.remote_objects[obj_id]['rotation'] = current_rot
# 线性插值缩放
if 'start_scale' in interp_data and 'end_scale' in interp_data:
start_scale = interp_data['start_scale']
end_scale = interp_data['end_scale']
current_scale = [
start_scale[i] + (end_scale[i] - start_scale[i]) * progress
for i in range(min(len(start_scale), len(end_scale)))
]
# 更新对象缩放
if obj_id in self.remote_objects:
self.remote_objects[obj_id]['scale'] = current_scale
return True
else:
return False
except Exception as e:
print(f"✗ 对象插值失败: {e}")
return False
def _update_extrapolation(self, current_time: float):
"""
更新外推
Args:
current_time: 当前时间
"""
try:
if not self.sync_config['enable_extrapolation']:
return
updated_count = 0
with self.sync_lock:
for obj_id, extrap_data in self.extrapolation_data.items():
if self._perform_object_extrapolation(obj_id, extrap_data, current_time):
updated_count += 1
self.sync_stats['extrapolations'] += updated_count
except Exception as e:
print(f"✗ 外推更新失败: {e}")
def _perform_object_extrapolation(self, obj_id: str, extrap_data: Dict[str, Any], current_time: float) -> bool:
"""
执行对象外推
Args:
obj_id: 对象ID
extrap_data: 外推数据
current_time: 当前时间
Returns:
是否外推成功
"""
try:
last_update_time = extrap_data.get('last_update_time', current_time)
time_diff = current_time - last_update_time
# 检查是否超出外推限制
if time_diff > self.sync_config['extrapolation_limit']:
return False
# 基于速度的外推
if 'position' in extrap_data and 'velocity' in extrap_data:
position = extrap_data['position']
velocity = extrap_data['velocity']
# 计算外推位置
extrapolated_pos = [
position[i] + velocity[i] * time_diff
for i in range(min(len(position), len(velocity)))
]
# 更新对象位置
if obj_id in self.remote_objects:
self.remote_objects[obj_id]['position'] = extrapolated_pos
return True
except Exception as e:
print(f"✗ 对象外推失败: {e}")
return False
def register_object(self, obj_id: str, obj_data: Dict[str, Any], is_local: bool = True) -> bool:
"""
注册同步对象
Args:
obj_id: 对象ID
obj_data: 对象数据
is_local: 是否为本地对象
Returns:
是否注册成功
"""
try:
with self.sync_lock:
# 存储对象数据
self.sync_objects[obj_id] = obj_data.copy()
if is_local:
self.local_objects[obj_id] = obj_data.copy()
else:
self.remote_objects[obj_id] = obj_data.copy()
# 初始化对象历史
self.object_history[obj_id] = {
'states': [obj_data.copy()],
'timestamps': [time.time()]
}
# 更新统计信息
self.sync_stats['objects_registered'] += 1
# 触发对象注册回调
self._trigger_sync_callback('object_registered', {
'object_id': obj_id,
'is_local': is_local,
'data': obj_data
})
print(f"✓ 对象已注册: {obj_id} ({'本地' if is_local else '远程'})")
return True
except Exception as e:
print(f"✗ 对象注册失败: {e}")
self.sync_stats['sync_errors'] += 1
return False
def unregister_object(self, obj_id: str) -> bool:
"""
注销同步对象
Args:
obj_id: 对象ID
Returns:
是否注销成功
"""
try:
with self.sync_lock:
# 从各个字典中移除对象
if obj_id in self.sync_objects:
del self.sync_objects[obj_id]
if obj_id in self.local_objects:
del self.local_objects[obj_id]
if obj_id in self.remote_objects:
del self.remote_objects[obj_id]
if obj_id in self.interpolation_data:
del self.interpolation_data[obj_id]
if obj_id in self.extrapolation_data:
del self.extrapolation_data[obj_id]
if obj_id in self.object_history:
del self.object_history[obj_id]
# 触发对象注销回调
self._trigger_sync_callback('object_unregistered', {
'object_id': obj_id
})
print(f"✓ 对象已注销: {obj_id}")
return True
except Exception as e:
print(f"✗ 对象注销失败: {e}")
self.sync_stats['sync_errors'] += 1
return False
def update_object(self, obj_id: str, obj_data: Dict[str, Any]) -> bool:
"""
更新对象数据
Args:
obj_id: 对象ID
obj_data: 对象数据
Returns:
是否更新成功
"""
try:
with self.sync_lock:
# 更新同步对象
if obj_id in self.sync_objects:
self.sync_objects[obj_id].update(obj_data)
# 更新本地对象
if obj_id in self.local_objects:
self.local_objects[obj_id].update(obj_data)
# 添加到对象历史(用于插值)
if obj_id in self.object_history:
history = self.object_history[obj_id]
history['states'].append(obj_data.copy())
history['timestamps'].append(time.time())
# 保持历史记录大小
if len(history['states']) > 10: # 保持最近10个状态
history['states'].pop(0)
history['timestamps'].pop(0)
# 触发对象更新回调
self._trigger_sync_callback('object_updated', {
'object_id': obj_id,
'data': obj_data
})
return True
except Exception as e:
print(f"✗ 对象更新失败: {e}")
self.sync_stats['sync_errors'] += 1
return False
def sync_object(self, obj_id: str, obj_data: Dict[str, Any]) -> bool:
"""
同步对象
Args:
obj_id: 对象ID
obj_data: 对象数据
Returns:
是否同步成功
"""
try:
if not self.enabled:
print("✗ 对象同步器未启用")
return False
# 更新对象数据
success = self.update_object(obj_id, obj_data)
if success:
self.sync_stats['objects_synced'] += 1
return True
else:
self.sync_stats['sync_errors'] += 1
return False
except Exception as e:
print(f"✗ 对象同步失败: {e}")
self.sync_stats['sync_errors'] += 1
return False
def receive_sync_data(self, obj_id: str, obj_data: Dict[str, Any], client_id: str = None) -> bool:
"""
接收同步数据
Args:
obj_id: 对象ID
obj_data: 对象数据
client_id: 客户端ID可选
Returns:
是否接收成功
"""
try:
with self.sync_lock:
# 存储远程对象数据
self.remote_objects[obj_id] = obj_data.copy()
self.sync_objects[obj_id] = obj_data.copy()
# 设置插值数据
current_time = time.time()
if obj_id in self.interpolation_data:
# 更新现有插值数据
interp_data = self.interpolation_data[obj_id]
interp_data['start_time'] = current_time
interp_data['end_time'] = current_time + self.sync_config['interpolation_time']
interp_data['start_position'] = interp_data.get('end_position', obj_data.get('position', [0, 0, 0]))
interp_data['end_position'] = obj_data.get('position', [0, 0, 0])
interp_data['start_rotation'] = interp_data.get('end_rotation', obj_data.get('rotation', [0, 0, 0]))
interp_data['end_rotation'] = obj_data.get('rotation', [0, 0, 0])
interp_data['start_scale'] = interp_data.get('end_scale', obj_data.get('scale', [1, 1, 1]))
interp_data['end_scale'] = obj_data.get('scale', [1, 1, 1])
else:
# 创建新的插值数据
self.interpolation_data[obj_id] = {
'start_time': current_time,
'end_time': current_time + self.sync_config['interpolation_time'],
'start_position': obj_data.get('position', [0, 0, 0]),
'end_position': obj_data.get('position', [0, 0, 0]),
'start_rotation': obj_data.get('rotation', [0, 0, 0]),
'end_rotation': obj_data.get('rotation', [0, 0, 0]),
'start_scale': obj_data.get('scale', [1, 1, 1]),
'end_scale': obj_data.get('scale', [1, 1, 1])
}
# 设置外推数据
self.extrapolation_data[obj_id] = {
'position': obj_data.get('position', [0, 0, 0]),
'velocity': obj_data.get('velocity', [0, 0, 0]),
'last_update_time': current_time
}
# 更新对象历史
if obj_id in self.object_history:
history = self.object_history[obj_id]
history['states'].append(obj_data.copy())
history['timestamps'].append(current_time)
# 保持历史记录大小
if len(history['states']) > 10:
history['states'].pop(0)
history['timestamps'].pop(0)
else:
self.object_history[obj_id] = {
'states': [obj_data.copy()],
'timestamps': [current_time]
}
# 更新统计信息
self.sync_stats['sync_data_received'] += 1
# 触发同步数据接收回调
self._trigger_sync_callback('sync_data_received', {
'object_id': obj_id,
'data': obj_data,
'client_id': client_id
})
return True
except Exception as e:
print(f"✗ 同步数据接收失败: {e}")
self.sync_stats['sync_errors'] += 1
return False
def get_object_data(self, obj_id: str) -> Optional[Dict[str, Any]]:
"""
获取对象数据
Args:
obj_id: 对象ID
Returns:
对象数据或None
"""
try:
with self.sync_lock:
return self.sync_objects.get(obj_id, {}).copy()
except Exception as e:
print(f"✗ 对象数据获取失败: {e}")
return None
def get_local_objects(self) -> Dict[str, Dict[str, Any]]:
"""
获取所有本地对象
Returns:
本地对象字典
"""
try:
with self.sync_lock:
return {k: v.copy() for k, v in self.local_objects.items()}
except Exception as e:
print(f"✗ 本地对象获取失败: {e}")
return {}
def get_remote_objects(self) -> Dict[str, Dict[str, Any]]:
"""
获取所有远程对象
Returns:
远程对象字典
"""
try:
with self.sync_lock:
return {k: v.copy() for k, v in self.remote_objects.items()}
except Exception as e:
print(f"✗ 远程对象获取失败: {e}")
return {}
def get_sync_stats(self) -> Dict[str, Any]:
"""
获取同步统计信息
Returns:
同步统计字典
"""
return self.sync_stats.copy()
def reset_sync_stats(self):
"""重置同步统计信息"""
try:
self.sync_stats = {
'objects_registered': 0,
'objects_synced': 0,
'sync_data_sent': 0,
'sync_data_received': 0,
'interpolations': 0,
'extrapolations': 0,
'sync_errors': 0,
'delta_compressions': 0
}
print("✓ 对象同步统计信息已重置")
except Exception as e:
print(f"✗ 对象同步统计信息重置失败: {e}")
def set_sync_config(self, config: Dict[str, Any]) -> bool:
"""
设置同步配置
Args:
config: 同步配置字典
Returns:
是否设置成功
"""
try:
self.sync_config.update(config)
print(f"✓ 同步配置已更新: {self.sync_config}")
return True
except Exception as e:
print(f"✗ 同步配置设置失败: {e}")
return False
def get_sync_config(self) -> Dict[str, Any]:
"""
获取同步配置
Returns:
同步配置字典
"""
return self.sync_config.copy()
def _trigger_sync_callback(self, callback_type: str, data: Dict[str, Any]):
"""
触发同步回调
Args:
callback_type: 回调类型
data: 回调数据
"""
try:
if callback_type in self.sync_callbacks:
for callback in self.sync_callbacks[callback_type]:
try:
callback(data)
except Exception as e:
print(f"✗ 同步回调执行失败: {e}")
except Exception as e:
print(f"✗ 同步回调触发失败: {e}")
def register_sync_callback(self, callback_type: str, callback: callable):
"""
注册同步回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.sync_callbacks:
self.sync_callbacks[callback_type].append(callback)
print(f"✓ 同步回调已注册: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 同步回调注册失败: {e}")
def unregister_sync_callback(self, callback_type: str, callback: callable):
"""
注销同步回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.sync_callbacks:
if callback in self.sync_callbacks[callback_type]:
self.sync_callbacks[callback_type].remove(callback)
print(f"✓ 同步回调已注销: {callback_type}")
except Exception as e:
print(f"✗ 同步回调注销失败: {e}")