ReboundEmulator/Core/Rooms/RoomManager.cs
Moonbase 68e3ac5b4a Remove WordRiotRoom (was mostly for prototyping)
Load CDL Rooms From File
Move ext.rslt To Game Specific Rooms
2026-10-07 12:50:56 -07:00

60 lines
3.1 KiB
C#

using System.Collections.Concurrent;
using System.Reflection;
using System.Text.Json;
namespace NotPogo.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 Rule, int Capacity = 50);
public static void LoadFromFile(string path)
{
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, 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) =>
Factories.TryGetValue(gameCode, out var create) ? create(ruleId) : new ChatOnlyRoom();
public static Room Define(string key, string humanName, string gameCode, string ruleId, bool isLive, int softCapacity = 50, int tabId = 1) =>
Rooms.GetOrAdd(key, _ => new Room(key, humanName, gameCode, ruleId, softCapacity, tabId, isLive, CreateGame(gameCode, ruleId)));
public static Room GetOrCreate(string key, string gameCode, string ruleId = "") =>
Rooms.GetOrAdd(key, _ => new Room(key, key, gameCode, ruleId, 50, 1, false, CreateGame(gameCode, ruleId)));
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);
}
}