A wiped/fresh client (NukeIdentityOnStartup, new install, or any path that clears PlayerPrefs) defaults its stored RES_VER to "00000000" per Cute/SavedataManager.GetResourceVersion. The client builds the Akamai manifest URL as dl/Manifest/<RES_VER>/<lang>/<Platform>/, and Akamai 404s the "00000000" path -> Toolbox.AssetManager.InitializeManifest fails -> the title screen shows "Connection Error / Reconnect" before any tutorial UI loads. Fix: - New ResourceConfig [ConfigSection] in SVSim.Database — single field RequiredResVer defaulting to "4670rPsPMVlRTd2" (the value prod returned in data_dumps/traffic_prod_tutorial.ndjson and was still returning at 2026-05-28 21:00 UTC). Lives in GameConfigs so it can be tuned via DB / appsettings without code edits. - ShadowverseTranslationMiddleware injects IGameConfigService and emits required_res_ver in data_headers ONLY on /check/game_start responses. NetworkTask.Parse opens a "new data is available" popup whenever required_res_ver is present and the URL is anything other than GameStartCheck (NetworkTask.cs:128-138); the suppression on game_start is what lets us silently bump PlayerPrefs["RES_VER"] before ResourceDownloader runs. - DataHeaders gains a nullable RequiredResVer field. DataWrapper.DataHeaders is now Dictionary<string, object?> instead of the typed DataHeaders POCO directly — the construction site stays type-safe (the middleware builds the typed POCO, then projects through the same STJ + ConvertJsonTreeToPlainObject pipeline that DataWrapper.Data uses) so null-valued optional fields are absent from the wire instead of being written as "key":null. Without this, MessagePack's ContractlessStandardResolver walked the typed properties and wrote required_res_ver=null on every non-game_start response, tripping the popup on every boot. - GameConfigurationJsonbTests updated to expect the 9th config section. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
55 lines
2.2 KiB
C#
55 lines
2.2 KiB
C#
using MessagePack;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Internal;
|
|
|
|
[MessagePackObject]
|
|
public class DataHeaders
|
|
{
|
|
[JsonPropertyName("short_udid")]
|
|
[Key("short_udid")]
|
|
public long ShortUdid { get; set; }
|
|
[JsonPropertyName("viewer_id")]
|
|
[Key("viewer_id")]
|
|
public long ViewerId { get; set; }
|
|
[JsonPropertyName("sid")]
|
|
[Key("sid")]
|
|
public string Sid { get; set; }
|
|
[JsonPropertyName("servertime")]
|
|
[Key("servertime")]
|
|
public long Servertime { get; set; }
|
|
[JsonPropertyName("result_code")]
|
|
[Key("result_code")]
|
|
public int ResultCode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Echoed UDID. Read by <c>SignUpTask.Parse</c> to validate response identity (client logs
|
|
/// <c>udid一致しません</c> and discards the response on mismatch); ignored by every other
|
|
/// client task. Always set by <c>ShadowverseTranslationMiddleware</c> from the request's
|
|
/// resolved UDID — never from controller state. Empty string when the SID→UDID lookup misses
|
|
/// (request without UDID/SID headers).
|
|
/// </summary>
|
|
[JsonPropertyName("udid")]
|
|
[Key("udid")]
|
|
public string Udid { get; set; } = "";
|
|
|
|
/// <summary>
|
|
/// Tells the client the required version path component for asset manifests on the
|
|
/// resource server (Akamai CDN, hardcoded to <c>shadowverse.akamaized.net/</c> in
|
|
/// <c>Wizard/SetUp.cs:48</c>). <c>NetworkTask.setResourceVersion</c> writes the value
|
|
/// to <c>PlayerPrefs["RES_VER"]</c>; the manifest URL becomes
|
|
/// <c>dl/Manifest/<RES_VER>/<lang>/<Platform>/</c>. When the client
|
|
/// has no cached <c>RES_VER</c> (e.g., after <c>NukeIdentityOnStartup</c> wipes
|
|
/// PlayerPrefs), it defaults to <c>"00000000"</c>, which Akamai doesn't serve — the
|
|
/// manifest fetch 404s and the client shows "Connection Error / Reconnect" before
|
|
/// the tutorial UI ever appears.
|
|
/// <para>
|
|
/// Nullable to keep it off the wire on responses that don't need it (the global
|
|
/// <c>WhenWritingNull</c> policy in Program.cs handles the omission).
|
|
/// </para>
|
|
/// </summary>
|
|
[JsonPropertyName("required_res_ver")]
|
|
[Key("required_res_ver")]
|
|
public string? RequiredResVer { get; set; }
|
|
}
|