191 lines
6.4 KiB
C#
191 lines
6.4 KiB
C#
using Microsoft.AspNetCore.StaticFiles;
|
|
using System.Runtime.InteropServices.Marshalling;
|
|
|
|
namespace NotPogo.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; }
|
|
|
|
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)
|
|
{
|
|
Key = key; HumanName = humanName; GameCode = gameCode; RuleId = ruleId;
|
|
SoftCapacity = softCapacity; TabId = tabId; Live = live; Game = game;
|
|
}
|
|
|
|
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))
|
|
Console.WriteLine($"[Room {Key}] Unhandled OP '{op}' From {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", "")
|
|
);
|
|
}
|
|
}
|
|
} |