""" 时钟同步模块 负责客户端与服务器之间的时间同步 """ import time from typing import Dict, Any, List, Optional import threading class ClockSync: """ 时钟同步器 负责客户端与服务器之间的时间同步 """ def __init__(self, plugin): """ 初始化时钟同步器 Args: plugin: 网络同步插件实例 """ self.plugin = plugin self.enabled = False self.initialized = False # 时钟同步配置 self.clock_config = { 'sync_interval': 5.0, # 同步间隔(秒) 'samples_per_sync': 10, # 每次同步的样本数 'max_offset_samples': 100, # 最大偏移样本数 'enable_interpolation': True, # 启用时间插值 'interpolation_rate': 60.0, # 插值更新频率 'max_drift_correction': 0.1, # 最大漂移校正(秒/秒) 'min_sync_quality': 0.8, # 最小同步质量 'timeout': 10.0 # 同步超时时间 } # 时钟状态 self.clock_state = { 'is_synchronized': False, 'time_offset': 0.0, # 本地时间与服务器时间的偏移 'time_drift': 0.0, # 时间漂移率 'last_sync_time': 0.0, # 最后同步时间 'sync_quality': 0.0, # 同步质量 'round_trip_time': 0.0, # 往返时间 'sync_samples': [] # 同步样本 } # 插值状态 self.interpolation_state = { 'interpolated_time': 0.0, 'target_time': 0.0, 'interpolation_start': 0.0, 'interpolation_duration': 0.0 } # 时钟统计 self.clock_stats = { 'sync_attempts': 0, 'successful_syncs': 0, 'failed_syncs': 0, 'average_rtt': 0.0, 'min_rtt': float('inf'), 'max_rtt': 0.0, 'sync_errors': 0 } # 同步请求队列 self.sync_requests = [] self.sync_lock = threading.Lock() # 回调函数 self.clock_callbacks = { 'sync_started': [], 'sync_completed': [], 'sync_failed': [], 'time_updated': [], 'sync_quality_changed': [] } # 时间戳记录 self.last_sync_attempt = 0.0 self.last_time_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_requests.clear() self.clock_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() # 定期发起时钟同步 if current_time - self.last_sync_attempt >= self.clock_config['sync_interval']: self._request_time_sync() self.last_sync_attempt = current_time # 更新时间插值 if self.clock_config['enable_interpolation']: self._update_time_interpolation(current_time) self.last_time_update = current_time except Exception as e: print(f"✗ 时钟同步器更新失败: {e}") import traceback traceback.print_exc() def _request_time_sync(self): """请求时间同步""" try: if not self.plugin.network_manager or not self.plugin.protocol_handler: return # 增加同步尝试计数 self.clock_stats['sync_attempts'] += 1 # 触发同步开始回调 self._trigger_clock_callback('sync_started', { 'timestamp': time.time() }) # 发送时间同步请求 sync_data = { 'client_time': time.time(), 'request_id': f"sync_{int(time.time() * 1000000)}" } success = self.plugin.protocol_handler.send_message('SYNC_REQUEST', sync_data) if success: # 记录同步请求 with self.sync_lock: self.sync_requests.append({ 'request_id': sync_data['request_id'], 'send_time': time.time(), 'completed': False }) else: self.clock_stats['failed_syncs'] += 1 self._trigger_clock_callback('sync_failed', { 'reason': 'send_failed', 'timestamp': time.time() }) except Exception as e: print(f"✗ 时间同步请求失败: {e}") self.clock_stats['sync_errors'] += 1 def handle_sync_request(self, data: Dict[str, Any], client_id: str = None): """ 处理时间同步请求 Args: data: 同步请求数据 client_id: 客户端ID """ try: # 构造同步响应 response_data = { 'client_time': data.get('client_time', 0), 'server_time': time.time(), 'request_id': data.get('request_id', ''), 'client_id': client_id } # 发送同步响应 if self.plugin.protocol_handler: self.plugin.protocol_handler.send_message('SYNC_RESPONSE', response_data, client_id) except Exception as e: print(f"✗ 时间同步请求处理失败: {e}") def handle_sync_response(self, data: Dict[str, Any]): """ 处理时间同步响应 Args: data: 同步响应数据 """ try: client_send_time = data.get('client_time', 0) server_time = data.get('server_time', 0) request_id = data.get('request_id', '') receive_time = time.time() # 计算往返时间 rtt = receive_time - client_send_time # 计算时间偏移(假设网络延迟对称) time_offset = server_time - (client_send_time + rtt / 2) # 更新统计信息 self.clock_stats['successful_syncs'] += 1 self.clock_stats['average_rtt'] = ( (self.clock_stats['average_rtt'] * (self.clock_stats['successful_syncs'] - 1) + rtt) / self.clock_stats['successful_syncs'] ) self.clock_stats['min_rtt'] = min(self.clock_stats['min_rtt'], rtt) self.clock_stats['max_rtt'] = max(self.clock_stats['max_rtt'], rtt) # 添加同步样本 sample = { 'offset': time_offset, 'rtt': rtt, 'timestamp': receive_time } with self.sync_lock: self.clock_state['sync_samples'].append(sample) # 保持样本数量在限制范围内 if len(self.clock_state['sync_samples']) > self.clock_config['max_offset_samples']: self.clock_state['sync_samples'].pop(0) # 更新时钟状态 self._update_clock_state() # 标记请求完成 with self.sync_lock: for request in self.sync_requests: if request['request_id'] == request_id: request['completed'] = True break # 触发同步完成回调 self._trigger_clock_callback('sync_completed', { 'offset': time_offset, 'rtt': rtt, 'quality': self.clock_state['sync_quality'], 'timestamp': receive_time }) self.clock_state['last_sync_time'] = receive_time except Exception as e: print(f"✗ 时间同步响应处理失败: {e}") self.clock_stats['sync_errors'] += 1 self._trigger_clock_callback('sync_failed', { 'reason': 'process_failed', 'error': str(e), 'timestamp': time.time() }) def _update_clock_state(self): """更新时钟状态""" try: with self.sync_lock: if not self.clock_state['sync_samples']: return # 计算平均时间偏移 offsets = [sample['offset'] for sample in self.clock_state['sync_samples']] avg_offset = sum(offsets) / len(offsets) # 计算时间偏移的标准差(用于质量评估) if len(offsets) > 1: variance = sum((offset - avg_offset) ** 2 for offset in offsets) / (len(offsets) - 1) std_dev = variance ** 0.5 else: std_dev = 0.0 # 计算同步质量(基于标准差和RTT) if std_dev < 0.001: # 小于1毫秒的标准差 quality = 1.0 else: # 质量与标准差成反比 quality = max(0.0, 1.0 - (std_dev * 1000)) # 转换为毫秒 # 计算平均RTT rtts = [sample['rtt'] for sample in self.clock_state['sync_samples']] avg_rtt = sum(rtts) / len(rtts) # 更新时钟状态 self.clock_state['time_offset'] = avg_offset self.clock_state['round_trip_time'] = avg_rtt self.clock_state['sync_quality'] = quality self.clock_state['is_synchronized'] = quality >= self.clock_config['min_sync_quality'] # 触发同步质量变化回调 self._trigger_clock_callback('sync_quality_changed', { 'quality': quality, 'offset': avg_offset, 'rtt': avg_rtt }) except Exception as e: print(f"✗ 时钟状态更新失败: {e}") def _update_time_interpolation(self, current_time: float): """ 更新时间插值 Args: current_time: 当前时间 """ try: if not self.clock_config['enable_interpolation']: return # 计算插值时间 server_time = self.get_server_time() if self.interpolation_state['interpolated_time'] == 0.0: # 初始化插值 self.interpolation_state['interpolated_time'] = server_time self.interpolation_state['target_time'] = server_time else: # 更新目标时间 self.interpolation_state['target_time'] = server_time # 执行插值 if self.interpolation_state['interpolated_time'] != self.interpolation_state['target_time']: interpolation_speed = self.clock_config['interpolation_rate'] time_diff = self.interpolation_state['target_time'] - self.interpolation_state['interpolated_time'] max_step = interpolation_speed * (1.0 / 60.0) # 假设60FPS if abs(time_diff) > max_step: # 逐步接近目标时间 step = max_step if time_diff > 0 else -max_step self.interpolation_state['interpolated_time'] += step else: # 直接设置为目标时间 self.interpolation_state['interpolated_time'] = self.interpolation_state['target_time'] # 触发时间更新回调 self._trigger_clock_callback('time_updated', { 'server_time': server_time, 'interpolated_time': self.interpolation_state['interpolated_time'], 'local_time': current_time }) self.last_interpolation_update = current_time except Exception as e: print(f"✗ 时间插值更新失败: {e}") def get_server_time(self) -> float: """ 获取服务器时间 Returns: 服务器时间戳 """ try: local_time = time.time() return local_time + self.clock_state['time_offset'] except Exception as e: print(f"✗ 服务器时间获取失败: {e}") return time.time() def get_interpolated_time(self) -> float: """ 获取插值时间 Returns: 插值时间戳 """ try: if self.clock_config['enable_interpolation'] and self.interpolation_state['interpolated_time'] != 0.0: return self.interpolation_state['interpolated_time'] else: return self.get_server_time() except Exception as e: print(f"✗ 插值时间获取失败: {e}") return time.time() def get_time_offset(self) -> float: """ 获取时间偏移 Returns: 时间偏移值 """ return self.clock_state['time_offset'] def get_sync_quality(self) -> float: """ 获取同步质量 Returns: 同步质量值 (0.0-1.0) """ return self.clock_state['sync_quality'] def is_synchronized(self) -> bool: """ 检查是否已同步 Returns: 是否已同步 """ return self.clock_state['is_synchronized'] def get_round_trip_time(self) -> float: """ 获取往返时间 Returns: 往返时间(秒) """ return self.clock_state['round_trip_time'] def get_clock_stats(self) -> Dict[str, Any]: """ 获取时钟统计信息 Returns: 时钟统计字典 """ return self.clock_stats.copy() def reset_clock_stats(self): """重置时钟统计信息""" try: self.clock_stats = { 'sync_attempts': 0, 'successful_syncs': 0, 'failed_syncs': 0, 'average_rtt': 0.0, 'min_rtt': float('inf'), 'max_rtt': 0.0, 'sync_errors': 0 } print("✓ 时钟统计信息已重置") except Exception as e: print(f"✗ 时钟统计信息重置失败: {e}") def force_sync(self) -> bool: """ 强制进行时钟同步 Returns: 是否成功发起同步 """ try: self._request_time_sync() self.last_sync_attempt = time.time() print("✓ 强制时钟同步已发起") return True except Exception as e: print(f"✗ 强制时钟同步失败: {e}") return False def reset_sync(self): """重置时钟同步状态""" try: with self.sync_lock: self.clock_state = { 'is_synchronized': False, 'time_offset': 0.0, 'time_drift': 0.0, 'last_sync_time': 0.0, 'sync_quality': 0.0, 'round_trip_time': 0.0, 'sync_samples': [] } self.interpolation_state = { 'interpolated_time': 0.0, 'target_time': 0.0, 'interpolation_start': 0.0, 'interpolation_duration': 0.0 } self.sync_requests.clear() print("✓ 时钟同步状态已重置") except Exception as e: print(f"✗ 时钟同步状态重置失败: {e}") def set_clock_config(self, config: Dict[str, Any]) -> bool: """ 设置时钟配置 Args: config: 时钟配置字典 Returns: 是否设置成功 """ try: self.clock_config.update(config) print(f"✓ 时钟配置已更新: {self.clock_config}") return True except Exception as e: print(f"✗ 时钟配置设置失败: {e}") return False def get_clock_config(self) -> Dict[str, Any]: """ 获取时钟配置 Returns: 时钟配置字典 """ return self.clock_config.copy() def _trigger_clock_callback(self, callback_type: str, data: Dict[str, Any]): """ 触发时钟回调 Args: callback_type: 回调类型 data: 回调数据 """ try: if callback_type in self.clock_callbacks: for callback in self.clock_callbacks[callback_type]: try: callback(data) except Exception as e: print(f"✗ 时钟回调执行失败: {e}") except Exception as e: print(f"✗ 时钟回调触发失败: {e}") def register_clock_callback(self, callback_type: str, callback: callable): """ 注册时钟回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.clock_callbacks: self.clock_callbacks[callback_type].append(callback) print(f"✓ 时钟回调已注册: {callback_type}") else: print(f"✗ 无效的回调类型: {callback_type}") except Exception as e: print(f"✗ 时钟回调注册失败: {e}") def unregister_clock_callback(self, callback_type: str, callback: callable): """ 注销时钟回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.clock_callbacks: if callback in self.clock_callbacks[callback_type]: self.clock_callbacks[callback_type].remove(callback) print(f"✓ 时钟回调已注销: {callback_type}") except Exception as e: print(f"✗ 时钟回调注销失败: {e}")