From 68b77bb9c3ef73ae43c715f11b91bbc04c106bbe Mon Sep 17 00:00:00 2001 From: Kayori Date: Sun, 6 Sep 2026 23:54:15 +0200 Subject: [PATCH] Fix PASELI recharge config crash and profile/schema mismatches - GetConfigEaChargeHandler: was declared as Handler, which made HandlerService attempt to XML-deserialize an EmptyRequest against the incoming root, crashing on every getconf call. Switched to HandlerWithoutRequest, matching every other parameterless handler (e.g. SppassOpenHandler). - ChargeMachinePlugin.DoesProfileExist: was a synchronous Func, but PluginService.DoesProfileExistAsync casts the DynamicInvoke result to Task, throwing InvalidCastException on every card inquire. Now returns Task.FromResult(true) - a PASELI profile always exists once a user is created, so this plugin never needs to report "no profile" here. - EaChargeConfigResponse: dropped the multibills/readagreement fields entirely and fixed articlelist's XML shape. A real getconf response (captured via spice2x's automap against the genuine Konami server) has neither field at all, and wraps articlelist entries in children rather than repeating sibling elements. The denomination-button limitation this was chasing turned out to be an unrelated spice2x bill-validator emulation gap (see spice2x issue #123), not anything server-side. - GetConfigEaChargeHandler: DOCMT_* article types now send an empty articledoc, matching the real server - the disclosure/agreement text is rendered client-side from a bundled asset, not delivered over the wire. Sending real text there produced a solid black screen on a real cabinet instead of the disclosure text. Claude-Session: https://claude.ai/code/session_012FiU5Qe8fbePFxraxWHSd5 --- .../ChargeMachinePlugin.cs | 2 +- .../Handlers/LA9/GetConfigEaChargeHandler.cs | 16 ++++++++---- .../Models/Response/EaChargeConfigResponse.cs | 25 ++++++++----------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/MedusaPluginChargeMachine/ChargeMachinePlugin.cs b/MedusaPluginChargeMachine/ChargeMachinePlugin.cs index e8488d7..4491610 100644 --- a/MedusaPluginChargeMachine/ChargeMachinePlugin.cs +++ b/MedusaPluginChargeMachine/ChargeMachinePlugin.cs @@ -18,7 +18,7 @@ public class ChargeMachinePlugin : IMedusaPlugin public int? MaxVer => null; public Encoding? ForcedEncoding => null; public PluginUiManifest? UiManifest => null; - public Delegate DoesProfileExist => () => false; + public Delegate DoesProfileExist => () => Task.FromResult(true); public Task OnBuilderInitialize(WebApplicationBuilder builder) => Task.CompletedTask; diff --git a/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs b/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs index 424a57b..f95ac3c 100644 --- a/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs +++ b/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs @@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore; namespace MedusaPluginChargeMachine.Handlers.LA9; -public class GetConfigEaChargeHandler(ChargeMachineDbContext db) : Handler + public class GetConfigEaChargeHandler(ChargeMachineDbContext db) : HandlerWithoutRequest { public override void Configure() { @@ -14,15 +14,23 @@ public class GetConfigEaChargeHandler(ChargeMachineDbContext db) : Handler HandleAsync(EmptyRequest _, GameModel model) + public override async Task HandleAsync(GameModel model) { var articles = await db.ArticleContents.ToListAsync(); + // Real server ("automap" capture against services.tablanbass.net) sends + // an EMPTY articledoc for every DOCMT_* type - the disclosure/agreement + // text itself is apparently rendered client-side from a bundled local + // asset, not delivered over the wire. Sending real text for DOCMT_* + // here produced a solid black content area on a real cabinet (working + // touch, live server) instead of the disclosure text, so match the + // real server's (empty) behavior instead of guessing at content. var articleList = articles .Select(a => new EaChargeConfigChargeArticleItem { ArticleType = new XrpcString(a.ArticleType.ToString()), - ArticleDoc = new XrpcString(a.ArticleDoc) + ArticleDoc = new XrpcString( + a.ArticleType.ToString().StartsWith("DOCMT_") ? "" : a.ArticleDoc) }) .ToList(); @@ -30,8 +38,6 @@ public class GetConfigEaChargeHandler(ChargeMachineDbContext db) : Handler ArticleList { get; set; } } @@ -42,7 +37,7 @@ public record EaChargeConfigChargeArticleItem { [XmlElement("articletype")] public required XrpcString ArticleType { get; set; } - + [XmlElement("articledoc")] public required XrpcString ArticleDoc { get; set; } } @@ -51,7 +46,7 @@ public record EaChargeConfigChargeDetail { [XmlElement("chargedaily")] public required XrpcInt ChargeDaily { get; set; } - + [XmlElement("chargedailylimit")] public required XrpcInt ChargeDailyLimit { get; set; } } @@ -60,7 +55,7 @@ public record EaChargeConfigChargeStatus { [XmlElement("currentcode")] public required XrpcInt CurrentCode { get; set; } - + [XmlElement("lastchargestatus")] public required XrpcInt LastChargeStatus { get; set; } }