From b544f0f9eb152065172e3040392733232f47d657 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Thu, 11 Jun 2026 11:44:40 -0400 Subject: [PATCH] feat(loader): Connection.ResourceUrl patch for GetResourceServerURL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Harmony prefix on CustomPreference.GetResourceServerURL mirroring the existing GetApplicationServerURL pattern, gated on a new BepInEx config key Connection.ResourceUrl. Default mirrors prod (https://shadowverse.akamaized.net/) so the patch is functionally a no-op until the user opts in. To redirect at a local SVSim.ContentServer (typically on :5149 per the project's launchSettings), set: [Connection] ResourceUrl = http://localhost:5149/ The stock client composes manifest / asset-bundle / sound / movie URLs as GetResourceServerURL() + "dl/Manifest/{resVer}/{lang}/{plat}/..." (and similar for Resource/, Sound/) — the trailing slash on the returned host is load-bearing. Sidestepping the scheme accessor (GetCDNScheme) is intentional: we supply the full URL with scheme ourselves, the same shape the ApplicationUrl patch returns. Co-Authored-By: Claude Opus 4.7 --- SVSimLoader/Patches/UrlPatches.cs | 24 ++++++++++++++++++++++++ SVSimLoader/Plugin.cs | 7 +++++++ SVSimLoader/SvSimConfig.cs | 1 + 3 files changed, 32 insertions(+) diff --git a/SVSimLoader/Patches/UrlPatches.cs b/SVSimLoader/Patches/UrlPatches.cs index 511c6b0..08f8d63 100644 --- a/SVSimLoader/Patches/UrlPatches.cs +++ b/SVSimLoader/Patches/UrlPatches.cs @@ -30,4 +30,28 @@ public static class UrlPatches __result = SvSimConfig.ApplicationUrl; return false; } + + /// + /// Redirects the asset CDN ("resource server" — #3 of the 4-server topology, shadowverse. + /// akamaized.net in prod) to a configured URL, typically a local SVSim.ContentServer. The + /// stock client composes manifest / asset-bundle / sound / movie URLs as + /// GetResourceServerURL() + "dl/Manifest/{resVer}/{lang}/{plat}/..." (and similar + /// for Resource/, Sound/), so this prefix needs to return the bare host root WITH a + /// trailing slash. Stock GetResourceServerURL returns GetCDNScheme() + + /// _resourceServerUrl — we sidestep both the scheme accessor and the stored host by + /// supplying the full URL ourselves. + /// + /// Default value mirrors prod so this patch is functionally a no-op until the user opts + /// in by changing the BepInEx config. To point at a local content server populated by + /// data_dumps/scripts/content_cdn_mirror.py, set + /// Connection.ResourceUrl=http://localhost:5149/. + /// + /// + [HarmonyPatch(typeof(CustomPreference), nameof(CustomPreference.GetResourceServerURL))] + [HarmonyPrefix] + public static bool GetResourceServerURL(ref string __result) + { + __result = SvSimConfig.ResourceUrl; + return false; + } } \ No newline at end of file diff --git a/SVSimLoader/Plugin.cs b/SVSimLoader/Plugin.cs index 0d5a75d..ce49bd5 100644 --- a/SVSimLoader/Plugin.cs +++ b/SVSimLoader/Plugin.cs @@ -13,6 +13,7 @@ namespace SVSimLoader internal static ManualLogSource Log; public static Plugin Instance { get; private set; } private ConfigEntry _applicationUrl; + private ConfigEntry _resourceUrl; private ConfigEntry _disableEncryption; private void Awake() { @@ -22,6 +23,10 @@ namespace SVSimLoader Logger.LogInfo($"Plugin {PluginInfo.PLUGIN_GUID} is loaded!"); _applicationUrl = Config.Bind("Connection", "ApplicationUrl", "https://utoongaize.shadowverse.jp/shadowverse/", "The URL to the application server."); + _resourceUrl = Config.Bind("Connection", "ResourceUrl", "https://shadowverse.akamaized.net/", + "The URL to the asset CDN (resource server #3). Must end with a trailing slash. " + + "Default points at the prod Akamai CDN — change to e.g. http://localhost:5149/ to redirect " + + "to a local SVSim.ContentServer populated by data_dumps/scripts/content_cdn_mirror.py."); _disableEncryption = Config.Bind("Connection", "DisableEncryption", false, "Whether to disable encrypting HTTP requests"); SvSimConfig.EnableTrafficCapture = @@ -70,6 +75,7 @@ namespace SVSimLoader Config.Bind("Identity", "NukeIdentityOnStartup", false, "On plugin Awake (before the game reads PlayerPrefs), wipe all PlayerPrefs via PlayerPrefs.DeleteAll(). Clears the obscured UDID/VIEWER_ID/SHORT_UDID keys that Cute.Certification reads on login, so the next launch behaves like a brand-new install and re-runs SignUpTask. Use this when switching Steam accounts gives a linking error. SIDE EFFECT: also resets language/sound/RES_VER prefs — they're rebuilt from defaults next boot. Recovery files and capture sessions are NOT touched.").Value; SvSimConfig.ApplicationUrl = _applicationUrl.Value; + SvSimConfig.ResourceUrl = _resourceUrl.Value; SvSimConfig.DisableEncryption = _disableEncryption.Value; if (SvSimConfig.NukeIdentityOnStartup) { @@ -79,6 +85,7 @@ namespace SVSimLoader CaptureWriter.Initialize(); Logger.LogInfo($"Capture session directory: {CaptureWriter.SessionDirectory}"); Logger.LogInfo($"Connecting to application server at {_applicationUrl.Value}"); + Logger.LogInfo($"Fetching assets from resource server at {_resourceUrl.Value}"); ExceptionLogging.Install(); var harmony = new Harmony(PluginInfo.PLUGIN_GUID); harmony.PatchAll(Assembly.GetExecutingAssembly()); diff --git a/SVSimLoader/SvSimConfig.cs b/SVSimLoader/SvSimConfig.cs index a0804af..b6298f9 100644 --- a/SVSimLoader/SvSimConfig.cs +++ b/SVSimLoader/SvSimConfig.cs @@ -3,6 +3,7 @@ namespace SVSimLoader; public static class SvSimConfig { public static string ApplicationUrl { get; set; } + public static string ResourceUrl { get; set; } public static bool DisableEncryption { get; set; } public static bool DumpCardDB { get; set; } public static bool EnableTrafficCapture { get; set; }