From d6d643ec022c145064d1c89e24f0b387e75c32af Mon Sep 17 00:00:00 2001 From: Moonbase Date: Fri, 9 Oct 2026 00:13:04 -0700 Subject: [PATCH] Rename Project To 'ReboundEmulator' Add Partial Support For Boardwalk Seaball --- Amf/Amf0.cs | 2 +- Controllers/CDLController.cs | 6 ++-- Controllers/ConfigAndAssetsController.cs | 8 ++--- Core/BowlingGame.cs | 2 +- Core/Player.cs | 9 ++++-- Core/Rooms/GameRoomAttribute.cs | 5 ++-- Core/Rooms/GameRooms/Lottso2Room.cs | 4 ++- Core/Rooms/GameRooms/SkeeballRoom.cs | 38 ++++++++++++++++++++++++ Core/Rooms/IGameRoom.cs | 3 +- Core/Rooms/Room.cs | 8 ++++- Core/Rooms/RoomManager.cs | 15 +++++++--- Core/Sessions.cs | 2 +- FlashGateway.cs | 8 ++--- Model/GamePage.cs | 2 +- NotPogo.slnx | 3 -- Program.cs | 6 ++-- NotPogo.csproj => ReboundEmulator.csproj | 0 ReboundEmulator.slnx | 3 ++ TCPGameServer.cs | 9 +++--- TCPProtocol.cs | 2 +- Views/Shared/GamePage.cshtml | 2 +- 21 files changed, 96 insertions(+), 41 deletions(-) create mode 100644 Core/Rooms/GameRooms/SkeeballRoom.cs delete mode 100644 NotPogo.slnx rename NotPogo.csproj => ReboundEmulator.csproj (100%) create mode 100644 ReboundEmulator.slnx diff --git a/Amf/Amf0.cs b/Amf/Amf0.cs index f0ccb69..47c8ae4 100644 --- a/Amf/Amf0.cs +++ b/Amf/Amf0.cs @@ -18,7 +18,7 @@ using System.Collections; using System.Reflection; using System.Text; -namespace NotPogo.Amf; +namespace ReboundEmulator.Amf; public sealed record AmfHeader(string Name, bool MustUnderstand, object? Value); public sealed record AmfMessage(string Target, string Response, object? Body); diff --git a/Controllers/CDLController.cs b/Controllers/CDLController.cs index d578b57..63a4029 100644 --- a/Controllers/CDLController.cs +++ b/Controllers/CDLController.cs @@ -1,8 +1,8 @@ using Microsoft.AspNetCore.Mvc; -using NotPogo.Core; -using NotPogo.Core.Rooms; +using ReboundEmulator.Core.Rooms; +using ReboundEmulator.Core; -namespace NotPogo.Controllers +namespace ReboundEmulator.Controllers { public class CDLController : Controller { diff --git a/Controllers/ConfigAndAssetsController.cs b/Controllers/ConfigAndAssetsController.cs index 6371cc9..0f609b5 100644 --- a/Controllers/ConfigAndAssetsController.cs +++ b/Controllers/ConfigAndAssetsController.cs @@ -1,12 +1,12 @@ using Microsoft.AspNetCore.Mvc; -using NotPogo.Core; -using NotPogo.Model; +using ReboundEmulator.Core; +using ReboundEmulator.Model; using System.IO.Compression; using System.Net; using System.Reflection.Metadata.Ecma335; using System.Text; -namespace NotPogo.Controllers +namespace ReboundEmulator.Controllers { [Route("/")] public class ConfigAndAssetsController(ILogger logger) : Controller @@ -27,7 +27,6 @@ namespace NotPogo.Controllers string appletClass, string site, string locale, - string hostedGameClass, string scrn = null!, // user will get a username assigned if screenName is not set bool isSingleApplet = true) { @@ -55,7 +54,6 @@ namespace NotPogo.Controllers Parameters = new() { { "name", game }, - { "hosted.game.class", hostedGameClass ?? "" }, { "standalone", "false" }, { "type", game }, { "config", $"client-props.jsp?game={game}" }, diff --git a/Core/BowlingGame.cs b/Core/BowlingGame.cs index 7a03a0a..1acb814 100644 --- a/Core/BowlingGame.cs +++ b/Core/BowlingGame.cs @@ -2,7 +2,7 @@ using System.Net.Sockets; using System.Reflection.Metadata.Ecma335; -namespace NotPogo.Core +namespace ReboundEmulator.Core { public class BowlingGame { diff --git a/Core/Player.cs b/Core/Player.cs index 3d8845e..6f86524 100644 --- a/Core/Player.cs +++ b/Core/Player.cs @@ -1,7 +1,8 @@ -using NotPogo.Core.Rooms; +using ReboundEmulator; +using ReboundEmulator.Core.Rooms; using System.Net.Sockets; -namespace NotPogo.Core +namespace ReboundEmulator.Core { public sealed class Player { @@ -15,6 +16,8 @@ namespace NotPogo.Core public Room? Room { get; set; } public DateTime? LastSeen { get; set; } + public ILogger? Log { get; set; } + readonly NetworkStream _stream; readonly SemaphoreSlim _writeLock = new(1, 1); @@ -27,7 +30,7 @@ namespace NotPogo.Core await SendAsync(msg); msg.TryGetValue("msg.op", out var op); - Console.WriteLine($"[GameServer] [plid {Id}] <- {op} {string.Join(" ", msg.Where(kv => kv.Key != "msg.op").Select(kv => $"{kv.Key}='{kv.Value}'"))}"); + Log?.LogInformation("[plid {Id}] -> {Op} {Msg}", Id, op, string.Join(" ", msg.Where(kv => kv.Key != "msg.op").Select(kv => $"{kv.Key}='{kv.Value}'"))); } public async Task SendAsync(Dictionary msg) diff --git a/Core/Rooms/GameRoomAttribute.cs b/Core/Rooms/GameRoomAttribute.cs index 3fcea62..d1a319e 100644 --- a/Core/Rooms/GameRoomAttribute.cs +++ b/Core/Rooms/GameRoomAttribute.cs @@ -1,8 +1,9 @@ -namespace NotPogo.Core.Rooms +namespace ReboundEmulator.Core.Rooms { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - public sealed class GameRoomAttribute(string gameCode) : Attribute + public sealed class GameRoomAttribute(string gameCode, string? opPrefix = null) : Attribute { public string GameCode { get; } = gameCode; + public string? OpPrefix { get; init; } = opPrefix; } } \ No newline at end of file diff --git a/Core/Rooms/GameRooms/Lottso2Room.cs b/Core/Rooms/GameRooms/Lottso2Room.cs index d08d566..97e410d 100644 --- a/Core/Rooms/GameRooms/Lottso2Room.cs +++ b/Core/Rooms/GameRooms/Lottso2Room.cs @@ -1,4 +1,6 @@ -namespace NotPogo.Core.Rooms.GameRooms +using ReboundEmulator; + +namespace ReboundEmulator.Core.Rooms.GameRooms { [GameRoom("lottso2")] public class Lottso2Room : IGameRoom diff --git a/Core/Rooms/GameRooms/SkeeballRoom.cs b/Core/Rooms/GameRooms/SkeeballRoom.cs new file mode 100644 index 0000000..2578337 --- /dev/null +++ b/Core/Rooms/GameRooms/SkeeballRoom.cs @@ -0,0 +1,38 @@ +namespace ReboundEmulator.Core.Rooms.GameRooms +{ + [GameRoom("seaball", "sb.")] + public class SkeeballRoom : IGameRoom + { + public Task OnGameJoinAsync(Room room, Player player) => Task.CompletedTask; + + public Task OnMessageAsync(Room room, Player player, string op, Dictionary msg) + { + return op switch + { + "sb.redy" => StartGame(room, player), + _ => Task.FromResult(false), + }; + } + + private static async Task StartGame(Room room, Player player) + { + string roundString = $"0;f;c;0;0;0;0,0,0,0,0~0,0,0,0,0~0,0,0,0,0~0,0,0,0,0~0,0,0,0,0~0~0,0,0,0,0~-~-~-~-~-~f,f,f,f,f~0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0~0,0,0,0~0,0,0,0~0,0,0,0~-~-1~0~t~0~1000,1000,1000,1000~0~0~t~-1~0~-~;-;-;-;0;0;0;{player.ScreenName};-;0;0.1~5~10~1,2,3,3,2,1~1,2,3,3,2,1~1,2,3,3,2,1~2,4,6,6,4,2~10,20,30,30,20,10~20,40,60,60,40,20~-~100~1000~500~1,2,3,4,5~100~10,20,30,40,50~200~10~50~50~500~100,200,300~200,300,500~-100,-50~100,200,300~100~1000~5~5000~-1~;"; + + await player.SendAsync(("msg.op", "sb.state"), ("gs", roundString)); + + await Task.Delay(TimeSpan.FromSeconds(15)); + + await player.SendAsync(("msg.op", "sb.prep"), ("id", "1"), ("rnd", "0"), ("mode", "0"), ("opac", "1.0"), ("dur", "5000")); + + await Task.Delay(TimeSpan.FromSeconds(5)); + + await player.SendAsync(("msg.op", "sb.play"), ("id", "1"), ("dur", "25000")); + + return true; + } + + public Task OnPlayerJoinedAsync(Room room, Player player) => Task.CompletedTask; + + public Task OnPlayerLeftAsync(Room room, Player player) => Task.CompletedTask; + } +} diff --git a/Core/Rooms/IGameRoom.cs b/Core/Rooms/IGameRoom.cs index f7b34b6..a34b5a2 100644 --- a/Core/Rooms/IGameRoom.cs +++ b/Core/Rooms/IGameRoom.cs @@ -1,7 +1,8 @@ -namespace NotPogo.Core.Rooms +namespace ReboundEmulator.Core.Rooms { public interface IGameRoom { + string? OpPrefix => null; Task OnPlayerJoinedAsync(Room room, Player player); Task OnPlayerLeftAsync(Room room, Player player); Task OnMessageAsync(Room room, Player player, string op, Dictionary msg); diff --git a/Core/Rooms/Room.cs b/Core/Rooms/Room.cs index adfc3bf..23ab372 100644 --- a/Core/Rooms/Room.cs +++ b/Core/Rooms/Room.cs @@ -1,13 +1,19 @@ using Microsoft.AspNetCore.StaticFiles; using System.Runtime.InteropServices.Marshalling; +using System.Reflection; +using ReboundEmulator.Core; -namespace NotPogo.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() + .FirstOrDefault(a => string.Equals(a.GameCode, GameCode, StringComparison.OrdinalIgnoreCase)) + ?.OpPrefix ?? GameCode + "."; public string RuleId { get; } public int SoftCapacity { get; } public int TabId { get; } diff --git a/Core/Rooms/RoomManager.cs b/Core/Rooms/RoomManager.cs index 4032a92..1190c1e 100644 --- a/Core/Rooms/RoomManager.cs +++ b/Core/Rooms/RoomManager.cs @@ -2,7 +2,7 @@ using System.Reflection; using System.Text.Json; -namespace NotPogo.Core.Rooms +namespace ReboundEmulator.Core.Rooms { public static class RoomManager { @@ -10,7 +10,7 @@ namespace NotPogo.Core.Rooms static readonly Dictionary> Factories = BuildFactories(); - public sealed record RoomDef(string Key, string Name, string Rule, int Capacity = 50); + public sealed record RoomDef(string Key, string Name, string OpCode, string Rule, int Capacity = 50); public static void LoadFromFile(string path) { @@ -44,8 +44,15 @@ namespace NotPogo.Core.Rooms return map; } - static IGameRoom CreateGame(string gameCode, string ruleId) => - Factories.TryGetValue(gameCode, out var create) ? create(ruleId) : new ChatOnlyRoom(); + 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, int softCapacity = 50, int tabId = 1) => Rooms.GetOrAdd(key, _ => new Room(key, humanName, gameCode, ruleId, softCapacity, tabId, isLive, CreateGame(gameCode, ruleId))); diff --git a/Core/Sessions.cs b/Core/Sessions.cs index b5947f6..46dfa81 100644 --- a/Core/Sessions.cs +++ b/Core/Sessions.cs @@ -3,7 +3,7 @@ using System.Collections.Concurrent; using System.Security.Cryptography; using System.Text; -namespace NotPogo.Core +namespace ReboundEmulator.Core { public sealed class Account { diff --git a/FlashGateway.cs b/FlashGateway.cs index 61eafc0..5a57db2 100644 --- a/FlashGateway.cs +++ b/FlashGateway.cs @@ -1,11 +1,9 @@ // /flashservices/gateway endpoint for roomsel.swf (com.pogo.roomsel.RoomTabs). // Register in Program.cs: app.MapFlashGateway(); -using NotPogo.Amf; +using ReboundEmulator.Core.Rooms; +using ReboundEmulator.Amf; -using NotPogo; -using NotPogo.Core.Rooms; - -namespace NotPogo; +namespace ReboundEmulator; public static class FlashGateway { diff --git a/Model/GamePage.cs b/Model/GamePage.cs index f28e36e..ae8b59c 100644 --- a/Model/GamePage.cs +++ b/Model/GamePage.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Mvc.RazorPages; -namespace NotPogo.Model +namespace ReboundEmulator.Model { public class AppletDefinition { diff --git a/NotPogo.slnx b/NotPogo.slnx deleted file mode 100644 index cab92f0..0000000 --- a/NotPogo.slnx +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Program.cs b/Program.cs index 3f9e84e..ca519c1 100644 --- a/Program.cs +++ b/Program.cs @@ -1,9 +1,9 @@ using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.FileProviders; -using NotPogo.Core; -using NotPogo.Core.Rooms; +using ReboundEmulator.Core; +using ReboundEmulator.Core.Rooms; -namespace NotPogo +namespace ReboundEmulator { public class Program { diff --git a/NotPogo.csproj b/ReboundEmulator.csproj similarity index 100% rename from NotPogo.csproj rename to ReboundEmulator.csproj diff --git a/ReboundEmulator.slnx b/ReboundEmulator.slnx new file mode 100644 index 0000000..e51ac7d --- /dev/null +++ b/ReboundEmulator.slnx @@ -0,0 +1,3 @@ + + + diff --git a/TCPGameServer.cs b/TCPGameServer.cs index 2911e3a..855419f 100644 --- a/TCPGameServer.cs +++ b/TCPGameServer.cs @@ -1,9 +1,9 @@ using System.Net.Sockets; using System.Net; -using NotPogo.Core; -using NotPogo.Core.Rooms; +using ReboundEmulator.Core; +using ReboundEmulator.Core.Rooms; -namespace NotPogo +namespace ReboundEmulator { public class TCPGameServer(ILogger logger, IConfiguration configuration) : BackgroundService { @@ -73,7 +73,7 @@ namespace NotPogo { player.LastSeen = DateTime.UtcNow; } - else if (player.Room is not null && (RoomOps.Contains(op) || op.StartsWith(player.Room.GameCode + "."))) + else if (player.Room is not null && (RoomOps.Contains(op) || op.StartsWith(player.Room.OpPrefix))) { await player.Room.HandleAsync(player, op, received); } @@ -104,6 +104,7 @@ namespace NotPogo // populate player information player.Account = accnt; player.ScreenName = accnt?.ScreenName ?? $"Guest_{player.Id}"; + player.Log = _logger; // get game code and rule id string game = logn.GetValueOrDefault("game", ""); diff --git a/TCPProtocol.cs b/TCPProtocol.cs index 03741df..fd0c4de 100644 --- a/TCPProtocol.cs +++ b/TCPProtocol.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Server.HttpSys; using System.Net.Sockets; using System.Text; -namespace NotPogo +namespace ReboundEmulator { public static class TCPProtocol { diff --git a/Views/Shared/GamePage.cshtml b/Views/Shared/GamePage.cshtml index d67d759..7d6218b 100644 --- a/Views/Shared/GamePage.cshtml +++ b/Views/Shared/GamePage.cshtml @@ -1,4 +1,4 @@ -@model NotPogo.Model.GamePage +@model ReboundEmulator.Model.GamePage