""" 统计数据管理器模块 收集和分析匹配数据 """ import time import json from typing import Dict, Any, List, Optional from collections import defaultdict, deque class StatsManager: """ 统计数据管理器 收集和分析匹配数据 """ def __init__(self, plugin): """ 初始化统计数据管理器 Args: plugin: 匹配系统插件实例 """ self.plugin = plugin self.enabled = False self.initialized = False # 统计配置 self.stats_config = { "enable_statistics": True, "data_retention_period": 86400, # 24小时 "max_data_points": 10000, "enable_realtime_stats": True, "stats_collection_interval": 10.0, "enable_export": True, "export_format": "json" } # 统计数据存储 self.statistics = { "match_times": deque(maxlen=1000), "queue_times": deque(maxlen=1000), "success_rates": deque(maxlen=1000), "player_counts": deque(maxlen=1000), "algorithm_performance": deque(maxlen=1000), "system_performance": deque(maxlen=1000) } # 统计状态 self.stats_state = { "total_matches": 0, "successful_matches": 0, "failed_matches": 0, "total_players": 0, "matched_players": 0, "last_stats_update": 0.0 } # 历史统计数据 self.historical_stats = { "daily": defaultdict(dict), "weekly": defaultdict(dict), "monthly": defaultdict(dict) } # 统计报告 self.stat_reports = { "last_report": None, "report_cache": {} } # 统计回调 self.stats_callbacks = { "stats_updated": [], "report_generated": [], "data_exported": [], "stats_error": [] } # 时间戳记录 self.last_stats_collection = 0.0 self.last_report_generation = 0.0 print("✓ 统计数据管理器已创建") def initialize(self) -> bool: """ 初始化统计数据管理器 Returns: 是否初始化成功 """ try: print("正在初始化统计数据管理器...") 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: # 禁用统计数据管理器 if self.enabled: self.disable() # 清理回调 self.stats_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_stats_collection >= self.stats_config["stats_collection_interval"]: self._collect_statistics() self.last_stats_collection = current_time self.stats_state["last_stats_update"] = current_time except Exception as e: print(f"✗ 统计数据管理器更新失败: {e}") import traceback traceback.print_exc() def _collect_statistics(self): """收集统计数据""" try: current_time = time.time() stats_data = {} # 收集匹配管理器统计数据 if self.plugin.match_manager: match_stats = self.plugin.match_manager.get_match_stats() match_state = match_stats.get("state", {}) stats_data["active_matches"] = match_state.get("active_matches", 0) stats_data["successful_matches"] = match_state.get("successful_matches", 0) stats_data["failed_matches"] = match_state.get("failed_matches", 0) # 更新总计数 self.stats_state["total_matches"] = ( match_state.get("successful_matches", 0) + match_state.get("failed_matches", 0) ) self.stats_state["successful_matches"] = match_state.get("successful_matches", 0) self.stats_state["failed_matches"] = match_state.get("failed_matches", 0) # 收集队列管理器统计数据 if self.plugin.queue_manager: queue_stats = self.plugin.queue_manager.get_queue_stats() queue_state = queue_stats.get("state", {}) stats_data["total_players"] = queue_state.get("total_players", 0) stats_data["players_matched"] = queue_state.get("players_matched", 0) stats_data["players_timed_out"] = queue_state.get("players_timed_out", 0) # 更新总计数 self.stats_state["total_players"] = queue_state.get("total_players", 0) self.stats_state["matched_players"] = queue_state.get("players_matched", 0) # 收集算法管理器统计数据 if self.plugin.algorithm_manager: algorithm_stats = self.plugin.algorithm_manager.get_algorithm_stats() algorithm_state = algorithm_stats.get("state", {}) stats_data["total_algorithms"] = algorithm_state.get("total_matches", 0) stats_data["successful_algorithms"] = algorithm_state.get("successful_matches", 0) stats_data["average_match_quality"] = algorithm_state.get("average_match_quality", 0) # 记录算法性能 self.statistics["algorithm_performance"].append( (current_time, stats_data["average_match_quality"]) ) # 收集房间分配器统计数据 if self.plugin.room_allocator: room_stats = self.plugin.room_allocator.get_room_stats() room_state = room_stats.get("state", {}) stats_data["active_rooms"] = room_state.get("active_rooms", 0) stats_data["total_rooms"] = room_state.get("total_rooms", 0) # 记录统计数据 self.statistics["player_counts"].append((current_time, stats_data.get("total_players", 0))) # 触发统计更新回调 self._trigger_stats_callback("stats_updated", { "stats_data": stats_data, "timestamp": current_time }) except Exception as e: print(f"✗ 统计数据收集失败: {e}") self._trigger_stats_callback("stats_error", { "error": str(e), "timestamp": time.time() }) def record_match_time(self, match_time: float): """ 记录匹配时间 Args: match_time: 匹配时间(秒) """ try: current_time = time.time() self.statistics["match_times"].append((current_time, match_time)) except Exception as e: print(f"✗ 匹配时间记录失败: {e}") def record_queue_time(self, queue_time: float): """ 记录队列时间 Args: queue_time: 队列时间(秒) """ try: current_time = time.time() self.statistics["queue_times"].append((current_time, queue_time)) except Exception as e: print(f"✗ 队列时间记录失败: {e}") def record_success_rate(self, success_rate: float): """ 记录成功率 Args: success_rate: 成功率(百分比) """ try: current_time = time.time() self.statistics["success_rates"].append((current_time, success_rate)) except Exception as e: print(f"✗ 成功率记录失败: {e}") def get_realtime_stats(self) -> Dict[str, Any]: """ 获取实时统计数据 Returns: 实时统计数据字典 """ try: realtime_stats = { "current_time": time.time(), "state": self.stats_state.copy(), "statistics": {} } # 获取最新的统计数据 for stat_name, stat_data in self.statistics.items(): if stat_data: realtime_stats["statistics"][stat_name] = list(stat_data)[-10:] # 最近10个数据点 else: realtime_stats["statistics"][stat_name] = [] return realtime_stats except Exception as e: print(f"✗ 实时统计数据获取失败: {e}") return {} def generate_report(self, report_type: str = "summary", time_range: str = "24h") -> Dict[str, Any]: """ 生成统计报告 Args: report_type: 报告类型(summary, detailed, custom) time_range: 时间范围(24h, 7d, 30d) Returns: 统计报告字典 """ try: current_time = time.time() report = { "report_type": report_type, "time_range": time_range, "generated_time": current_time, "data": {} } # 根据报告类型生成不同内容 if report_type == "summary": report["data"] = self._generate_summary_report() elif report_type == "detailed": report["data"] = self._generate_detailed_report() else: report["data"] = self._generate_custom_report(report_type) self.stat_reports["last_report"] = report self.stat_reports["report_cache"][f"{report_type}_{time_range}"] = report # 触发报告生成回调 self._trigger_stats_callback("report_generated", { "report": report, "timestamp": current_time }) return report except Exception as e: print(f"✗ 统计报告生成失败: {e}") self._trigger_stats_callback("stats_error", { "error": str(e), "timestamp": time.time() }) return {} def _generate_summary_report(self) -> Dict[str, Any]: """生成摘要报告""" try: summary = { "total_matches": self.stats_state["total_matches"], "successful_matches": self.stats_state["successful_matches"], "failed_matches": self.stats_state["failed_matches"], "match_success_rate": 0.0, "total_players": self.stats_state["total_players"], "matched_players": self.stats_state["matched_players"], "player_match_rate": 0.0, "average_match_time": 0.0, "average_queue_time": 0.0 } # 计算成功率 if self.stats_state["total_matches"] > 0: summary["match_success_rate"] = ( self.stats_state["successful_matches"] / self.stats_state["total_matches"] ) * 100 # 计算玩家匹配率 if self.stats_state["total_players"] > 0: summary["player_match_rate"] = ( self.stats_state["matched_players"] / self.stats_state["total_players"] ) * 100 # 计算平均匹配时间 if self.statistics["match_times"]: times = [t[1] for t in self.statistics["match_times"]] summary["average_match_time"] = sum(times) / len(times) # 计算平均队列时间 if self.statistics["queue_times"]: times = [t[1] for t in self.statistics["queue_times"]] summary["average_queue_time"] = sum(times) / len(times) return summary except Exception as e: print(f"✗ 摘要报告生成失败: {e}") return {} def _generate_detailed_report(self) -> Dict[str, Any]: """生成详细报告""" try: detailed = { "summary": self._generate_summary_report(), "trends": self._generate_trend_data(), "performance": self._generate_performance_data(), "historical": self._get_historical_data() } return detailed except Exception as e: print(f"✗ 详细报告生成失败: {e}") return {} def _generate_custom_report(self, report_type: str) -> Dict[str, Any]: """生成自定义报告""" try: # 简化实现,返回摘要报告 return self._generate_summary_report() except Exception as e: print(f"✗ 自定义报告生成失败: {e}") return {} def _generate_trend_data(self) -> Dict[str, Any]: """生成趋势数据""" try: trends = {} # 匹配趋势 if self.statistics["match_times"]: recent_matches = list(self.statistics["match_times"])[-100:] # 最近100个数据点 trends["match_times"] = [t[1] for t in recent_matches] # 成功率趋势 if self.statistics["success_rates"]: recent_rates = list(self.statistics["success_rates"])[-100:] trends["success_rates"] = [r[1] for r in recent_rates] # 玩家数量趋势 if self.statistics["player_counts"]: recent_players = list(self.statistics["player_counts"])[-100:] trends["player_counts"] = [p[1] for p in recent_players] return trends except Exception as e: print(f"✗ 趋势数据生成失败: {e}") return {} def _generate_performance_data(self) -> Dict[str, Any]: """生成性能数据""" try: performance = {} # 算法性能 if self.statistics["algorithm_performance"]: recent_performance = list(self.statistics["algorithm_performance"])[-100:] performance["algorithm_performance"] = [p[1] for p in recent_performance] # 系统性能 if self.statistics["system_performance"]: recent_system = list(self.statistics["system_performance"])[-100:] performance["system_performance"] = [s[1] for s in recent_system] return performance except Exception as e: print(f"✗ 性能数据生成失败: {e}") return {} def _get_historical_data(self) -> Dict[str, Any]: """获取历史数据""" try: return { "daily": dict(self.historical_stats["daily"]), "weekly": dict(self.historical_stats["weekly"]), "monthly": dict(self.historical_stats["monthly"]) } except Exception as e: print(f"✗ 历史数据获取失败: {e}") return {} def export_stats(self, file_path: str, format: str = "json") -> bool: """ 导出统计数据 Args: file_path: 导出文件路径 format: 导出格式(json, csv) Returns: 是否导出成功 """ try: import os # 创建导出目录 export_dir = os.path.dirname(file_path) if not os.path.exists(export_dir): os.makedirs(export_dir) # 生成统计数据 stats_data = { "statistics": self.get_realtime_stats(), "reports": self.stat_reports, "config": self.stats_config } if format.lower() == "json": # 导出为JSON格式 with open(file_path, 'w', encoding='utf-8') as f: json.dump(stats_data, f, indent=2, ensure_ascii=False, default=str) else: # 默认导出为JSON格式 with open(file_path, 'w', encoding='utf-8') as f: json.dump(stats_data, f, indent=2, ensure_ascii=False, default=str) # 触发数据导出回调 self._trigger_stats_callback("data_exported", { "file_path": file_path, "format": format, "timestamp": time.time() }) print(f"✓ 统计数据已导出到: {file_path}") return True except Exception as e: print(f"✗ 统计数据导出失败: {e}") self._trigger_stats_callback("stats_error", { "error": str(e), "timestamp": time.time() }) return False def get_stats_config(self) -> Dict[str, Any]: """ 获取统计配置 Returns: 统计配置字典 """ return self.stats_config.copy() def set_stats_config(self, config: Dict[str, Any]) -> bool: """ 设置统计配置 Args: config: 统计配置字典 Returns: 是否设置成功 """ try: self.stats_config.update(config) print(f"✓ 统计配置已更新: {self.stats_config}") return True except Exception as e: print(f"✗ 统计配置设置失败: {e}") return False def get_stats_state(self) -> Dict[str, Any]: """ 获取统计状态 Returns: 统计状态字典 """ return self.stats_state.copy() def reset_stats(self): """重置统计数据""" try: # 重置统计数据 for stat_name in self.statistics: self.statistics[stat_name].clear() # 重置状态 self.stats_state = { "total_matches": 0, "successful_matches": 0, "failed_matches": 0, "total_players": 0, "matched_players": 0, "last_stats_update": 0.0 } print("✓ 统计数据已重置") except Exception as e: print(f"✗ 统计数据重置失败: {e}") def _trigger_stats_callback(self, callback_type: str, data: Dict[str, Any]): """ 触发统计回调 Args: callback_type: 回调类型 data: 回调数据 """ try: if callback_type in self.stats_callbacks: for callback in self.stats_callbacks[callback_type]: try: callback(data) except Exception as e: print(f"✗ 统计回调执行失败: {callback_type} - {e}") except Exception as e: print(f"✗ 统计回调触发失败: {e}") def register_stats_callback(self, callback_type: str, callback: callable): """ 注册统计回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.stats_callbacks: self.stats_callbacks[callback_type].append(callback) print(f"✓ 统计回调已注册: {callback_type}") else: print(f"✗ 无效的回调类型: {callback_type}") except Exception as e: print(f"✗ 统计回调注册失败: {e}") def unregister_stats_callback(self, callback_type: str, callback: callable): """ 注销统计回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.stats_callbacks: if callback in self.stats_callbacks[callback_type]: self.stats_callbacks[callback_type].remove(callback) print(f"✓ 统计回调已注销: {callback_type}") else: print(f"✗ 无效的回调类型: {callback_type}") except Exception as e: print(f"✗ 统计回调注销失败: {e}")