gamer147 6426c0af77 feat(loader): GachaExchangeSweep over full master pack list
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>
2026-05-30 18:04:02 -04:00
2024-09-08 10:32:52 -04:00
2024-09-08 10:32:52 -04:00
2026-05-28 11:21:37 -04:00
2024-09-08 10:32:52 -04:00

SVSimLoader

BepInEx 5 / HarmonyX plugin injected into the Steam Shadowverse client. Two jobs:

  1. Redirect the client to a local emulated server (or a capture proxy).
  2. Observe the live client/server conversation and dump structured artifacts that feed SVSim.Bootstrap and the api-spec docs.

Built against the official Cygames build (decompiled source in Shadowverse_Code_2026-05-23/). Lives upstream of the rest of the SVSim project — everything else in the repo consumes what this plugin captures.

Quick start

  1. Install BepInEx 5 (Mono build, matching the game's bitness) into the Shadowverse game directory. Launch the game once so BepInEx generates its folder tree, then close.

  2. From this repo, build the plugin:

    cd ClientLoader/SVSimLoader
    dotnet build
    
  3. Copy SVSimLoader/bin/Debug/net46/SVSimLoader.dll<game-dir>/BepInEx/plugins/.

  4. Launch the game once to generate <game-dir>/BepInEx/config/SVSimLoader.cfg, then close.

  5. Edit the config. For local server work:

    • [Connection] ApplicationUrl = http://localhost:5148/

    That's it — DCGEngine speaks the same AES-encrypted wire format as the prod server, so the default DisableEncryption = false is correct against the local server and against any other compliant emulator. Leave DisableEncryption alone unless you're debugging the wire layer itself (see below).

    For prod capture, leave [Connection] at defaults and toggle whichever [Capture] / [Sweeps] flags you need.

  6. Launch the game. A capture session directory appears under <game-dir>/BepInEx/svsim-captures/.

Build notes

Targets net46 (Unity 5.6 / Mono). The csproj references Assembly-CSharp.dll and UnityEngine.CoreModule.dll out of SVSimLoader/lib/ — populate from a working game install if those aren't already present. No dotnet restore quirks; a plain dotnet build is enough.

Configuration

Settings live in BepInEx/config/SVSimLoader.cfg, generated on first launch. Three sections:

[Connection] — where and how to talk to the server

Key Default Purpose
ApplicationUrl prod URL Overrides CustomPreference.GetApplicationServerURL. Point at http://localhost:5148/ for the local DCGEngine.
DisableEncryption false Forces the encrypt arg on NetworkManager.Connect to false, so request/response bodies go over the wire as plain base64(msgpack(...)) instead of base64(AES(msgpack(...))). You do NOT need to enable this for any server — DCGEngine and any other compliant emulator handle the standard AES path the same way prod does. It exists for wire-format debugging: makes traffic.ndjson and proxy-side inspection readable without round-tripping through CryptAES. Leave it at false for normal use.

[Capture] — passive observe-and-record (safe to leave on)

Key Default Output file
EnableTrafficCapture true traffic.ndjson — every HTTP request + response body
EnableBattleCapture true battle-traffic.ndjson — every Socket.IO battle frame
DumpCardDB false cards.json — full card master, one-shot on load
DumpUserData false user-data.json — viewer fields from /load/index, shaped for /admin/import_viewer

[Sweeps] — active prod-API traffic (deliberate opt-in, hits prod)

Probes (one extra request) and sweeps (many) fire automatically once the gating screen loads. All responses land in traffic.ndjson via the normal capture hook.

Key Default Effect
ProbeLimitedSection false Fires /limited_story/section once on first /mypage/refresh
ProbeEventSection false Same for /event_story/section, 1s after the limited probe
SweepLeaderSkinPools false Walks every parent gacha id from /pack/info; ~18s for 35 packs
SweepMainStory false Walks every (section, chara, chapter); captures master special_battle_setting payloads. Side effect: unfinished chapters become is_skipped=true (blue "Cleared", no rewards). Use a throwaway account.
SweepLimitedStory false Same shape for limited-story sections
SweepEventStory false Same shape for event-story sections
StorySweepPacingSeconds 5.0 Seconds between requests (min 1s). 5s = ~6h for full main-story tree.
StorySectionIdFilter "" Comma-separated section IDs to scope down. Empty = sweep all. Used to resume runs that hit MAX_PASSES_PER_PAIR.

Capture output

Each game launch creates a fresh session directory:

BepInEx/svsim-captures/<yyyy-MM-dd_HH-mm-ss>_<host>/
  traffic.ndjson                 # HTTP req/resp (always, when EnableTrafficCapture)
  battle-traffic.ndjson          # Socket.IO frames
  cards.json                     # one-shot card master dump
  user-data.json                 # /admin/import_viewer-shaped viewer extract
  special-battle-settings.ndjson # deduped sbs payloads from story sweeps

The capture hook decrypts each response before writing, so traffic.ndjson is always readable JSON regardless of whether the underlying connection used AES. DisableEncryption is therefore not required to make captures inspectable; it only affects what flows over the wire itself.

The traffic_prod.ndjson checked into data_dumps/ is a curated paste of one such session, used as the seed source for SVSim.Bootstrap/Data/prod-captures/.

Code layout

SVSimLoader/
  Plugin.cs              # BepInEx entry point, Config.Bind, Harmony.PatchAll
  SvSimConfig.cs         # plain static fields populated from Config.Bind
  CaptureWriter.cs       # session dir, ndjson writers, user-data extraction
  Patches/
    UrlPatches.cs        # GetApplicationServerURL -> SvSimConfig.ApplicationUrl
    DecryptPatch.cs      # NetworkManager.Connect: optionally clear `encrypt` flag
    ExaminationPatches.cs# NetworkTask.SetResponseData: traffic-capture fan-out hub
    LeaderSkinPoolSweep.cs   # /pack/info -> /pack/get_gacha_point_rewards sweep
    StorySectionProbe.cs # /mypage/refresh -> /{limited,event}_story/section probes
    StorySweep.cs        # /*/section -> /{main,limited,event}_story/{start,finish} sweep
    DummyLogging.cs      # short-circuits LocalLog.MakeTreceLogToSend (no telemetry)
    ExceptionLogging.cs  # Unity exception/error -> BepInEx log, with last-response JSON

ExaminationPatches.SetResponseData is the central hub: every response goes through it, and it dispatches into the dump / probe / sweep modules based on URL + config. Adding a new passive extractor usually means adding one if (...EndsWith("/some/url")) { ... } block there plus a writer in CaptureWriter.

Background

Live Cygames servers shut down end of June 2026 — this plugin's main reason for existing is to capture as much server-only data (special battle settings, gacha pool composition, reward tables) as possible before then. Spec fidelity downstream depends on the artifacts it dumps. See docs/audits/ for the per-endpoint audit reports that drive what gets captured next.

Description
A BepinEx plugin for logging SV client data and traffic, alongside redirecting requests to a custom server.
Readme 4.5 MiB
Languages
C# 100%