""" 队列管理器模块 管理等待匹配的玩家队列 """ import time import threading import uuid from typing import Dict, Any, List, Optional from collections import deque class QueueManager: """ 队列管理器 管理等待匹配的玩家队列 """ def __init__(self, plugin): """ 初始化队列管理器 Args: plugin: 匹配系统插件实例 """ self.plugin = plugin self.enabled = False self.initialized = False # 队列配置 self.queue_config = { "default_queue_timeout": 300.0, # 5分钟 "queue_processing_interval": 2.0, "max_players_per_match": 100, "min_players_per_match": 2, "enable_queue_prioritization": True, "enable_skill_based_queue": True, "enable_region_based_queue": True } # 队列状态 self.queue_state = { "total_players": 0, "active_queues": 0, "players_matched": 0, "players_timed_out": 0 } # 队列存储 self.queues = {} # 按游戏模式分类的队列 self.player_queues = {} # 玩家所在的队列映射 self.queue_lock = threading.RLock() # 队列统计 self.queue_stats = { "players_added": 0, "players_removed": 0, "matches_created": 0, "queue_timeouts": 0, "queue_errors": 0 } # 回调函数 self.queue_callbacks = { "player_queued": [], "player_dequeued": [], "match_found": [], "queue_timeout": [], "queue_error": [] } # 时间戳记录 self.last_queue_process = 0.0 self.last_cleanup = 0.0 print("✓ 队列管理器已创建") def initialize(self) -> bool: """ 初始化队列管理器 Returns: 是否初始化成功 """ try: print("正在初始化队列管理器...") self.initialized = True print("✓ 队列管理器初始化完成") return True except Exception as e: print(f"✗ 队列管理器初始化失败: {e}") self.queue_stats["queue_errors"] += 1 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}") self.queue_stats["queue_errors"] += 1 import traceback traceback.print_exc() return False def disable(self): """禁用队列管理器""" try: self.enabled = False # 清空所有队列 with self.queue_lock: self.queues.clear() self.player_queues.clear() print("✓ 队列管理器已禁用") except Exception as e: print(f"✗ 队列管理器禁用失败: {e}") self.queue_stats["queue_errors"] += 1 import traceback traceback.print_exc() def finalize(self): """清理队列管理器资源""" try: # 禁用队列管理器 if self.enabled: self.disable() # 清理回调 self.queue_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_queue_process >= self.queue_config["queue_processing_interval"]: self.process_queues() self.last_queue_process = current_time # 定期清理 if current_time - self.last_cleanup >= 60.0: # 每分钟清理一次 self._cleanup_expired_players(current_time) self.last_cleanup = current_time except Exception as e: print(f"✗ 队列管理器更新失败: {e}") self.queue_stats["queue_errors"] += 1 import traceback traceback.print_exc() def _cleanup_expired_players(self, current_time: float): """清理过期玩家""" try: expired_players = [] with self.queue_lock: for player_id, queue_info in self.player_queues.items(): join_time = queue_info["join_time"] timeout = queue_info.get("timeout", self.queue_config["default_queue_timeout"]) if current_time - join_time > timeout: expired_players.append(player_id) # 移除过期玩家 for player_id in expired_players: self._remove_player_from_queue(player_id, "timeout") self.queue_stats["queue_timeouts"] += 1 # 触发队列超时回调 self._trigger_queue_callback("queue_timeout", { "player_id": player_id, "timestamp": current_time }) except Exception as e: print(f"✗ 过期玩家清理失败: {e}") self.queue_stats["queue_errors"] += 1 def add_players_to_queue(self, player_ids: List[str], queue_params: Dict[str, Any]) -> bool: """ 添加玩家到队列 Args: player_ids: 玩家ID列表 queue_params: 队列参数 Returns: 是否添加成功 """ try: if not self.enabled: return False queue_name = queue_params.get("queue_name", "default") game_mode = queue_params.get("game_mode", "default") region = queue_params.get("region", "global") skill_level = queue_params.get("skill_level", 0) timeout = queue_params.get("timeout", self.queue_config["default_queue_timeout"]) with self.queue_lock: # 创建队列(如果不存在) if queue_name not in self.queues: self.queues[queue_name] = { "name": queue_name, "game_mode": game_mode, "region": region, "players": deque(), "created_time": time.time() } self.queue_state["active_queues"] += 1 # 添加玩家到队列 queue = self.queues[queue_name] for player_id in player_ids: player_info = { "player_id": player_id, "skill_level": skill_level, "region": region, "join_time": time.time(), "timeout": timeout, "queue_params": queue_params } queue["players"].append(player_info) self.player_queues[player_id] = { "queue_name": queue_name, "join_time": time.time(), "timeout": timeout } self.queue_state["total_players"] += len(player_ids) self.queue_stats["players_added"] += len(player_ids) # 触发玩家入队回调 self._trigger_queue_callback("player_queued", { "player_ids": player_ids, "queue_name": queue_name, "game_mode": game_mode, "timestamp": time.time() }) print(f"✓ {len(player_ids)}名玩家已添加到队列: {queue_name}") return True except Exception as e: print(f"✗ 玩家添加到队列失败: {e}") self.queue_stats["queue_errors"] += 1 return False def remove_players_from_queue(self, match_id: str = None, player_ids: List[str] = None) -> bool: """ 从队列移除玩家 Args: match_id: 匹配ID(可选) player_ids: 玩家ID列表(可选) Returns: 是否移除成功 """ try: if not self.enabled: return False removed_count = 0 if player_ids: # 移除指定玩家 for player_id in player_ids: if self._remove_player_from_queue(player_id): removed_count += 1 else: # 移除所有玩家(这种情况较少使用) with self.queue_lock: player_ids = list(self.player_queues.keys()) for player_id in player_ids: if self._remove_player_from_queue(player_id): removed_count += 1 self.queue_stats["players_removed"] += removed_count # 触发玩家离队回调 if player_ids: self._trigger_queue_callback("player_dequeued", { "player_ids": player_ids, "match_id": match_id, "timestamp": time.time() }) print(f"✓ {removed_count}名玩家已从队列移除") return removed_count > 0 except Exception as e: print(f"✗ 玩家从队列移除失败: {e}") self.queue_stats["queue_errors"] += 1 return False def _remove_player_from_queue(self, player_id: str, reason: str = "manual") -> bool: """ 从队列移除单个玩家 Args: player_id: 玩家ID reason: 移除原因 Returns: 是否移除成功 """ try: with self.queue_lock: if player_id not in self.player_queues: return False queue_name = self.player_queues[player_id]["queue_name"] del self.player_queues[player_id] # 从队列中移除玩家 if queue_name in self.queues: queue = self.queues[queue_name] players = queue["players"] # 查找并移除玩家 player_found = False for i, player_info in enumerate(list(players)): if player_info["player_id"] == player_id: del players[i] player_found = True break # 如果队列为空,移除队列 if len(players) == 0: del self.queues[queue_name] self.queue_state["active_queues"] -= 1 if player_found: self.queue_state["total_players"] -= 1 return True return False except Exception as e: print(f"✗ 玩家从队列移除失败: {e}") self.queue_stats["queue_errors"] += 1 return False def process_queues(self): """处理队列(寻找匹配)""" try: if not self.enabled: return with self.queue_lock: queue_names = list(self.queues.keys()) for queue_name in queue_names: self._process_queue(queue_name) except Exception as e: print(f"✗ 队列处理失败: {e}") self.queue_stats["queue_errors"] += 1 def _process_queue(self, queue_name: str): """ 处理单个队列 Args: queue_name: 队列名称 """ try: with self.queue_lock: if queue_name not in self.queues: return queue = self.queues[queue_name] players = list(queue["players"]) # 检查是否有足够的玩家进行匹配 min_players = self.queue_config["min_players_per_match"] max_players = self.queue_config["max_players_per_match"] if len(players) >= min_players: # 确定匹配的玩家数量 match_player_count = min(len(players), max_players) # 选择玩家(简化实现,实际中可能需要考虑技能匹配等因素) selected_players = players[:match_player_count] # 创建匹配 if self._create_match(selected_players, queue): # 从队列中移除已匹配的玩家 for player_info in selected_players: self._remove_player_from_queue(player_info["player_id"]) self.queue_state["players_matched"] += len(selected_players) self.queue_stats["matches_created"] += 1 except Exception as e: print(f"✗ 队列处理失败: {e}") self.queue_stats["queue_errors"] += 1 def _create_match(self, players: List[Dict[str, Any]], queue: Dict[str, Any]) -> bool: """ 创建匹配 Args: players: 玩家列表 queue: 队列信息 Returns: 是否创建成功 """ try: # 生成匹配ID match_id = f"match_{int(time.time() * 1000000)}" # 提取玩家ID player_ids = [player["player_id"] for player in players] # 创建房间 room_id = None if self.plugin.room_allocator: room_settings = { "game_mode": queue["game_mode"], "region": queue["region"], "max_players": len(players) } room_id = self.plugin.room_allocator.create_room( room_name=f"Match_{match_id[:8]}", room_settings=room_settings ) # 添加玩家到房间 if room_id and self.plugin.room_allocator: for player_id in player_ids: self.plugin.room_allocator.add_client_to_room(room_id, player_id) # 通知匹配管理器匹配完成 if self.plugin.match_manager: self.plugin.match_manager.complete_match(match_id, room_id or "") # 触发匹配找到回调 self._trigger_queue_callback("match_found", { "match_id": match_id, "room_id": room_id, "player_ids": player_ids, "queue_name": queue["name"], "timestamp": time.time() }) print(f"✓ 匹配已创建: {match_id} ({len(player_ids)}名玩家)") return True except Exception as e: print(f"✗ 匹配创建失败: {e}") self.queue_stats["queue_errors"] += 1 return False def get_queue_info(self, queue_name: str = None) -> Dict[str, Any]: """ 获取队列信息 Args: queue_name: 队列名称(可选,如果未指定则返回所有队列信息) Returns: 队列信息字典 """ try: with self.queue_lock: if queue_name: if queue_name in self.queues: queue = self.queues[queue_name] return { "name": queue["name"], "game_mode": queue["game_mode"], "region": queue["region"], "player_count": len(queue["players"]), "created_time": queue["created_time"] } else: return {} else: # 返回所有队列信息 queue_info = {} for name, queue in self.queues.items(): queue_info[name] = { "name": queue["name"], "game_mode": queue["game_mode"], "region": queue["region"], "player_count": len(queue["players"]), "created_time": queue["created_time"] } return queue_info except Exception as e: print(f"✗ 队列信息获取失败: {e}") self.queue_stats["queue_errors"] += 1 return {} def get_player_queue_info(self, player_id: str) -> Optional[Dict[str, Any]]: """ 获取玩家队列信息 Args: player_id: 玩家ID Returns: 玩家队列信息或None """ try: with self.queue_lock: if player_id in self.player_queues: return self.player_queues[player_id].copy() else: return None except Exception as e: print(f"✗ 玩家队列信息获取失败: {e}") self.queue_stats["queue_errors"] += 1 return None def get_queue_stats(self) -> Dict[str, Any]: """ 获取队列统计信息 Returns: 队列统计字典 """ return { "state": self.queue_state.copy(), "stats": self.queue_stats.copy(), "config": self.queue_config.copy(), "current_queues": len(self.queues), "current_players": len(self.player_queues) } def reset_stats(self): """重置队列统计信息""" try: self.queue_stats = { "players_added": 0, "players_removed": 0, "matches_created": 0, "queue_timeouts": 0, "queue_errors": 0 } print("✓ 队列统计信息已重置") except Exception as e: print(f"✗ 队列统计信息重置失败: {e}") def set_queue_config(self, config: Dict[str, Any]) -> bool: """ 设置队列配置 Args: config: 队列配置字典 Returns: 是否设置成功 """ try: self.queue_config.update(config) print(f"✓ 队列配置已更新: {self.queue_config}") return True except Exception as e: print(f"✗ 队列配置设置失败: {e}") return False def get_queue_config(self) -> Dict[str, Any]: """ 获取队列配置 Returns: 队列配置字典 """ return self.queue_config.copy() def _trigger_queue_callback(self, callback_type: str, data: Dict[str, Any]): """ 触发队列回调 Args: callback_type: 回调类型 data: 回调数据 """ try: if callback_type in self.queue_callbacks: for callback in self.queue_callbacks[callback_type]: try: callback(data) except Exception as e: print(f"✗ 队列回调执行失败: {callback_type} - {e}") except Exception as e: print(f"✗ 队列回调触发失败: {e}") def register_queue_callback(self, callback_type: str, callback: callable): """ 注册队列回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.queue_callbacks: self.queue_callbacks[callback_type].append(callback) print(f"✓ 队列回调已注册: {callback_type}") else: print(f"✗ 无效的回调类型: {callback_type}") except Exception as e: print(f"✗ 队列回调注册失败: {e}") def unregister_queue_callback(self, callback_type: str, callback: callable): """ 注销队列回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.queue_callbacks: if callback in self.queue_callbacks[callback_type]: self.queue_callbacks[callback_type].remove(callback) print(f"✓ 队列回调已注销: {callback_type}") else: print(f"✗ 无效的回调类型: {callback_type}") except Exception as e: print(f"✗ 队列回调注销失败: {e}")