ReboundEmulator/Core/Rooms/RoomManager.cs
Moonbase 64273ab651 Code Cleanup
Rework How Room OPs Are Handled Per Room (if the game server itself isn't handling it, just send it to the room every time)
2026-10-09 14:36:32 -07:00

67 lines
3.4 KiB
C#

using System.Collections.Concurrent;
using System.Reflection;
using System.Text.Json;
namespace ReboundEmulator.Core.Rooms
{
public static class RoomManager
{
static readonly ConcurrentDictionary<string, Room> Rooms = new();
static readonly Dictionary<string, Func<string, IGameRoom>> Factories = BuildFactories();
public sealed record RoomDef(string Key, string Name, string OpCode, string Rule, int Capacity = 50);
public static void LoadFromFile(string path, ILogger log)
{
var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true };
var games = JsonSerializer.Deserialize<Dictionary<string, RoomDef[]>>(File.ReadAllText(path), opts)!;
foreach (var (gameCode, rooms) in games)
foreach (var r in rooms)
Define(r.Key, r.Name, gameCode, r.Rule, true, log, r.Capacity);
}
static Dictionary<string, Func<string, IGameRoom>> BuildFactories()
{
var map = new Dictionary<string, Func<string, IGameRoom>>(StringComparer.OrdinalIgnoreCase);
foreach (var type in typeof(IGameRoom).Assembly.GetTypes()
.Where(t => typeof(IGameRoom).IsAssignableFrom(t) && !t.IsAbstract))
{
foreach (var attr in type.GetCustomAttributes<GameRoomAttribute>())
{
// constructor convention: (string ruleId) if the game has modes, otherwise parameterless
Func<string, IGameRoom> factory =
type.GetConstructor([typeof(string)]) is not null ? rule => (IGameRoom)Activator.CreateInstance(type, rule)!
: type.GetConstructor(Type.EmptyTypes) is not null ? _ => (IGameRoom)Activator.CreateInstance(type)!
: throw new InvalidOperationException($"{type.Name} needs a (string ruleId) or parameterless constructor");
if (!map.TryAdd(attr.GameCode, factory))
throw new InvalidOperationException($"Game code '{attr.GameCode}' is claimed by more than one room class");
}
}
return map;
}
static IGameRoom CreateGame(string gameCode, string ruleId)
{
var gameRoom = Factories.TryGetValue(gameCode, out var create) ? create(ruleId) : new ChatOnlyRoom();
if (gameRoom is ChatOnlyRoom)
Console.WriteLine($"[RoomManager] Game Logic For Game {gameCode} Doesn't Exist. Fell Back To Chat Only...");
return gameRoom;
}
public static Room Define(string key, string humanName, string gameCode, string ruleId, bool isLive, ILogger log, int softCapacity = 50, int tabId = 1) =>
Rooms.GetOrAdd(key, _ => new Room(key, humanName, gameCode, ruleId, softCapacity, tabId, isLive, CreateGame(gameCode, ruleId), log));
public static Room GetOrCreate(string key, string gameCode, ILogger log, string ruleId = "") =>
Rooms.GetOrAdd(key, _ => new Room(key, key, gameCode, ruleId, 50, 1, false, CreateGame(gameCode, ruleId), log));
public static Room? Find(string key) => Rooms.TryGetValue(key, out var r) ? r : null;
public static IEnumerable<Room> ForGame(string gameCode) => Rooms.Values.Where(r => r.GameCode == gameCode);
}
}