EG/plugins/user/matchmaking_system/rooms/room_allocator.py
2025-12-12 16:16:15 +08:00

752 lines
24 KiB
Python

"""
房间分配器模块
为匹配成功的玩家创建和分配房间
"""
import time
import uuid
from typing import Dict, Any, List, Optional
class RoomAllocator:
"""
房间分配器
为匹配成功的玩家创建和分配房间
"""
def __init__(self, plugin):
"""
初始化房间分配器
Args:
plugin: 匹配系统插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 房间配置
self.room_config = {
"default_max_players": 8,
"enable_room_passwords": True,
"enable_room_visibility": True,
"room_timeout": 3600, # 1小时无活动房间自动关闭
"max_rooms": 1000,
"enable_persistent_rooms": False
}
# 房间状态
self.room_state = {
"total_rooms": 0,
"active_rooms": 0,
"occupied_rooms": 0,
"available_rooms": 0
}
# 房间存储
self.rooms = {} # 房间数据
self.player_rooms = {} # 玩家所在房间映射
# 房间统计
self.room_stats = {
"rooms_created": 0,
"rooms_destroyed": 0,
"players_added": 0,
"players_removed": 0,
"room_errors": 0
}
# 回调函数
self.room_callbacks = {
"room_created": [],
"room_destroyed": [],
"player_added": [],
"player_removed": [],
"room_error": []
}
# 时间戳记录
self.last_cleanup = 0.0
self.last_stats_reset = 0.0
print("✓ 房间分配器已创建")
def initialize(self) -> bool:
"""
初始化房间分配器
Returns:
是否初始化成功
"""
try:
print("正在初始化房间分配器...")
self.initialized = True
print("✓ 房间分配器初始化完成")
return True
except Exception as e:
print(f"✗ 房间分配器初始化失败: {e}")
self.room_stats["room_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.room_stats["room_errors"] += 1
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用房间分配器"""
try:
self.enabled = False
# 销毁所有房间
self._destroy_all_rooms()
print("✓ 房间分配器已禁用")
except Exception as e:
print(f"✗ 房间分配器禁用失败: {e}")
self.room_stats["room_errors"] += 1
import traceback
traceback.print_exc()
def finalize(self):
"""清理房间分配器资源"""
try:
# 禁用房间分配器
if self.enabled:
self.disable()
# 清理回调
self.room_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_cleanup >= 300.0: # 每5分钟清理一次
self._cleanup_expired_rooms(current_time)
self.last_cleanup = current_time
except Exception as e:
print(f"✗ 房间分配器更新失败: {e}")
self.room_stats["room_errors"] += 1
import traceback
traceback.print_exc()
def _cleanup_expired_rooms(self, current_time: float):
"""清理过期房间"""
try:
expired_rooms = []
for room_id, room_data in self.rooms.items():
# 检查房间是否超时
if current_time - room_data.get("last_activity", 0) > self.room_config["room_timeout"]:
# 检查房间是否为空
if len(room_data.get("players", {})) == 0:
expired_rooms.append(room_id)
# 销毁过期房间
for room_id in expired_rooms:
self.destroy_room(room_id)
except Exception as e:
print(f"✗ 过期房间清理失败: {e}")
self.room_stats["room_errors"] += 1
def _destroy_all_rooms(self):
"""销毁所有房间"""
try:
room_ids = list(self.rooms.keys())
for room_id in room_ids:
self.destroy_room(room_id)
except Exception as e:
print(f"✗ 所有房间销毁失败: {e}")
self.room_stats["room_errors"] += 1
def create_room(self, room_name: str = None, room_settings: Dict[str, Any] = None,
room_password: str = None) -> Optional[str]:
"""
创建房间
Args:
room_name: 房间名称
room_settings: 房间设置
room_password: 房间密码
Returns:
房间ID或None
"""
try:
if not self.enabled:
return None
# 检查房间数量限制
if len(self.rooms) >= self.room_config["max_rooms"]:
print("✗ 房间数量已达上限")
self.room_stats["room_errors"] += 1
return None
# 生成房间ID
room_id = f"room_{int(time.time() * 1000000)}"
# 使用默认设置或传入设置
settings = {
"max_players": self.room_config["default_max_players"],
"is_public": True,
"allow_spectators": True
}
if room_settings:
settings.update(room_settings)
# 创建房间数据
room_data = {
"room_id": room_id,
"room_name": room_name or f"房间-{room_id[:8]}",
"settings": settings,
"password": room_password,
"players": {}, # 玩家ID到玩家数据的映射
"host_player_id": None,
"created_time": time.time(),
"last_activity": time.time(),
"room_state": {}, # 房间状态数据
"custom_data": {} # 自定义房间数据
}
# 添加到房间列表
self.rooms[room_id] = room_data
self.room_state["total_rooms"] += 1
self.room_state["active_rooms"] += 1
self.room_stats["rooms_created"] += 1
# 触发房间创建回调
self._trigger_room_callback("room_created", {
"room_id": room_id,
"room_name": room_data["room_name"],
"settings": settings,
"timestamp": room_data["created_time"]
})
print(f"✓ 房间已创建: {room_id} ({room_data['room_name']})")
return room_id
except Exception as e:
print(f"✗ 房间创建失败: {e}")
self.room_stats["room_errors"] += 1
return None
def destroy_room(self, room_id: str) -> bool:
"""
销毁房间
Args:
room_id: 房间ID
Returns:
是否销毁成功
"""
try:
if not self.enabled:
return False
# 检查房间是否存在
if room_id not in self.rooms:
print(f"✗ 房间不存在: {room_id}")
return False
room_data = self.rooms[room_id]
# 通知房间内所有玩家
player_ids = list(room_data["players"].keys())
for player_id in player_ids:
self._notify_player_room_destroyed(player_id, room_id)
# 移除房间
del self.rooms[room_id]
self.room_state["active_rooms"] -= 1
self.room_stats["rooms_destroyed"] += 1
# 触发房间销毁回调
self._trigger_room_callback("room_destroyed", {
"room_id": room_id,
"room_name": room_data["room_name"],
"timestamp": time.time()
})
print(f"✓ 房间已销毁: {room_id}")
return True
except Exception as e:
print(f"✗ 房间销毁失败: {e}")
self.room_stats["room_errors"] += 1
return False
def _notify_player_room_destroyed(self, player_id: str, room_id: str):
"""
通知玩家房间被销毁
Args:
player_id: 玩家ID
room_id: 房间ID
"""
try:
# 从玩家房间映射中移除
if player_id in self.player_rooms:
del self.player_rooms[player_id]
except Exception as e:
print(f"✗ 玩家房间销毁通知失败: {e}")
self.room_stats["room_errors"] += 1
def add_client_to_room(self, room_id: str, player_id: str, player_data: Dict[str, Any] = None) -> bool:
"""
添加玩家到房间
Args:
room_id: 房间ID
player_id: 玩家ID
player_data: 玩家数据
Returns:
是否添加成功
"""
try:
if not self.enabled:
return False
# 检查房间是否存在
if room_id not in self.rooms:
print(f"✗ 房间不存在: {room_id}")
self.room_stats["room_errors"] += 1
return False
room_data = self.rooms[room_id]
# 检查房间是否已满
if len(room_data["players"]) >= room_data["settings"]["max_players"]:
print(f"✗ 房间已满: {room_id}")
return False
# 检查房间密码
if room_data["password"] and not self._verify_room_password(room_id, player_data):
print(f"✗ 房间密码错误: {room_id}")
return False
# 添加玩家到房间
player_info = player_data or {}
player_info["join_time"] = time.time()
player_info["last_activity"] = time.time()
room_data["players"][player_id] = player_info
room_data["last_activity"] = time.time()
# 设置房间主机(如果是第一个玩家)
if room_data["host_player_id"] is None:
room_data["host_player_id"] = player_id
# 更新玩家房间映射
self.player_rooms[player_id] = room_id
self.room_stats["players_added"] += 1
# 触发玩家添加回调
self._trigger_room_callback("player_added", {
"room_id": room_id,
"room_name": room_data["room_name"],
"player_id": player_id,
"timestamp": time.time()
})
print(f"✓ 玩家已加入房间: {player_id} -> {room_id}")
return True
except Exception as e:
print(f"✗ 玩家加入房间失败: {e}")
self.room_stats["room_errors"] += 1
return False
def remove_client_from_room(self, room_id: str, player_id: str) -> bool:
"""
从房间移除玩家
Args:
room_id: 房间ID
player_id: 玩家ID
Returns:
是否移除成功
"""
try:
if not self.enabled:
return False
# 检查房间是否存在
if room_id not in self.rooms:
print(f"✗ 房间不存在: {room_id}")
return False
room_data = self.rooms[room_id]
# 检查玩家是否在房间中
if player_id not in room_data["players"]:
print(f"✗ 玩家不在房间中: {player_id}")
return False
# 移除玩家
del room_data["players"][player_id]
room_data["last_activity"] = time.time()
# 更新主机(如果移除的是主机)
if room_data["host_player_id"] == player_id:
if room_data["players"]:
# 选择第一个玩家作为新主机
room_data["host_player_id"] = next(iter(room_data["players"]))
else:
room_data["host_player_id"] = None
# 移除玩家房间映射
if player_id in self.player_rooms:
del self.player_rooms[player_id]
self.room_stats["players_removed"] += 1
# 触发玩家移除回调
self._trigger_room_callback("player_removed", {
"room_id": room_id,
"room_name": room_data["room_name"],
"player_id": player_id,
"timestamp": time.time()
})
# 如果房间为空,销毁房间
if len(room_data["players"]) == 0:
self.destroy_room(room_id)
print(f"✓ 玩家已离开房间: {player_id} <- {room_id}")
return True
except Exception as e:
print(f"✗ 玩家离开房间失败: {e}")
self.room_stats["room_errors"] += 1
return False
def _verify_room_password(self, room_id: str, player_data: Dict[str, Any]) -> bool:
"""
验证房间密码
Args:
room_id: 房间ID
player_data: 玩家数据
Returns:
密码是否正确
"""
try:
if not self.room_config["enable_room_passwords"]:
return True
if room_id not in self.rooms:
return False
room_data = self.rooms[room_id]
if not room_data["password"]:
return True
player_password = player_data.get("password") if player_data else None
return player_password == room_data["password"]
except Exception as e:
print(f"✗ 房间密码验证失败: {e}")
self.room_stats["room_errors"] += 1
return False
def get_room_info(self, room_id: str) -> Optional[Dict[str, Any]]:
"""
获取房间信息
Args:
room_id: 房间ID
Returns:
房间信息或None
"""
try:
if room_id in self.rooms:
room_data = self.rooms[room_id]
# 返回不包含敏感信息的房间信息
safe_room_data = {
"room_id": room_data["room_id"],
"room_name": room_data["room_name"],
"settings": room_data["settings"],
"player_count": len(room_data["players"]),
"has_password": bool(room_data["password"]),
"host_player_id": room_data["host_player_id"],
"created_time": room_data["created_time"],
"last_activity": room_data["last_activity"]
}
return safe_room_data
else:
return None
except Exception as e:
print(f"✗ 获取房间信息失败: {e}")
self.room_stats["room_errors"] += 1
return None
def get_player_room(self, player_id: str) -> Optional[str]:
"""
获取玩家所在房间
Args:
player_id: 玩家ID
Returns:
房间ID或None
"""
try:
return self.player_rooms.get(player_id)
except Exception as e:
print(f"✗ 获取玩家房间失败: {e}")
self.room_stats["room_errors"] += 1
return None
def get_room_players(self, room_id: str) -> List[str]:
"""
获取房间内所有玩家
Args:
room_id: 房间ID
Returns:
玩家ID列表
"""
try:
if room_id in self.rooms:
return list(self.rooms[room_id]["players"].keys())
else:
return []
except Exception as e:
print(f"✗ 获取房间玩家失败: {e}")
self.room_stats["room_errors"] += 1
return []
def update_room_state(self, room_id: str, state_data: Dict[str, Any]) -> bool:
"""
更新房间状态
Args:
room_id: 房间ID
state_data: 状态数据
Returns:
是否更新成功
"""
try:
if room_id not in self.rooms:
return False
self.rooms[room_id]["room_state"].update(state_data)
self.rooms[room_id]["last_activity"] = time.time()
return True
except Exception as e:
print(f"✗ 更新房间状态失败: {e}")
self.room_stats["room_errors"] += 1
return False
def set_room_custom_data(self, room_id: str, key: str, value: Any) -> bool:
"""
设置房间自定义数据
Args:
room_id: 房间ID
key: 数据键
value: 数据值
Returns:
是否设置成功
"""
try:
if room_id not in self.rooms:
return False
self.rooms[room_id]["custom_data"][key] = value
return True
except Exception as e:
print(f"✗ 设置房间自定义数据失败: {e}")
self.room_stats["room_errors"] += 1
return False
def get_room_custom_data(self, room_id: str, key: str, default: Any = None) -> Any:
"""
获取房间自定义数据
Args:
room_id: 房间ID
key: 数据键
default: 默认值
Returns:
数据值或默认值
"""
try:
if room_id not in self.rooms:
return default
return self.rooms[room_id]["custom_data"].get(key, default)
except Exception as e:
print(f"✗ 获取房间自定义数据失败: {e}")
self.room_stats["room_errors"] += 1
return default
def get_room_stats(self) -> Dict[str, Any]:
"""
获取房间统计信息
Returns:
房间统计字典
"""
return {
"state": self.room_state.copy(),
"stats": self.room_stats.copy(),
"config": self.room_config.copy(),
"current_rooms": len(self.rooms),
"current_players": len(self.player_rooms)
}
def reset_stats(self):
"""重置房间统计信息"""
try:
self.room_stats = {
"rooms_created": 0,
"rooms_destroyed": 0,
"players_added": 0,
"players_removed": 0,
"room_errors": 0
}
print("✓ 房间统计信息已重置")
except Exception as e:
print(f"✗ 房间统计信息重置失败: {e}")
def set_room_config(self, config: Dict[str, Any]) -> bool:
"""
设置房间配置
Args:
config: 房间配置字典
Returns:
是否设置成功
"""
try:
self.room_config.update(config)
print(f"✓ 房间配置已更新: {self.room_config}")
return True
except Exception as e:
print(f"✗ 房间配置设置失败: {e}")
return False
def get_room_config(self) -> Dict[str, Any]:
"""
获取房间配置
Returns:
房间配置字典
"""
return self.room_config.copy()
def _trigger_room_callback(self, callback_type: str, data: Dict[str, Any]):
"""
触发房间回调
Args:
callback_type: 回调类型
data: 回调数据
"""
try:
if callback_type in self.room_callbacks:
for callback in self.room_callbacks[callback_type]:
try:
callback(data)
except Exception as e:
print(f"✗ 房间回调执行失败: {callback_type} - {e}")
except Exception as e:
print(f"✗ 房间回调触发失败: {e}")
def register_room_callback(self, callback_type: str, callback: callable):
"""
注册房间回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.room_callbacks:
self.room_callbacks[callback_type].append(callback)
print(f"✓ 房间回调已注册: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 房间回调注册失败: {e}")
def unregister_room_callback(self, callback_type: str, callback: callable):
"""
注销房间回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.room_callbacks:
if callback in self.room_callbacks[callback_type]:
self.room_callbacks[callback_type].remove(callback)
print(f"✓ 房间回调已注销: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 房间回调注销失败: {e}")