Files
2026-10-30 23:54:07 +07:00

6.3 KiB

Currency Wars 4.6.53 protocol and pending selections

The six delta cases and their five payload messages were already present in protocol/src/protocol.pb.zig when this verification began. Their definitions were retained. No additional exports in protocol/src/root.zig were needed.

Container Field Payload Fields
MGBHKCMHDOK 424 BODGPACJIDJ 7: AFEDCLCMIPE, uint32 role config ID
CHCHAJIANIM 1506 CEHMHNJPDGC 2: packed uint32 role IDs; 12: trait ID; 13: effect ID
KFNCAIHIHCM 1991 bool SpotLight return-to-preparation state
GridFightHandleBonfireHealHpCsReq 376 OCABBNOOBJL empty message, return from SpotLight
GridFightHandleBonfireHealHpCsReq 1717 JKNGGJGFFPN 13: KGHDNKONLNH, uint32 selected role ID
GridFightTraitUpdateCsReq 606 OOBHMHFHLDA 1: KGHDNKONLNH, uint32 selected role ID

Evidence comes from the full OSBETAWin4.6.53 metadata dump and objdump -d -M intel of its GameAssembly.dll. Native addresses below are RVAs (image base 0x180000000).

  • Payload WriteTo/MergeFrom(CodedInputStream): BODGPACJIDJ 1F1CED70/1F1CEEB0; CEHMHNJPDGC 1F22D700/1F22DA50; JKNGGJGFFPN 1F972790/1F9728D0; OOBHMHFHLDA 1F072CE0/1F072E20; OCABBNOOBJL 1EF7F880/1EF7F8E0.
  • GainOtherRoleTraitPendingAction._SyncFromProto DA79590 reads case 1506, trait and effect IDs, and the role candidate list. SelectRole DA7A000 uses queued selection E3A8DC0 (1717) or local editing E3A8E90 (606).
  • GainOtherRoleTraitTraitEffect.SelectedRoleID DA7AC60 reads case 424 field 7. Candidate predicate DA7C360 accepts Front and Back placements, excluding Bench/Overcrowd. GetGainOtherRoleTraitIDs.MoveNext DAD1540 skips TraitType 2.
  • Client tables identify Apprenticeship as trait 400502, effect 4005021, effect type 34, active at one member. The persisted selection is a role config ID, not a particular owned copy's unique ID.
  • SpotLightSelectAction.ReturnPreparation DC01970 calls E3A6450, which builds case 376. GameSession update case 1991 dispatches to SpotLightManager.SyncReturnPreparation DBF9E10.

Supply Phase completion

DraftSelectAction._SyncFromProto DA20BE0 reads the outer queue position into ActionID and expects pending case 693. IAKEDFLIOFD has item list field 11, select count field 8, refresh count field 5 and refresh limit field 10. HMNMJKCHABE carries selected indexes in packed field 9.

GameSession's case 1813 at DAC1C18 calls PendingSelection.SyncFinish DB97470, which compares the supplied ID with the current action ID before finishing. BonusSummarizer.UpdateAfter DA07340 distributes source-2 initial-supply rewards.

Accepted start choices now put state/reward changes and the finishing 1813 update in one bundle, with completion after the state changes and before UpdateAfter distributes rewards. A subsequent pending choice still has its own notification. The draft regression decodes actual framed replies, asserts source 2, role grant, final completion ID 9002 and absence of another notification, then rejects a duplicate pick and verifies restored state. This ordering is covered by server tests; UI closure still needs an in-game check on the current client.

Scope

Apprenticeship initial selections, edits, stale queues, battle tallies, session effect state and settlement snapshots are connected. Native ordinary mentor traits are added once per learner; unique origins are excluded. The return-to-preparation handler emits state 1991 and completes a nonzero client action ID; it refuses to cancel an unrelated server-side pending choice. No running process or player save is modified.

SpotLight picks: how Apprenticeship is earned

No role carries trait 400502 (or any of 400102/400202/400302/400402). The only source is a SpotLight: GridFightSpotLightConfigRow.TraitID is non-zero for exactly five rows (100705 -> 400502 Apprenticeship, 100800 -> 400102, 110801 -> 400202, 100801 -> 400302, 120902 -> 400402), and the client derives the Bond from the binding (GridFightSpotLightConfig.TraitID).

Wire, read from the 4.6.53 dump and GameAssembly (RVAs):

  • Offer: pending case 1817 (SpotLightSelectAction._SyncFromProto DC00CD0). f4 IsGrant, f5 candidates {f13 SpotLight ID}, f9 TargetRoleId (role config ID), f14 IsAbandonForbidden, f2 refresh count, f7 unlimited tier, f8 refresh cost, f12 target SpotLight UID (replace flow).
  • Answer: HandlePendingAction case 263 {f1 SpotLight ID, f9 role} (Select DC01390 -> E3A61E0; SelectCandidate passes the candidate ID as f1).
  • Binding: FMBACDOFCAL {f1 role UID, f2 SpotLight UID, f9 role config ID, f11 IsLoss, f13 SpotLight ID}. Update cases 1433 and 1651 call SpotLightManager.AddOrUpdate (DBFB3F0, keyed by f2), case 166 calls Remove (DBFB520); the GameInfo section carries them in f1 (Sync DBF7610).
  • SpotLightReplace takes a SpotLight UID and spends resource GridFightS2_SpotLightReplace_Resource_ID (3); not implemented.

Server: bindings (spot_bound, 8 slots) persist with the match, feed wearerHasTrait and the battle tally, follow a role through a merge and are freed when it is sold or absorbed. spot_queue counts granted picks; each opens one selection (first unbound on-field role, up to three candidates the role suits and that are not bound elsewhere). A pick of 100705 activates Apprenticeship, so the existing mentor choice follows. Nothing in the client data says when the native server grants a pick, so none is granted by default; gridfight.json "spotlight_picks": N (max 4) queues N at match start.

Still open: the native grant rule, the Replace RPC, candidate refresh costs, and spendable weekly credits (item.zig rebuilds the bag from custom.json materials and has no grant API; it is outside this change).

Temporary native extracts and test logs are under /tmp/cwdelta.

Verification

  • Isolated current-source Zig suite: 138 passed, zero skipped (-fstrip, Debug). Log: /tmp/cwdelta/current-spot/all-tests.log.
  • gameserver/zig build test: passed.
  • Node extractor suite: passed.
  • Final root zig build -j2: passed. Log: /tmp/cwdelta/root-build-final.log.

Concurrent optional handlers are preserved. handleRest has no dispatcher call in the permitted files; wiring those extra commands requires a separate shared file change. This does not affect the registered pending-action and trait-update handlers used for the protocol delta.