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 <noreply@anthropic.com>
Logs {event,uri,spin,count} per battle frame to spin-rng.ndjson, where
count is BattleManagerBase.stableRandomCount (cumulative shared-RNG draws,
read before the spin crank). Lets us compare per-turn local draw deltas
against the inbound spin to determine whether prod authors spin from
server-side simulation or it is wire-derivable bookkeeping.
- SpinProbe.cs: HarmonyPrefix on OperateReceive.StartOperate (receive,
pre-crank) and NetworkBattleSender.EmitMsg (send); stableRandomCount
read reflectively via AccessTools.
- CaptureWriter.AppendSpinProbe -> spin-rng.ndjson.
- SvSimConfig.EnableSpinProbe + Plugin.cs Config.Bind (default off).
See docs/audits/battle-node-spin-rng-model-2026-06-04.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror of the outer-repo data_dumps/ reorganization: README now points
at data_dumps/captures/ for traffic_prod.ndjson; the GachaExchangeSweep
comment naming the tradeables capture follows the same path rewrite.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Brings four feature commits onto master:
- export owned cards, decks, items; fix rupy currency key
- descend into envelope data key in user-data dump
- skip empty deck slots in user-data export
- GachaExchangeSweep over full master pack list
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces LeaderSkinPoolSweep. The old sweep drove from /pack/info's
pack_config_list (35 in-catalog packs), missing the off-catalog families
(Throwback, Rotation Select, Premium, anniversary) where the drawrates
parser still has 75 ambiguous card_id joins. The new sweep drives from
Wizard.Data.Master.CardSetNameMgr.GetList() — the full 279 client-master
pack ids — and persists a miss ledger at
BepInEx/svsim-captures/gacha-sweep-misses.json so re-runs skip known-dead
ids. Adds SweepDryRunIds for smoke-testing on a handful of ids before
committing the session to a full ~5min sweep. Capture path unchanged.
Design: docs/superpowers/specs/2026-05-30-gacha-exchange-sweep-design.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A /load/index response carries every deck slot, mostly empty placeholders;
emit only the real (non-empty) decks so the dump is a handful of decks
instead of ~100 empty slots.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WriteUserDataFromLoadIndex received the full response envelope
{ data_headers, data } but read viewer fields from the top level, so
every SafeGet missed and the dump contained only steam_id. Descend into
the inner data key first (mirrors TryExtractSpecialBattleSettings).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Calling PlayerPrefs.DeleteAll() in IdentityWipe.Execute wiped more
than the three account-keyed entries: it also took out RES_VER (the
Akamai manifest version path), the asset layer's cache-index metadata
in PlayerPrefs, language/sound prefs, and anything else CodeStage
ObscuredPrefs had stashed.
Two observable symptoms on every nuked launch against either a local
or a prod server:
- The client lost track of which asset bundles it had on disk, so
ResourceDownloader.CheckAndStartNeedDownload prompted "Do you want
to download the tutorial data? (15.8 MB)" even when the bundles
were already cached.
- After saying yes, the follow-up
ShowTutorialBgDownloadDialog prompted "Download data in background?
(497.1 MB)" for the same reason against the post-tutorial assets.
Narrow IdentityWipe to call ObscuredPrefs.DeleteKey on exactly
"UDID", "VIEWER_ID", and "SHORT_UDID" — the three keys
Cute/Certification.InitializeFileds would clear in the game itself.
Everything else in PlayerPrefs survives, the cache index stays in
sync with the on-disk bundles, and a nuked relaunch behaves like a
Steam-account switch (fresh signup, intact downloads).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Redirects shadowverse-portal.com deck-builder calls to SvSimConfig.ApplicationUrl
so the GenerateDeckCodeTask / GetDeckDataFromCodeTask URLs land on the emulator's
DeckBuilderController routes (/deck_code, /deck). Both client call sites already
pass encrypt:false to NetworkManager.Connect, so no additional encryption-side
patch is needed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Body field in traffic.ndjson / battle-traffic.ndjson is now a real nested
JSON object instead of an escaped JSON string. Parse-on-write is wrapped in
ParseBodyOrKeep with a string-fallback so a future non-JSON caller doesn't
crash the line write.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>