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

190 lines
6.5 KiB
C#

namespace ReboundEmulator.Core.Rooms
{
public sealed class Room
{
public string Key { get; }
public string HumanName { get; }
public string GameCode { get; }
public string RuleId { get; }
public int SoftCapacity { get; }
public int TabId { get; }
public bool Live { get; set; } = true;
public IGameRoom Game { get; }
public static ILogger Log { get; private set; }
readonly List<Player> _players = new();
readonly object _lock = new();
public Room(string key, string humanName, string gameCode, string ruleId,
int softCapacity, int tabId, bool live, IGameRoom game, ILogger log)
{
Key = key; HumanName = humanName; GameCode = gameCode; RuleId = ruleId;
SoftCapacity = softCapacity; TabId = tabId; Live = live; Game = game;
Log = log;
}
public bool IsJoinable => Live && PlayerCount < SoftCapacity;
public int PlayerCount { get { lock (_lock) return _players.Count; } }
public Player[] Snapshot() { lock (_lock) { return [.. _players]; } }
public static (string, string)[] PresenceFields(Player p) =>
[
("msg.op", "rm.join"), ("scrn", p.ScreenName), ("snme", p.ScreenName), ("pfid", p.ProfileId),
("plid", p.Id.ToString()), ("entl", "ictsebaulovfFmMrRG"), ("priv", "0"),
("aepc", ""), ("acvw", ""), ("agvs", ""), ("alrc", ""),
];
public static (string, string)[][] PlayerState(Player p) =>
[
[("msg.op", "pl.rm.stte"), ("plid", p.Id.ToString()), ("gmpf", ""), ("glpf", "..."), ("frls", "")],
[("msg.op", "pl.rm.stte"), ("plid", p.Id.ToString()), ("tokb", "9999")],
[("msg.op", "pl.rm.stte"), ("plid", p.Id.ToString()), ("avtr", ""), ("icon", "avatarminighost")]
];
public async Task JoinAsync(Player player)
{
Player[] others;
lock (_lock)
{
others = [.. _players];
_players.Add(player);
player.Room = this;
}
await player.SendAsync(
("msg.op", "load"),
("rmst", "start")
);
await player.SendAsync(PresenceFields(player));
foreach (var other in others)
await player.SendAsync(PresenceFields(other));
await player.SendAsync(
("msg.op", "gm.crea"),
("launch", "y"),
("live", "0"),
("port", "0"),
("iali", "86400000"),
("gins", HumanName),
("dead", "0"),
("iaid", "15000"),
("shut", ""),
("gmid", "0")
);
await player.SendAsync(
("msg.op", "load"),
("rmst", "end")
);
await player.SendAsync(
("msg.op", "say"),
("chnl", "serv"),
("scrn", ""),
("type", "stnd"),
("text", "NotPogo Is Alpha Software! Some Things May Not Function Correctly.")
);
foreach (var other in others)
foreach (var m in PlayerState(other)) await player.SendAsync(m);
await BroadcastAsync(PresenceFields(player), except: player);
foreach (var m in PlayerState(player)) await BroadcastAsync(m);
await Game.OnPlayerJoinedAsync(this, player);
}
public async Task LeaveAsync(Player player)
{
lock (_lock)
{
if (!_players.Remove(player)) return;
player.Room = null;
}
await BroadcastAsync([("msg.op", "rm.left"), ("plid", player.Id.ToString()), ("scrn", player.ScreenName)]);
await Game.OnPlayerLeftAsync(this, player);
}
public Task BroadcastAsync((string, string)[] values, Player? except = null)
{
var msg = new Dictionary<string, string>();
foreach (var (k, v) in values) msg[k] = v;
return BroadcastAsync(msg, except);
}
public Task BroadcastAsync(Dictionary<string, string> msg, Player? except = null) =>
Task.WhenAll(Snapshot().Where(p => p != except).Select(p => p.SendAsync(msg)));
public async Task HandleAsync(Player player, string op, Dictionary<string, string> msg)
{
switch (op)
{
case "gm.join":
await GameJoinAsync(player);
return;
case "say":
msg.TryGetValue("text", out var text);
await BroadcastAsync(
[("msg.op", "say"),
("chnl", msg.GetValueOrDefault("chnl", "")),
("plid", player.Id.ToString()),
("scrn", player.ScreenName),
("type", "stnd"),
("text", text ?? "")]
);
return;
case "rm.left":
case "disc":
await LeaveAsync(player);
return;
}
if (!await Game.OnMessageAsync(this, player, op, msg) && Game is not ChatOnlyRoom)
Log.LogInformation("[Room {Key}] Unhandled OP '{OP}' From {ScreenName}", Key, op, player.ScreenName);
}
public async Task GameJoinAsync(Player player)
{
string plid = player.Id.ToString();
await player.SendAsync(
("msg.op", "gm.join"),
("plid", plid),
("snme", player.ScreenName),
("gmid", "0"),
("scrn", player.ScreenName),
("join", "join")
);
await player.SendAsync(
("msg.op", "gm.lnch"),
("gmid", "0")
);
await player.SendAsync(
("msg.op", "tokb"),
("tokb", "9999")
);
await player.SendAsync(
("msg.op", "tick"),
("scrn", player.ScreenName),
("text", "Welcome to Not Pogo!")
);
await player.SendAsync(
("msg.op", "cnfg"),
("impd", "40")
);
await player.SendAsync(
("msg.op", "ext.pref"),
("pref", "")
);
}
}
}