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)
This commit is contained in:
parent
a3ac23d492
commit
64273ab651
60
Amf/Amf0.cs
60
Amf/Amf0.cs
@ -119,29 +119,29 @@ public sealed class Amf0Reader
|
||||
case 0x06: return null; // undefined
|
||||
case 0x07: return _refs[U16()]; // reference
|
||||
case 0x08: // ECMA (associative) array
|
||||
{
|
||||
U32(); // approximate count; ignore
|
||||
var o = new Dictionary<string, object?>(); _refs.Add(o); ReadProps(o); return o;
|
||||
}
|
||||
{
|
||||
U32(); // approximate count; ignore
|
||||
var o = new Dictionary<string, object?>(); _refs.Add(o); ReadProps(o); return o;
|
||||
}
|
||||
case 0x0A: // strict array
|
||||
{
|
||||
uint n = U32();
|
||||
var list = new List<object?>((int)Math.Min(n, 4096)); _refs.Add(list);
|
||||
for (uint i = 0; i < n; i++) list.Add(ReadValue());
|
||||
return list;
|
||||
}
|
||||
{
|
||||
uint n = U32();
|
||||
var list = new List<object?>((int)Math.Min(n, 4096)); _refs.Add(list);
|
||||
for (uint i = 0; i < n; i++) list.Add(ReadValue());
|
||||
return list;
|
||||
}
|
||||
case 0x0B: // date: ms since epoch + tz (ignored)
|
||||
{
|
||||
double ms = F64(); U16();
|
||||
return DateTime.UnixEpoch.AddMilliseconds(ms);
|
||||
}
|
||||
{
|
||||
double ms = F64(); U16();
|
||||
return DateTime.UnixEpoch.AddMilliseconds(ms);
|
||||
}
|
||||
case 0x0C: return Utf8((int)U32()); // long string
|
||||
case 0x0F: return Utf8((int)U32()); // XML document (as text)
|
||||
case 0x10: // typed object
|
||||
{
|
||||
string cls = Utf8(U16());
|
||||
var o = new Dictionary<string, object?> { ["__className"] = cls }; _refs.Add(o); ReadProps(o); return o;
|
||||
}
|
||||
{
|
||||
string cls = Utf8(U16());
|
||||
var o = new Dictionary<string, object?> { ["__className"] = cls }; _refs.Add(o); ReadProps(o); return o;
|
||||
}
|
||||
case 0x11: throw new NotSupportedException("AMF3 value inside AMF0 (Flash 9+ only; AS2 never sends this)");
|
||||
default: throw new FormatException($"Unknown AMF0 marker 0x{marker:X2} at offset {_p - 1}");
|
||||
}
|
||||
@ -184,12 +184,12 @@ public sealed class Amf0Writer
|
||||
case null: U8(0x05); return;
|
||||
case bool b: U8(0x01); U8((byte)(b ? 1 : 0)); return;
|
||||
case string s:
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(s);
|
||||
if (bytes.Length <= ushort.MaxValue) { U8(0x02); U16((ushort)bytes.Length); }
|
||||
else { U8(0x0C); U32((uint)bytes.Length); }
|
||||
_s.Write(bytes); return;
|
||||
}
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(s);
|
||||
if (bytes.Length <= ushort.MaxValue) { U8(0x02); U16((ushort)bytes.Length); }
|
||||
else { U8(0x0C); U32((uint)bytes.Length); }
|
||||
_s.Write(bytes); return;
|
||||
}
|
||||
case byte or sbyte or short or ushort or int or uint or long or ulong or float or double or decimal:
|
||||
U8(0x00); F64(Convert.ToDouble(v)); return;
|
||||
case Enum e: U8(0x00); F64(Convert.ToDouble(e)); return;
|
||||
@ -200,12 +200,12 @@ public sealed class Amf0Writer
|
||||
foreach (DictionaryEntry kv in dict) { ShortString(kv.Key.ToString()!); WriteValue(kv.Value); }
|
||||
EndObject(); return;
|
||||
case IEnumerable list:
|
||||
{
|
||||
var items = list.Cast<object?>().ToList();
|
||||
U8(0x0A); U32((uint)items.Count);
|
||||
foreach (var item in items) WriteValue(item);
|
||||
return;
|
||||
}
|
||||
{
|
||||
var items = list.Cast<object?>().ToList();
|
||||
U8(0x0A); U32((uint)items.Count);
|
||||
foreach (var item in items) WriteValue(item);
|
||||
return;
|
||||
}
|
||||
default: // POCO / anonymous object -> anonymous AMF object
|
||||
U8(0x03);
|
||||
foreach (var prop in v.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReboundEmulator.Core.Rooms;
|
||||
using ReboundEmulator.Core;
|
||||
|
||||
namespace ReboundEmulator.Controllers
|
||||
@ -32,19 +31,11 @@ namespace ReboundEmulator.Controllers
|
||||
{
|
||||
var lkey = Sessions.Issue(name);
|
||||
|
||||
// more satisfying
|
||||
return Results.Text($"<LoginResponse error=\"none\">\n<LoginSessionKey>{lkey}</LoginSessionKey></LoginResponse>", "text/xml");
|
||||
}
|
||||
|
||||
[HttpGet("/cdl/1/cdl-clientprops")]
|
||||
public IActionResult CDLClientProps(string game)
|
||||
{
|
||||
string pathToProps = Path.Combine(AppContext.BaseDirectory, "StaticFiles", "Configs", "CDL", $"{game}.properties");
|
||||
|
||||
if (System.IO.File.Exists(pathToProps))
|
||||
return Ok(System.IO.File.ReadAllText(pathToProps));
|
||||
else
|
||||
return Ok(); // don't send anything since we don't have the config for it on the server yet
|
||||
}
|
||||
public IActionResult CDLClientProps() { return Ok(); } // CDL games don't really need the client props to be present on the server,
|
||||
// it was there so Pogo could update assets for CDL games on the fly
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
using ReboundEmulator.Core;
|
||||
using ReboundEmulator.Model;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Text;
|
||||
|
||||
namespace ReboundEmulator.Controllers
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace ReboundEmulator.Core
|
||||
{
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using ReboundEmulator;
|
||||
using ReboundEmulator.Core.Rooms;
|
||||
using ReboundEmulator.Core.Rooms;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace ReboundEmulator.Core
|
||||
@ -23,10 +22,10 @@ namespace ReboundEmulator.Core
|
||||
|
||||
public Player(NetworkStream stream) => _stream = stream;
|
||||
|
||||
public async Task SendAsync(params(string key, string value)[] fields)
|
||||
public async Task SendAsync(params (string key, string value)[] fields)
|
||||
{
|
||||
var msg = new Dictionary<string, string>();
|
||||
foreach(var (k, v) in fields) msg[k] = v;
|
||||
foreach (var (k, v) in fields) msg[k] = v;
|
||||
await SendAsync(msg);
|
||||
|
||||
msg.TryGetValue("msg.op", out var op);
|
||||
@ -37,8 +36,8 @@ namespace ReboundEmulator.Core
|
||||
{
|
||||
await _writeLock.WaitAsync();
|
||||
try { await TCPProtocol.WriteMessageAsync(_stream, msg); }
|
||||
catch(IOException) {}
|
||||
catch(ObjectDisposedException) {}
|
||||
catch (IOException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
finally { _writeLock.Release(); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
namespace ReboundEmulator.Core.Rooms
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
public sealed class GameRoomAttribute(string gameCode, string? opPrefix = null) : Attribute
|
||||
public sealed class GameRoomAttribute(string gameCode) : Attribute
|
||||
{
|
||||
public string GameCode { get; } = gameCode;
|
||||
public string? OpPrefix { get; init; } = opPrefix;
|
||||
}
|
||||
}
|
||||
26
Core/Rooms/GameRooms/BowlingRoom.cs
Normal file
26
Core/Rooms/GameRooms/BowlingRoom.cs
Normal file
@ -0,0 +1,26 @@
|
||||
namespace ReboundEmulator.Core.Rooms.GameRooms
|
||||
{
|
||||
[GameRoom("bowling")]
|
||||
public class BowlingRoom : IGameRoom
|
||||
{
|
||||
public Task OnGameJoinAsync(Room room, Player player)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<bool> OnMessageAsync(Room room, Player player, string op, Dictionary<string, string> msg)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task OnPlayerJoinedAsync(Room room, Player player)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task OnPlayerLeftAsync(Room room, Player player)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,4 @@
|
||||
using ReboundEmulator;
|
||||
|
||||
namespace ReboundEmulator.Core.Rooms.GameRooms
|
||||
namespace ReboundEmulator.Core.Rooms.GameRooms
|
||||
{
|
||||
[GameRoom("lottso2")]
|
||||
public class Lottso2Room : IGameRoom
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
namespace ReboundEmulator.Core.Rooms.GameRooms
|
||||
{
|
||||
[GameRoom("seaball", "sb.")]
|
||||
[GameRoom("seaball")]
|
||||
public class SkeeballRoom : IGameRoom
|
||||
{
|
||||
public Task OnGameJoinAsync(Room room, Player player) => Task.CompletedTask;
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
{
|
||||
public interface IGameRoom
|
||||
{
|
||||
string? OpPrefix => null;
|
||||
Task OnPlayerJoinedAsync(Room room, Player player);
|
||||
Task OnPlayerLeftAsync(Room room, Player player);
|
||||
Task<bool> OnMessageAsync(Room room, Player player, string op, Dictionary<string, string> msg);
|
||||
|
||||
@ -1,33 +1,26 @@
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Reflection;
|
||||
using ReboundEmulator.Core;
|
||||
|
||||
namespace ReboundEmulator.Core.Rooms
|
||||
namespace ReboundEmulator.Core.Rooms
|
||||
{
|
||||
public sealed class Room
|
||||
{
|
||||
public string Key { get; }
|
||||
public string HumanName { get; }
|
||||
public string GameCode { get; }
|
||||
public string OpPrefix =>
|
||||
Game.GetType().GetCustomAttributes<GameRoomAttribute>()
|
||||
.FirstOrDefault(a => string.Equals(a.GameCode, GameCode, StringComparison.OrdinalIgnoreCase))
|
||||
?.OpPrefix ?? GameCode + ".";
|
||||
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)
|
||||
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;
|
||||
@ -42,7 +35,7 @@ namespace ReboundEmulator.Core.Rooms
|
||||
("aepc", ""), ("acvw", ""), ("agvs", ""), ("alrc", ""),
|
||||
];
|
||||
|
||||
public static (string, string)[][] PlayerState(Player p) =>
|
||||
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")],
|
||||
@ -126,7 +119,7 @@ namespace ReboundEmulator.Core.Rooms
|
||||
|
||||
public async Task HandleAsync(Player player, string op, Dictionary<string, string> msg)
|
||||
{
|
||||
switch(op)
|
||||
switch (op)
|
||||
{
|
||||
case "gm.join":
|
||||
await GameJoinAsync(player);
|
||||
@ -135,11 +128,11 @@ namespace ReboundEmulator.Core.Rooms
|
||||
msg.TryGetValue("text", out var text);
|
||||
|
||||
await BroadcastAsync(
|
||||
[("msg.op", "say"),
|
||||
("chnl", msg.GetValueOrDefault("chnl", "")),
|
||||
("plid", player.Id.ToString()),
|
||||
("scrn", player.ScreenName),
|
||||
("type", "stnd"),
|
||||
[("msg.op", "say"),
|
||||
("chnl", msg.GetValueOrDefault("chnl", "")),
|
||||
("plid", player.Id.ToString()),
|
||||
("scrn", player.ScreenName),
|
||||
("type", "stnd"),
|
||||
("text", text ?? "")]
|
||||
);
|
||||
|
||||
@ -150,8 +143,8 @@ namespace ReboundEmulator.Core.Rooms
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await Game.OnMessageAsync(this, player, op, msg))
|
||||
Console.WriteLine($"[Room {Key}] Unhandled OP '{op}' From {player.ScreenName}");
|
||||
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)
|
||||
@ -159,32 +152,32 @@ namespace ReboundEmulator.Core.Rooms
|
||||
string plid = player.Id.ToString();
|
||||
|
||||
await player.SendAsync(
|
||||
("msg.op", "gm.join"),
|
||||
("plid", plid),
|
||||
("snme", player.ScreenName),
|
||||
("gmid", "0"),
|
||||
("scrn", player.ScreenName),
|
||||
("msg.op", "gm.join"),
|
||||
("plid", plid),
|
||||
("snme", player.ScreenName),
|
||||
("gmid", "0"),
|
||||
("scrn", player.ScreenName),
|
||||
("join", "join")
|
||||
);
|
||||
|
||||
await player.SendAsync(
|
||||
("msg.op", "gm.lnch"),
|
||||
("msg.op", "gm.lnch"),
|
||||
("gmid", "0")
|
||||
);
|
||||
|
||||
await player.SendAsync(
|
||||
("msg.op", "tokb"),
|
||||
("msg.op", "tokb"),
|
||||
("tokb", "9999")
|
||||
);
|
||||
|
||||
await player.SendAsync(
|
||||
("msg.op", "tick"),
|
||||
("scrn", player.ScreenName),
|
||||
("msg.op", "tick"),
|
||||
("scrn", player.ScreenName),
|
||||
("text", "Welcome to Not Pogo!")
|
||||
);
|
||||
|
||||
await player.SendAsync(
|
||||
("msg.op", "cnfg"),
|
||||
("msg.op", "cnfg"),
|
||||
("impd", "40")
|
||||
);
|
||||
|
||||
|
||||
@ -12,14 +12,14 @@ namespace ReboundEmulator.Core.Rooms
|
||||
|
||||
public sealed record RoomDef(string Key, string Name, string OpCode, string Rule, int Capacity = 50);
|
||||
|
||||
public static void LoadFromFile(string path)
|
||||
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, r.Capacity);
|
||||
Define(r.Key, r.Name, gameCode, r.Rule, true, log, r.Capacity);
|
||||
}
|
||||
|
||||
static Dictionary<string, Func<string, IGameRoom>> BuildFactories()
|
||||
@ -54,11 +54,11 @@ namespace ReboundEmulator.Core.Rooms
|
||||
return gameRoom;
|
||||
}
|
||||
|
||||
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 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, string ruleId = "") =>
|
||||
Rooms.GetOrAdd(key, _ => new Room(key, key, gameCode, ruleId, 50, 1, false, CreateGame(gameCode, ruleId)));
|
||||
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);
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// /flashservices/gateway endpoint for roomsel.swf (com.pogo.roomsel.RoomTabs).
|
||||
// Register in Program.cs: app.MapFlashGateway();
|
||||
using ReboundEmulator.Core.Rooms;
|
||||
using ReboundEmulator.Amf;
|
||||
using ReboundEmulator.Core.Rooms;
|
||||
|
||||
namespace ReboundEmulator;
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ namespace ReboundEmulator
|
||||
app.MapFlashGateway();
|
||||
|
||||
// Define Rooms For CDL Games
|
||||
RoomManager.LoadFromFile(Path.Combine(AppContext.BaseDirectory, "StaticFiles", "rooms.json"));
|
||||
RoomManager.LoadFromFile(Path.Combine(AppContext.BaseDirectory, "StaticFiles", "rooms.json"), app.Services.GetService<ILogger<TCPGameServer>>()!);
|
||||
|
||||
app.Run();
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using ReboundEmulator.Core;
|
||||
using ReboundEmulator.Core;
|
||||
using ReboundEmulator.Core.Rooms;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace ReboundEmulator
|
||||
{
|
||||
@ -17,8 +17,6 @@ namespace ReboundEmulator
|
||||
public static List<TcpClient> Clients { get; } = [];
|
||||
public static BowlingGame? SingleplayerBowlingGame;
|
||||
|
||||
static readonly HashSet<string> RoomOps = ["say", "rm.left", "disc", "gm.join", "ext.over"];
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_tcpPort = _configuration.GetValue<int>("GameServerPort");
|
||||
@ -55,9 +53,9 @@ namespace ReboundEmulator
|
||||
catch (EndOfStreamException) { break; }
|
||||
|
||||
if (!received.TryGetValue("msg.op", out var op)) continue;
|
||||
_logger.LogInformation("[plid {Plid}] <- {Op} {Fields}",
|
||||
player.Id,
|
||||
op,
|
||||
_logger.LogInformation("[plid {Plid}] <- {Op} {Fields}",
|
||||
player.Id,
|
||||
op,
|
||||
string.Join(" ", received.Where(kv => kv.Key != "msg.op").Select(kv => $"{kv.Key}='{kv.Value}'")));
|
||||
|
||||
|
||||
@ -73,13 +71,14 @@ namespace ReboundEmulator
|
||||
{
|
||||
player.LastSeen = DateTime.UtcNow;
|
||||
}
|
||||
else if (player.Room is not null && (RoomOps.Contains(op) || op.StartsWith(player.Room.OpPrefix)))
|
||||
{
|
||||
|
||||
// if we aren't handling a command here, just send it to the player's room
|
||||
if (player.Room is not null)
|
||||
await player.Room.HandleAsync(player, op, received);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) when (e is EndOfStreamException or IOException or SocketException) { _logger.LogInformation("plid {Plid} disconnected ({Reason})", player.Id, e.GetBaseException().Message); }
|
||||
catch(Exception e)
|
||||
}
|
||||
catch (Exception e) when (e is EndOfStreamException or IOException or SocketException) { _logger.LogInformation("plid {Plid} disconnected ({Reason})", player.Id, e.GetBaseException().Message); }
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error Handling plid {Plid}", player.Id);
|
||||
}
|
||||
@ -89,7 +88,7 @@ namespace ReboundEmulator
|
||||
{
|
||||
if (player.Room is { } room) await room.LeaveAsync(player);
|
||||
}
|
||||
catch(Exception e) { _logger.LogError(e, "Cleanup Failed For plid {Plid}", player.Id); }
|
||||
catch (Exception e) { _logger.LogError(e, "Cleanup Failed For plid {Plid}", player.Id); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,10 +110,10 @@ namespace ReboundEmulator
|
||||
string rkey = logn.GetValueOrDefault("rkey", "");
|
||||
|
||||
// pick the room
|
||||
var room = !string.IsNullOrEmpty(rkey) ?
|
||||
RoomManager.Find(rkey) ??
|
||||
RoomManager.GetOrCreate(rkey, game) :
|
||||
RoomManager.GetOrCreate($"{(game == "" ? "default" : game)}_lobby", game);
|
||||
var room = !string.IsNullOrEmpty(rkey) ?
|
||||
RoomManager.Find(rkey) ??
|
||||
RoomManager.GetOrCreate(rkey, game, _logger) :
|
||||
RoomManager.GetOrCreate($"{(game == "" ? "default" : game)}_lobby", game, _logger);
|
||||
|
||||
string plid = player.Id.ToString();
|
||||
|
||||
@ -145,7 +144,7 @@ namespace ReboundEmulator
|
||||
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if(!cancellationToken.IsCancellationRequested)
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
Clients.Clear();
|
||||
Listener?.Stop();
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using Microsoft.AspNetCore.Routing.Constraints;
|
||||
using Microsoft.AspNetCore.Server.HttpSys;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace ReboundEmulator
|
||||
@ -22,7 +20,7 @@ namespace ReboundEmulator
|
||||
|
||||
var props = new Dictionary<string, string>();
|
||||
using var ms = new MemoryStream(payload);
|
||||
while(ms.Position < ms.Length)
|
||||
while (ms.Position < ms.Length)
|
||||
{
|
||||
string key = ReadJavaUtf(ms);
|
||||
string value = ReadJavaUtf(ms);
|
||||
@ -40,7 +38,7 @@ namespace ReboundEmulator
|
||||
public static async Task WriteMessageAsync(NetworkStream stream, IEnumerable<KeyValuePair<string, string>> props)
|
||||
{
|
||||
using var payload = new MemoryStream();
|
||||
foreach(var kv in props)
|
||||
foreach (var kv in props)
|
||||
{
|
||||
WriteJavaUtf(payload, kv.Key);
|
||||
WriteJavaUtf(payload, kv.Value);
|
||||
@ -141,7 +139,7 @@ namespace ReboundEmulator
|
||||
private static void WriteJavaUtf(Stream s, string str)
|
||||
{
|
||||
using var buf = new MemoryStream();
|
||||
foreach(char ch in str)
|
||||
foreach (char ch in str)
|
||||
{
|
||||
if (ch >= 0x001 && ch <= 0x007F)
|
||||
buf.WriteByte((byte)ch);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user