From d815bfa9946c797352ae3548e622750acf8c46cf Mon Sep 17 00:00:00 2001 From: gamer147 Date: Sat, 4 Jul 2026 18:25:28 -0400 Subject: [PATCH] fix(admin): parse mission_change_time as wire datetime string Real /load/index captures ship mission_meta.mission_change_time as a "yyyy-MM-dd HH:mm:ss" string (see FriendService.DefaultMissionChangeTime for the canonical game format) but ImportViewerRequest typed it as long? Unix seconds. The FromUnixTimeSeconds branch had never been reachable with a real capture, and any loader dump carrying mission_meta 400d the whole request. Change the DTO field to string? and parse in the controller with DateTime.TryParseExact + invariant culture (AssumeUniversal | AdjustToUniversal); unparseable values skip cleanly instead of poisoning the whole viewer import. Also fix is_received_two_pick_mission: DTO's JsonPropertyName was has_received_pick_two_mission (never matched the wire key), and the wire ships "1" /"0" strings not booleans. Rename to the actual wire key, retype to int?, controller normalizes `hrptm != 0` before assigning to the bool DB property. Co-Authored-By: Claude Opus 4.7 --- .../Controllers/AdminController.cs | 12 +++++++++--- .../Dtos/Requests/Admin/ImportViewerRequest.cs | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs b/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs index 09e7713f..488ecc7e 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs @@ -267,11 +267,17 @@ public class AdminController : SVSimController { viewer.MissionData ??= new ViewerMissionData(); if (meta.HasReceivedPickTwoMission is { } hrptm) - viewer.MissionData.HasReceivedPickTwoMission = hrptm; + viewer.MissionData.HasReceivedPickTwoMission = hrptm != 0; if (meta.MissionReceiveType is { } mrt) viewer.MissionData.MissionReceiveType = mrt; - if (meta.MissionChangeTime is { } mct) - viewer.MissionData.MissionChangeTime = DateTimeOffset.FromUnixTimeSeconds(mct).UtcDateTime; + if (meta.MissionChangeTime is { } mct + && DateTime.TryParseExact(mct, "yyyy-MM-dd HH:mm:ss", + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.AssumeUniversal | System.Globalization.DateTimeStyles.AdjustToUniversal, + out var mctParsed)) + { + viewer.MissionData.MissionChangeTime = mctParsed; + } } // Pass B: Missions + ViewerEventCounter diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Admin/ImportViewerRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Admin/ImportViewerRequest.cs index 5a562aaf..d8c2ba5a 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Admin/ImportViewerRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Admin/ImportViewerRequest.cs @@ -124,12 +124,18 @@ public class ImportStoryProgress public class ImportMissionMeta { - [JsonPropertyName("has_received_pick_two_mission")] - public bool? HasReceivedPickTwoMission { get; set; } + // Wire key is `is_received_two_pick_mission` (loader-captured verbatim from /load/index + // user_info); the field ships as a string "1"/"0" not a bool. Keep the DTO type as int? + // so binding matches; the controller normalizes to bool. + [JsonPropertyName("is_received_two_pick_mission")] + public int? HasReceivedPickTwoMission { get; set; } [JsonPropertyName("mission_receive_type")] public int? MissionReceiveType { get; set; } + // Wire ships this as a "yyyy-MM-dd HH:mm:ss" string, NOT a Unix long (see + // FriendService.DefaultMissionChangeTime for the canonical game format). Controller + // parses via DateTime.TryParseExact with invariant culture. [JsonPropertyName("mission_change_time")] - public long? MissionChangeTime { get; set; } + public string? MissionChangeTime { get; set; } }