using System; using System.Collections.Generic; using XWorld.Framework; namespace XWorld.Server.Host { // TickAll 的结束房间条目:携带小游戏经 EndRoom(result) 给出的结算结果(可为 null) public readonly struct EndedRoom { public readonly string RoomId; public readonly RoomEndResult Result; public EndedRoom(string roomId, RoomEndResult result) { RoomId = roomId; Result = result; } } public sealed class RoomHost { private readonly GameModuleRegistry _registry; private readonly ILogger _logger; private readonly Dictionary _rooms = new Dictionary(); private struct RoomEntry { public Room Room; public LoadedGameModule Module; } public RoomHost(GameModuleRegistry registry, ILogger logger) { _registry = registry; _logger = logger; } public int ActiveRoomCount { get { int n = 0; foreach (var kv in _rooms) if (kv.Value.Room.IsActive) n++; return n; } } public Room CreateRoom(string roomId, string gameId, int version, RoomConfig config, IReadOnlyList players, IRoomOutput output) { if (_rooms.ContainsKey(roomId)) throw new InvalidOperationException($"房间 ID 已存在: {roomId}"); var module = _registry.Acquire(gameId, version); try { IGameServerRoom logic = module.CreateRoom(); var clock = new ManualClock(); Room room = null; var ctx = new RoomCtx( new DeterministicRandom(config.Seed), clock, _logger, new InMemoryStorage(), output, r => room.RequestEnd(r)); room = new Room(roomId, logic, clock, ctx, _logger); _rooms[roomId] = new RoomEntry { Room = room, Module = module }; room.Start(players); if (!room.IsActive) ReleaseRoom(roomId); // Start 内即结束/故障则立即回收 return room; } catch { // 构建失败(如游戏构造函数抛异常):释放已 Acquire 的模块,避免引用泄漏 if (_rooms.ContainsKey(roomId)) ReleaseRoom(roomId); else _registry.Release(module); throw; } } public IReadOnlyList TickAll(float dt) { List ended = null; foreach (var kv in _rooms) { var room = kv.Value.Room; if (!room.IsActive) { (ended ??= new List()).Add(new EndedRoom(kv.Key, room.TrustedEndResult)); continue; } room.Tick(dt); if (!room.IsActive) (ended ??= new List()).Add(new EndedRoom(kv.Key, room.TrustedEndResult)); } if (ended != null) foreach (var e in ended) ReleaseRoom(e.RoomId); return ended ?? (IReadOnlyList)System.Array.Empty(); } public void DeliverTo(string roomId, int playerId, NetMessage message) { if (_rooms.TryGetValue(roomId, out var entry)) entry.Room.Deliver(playerId, message); } private void ReleaseRoom(string roomId) { if (!_rooms.TryGetValue(roomId, out var entry)) return; _rooms.Remove(roomId); _registry.Release(entry.Module); } } }