Update GaCy-GO

This commit is contained in:
CAtlas0784 committed 2026-10-28 18:54:43 +07:00
1 parent da8a32f60d
commit 0cbe460e49
345 files changed
+98202 -77559

No files matched your search

+101
View File
@@ -0,0 +1,101 @@
# FFGO CW reference inspection — 2026-10-26
## Artifact identity and scope
The explicitly selected updated FFGO executable was inspected as a local,
read-only reference. It was not started, connected to the game, or allowed to
modify a player save.
- SHA-256: `235f5c3567f281cc99613ed84694ef23f492c15298dc868a8e78e6529f0cda86`.
- Embedded revision: `440df54730ba64935e9ad7ecae9147e55ad279a9`.
- Embedded build time: `2026-10-26T02:49:04Z`; Go build metadata: `go1.27.3`.
- Embedded metadata is reference evidence, not proof of official Client data
or runtime feature completeness.
## Reproducible dumps
All paths below are relative to the repository. Machine-specific installation
paths are supplied to tools as arguments and are not built into source.
`battle_diagnostics/ffgo-20261026/` contains:
| Artifact | Contents |
|---|---|
| `cmdids.json` | 2,860 named command enum entries extracted from the complete embedded protocol descriptor |
| `starrail.descriptor.pb` / `.json` | 4,939 top-level messages and 472 enums, including field numbers, types and oneofs |
| `gridfight_excel.descriptor.pb` / `.json` | 75 generated Excel schema messages |
| `functions.json` | 78,891 compiled Go function names, addresses and sizes recovered from pclntab |
| `gridfight-workflow.json` | Selected compiled functions, disassembly and direct-call references; includes generated protobuf/resource functions |
| `cw-handlers.json` | 37 named CW entry handlers and their direct calls; the service contains 1,469 compiled functions |
| `cw-command-comparison.json` | 109 CW commands compared with the repository command-name table and compiled message schemas |
| `cw-message-mapping.json` | Exact recursive wire-shape matches, with explicit limitations |
| `gridfight-excel-data.json` | Complete extracted CW tables; reward pools, basic bonuses, bonfire events/options, routes and Orbs |
| `gridfight-custom-data.json` | FFGO-authored declarative rules; these are implementation recipes, not original Client JSON |
| `resource-manifest.json` | Embedded blob offsets, compressed/uncompressed hashes and extraction provenance |
| `challenge_peak_extra_data.json` | Explicit adventure NPC/entrance/group mappings for 44 AA stages |
Tools:
```powershell
python tools/dump_go_workflow.py --binary <reference-exe> --output <dump-directory>
python tools/dump_embedded_proto.py --binary <reference-exe> --descriptor proto/starrail.proto --output <dump-directory>
python tools/dump_embedded_proto.py --binary <reference-exe> --descriptor proto/gridfight_excel.proto --output <dump-directory>
python tools/export_ffgo_embedded_resources.py --binary <reference-exe> --output <dump-directory>
protoc --proto_path=. --descriptor_set_out=<current-descriptors.pb> protocol/proto/StarRail.proto protocol/proto/current_handlers.proto
python tools/compare_cw_reference_protocol.py --reference <starrail.descriptor.pb> --current <current-descriptors.pb> --commands protocol/proto/upstream_cmdids.go --output <dump-directory>
```
## Protocol compatibility
Of the 109 CW command entries, 60 have the same current name. The remaining
49 include renamed and obfuscated messages; numerical agreement alone does
not establish compatibility. Recursive comparison finds 83 exact message
wire shapes and 26 differences. In particular, large GetData, PendingAction,
SyncUpdate and battle messages must not be copied wholesale from FFGO.
Matching checks field numbers, scalar/message types, repeated cardinality and
oneof partitions recursively. It does not establish enum meanings, business
semantics or Client success. No numeric aliases or extra response IDs are
registered by these dump tools.
Confirmed Orb comparison leads:
- FFGO `GridFightUseOrbCsReq` corresponds to current `IKMOCJBMGOJ`, with
repeated UID field 4 and `is_get_all` field 9.
- FFGO `GridFightUseOrbScRsp` corresponds to current `PNHDGCBLPGD`, uint32
retcode field 3.
- The notification's nested drop structure differs. Do not forward the FFGO
notification bytes to the current Client without translating that structure.
## Workflow findings
The updated reference contains real EnterBonfire implementation, unlike the
previously inspected reference. `OnGridFightEnterBonfireCsReq` at RVA
`0xc697e0` calls `gfBonfireEnter` (`0xc69940`), sends the state update before
acknowledgement, and saves the changed state. The pending queue can resend an
existing bonfire action or construct a type-11 action from the node's event
list. Event options, reward resolution and subsequent selection are separate
operations; retcode-only success cannot create the menu by itself.
Current route 2801's event `10200601` has an FFGO custom option involving the
`PetPalStarDown` rule. A working implementation must retain and apply the
effect; consuming the choice as a no-op would be incorrect.
The extracted reference player is on route 1800. Its node list, positions,
inventory and progress are not imported into this server's route-2801 save.
## AA recovery
The embedded mapping identifies Peak 204 as NPC `4015010`, entrance `3013701`,
maze group `10`. Our old configuration used NPC `4015011`, entrance `3013501`,
group `8`, and the actual Client rejected that NPC during scene creation.
The explicit mapping is now preserved in an editable resource with reference
provenance. See `aa-scene-npc-recovery.md` for validation and Client acceptance
status. Battle wave IDs and buffs are not replaced with adventure NPC IDs.
## Completion boundary
Extraction and source compilation do not prove CW, AA or a newly ported rule
works in the Client. FFGO itself declares partial/unimplemented/battle-only
recipes. Newly extracted schemas and recipes are leads to implement and
verify, not a claim that all modes are now complete.
+142
View File
@@ -0,0 +1,142 @@
# Native per-character Warp adapter
## Current Client observation
The enabled presentation configures 76 five-star banners, including collaboration characters. Sending all synthetic IDs in the native `GetGachaInfo` response caused `GachaModule._CmdGetGachaInfoScRsp` to throw in the running Client. The server now respects `mapped_banner_preview_count` (currently zero) even when presentation is enabled; the adapter registers mapped pools separately. The user confirmed Warp opens again, and the Client logged `PAGE_BIND ready=76 configured=76`. This confirms pool binding, not successful draws or a finished visual layout. Earlier release-gate notes below describe historical checkpoints, not current policy.
## Incremental projection, 2026-10-27
Early opening could previously freeze the native collections after only a few
of the configured banners had registered, leaving the remainder invisible until
the page closed. The adapter now registers at most two configured models per
tick and adds at most one missing tab per tick while Warp is open. It checks the
page's existing group objects before appending and does not call the native
`_refresh` or select another tab. The latter resets selection.
The append sequence follows the single-pool branch of the current Client's
`GachaMainPage._create_pools_panel`: load prefab, create/bind panel, set its pool
and timeout callback, add it to TabControl, then set up its group button. The
new content root is inactive until selected. The exact current baked modules
were captured read-only; `Ui.Component.TabControl.add_item_created` does not
reference the current selection field. Existing page arrays track the panel for
normal disposal. If the native add operation partially fails, there is no proven
individual-button removal API; `PAGE_APPEND_ERROR` reports the tracked failure,
and normal page disposal cleans it. Failure to load one supporting four-star
portrait leaves the other content visible. Registration failures retry on a
later bounded pass rather than permanently suppressing a banner.
This does not replace the native page's initial `_create_pools_panel` lifecycle:
if all pools are already registered before the page opens, that native function
may still instantiate those panels synchronously. The new incremental path,
its rollback behavior, selection preservation and performance need Client
confirmation; Lua parsing alone does not establish those outcomes. Experimental
loader scripts have been removed from `scripts/` and Frida detached.
## Client rank/item coverage — 2026-10-27
The captured `AvatarConfig.json` and current imported roster contain 76
five-star avatars. Five had previously been excluded because the older external
Eidolon resource did not contain their rank rows. Read-only, bounded lookups of
the exact `AvatarRankConfigExcelTable.GetData` rows for those avatars' captured
`RankIDList` yielded 30/30 rows and their `UnlockCost`; the five distinct cost
items were independently retrieved from the current Client's `ItemHelper` and
their ItemRows verified. The companion asset audit also found each avatar's head
icon, draw-card splash and result image, and a matching avatar ItemData.
`tools/merge_captured_eidolon.py` joins the captured IDs to AvatarConfig, checks
all six ranks and cost ItemRows, records capture hashes and preserves existing
Eidolon entries. The stable-ID generator then retained all 94 earlier identities
and added five; all 76 imported five-star avatars now have an active mapping.
The custom IDs remain sandbox identifiers, not official banner IDs. These
changes did not alter a player's save, inventory, rank, EX state or pity.
Evidence is retained in private `battle_diagnostics/` capture logs; the SHA256
digests and captured Client identity are recorded in `EidolonConfig.json`.
The five added banner entries still need native Client registration and draw
confirmation after the integrated build is deployed. First acquisition of an
avatar absent from the imported roster remains outside this sandbox flow.
## Current status — supersedes historical gate notes below
The enabled implementation was built and deployed on 2026-10-25. The Client
registered all 71 eligible rarity-five character banners. The user confirmed
the prototype's splash art and native panel placement after the opaque overlay
was removed. The implementation reuses the generic installed prefab and changes
only its owned content; these are custom banners, not restored official assets.
The latest source adds three featured four-star portraits, saved pity labels
and the user's requested hard guarantees: featured five-star by 80 pulls and
four-star-or-higher by 10 pulls. Shared limited pity and inventory awards commit
atomically. Three-star Light Cones come from the captured rarity catalog.
The three four-star companions rotate over the imported rarity-four roster;
they are sandbox lineups, not captured official banner companions. Base rates
are configurable sandbox defaults and are not represented as captured Beta odds.
The 94 stable mappings consist of 71 advertised rarity-five banners and 23
reserved rarity-four mappings. Five avatars lack the required Eidolon
conversion config. Registration is confirmed in Client logs; latest portrait
layout, draw results/pity persistence, and entering/exiting every new banner
have not been confirmed after the latest deployment. AA loading repair is the
current gameplay blocker. No tests were added or run for this continuation.
The sections below retain earlier audit checkpoints. Their OFF gate and
unproven ItemHelper notes describe those earlier states, not the current policy.
## Confirmed foundation
The previous uninitialized-pool approach is superseded. On 2026-10-25 the initialized `StandardGachaPoolData` / Row / SingleDrawData / MultiDrawData clone was registered through `_GachaPoolDatasThisVersion` and the native `_AddGachaPoolDataToGroupDict` using the five-argument reflection Invoke overload with boxed BindingFlags. The Client reported `pool=900001 pools=3 groups=3`.
Evidence: `battle_diagnostics/runtime-continuation-metadata-20261025.log`, `[GAC_GACHA_CLONE_REGISTER]`. Registration proves native lookup/group creation, not correct artwork or draws.
## Implementation
- `internal/gameserver/gacha_presentation.go` validates a policy-selected installed generic template and builds the presentation payload from the stable banner mapping and `AvatarConfig.json`.
- `internal/gameserver/gacha_presentation.lua` is embedded behind the policy, outside `scripts/`. It clones initialized models, assigns the mapped avatar's runtime `AvatarName`, uses the configured avatar icon, registers native single-pool groups, and hooks only the custom tab's content rendering.
- The new card uses `AvatarCutinFrontImgPath`. `AvatarCutinImgPath` denotes a different asset family; do not derive a DrawCard path from that field.
- Art loading uses the native BasePanel `_async_load_sprite_to` helper captured in `.runtime/named-baked-capture/gacha-avatar-panel.json`.
- The opaque card is local to the mapped tab's known `node_content` binder. It does not hide a global Canvas, world camera, phone menu or HUD.
- Registration and installed-asset checks are bounded to two entries per render interval. Actual native group keys are retained for rollback; no group-ID arithmetic or invented enum is used.
- Turning the policy off removes owned clone references after Warp closes. A currently open custom card is not removed mid-draw.
- The same mapping is accepted by `DoGacha`; when native presentation is enabled, `GetGachaInfo` advertises the full active mapping as well.
## Current release gate
`resources/GachaSandboxPolicy.json` has `native_presentation.enabled=false`. Do not turn it on solely because the Go binary compiles. Verify the single-banner card's constructor/binder, displayed avatar art/name and draw 1/10 behavior in the Client first. No tests were added or run.
There are 94 mapped avatars. Five imported avatars have no configured first Eidolon conversion and remain outside this sandbox mapping. First acquisition of an absent imported avatar is still rejected. This is a custom featured sandbox presentation, not restored official limited prefabs.
## Controlled runtime tools
`tools/build_gacha_presentation_probe.py --output <file>` renders one banner by default. It never stages a script, changes policy, or writes a save. `--limit 94 --assets-only` emits only a bounded AssetMgr.Exists capture under a separate global configuration name; it does not register pools or UI.
`tools/gacha_item_data_probe.lua` reads exact ItemData constructor and ItemHelper.GetItem metadata. The ItemHelper return type needs confirmation before relying on it as a native ItemData array element. The adapter now resolves the exact static `GetItem(UInt32)` reflection overload and rejects a return type that is not assignable to the captured native ItemData array element. It then checks the actual returned instance and ConfigID before mutating native pool collections. This is a runtime guard, not evidence that the current Client has that overload.
The staged one-banner adapter is a runtime adapter with an onBeforeRender callback. When finished, close Warp and send `_G.__GAC_GACHA_PRESENTATION={enabled=false}` to remove owned clones, then remove the staged file. A production heartbeat with the disabled policy supplies the same cleanup signal.
## Integration
The caller appends `loadGachaPresentationLua()` to PlayerHeartBeat.DownloadData, logging a presentation error without failing unrelated heartbeat callbacks. The function reads external resource policy, so an operator can disable it without replacing saves or executables.
Unknown at this checkpoint: the new card has not yet been Client-confirmed; callback failure must not be described as a working banner. Native registration is confirmed separately from presentation, asset availability, and successful draws.
## Offline adapter audit, 2026-10-25
These source changes were made without staging a probe, changing policy, running tests, rebuilding or restarting servers:
- Rendering now destroys the newly created opaque card if a later binding or sprite-request call throws. The previous path logged the exception but retained an untracked overlay. This covers synchronous setup failure; it does not prove the later asynchronous sprite request succeeds.
- Disposal explicitly destroys the owned card. No global Canvas, camera or unrelated page object is touched.
- Rendering hooks match the exact owned pool instance as well as its configured ID. A foreign extension's pool with the same ID must not be repainted as this adapter's character.
- Each hook captures its original callback locally. Replacing the mutable originals table on a later policy revision can no longer make a retained older wrapper delegate recursively into a newer wrapper.
- Native pool/group collections are frozen while the Warp page is open. Configuration changes, disabling, and registration reconciliation wait for the page to close; the selected pool is not removed during a draw.
- A new configuration digest removes the previous owned projection before installing a replacement. Cleanup also removes the exact owned group from the native cached group list and clears a selected-pool cache only when it refers to the removed clone. It does not remove unrelated groups or derive native group keys.
- Re-registration after a native GetInfo refresh removes that banner's stale owned references before creating its replacement. Registration rollback also removes newly created cached group entries.
- The Go payload and controlled-probe builder include the adapter source in the digest. A new server executable with unchanged banner data can therefore replace its older owned hooks after Warp closes, instead of keeping old closures for the whole Client process.
The release gate remains **OFF**. Still required before enabling:
1. Current-process evidence for `ItemHelper.GetItem(UInt32)` and the actual returned ItemData; old MethodHandles and native addresses are invalid after a Client restart.
2. One-banner card proof for `node_content`, text cloning/SafeSetTextID and the `_async_load_sprite_to(image,path)` call, including successful asynchronous art completion. A bytecode call site or `ART_REQUESTED` log alone does not prove the image appeared.
3. Native response/refresh lifecycle proof: synthetic IDs can be skipped before original pool construction, and the custom registration must remain consistent when GetGachaInfo refreshes the module. Merely registering an initialized clone once is not evidence for every refresh.
4. Draw 1/10 result/display behavior with the mapped avatar and configured duplicate materials, plus close/reopen behavior. No assertion of Client success should be made from compilation or native registration alone.
Current source has not been compiled or Client-exercised after this offline audit. All custom banner IDs remain the explicit resource-backed sandbox mapping; no additional game IDs, asset paths or group enum values were invented.
+136
View File
@@ -0,0 +1,136 @@
# ชุดข้อมูล Client Beta สำหรับ GLM
อัปเดต 24 ตุลาคม 2026 (Asia/Bangkok)
## เริ่มอ่านตรงนี้
ผู้ใช้ขอให้ช่วยหา event ของ Beta ที่ใช้จริง และส่งข้อมูลที่มีพร้อมวิธีเพิ่มตู้กาชาให้ GLM งานนี้จึงจัดทำ **ดัชนีและชุดส่งต่อข้อมูล** ไม่ได้เปิด event เพิ่ม เปลี่ยน backend หรือรีสตาร์ตเซิร์ฟเวอร์
- [ข้อมูลกิจกรรมและวิธีเชื่อม schedule](GLM-BETA-EVENTS.md)
- [ข้อมูลและวิธีเพิ่มตู้กาชา](GLM-GACHA-GUIDE.md)
- [งานค้าง/ข้อกำหนดเดิม](ZCODE-HANDOFF.md)
### ไฟล์ชุดส่งต่อ
- โฟลเดอร์: [glm-beta-handoff-20261024](../.runtime/glm-beta-handoff-20261024/)
- ZIP: [glm-beta-handoff-20261024.zip](../.runtime/glm-beta-handoff-20261024.zip)
- [manifest.json](../.runtime/glm-beta-handoff-20261024/manifest.json): รายการทุกไฟล์ในชุด พร้อม SHA-256 ขนาด ที่มา และขอบเขตการยืนยัน
- [event-index.json](../.runtime/glm-beta-handoff-20261024/derived/event-index.json) / [CSV](../.runtime/glm-beta-handoff-20261024/derived/event-index.csv)
- [preview-schedules.json](../.runtime/glm-beta-handoff-20261024/derived/preview-schedules.json)
- [gacha-index.json](../.runtime/glm-beta-handoff-20261024/derived/gacha-index.json)
`.runtime/` ถูก ignore ถ้า GLM อยู่คนละเครื่องต้องส่ง ZIP ให้ด้วย การส่งเฉพาะ Git diff จะไม่มีชุดข้อมูลและ evidence เหล่านี้
## 1. รุ่นและขอบเขต
ตรวจโปรเซสที่รันจริงและ hash `GameAssembly.dll` ซ้ำในรอบนี้แล้ว Client ปัจจุบันเป็น Beta .54:
```text
4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6
```
ข้อมูล CW เดิมหลายชุดมาจาก Beta .53:
```text
c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144
```
**ชุดนี้รวมข้อมูลที่มีอยู่ในโปรเจกต์และ capture ที่ระบุที่มาได้ ไม่ใช่การ dump ทุกตาราง/ทุก asset/ทุก script จาก Beta ทั้งเกมครบแล้ว** ไฟล์ที่ไม่มี provenance ไม่ถูกเปลี่ยนชื่อหรือรับรองเป็น .54 เนื่องจากวางอยู่ในโปรเจกต์เดียวกัน
ข้อมูลดิบถูกคัดลอกเป็น bytes เดิม Python ใช้ integer ที่ไม่เสียความละเอียดในการสร้างดัชนี จึงเก็บ `hash64` ได้ตรง ห้าม parse/re-serialize TextID hash64 ผ่าน JavaScript `Number` โดยไม่ใช้วิธีรักษาเลข 64-bit
## 2. ข้อมูลที่ตรงกับ capture ของ Client .54
| ชุด | จำนวน/ขอบเขต | ไฟล์ต้นทาง |
| --- | --- | --- |
| ActivityPanelRow | 181 หน้า รวม condition, prefab, icon, TextID และ display items | `resources/PreviewGameplayCatalog.json` → `tables.panels` |
| ActivityConfigRow | 361 รายการ รวม module/resident/panel/early-access mapping | ไฟล์เดียวกัน → `tables.activities` |
| GachaBasicInfoConfigRow | 6 แถวของตารางปัจจุบัน | ไฟล์เดียวกัน → `tables.gacha` |
| ParkourLevelConfigRow | 13 แถว; ไม่ใช่ Stella Jump ด้านข้าง | ไฟล์เดียวกัน → `tables.parkour` |
| ChenLingGameBoyCaseRow | 16 cases | `resources/StellaJumpConfig.json` |
| CW role flat config | 140 rows; ไม่ใช่ทุกตารางของ CW | `resources/CurrencyWarsCurrentRoles.json` |
| Event asset observations | 290 prefab/icon paths; 146/181 panels มีทั้งสอง path | `resources/PreviewAssetAvailability.json` |
| GachaGroupDataRow | ดึง flat GetAll จบครบ **0 แถว** ในรอบนี้ | `battle_diagnostics/glm-gacha-groups-current.json` |
| Group presentation asset observations | 3 path จาก Lua จริง ตรวจแล้วไม่มีทั้ง 3 | `battle_diagnostics/glm-gacha-group-assets.json` |
CW role compatibility .53→.54 แยกอยู่ใน `resources/CurrencyWarsRoleCompatibility.json` เป็น overlay หนึ่ง family/สาม star variants ไม่ใช่การ recapture CW ทั้งหมด
### ระวัง ActivityConfig ชื่อคล้ายกัน
`resources/ActivityConfig.json` เดิมมี 360 รายการและไม่มี provenance .54 ของตัวเอง ส่วน `PreviewGameplayCatalog.json.tables.activities` มี 361 รายการที่ capture ตรงรุ่น
เปรียบเทียบ key ได้ว่าใน capture ปัจจุบันมี ActivityID `10196`, `50157` เพิ่ม และไม่มี `50136` ที่อยู่ในไฟล์เดิม ใน ID ร่วมกัน main/resident module lists ตรงกันจากการเทียบครั้งนี้ แต่ไม่ได้ทำให้ไฟล์เก่ากลายเป็น current native dump
ให้เริ่มหา event ใหม่จาก **PreviewGameplayCatalog** อย่ายึดเฉพาะ ActivityConfig เดิมหรือค้น type ที่เดาชื่อแล้วสรุปว่าไม่มีข้อมูล
## 3. Event ที่หาเจอแล้ว
ตัวอย่างด้านล่างใช้ **ชื่อเทคนิคจาก prefab** ยังไม่ใช่ localized title ที่ถอดแล้ว และไม่ได้พิสูจน์ว่าเป็น official active schedule ของวันนี้
| Panel | ระบบ/Prefab | Main modules | Resident modules | Prefab + icon |
| ---: | --- | --- | --- | --- |
| 50132 | QuestMechCraftPanel | 5013201 | 5013202 | มี |
| 50142 | QuestComicDessertPanel | 5014201 | 5014202 | มี |
| 50143 | QuestRealityShowPanel | 5014301–5014305 | 5014311–5014315 | มี |
| 50125 | QuestFinalityBattlePanel | 5012501–5012505 | — | มี |
| 50114 | QuestTeamTowerPanel | 5011401 | 5011402 | มี |
| 50112 | QuestPixAirPanel | 5011201 | 5011202 | มี |
| 50111 | QuestB51RacingPanel | 5011101 | 5011102 | มี |
| 50107 | QuestChenLingFesPanel | 5010701 | — | มี |
| 50092 | QuestChenLingBattlePanel | 5009201 | 5009202 | มี |
| 50134 | QuestBlindBoxPanel | ดู raw mapping | ดู raw mapping | prefab ไม่มี |
Source ปัจจุบันเปิดเพียง policy-selected families และตัดหน้าที่มี dependencies/handler ยังไม่ครบ จึงต่างจาก “Beta ไม่มี event” รายละเอียดและแนวทางต่อ callback อยู่ใน `GLM-BETA-EVENTS.md`
จุดเชื่อมสำคัญ: ใน wire `ActivityScheduleData.ActivityId` ใช้ **moduleID** ส่วน `PanelId` ใช้ **panelID** ห้ามนำ ActivityConfig.ActivityID ใส่แทน moduleID โดยไม่ตรวจ
## 4. ข้อมูลเก่าและข้อมูลที่ยังไม่ยืนยัน revision
ชุด ZIP รวม resources ทั้งหมดที่มีและไฟล์ข้อมูล root ที่เกี่ยวข้อง โดยแยก provenance ไว้ใน manifest:
- CW .53/reference: divisions/routes/role defaults/variants/camps/levels/equipment/spotlights/monster recipes/rewards/craft/initial runs/node transitions/trials
- .53-identified scene, navigation, cosmetics, technique/world-battle resources
- External data: Eidolon/Inventory จาก Dimbreath, BattleRules/Profile จาก PearlSR, ทีม Prydwen, AhaHelp จากภาพที่ผู้ใช้ให้ ไม่ใช่ native .54 dump
- Unversioned/server data: Avatar/SkillTree/Quest/MainMission/Stage/Map/Tutorial ฯลฯ ซึ่งห้ามรับรองว่าทุก ID ใช้ได้กับ .54
- Root `res.json` กับ `resources/res.json` เป็นคนละ schema และคนละชุด ห้ามทับหรือย้ายแทนกันเพราะชื่อเหมือนกัน
- `mission_unlocks.json` เป็นรายการที่ server เปิดให้ ไม่ใช่หลักฐานว่า Client มี config ทุก ID; ดู MissionCompatibility และ missing-config evidence ประกอบ
## 5. Protocol และเครื่องมือ
รวม `.proto`, named command maps/pairs และ source revision ไว้ใน bundle โดยไม่รวม `.pb.go` ซ้ำทั้งชุด
Command source revision ที่ใช้อยู่:
```text
005d2c12db4781071f4b5b68e8f364587886a710
```
นี่ไม่ใช่ full native protocol dump ของ .54 ทุก packet บางคำสั่งถูกตรวจซ้ำกับ Client แล้ว แต่ส่วนที่ยัง obfuscated/ไม่ตรวจต้องเก็บข้อจำกัดไว้ ใช้ name resolver ของ repository อย่าฝัง CmdID หรือส่งหลาย aliases เพื่อเดา callback
เครื่องมือที่รวมเป็น source สำหรับอ่านต่อ **ไม่ได้ถูกรันโดย packaging helper**:
- `preview_flat_tables.js`: สี่ named flat tables; ตรวจ prologue/ขอบเขต; 16 rows ต่อ managed marker
- `preview_gameboy_tables.js`: ChenLing GameBoy flat table
- `glm_beta_gacha_groups.js`: named gacha group GetAll; 8 rows ต่อ marker; เก็บกรณีตารางว่างอย่างชัดเจน
- named metadata probes และ bounded trigger ที่พักเมื่ออยู่ Battle
- `inspect_luau_v4.py` และ GachaMainPage bytecode/parsed prototypes
- static PE range/call-reference readers และ protocol tooling ที่เกี่ยวข้อง
ก่อนใช้ native tools ต้องตรวจ **process path/hash ใหม่** เพราะ PID, MethodHandle และ base address เปลี่ยนหลัง restart การอ่าน metadata ครั้งนี้พบว่า `RPG.Client.TextID` อยู่ใน assembly **RPG.GameCore.Foundation** ไม่ใช่ Assembly-CSharp; lookup ใน assembly ผิดแล้วได้ nil ไม่ได้แปลว่า type หาย
## 6. ส่งต่อให้ GLM ทำต่อ
ข้อความพร้อมใช้:
> อ่าน `docs/GLM-BETA-DATA.md`, `docs/GLM-BETA-EVENTS.md` และ `docs/GLM-GACHA-GUIDE.md` ก่อน ข้อมูล event ของ Beta มีแล้ว 181 panels/361 activities ใน PreviewGameplayCatalog ไม่ใช่ไม่มี event ให้ใช้ event-index เชื่อม panel/module/conditions/assets และต่อ named data handlers ตามแต่ละระบบ กาชามีตารางจริง 6 แถว แต่ limited 4 prefab และ generic group 3 prefab ไม่มีใน manifest; flat GachaGroupDataRow ดึงครบได้ 0 แถว จึงยังไม่มี GroupIDs ให้ใช้ อย่าเดาตัวเลขหรือเปิด path ที่ไม่มีเพื่อกลบอาการ ต้องสร้าง compatible custom presentation จาก asset ที่มีจริงและให้ผลสุ่มตรงภาพตู้ รักษาเซฟ/rank/EX/Traces และอย่ารบกวน Battle ที่กำลังเล่น อ่าน manifest เพื่อแยก .54, .53/reference, external policy และ unversioned ห้ามอ้างว่าชุดนี้เป็น dump ทุกอย่างของ Beta ครบแล้ว
สิ่งที่ยังต้องหาเพิ่ม: localized title text, config/asset dependencies และ data/proxy callbacks ของ event ใหม่, ตารางอื่นของ Client ที่ยังไม่ได้ capture, gacha presentation/binding และ semantics ของ grouping fields ที่ยัง obfuscated
## 7. ขอบเขตการทำงานรอบนี้
- อ่าน source/resource และวิเคราะห์ config/capture เพื่อส่งต่อ
- ตรวจ hash ของ module จริง และอ่าน named gacha group table/metadata กับ asset existence เฉพาะ path ที่มีหลักฐานจาก Lua
- ถอด probe ที่เพิ่มในรอบนี้แล้ว และปิด Frida sessions ของรอบนี้
- ไม่แตะ probes ของ GLM ที่มีอยู่ ไม่แก้ gameplay backend ไม่เปลี่ยนเซฟ ไม่ build/deploy/restart และไม่รัน tests
- ชุดข้อมูลไม่รวม `persistent`, `freesr-data.json`, `server.local.json`, บัญชี/token logs หรือ game binaries ของผู้ใช้
- Snapshot เป็นการอ่านไฟล์ทีละไฟล์ขณะที่มีงานอื่นทำอยู่ ไม่ใช่ atomic snapshot ของ repository ทุกไฟล์ ณ nanosecond เดียว ค่า SHA ใน manifest อ้างอิง bytes ที่คัดลอกเข้าชุดจริง
+225
View File
@@ -0,0 +1,225 @@
# ข้อมูลกิจกรรม Client Beta สำหรับ GLM
อัปเดต 24 ตุลาคม 2026 (Asia/Bangkok) — ตรวจจาก resource/capture ที่มีอยู่เท่านั้น ไม่ได้แก้ production code ไม่ส่ง probe ไม่รัน tests และไม่รีสตาร์ตเกมหรือเซิร์ฟเวอร์ในงานจัดทำเอกสารนี้
ตำแหน่งชุดข้อมูลรวมและ manifest ของไฟล์ให้ดู [GLM-BETA-DATA.md](GLM-BETA-DATA.md) ภายใน package มี:
- `derived/event-index.json` — join panel/activity/modules พร้อมเงื่อนไขและสถานะ asset/policy
- `derived/event-index.csv` — รายการสำหรับค้น/กรองได้สะดวก
- `derived/preview-schedules.json` — schedules ที่ source/policy ปัจจุบันเลือกได้
- raw `PreviewGameplayCatalog.json`, `PreviewAssetAvailability.json` และ policy ที่ใช้ทำ index
## 1. สรุปสิ่งที่พบ
**ข้อมูลกิจกรรมมีอยู่ใน Beta นี้แล้ว** การหา type ชื่อหนึ่งไม่พบ หรือหน้ากิจกรรมยังไม่แสดง ไม่ได้แปลว่าไม่มีตารางกิจกรรมใน Client
ไฟล์หลักคือ `resources/PreviewGameplayCatalog.json`:
- Client assembly SHA-256: `4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6`
- Evidence: `ev_9ea0f171c212f18ef6442f116c0bd14dd3ba08a3c583141c9bad58a5d2c7bd27`
- `panels`: **181 แถว** ของ `RPG.GameCore.ActivityPanelRow`
- `activities`: **361 แถว** ของ `RPG.GameCore.ActivityConfigRow`
- ในไฟล์เดียวกันมี Gacha 6 แถว และ Parkour 13 แถว ซึ่งเป็นคนละระบบ
นี่เป็นข้อมูลทั้งหมดของ **สี่ตารางที่ capture ชุดนั้นอ่านได้** ไม่ใช่การ extract ทุกตาราง/ทุก asset/ทุก script ของเกมทั้งชุด และไม่ใช่รายการ event ที่เปิดจริงในวันหนึ่งโดยอัตโนมัติ Client เก็บ historical/future rows ร่วมกันได้
ตารางที่ยืนยันว่ามีชื่อดังนี้:
```text
RPG.GameCore.ActivityPanelRow
RPG.GameCore.ActivityConfigRow
RPG.Client.ActivityModule
```
การ probe `RPG.GameCore.ActivityModuleRow` เคยได้ nil เพราะเป็นชื่อที่ลองหา ข้อนี้ไม่ใช่หลักฐานว่า ActivityModuleIDList หรือระบบกิจกรรมหายไป
## 2. เหตุที่กิจกรรมยังไม่แสดง
`internal/common/activity_preview.go` ปัจจุบันกรองตาม `ActivityPreviewPolicy.json` ไม่ได้ส่งทุกแถวใน Client กลับไปเสมอ
เงื่อนไขก่อนประกาศ preview คือ:
1. UIPrefab ต้องอยู่ใน policy-listed family และมี handler ที่รองรับ
2. `PreviewAssetAvailability.json` ต้องระบุว่า UIPrefab และ TabIcon มีจริงทั้งคู่
3. `DisplayItemList` ต้องว่าง เพื่อไม่กลับไป trigger missing-item/invalid-item errors ที่เคยพบ
4. module ที่ถูกอ้างโดยหลายกิจกรรมต้อง resolve เป็น prefab/handler ที่ตรงกัน ไม่มี first-match เงียบ ๆ
ผลนับจาก resource และ source ปัจจุบัน:
| รายการ | จำนวน |
| --- | ---: |
| Panel rows ทั้งหมด | 181 |
| Activity rows ทั้งหมด | 361 |
| Unique prefab/icon paths ที่เคยตรวจ | 290 |
| Panels ที่ prefab และ icon มีทั้งคู่ | 146 |
| Panels ที่ไม่มี prefab | 27 |
| Panels ที่ไม่มี icon | 30 |
| Prefab families ที่ policy อนุญาต | 19 |
| Panels ที่ผ่าน policy + assets + no display items | 56 |
| Unique preview module schedules | 121 |
| QuestState schedules | 111 |
| GetMultipleDropInfo schedules | 10 |
| Conflicting module-to-panel mappings ใน selected set | 0 |
| Activity rows ที่ไม่พบ effective panel row ใน capture นี้ | 99 |
จำนวนไม่มี prefab/ไม่มี icon มีบางแถวซ้ำกัน จึงห้ามนำ 27 กับ 30 มาบวกแล้วลบจาก 181 ตรง ๆ
146 panels ที่มี asset ครบ **ไม่ได้แปลว่าเปิดเล่นได้ 146 กิจกรรม** ยังมี reward dependencies, data proxies, entry handlers, unlock/finish checks และ state machine ของแต่ละระบบที่ต้องต่อ
## 3. รายการที่หาเจอและควรใช้เริ่มไล่ Beta features
ชื่อด้านล่างเป็น **ชื่อเทคนิคจาก UIPrefab** ไม่ใช่ชื่อภาษาอังกฤษ/ไทยที่ยืนยันแล้วจาก TextMap และเลข ID สูงไม่ได้พิสูจน์เองว่า event นั้นเปิดจริงใน Beta รอบปัจจุบัน
ทุกแถวในตารางยกเว้น BlindBox ตรวจพบทั้ง prefab และ icon ใน installed asset index แล้ว:
| Activity / Panel ID | Technical panel | ActivityModuleIDList | ResidentModuleList | EarlyAccessContentID | Asset |
| --- | --- | --- | --- | ---: | --- |
| 50132 | QuestMechCraftPanel | 5013201 | 5013202 | 150132 | prefab + icon มี |
| 50142 | QuestComicDessertPanel | 5014201 | 5014202 | 150135 | prefab + icon มี |
| 50143 | QuestRealityShowPanel | 5014301–5014305 | 5014311–5014315 | 0 | prefab + icon มี |
| 50125 | QuestFinalityBattlePanel | 5012501–5012505 | ว่าง | 0 | prefab + icon มี |
| 50114 | QuestTeamTowerPanel | 5011401 | 5011402 | 150078 | prefab + icon มี |
| 50112 | QuestPixAirPanel | 5011201 | 5011202 | 150076 | prefab + icon มี |
| 50111 | QuestB51RacingPanel | 5011101 | 5011102 | 150079 | prefab + icon มี |
| 50107 | QuestChenLingFesPanel | 5010701 | ว่าง | 150077 | prefab + icon มี |
| 50092 | QuestChenLingBattlePanel | 5009201 | 5009202 | 150074 | prefab + icon มี |
| 50134 | QuestBlindBoxPanel | 5013401 | 5013402 | 150134 | prefab ไม่มี / icon มี |
รายการนี้ยังไม่อยู่ใน selected preview families ปัจจุบัน กลุ่มที่ assets มีถูกกันไว้เพราะ DisplayItemList และ event-specific data handlers ยังไม่ครบ จึงต้องแยกจากกรณี asset ไม่มีจริง
Exact paths ของสามรายการที่มีข้อมูลใหม่ชัดเจน:
```text
UI/Quest/Widget/QuestMechCraftPanel.prefab
UI/Quest/Widget/QuestComicDessertPanel.prefab
UI/Quest/Widget/QuestRealityShowPanel.prefab
```
BlindBox แถวที่ capture ได้เก็บ path `Assets/AsbRes/UI/Quest/Widget/QuestBlindBoxPanel.prefab` ซึ่ง `AssetMgr.Exists` ให้ false อย่าเดาว่าถอด prefix หรือเปลี่ยน case แล้วจะใช้งานได้ ต้องตรวจ canonical loader/path ก่อน
### เงื่อนไขที่อยู่ในแถวจริง
| Panel | UnlockConditions | FinishConditions ที่ต้องตามต่อ |
| --- | --- | --- |
| 50132 MechCraft | `[PlayerLevel:21]` | QuestClose ของ 6088098–6088120 ทุก ID ในช่วง |
| 50142 ComicDessert | `[PlayerLevel:21]` | QuestClose ของ 6090001–6090005 และ 6090014 |
| 50143 RealityShow | `[PlayerLevel:21]` | QuestClose ของ 6091004, 6091008, 6091012, 6091016, 6091020, 6091001, 6091005, 6091009, 6091013, 6091017 |
| 50134 BlindBox | `[PlayerLevel:4]` | `[QuestClose:6089009]` |
อย่า complete quest เหล่านี้ทั้งหมดเพื่อให้หน้าเปิด เพราะบางตัวเป็น **FinishConditions** ซึ่งอาจทำให้หน้าถูกถือว่าจบหรือหายไปแทน ต้องอ่าน semantic ของ condition checker และตรงกับ state จริงก่อน
### TextID สำหรับ resolve ชื่อหน้าจอแบบ targeted
| Panel | TabName.hash | TabName.hash64 |
| --- | ---: | ---: |
| 50132 | 1880458566 | 6958762709850968366 |
| 50142 | -2011224203 | 143653261616862737 |
| 50143 | -2011224202 | 14823125606058724992 |
| 50134 | 1880458564 | 7162233255424057948 |
raw capture รักษา integer strings เดิมไว้ เลข hash64 หลายตัวเกิน exact integer range ของ JavaScript Number ห้าม parse แล้ว serialize ด้วย Number จนค่าเปลี่ยน ใช้ parser ที่รักษา int64/uint64 หรือเก็บเป็น string สำหรับ derived exports
## 4. ID mapping ของ schedule ต้องไม่สลับ
ใน `internal/gameserver/handlers_challenge.go` handler `GetActivityScheduleConfig` ส่ง:
```text
ActivityScheduleData.ActivityId = ActivityModuleID
ActivityScheduleData.PanelId = ActivityPanelID
```
ตัวอย่าง MechCraft ตาม association ที่ capture มา:
```text
ActivityConfig.ActivityID = 50132
ActivityConfig.ActivityPanelID = 50132
ActivityConfig.ActivityModuleIDList = [5013201]
ActivityConfig.ResidentModuleList = [5013202]
```
อย่าเอา `50132` ไปส่งเป็น module schedule แทน `5013201` เพียงเพราะ field ใน wire ชื่อ ActivityId การมี resident module ก็ไม่ได้พิสูจน์ว่าใช้เป็น active preview แบบเดียวกับ main module ได้ ต้องตรวจ proxy/phase behavior ของกิจกรรมนั้น
`ActivityPanelID=0` บางแถวต้อง resolve ตาม Client behavior ที่ตรวจไว้ โดย loader ปัจจุบันใช้ fallback ActivityID แต่มี 99 activities ที่ยังไม่มี panel row ให้ match ใน capture นี้ อย่าส่งทุกแถวพร้อม panel 0 หรือสร้าง panel ID ขึ้นเอง
หลาย rerun activities อ้าง module เดียวกัน เช่น module 1002101 ถูกใช้กับ panel 10021/10113 ซึ่งเป็น prefab/handler เดียวกัน ปัจจุบันรวมเหลือรายการเดียวแบบ deterministic ถ้าเปลี่ยน policy แล้วพบต่าง prefab/handler loader จะ error แทนการเลือกแถวแรก
## 5. คำตอบ/data handlers ที่มีจริง กับที่ยังไม่มี
`internal/gameserver/handlers_activity_preview.go` มี:
- `GetMultipleDropInfo`: สร้าง explicit panel entries แต่ counter เป็นศูนย์ เป็น preview ไม่ใช่แจก quota/reward เพิ่ม
- `GetActiveActivityData`: มี handler แต่ policy ปัจจุบันไม่เปิด family ที่เคยเกิด invalid-item error กลับมา
- `GetFiveDimMiniGameData`: ยังตอบ list ว่าง ไม่ใช่ implementation ของ Stella Jump/gameplay
- `QuestState`: เป็นชื่อ policy grouping ที่อาศัย quest/mission handlers เดิม ไม่ใช่ generic handler ที่ทำ MechCraft/RealityShow ทุกระบบได้
ปัจจุบันยังไม่มีการพิสูจน์ event-specific data/entry callbacks ครบสำหรับ MechCraft, ComicDessert และ RealityShow อย่าส่ง null success response หรือ advertise ก่อนรู้ว่า Client จะขอ state อะไรต่อ
ตาราง CmdID ใน `protocol/proto/upstream_cmdids.go` ระบุ:
```text
Source: https://git.xeondev.com/HonkaiSlopRail/pearl-sr protocol/src/root.zig
Revision: 005d2c12db4781071f4b5b68e8f364587886a710
```
มีชื่อชัดเจนบางระบบ เช่น `PixAirGetData`, `GetChenLingFesData`, `StartFinalityBattleLevel`, `BlindBoxGetData` แต่การมีชื่อในตารางยังไม่ใช่หลักฐานว่า handler ใช้งานครบ และ MechCraft/ComicDessert/RealityShow ยังไม่พบชื่อชัดเจนจากการค้นนี้ อาจยังใช้ obfuscated names ต้องผูกจาก sender/callback schema จริง ห้ามเดา aliases หรือใช้เลขหลาย revision
## 6. ไปหาต่อจากไหนโดยไม่สแกนทั้ง assembly
### หลักฐาน named tables ที่มีแล้ว
`tools/preview_catalog_metadata.lua` ตรวจเฉพาะชื่อ type และ `FromBinary` ของ ActivityPanelRow/ActivityConfigRow แล้วนำไปตาม flat dictionary chain
`tools/preview_flat_tables.js` มี exact getter chain ของ assembly hash ข้างต้น:
| ตาราง | GetAll RVA สำหรับ hash ที่ระบุเท่านั้น |
| --- | --- |
| ActivityPanelRow | `0x1e4ca860` |
| ActivityConfigRow | `0x1dfbc4d0` |
getter traces อยู่ใน `battle_diagnostics/preview-activity-getter.asm`, `preview-panels-getter.asm` พร้อม `preview-activity-{loader,add}.asm` และ `preview-activity-panel-{loader,add}.asm`
Capture อ่านครั้งละ 16 แถวต่อ managed marker และตรวจ bounds ก่อน serialize ไม่ต้องเรียก scene/level factory `tools/preview_capture_trigger.lua` ส่ง marker `GAC_PREVIEW_TICK` แบบจำกัดครั้งและ pause ใน Battle
**ข้อมูลถูก capture แล้ว ไม่จำเป็นต้องติด probe ซ้ำเพียงเพื่อเปิดดูตารางเดิม** หากต้องอ่านใหม่ต้องตรวจ process/module hash ใหม่ก่อน RVA เป็นของ shipped binary เฉพาะรุ่น ไม่ใช่ production constants และ MethodHandle/pointer เก่าห้ามใช้ข้าม process
### จุดเริ่ม event page/proxy
จาก named metadata ของ `RPG.Client.ActivityModule` พบ:
```text
ActivityDataDict
ActivityPanelDataContainer
CustomizedPanelDataContainer
_PanelDataProxyFactory
_PanelID2TemplateIndexLUT
_PanelTemplates
_AvailablePanelDatas
_phaseMap / _phaseList
GetActivityData(UInt32)
_OnScheduleConfigRefresh(System.Object)
```
ข้อมูลนี้ใช้เลือก inspect object/proxy ของ **panel ID เป้าหมาย** ได้ ไม่ต้อง enumerate ทุก type ใน assembly
สำหรับ panel UI ให้ตาม prefab/binder registration ของ technical name ที่ระบุข้างบน เพื่อหา exact loaded Lua module/controller ก่อน เมื่อมี module name ที่ยืนยันแล้วค่อยอ่าน named functions/upvalues หรือ loader bytes ไม่สมมติ callback ชื่อ `_refresh`/`GetData` ว่าแต่ละ panel เหมือนกันหมด
มีตัวอย่างวิธีอ่าน Luau โดยไม่ execute closure ใน `tools/gacha_load_only.lua` และ bytecode reader `tools/inspect_luau_v4.py` สำหรับ GachaMainPage ที่ทำไว้ก่อน **ใช้เป็นรูปแบบการวิเคราะห์เท่านั้น** อย่า require/reload event controller หรือใช้ package loader ของชื่อที่เดาขึ้นเองระหว่าง gameplay
## 7. ลำดับงานที่แนะนำ
1. เปิด `derived/event-index.json`/CSV แล้วค้น panel 50132/50142/50143 ก่อน จะเห็น association, reward item IDs และ conditions โดยไม่ต้อง extract ใหม่
2. Resolve TabName/TitleName/IntroDesc จาก TextID ที่เจาะจง เพื่อบอกผู้ใช้ได้ว่า technical event นี้ตรงกับชื่อใดจริง
3. อ่าน exact UI controller/data proxy ของ panel หนึ่งระบบให้ครบ entry → data request → initialization → close/return map โดยไม่ execute action ระหว่างสำรวจ
4. ตรวจ display-item dependencies ทุก ID กับ current Client item assets/config และดูว่า reward preview สร้าง ItemData ได้จริงก่อนแสดงหน้า
5. ผูก main/resident modules และ early access state จาก schema ปัจจุบัน ไม่ตีความทุก module เป็น active event ชนิดเดียวกัน
6. Implement data/entry path ของระบบนั้นแล้วค่อยขยาย policy และ schedule อย่าเปิดทุก prefab ที่มีแล้วตอบว่าง
7. อัปเดตสถานะแยก asset present / source implemented / deployed / Client confirmed คำว่า “หาเจอ” ไม่ใช่คำว่า “เล่นได้แล้ว”
### ข้อจำกัดที่ยังเหลือ
- ยังไม่มี export official per-event active schedule ชุดปัจจุบันจาก Client/service ต้นทาง เวลาใน server ใช้ operator `cfg.ActivitySchedule` ร่วมกับ Endgame
- ยังไม่มี localized titles ที่ resolve ครบทุก panel
- raw catalog นี้ไม่รวมทุก event gameplay table, Lua/controller, stage/reward graph หรือ asset bundle ทั้งเกม
- เอกสารนี้ไม่ยืนยันว่า UI ใหม่เปิดได้หรือจอดำหาย ผู้ใช้ไม่ต้องถูกวนให้ลองทีละ handler ตามคำสั่งล่าสุด
ดังนั้นให้ใช้รายการนี้ช่วย GLM หา event และต่อข้อมูลที่ยังขาด แทนการสรุปว่า Beta นี้ไม่มี event เพราะชื่อ type หนึ่งหาไม่เจอ
+301
View File
@@ -0,0 +1,301 @@
# ข้อมูลและวิธีเพิ่มตู้กาชาให้ GLM — Client Beta ปัจจุบัน
อัปเดต: 24 ตุลาคม 2026 (Asia/Bangkok)
อ่านคู่กับ [GLM-BETA-DATA.md](GLM-BETA-DATA.md) และ [ZCODE-HANDOFF.md](ZCODE-HANDOFF.md)
## 1. เป้าหมายผู้ใช้และสถานะจริง
ผู้ใช้ต้องการเลือกตู้ตัวละคร โดยแต่ละตู้มีตัวเด่นหนึ่งตัว และผลสุ่มตรงกับตัวที่แสดงบนตู้ ไม่ได้ต้องการแค่หน้า Standard ที่เปิดดูได้แต่สุ่มไม่ได้
ตอนนี้ backend มีโค้ด featured-only sandbox สำหรับสุ่ม 1/10 ครั้ง และจัดการ duplicate material แต่ **ยังไม่มี featured banner ที่เปิดใช้งานจริง** Policy เปิดเพียง Standard เพื่อหลีกเลี่ยง Client crash จึงยังไม่ตรงคำขอ
เอกสารนี้ให้ข้อมูลที่ตรวจแล้วและลำดับพัฒนาต่อ ไม่ได้อ้างว่าการเพิ่ม path ใน JSON จะทำให้ตู้ใช้งานได้ หรือว่าดึง asset ที่หายกลับมาแล้ว
Client ที่อ้างอิงใน capture นี้: `GameAssembly.dll` SHA-256
```text
4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6
```
เป็น Client Beta .54 ที่ตรวจ runtime จริง ไม่ใช้ hash/RVA ของ CW capture .53 แทน
## 2. ตารางตู้จริงที่ดึงไว้แล้ว
`resources/PreviewGameplayCatalog.json` → `tables.gacha` มี `GachaBasicInfoConfigRow` ครบ 6 แถวของ capture นี้:
| GachaID | GachaType | SortID | PrefabPath | ผลตรวจ asset |
| ---: | ---: | ---: | --- | --- |
| 1001 | 1 | 99 | `UI/Drawcard/GachaPanel/StandardGacha_1001.prefab` | มี |
| 4001 | 2 | 1 | `UI/Drawcard/GachaPanel/NoviceGacha_4001.prefab` | มี |
| 2001 | 11 | 2 | `UI/Drawcard/GachaPanelLimited/AvatarGacha_1102.prefab` | ไม่มี |
| 2002 | 11 | 3 | `UI/Drawcard/GachaPanelLimited/AvatarGacha_1204.prefab` | ไม่มี |
| 3001 | 12 | 4 | `UI/Drawcard/GachaPanelLimited/LightConeGacha_23001.prefab` | ไม่มี |
| 3002 | 12 | 5 | `UI/Drawcard/GachaPanelLimited/LightConeGacha_23010.prefab` | ไม่มี |
ชื่อ enum ที่พบใน Lua คือ `Normal`, `Newbie`, `AvatarUp`, `WeaponUp` การจับคู่เลขข้างบนมาจาก captured rows ไม่ใช่การสร้างเลขเพิ่ม
แถวเหล่านี้ยังเก็บ `PoolLabelIcon`, `PoolLabelIconSelected`, `PoolName`, `PoolDesc`, `TypeTitle` และ TextID/hash64 ให้ใช้ original numbers ห้ามอ่านผ่านเครื่องมือที่ทำ uint64 เกิน 2^53 สูญเสีย precision
**ข้อจำกัด:** แถวในตารางไม่ได้พิสูจน์ว่ามี bundle ใน installation ผล `AssetMgr.Exists` ยืนยันแล้วว่า limited ทั้ง 4 path ข้างบนไม่มี
หลักฐาน: `battle_diagnostics/gacha-asset-exists-20261024.log` มีผลครบ 6 path และ `END` Policy เก็บผลพร้อม hash ไว้ใน `resources/GachaSandboxPolicy.json`
Seele prefab ที่ไม่มีเคยทำ `UIPrefabLoader._HandleLoadResult` ArgumentNullException ระหว่าง `GachaMainPage._create_pools_panel` แล้วออกกลับโลกจอดำ ห้ามเพิ่มกลับ allowlist เพื่อให้หน้าตู้ดูเยอะขึ้นทั้งที่ asset ยังไม่มี
## 3. Generic/group prefab ที่พบใหม่ — ตรวจแล้วไม่มีเช่นกัน
ถอดจาก bytecode ของ GachaMainPage ปัจจุบัน พบ group presentation ที่มี path จริงดังนี้:
| Group enum และค่าที่ capture จริง | Path ที่อ้างถึง | ผลตรวจใน Client ปัจจุบัน |
| --- | --- | --- |
| `MultiAvatarUp=1` / `MultiWeaponUp=2` | `UI/Drawcard/GachaPanel/MultiAvatarGacha.prefab` | ไม่มี |
| `Collaboration=3` | `UI/Drawcard/CollaborationGacha/CollaborationGacha.prefab` | ไม่มี |
| `CollaborationMerge=4` | `UI/Drawcard/CollaborationGacha0440/CollaborationGacha0440.prefab` | ไม่มี |
หลักฐานรอบล่าสุด: `battle_diagnostics/glm-beta-targeted-metadata.log`
```text
ASSET UI/Drawcard/GachaPanel/MultiAvatarGacha.prefab true false
ASSET UI/Drawcard/CollaborationGacha/CollaborationGacha.prefab true false
ASSET UI/Drawcard/CollaborationGacha0440/CollaborationGacha0440.prefab true false
END
```
ใน log นี้ boolean แรกคือการเรียกตรวจสำเร็จ ส่วน boolean ที่สองคือผล Exists จึงหมายถึง **ตรวจสำเร็จและไม่มี asset** ไม่ใช่พบ asset แล้ว
Group path เป็นข้อมูลสำหรับเข้าใจโครงสร้าง UI ไม่ใช่ fallback ที่พร้อมเปิดใช้ อย่าเสนอว่าเปลี่ยนมาใช้ MultiAvatarGacha แล้วจะหายทันที
ผลตรวจ paths แยกเป็น machine-readable data ใน `battle_diagnostics/glm-gacha-group-assets.json` ส่วนผลอ่าน **ตาราง group จริง** ล่าสุดอยู่ใน `battle_diagnostics/glm-gacha-groups-current.json`: `BEGIN count=0` จน `END count=0` จึงเป็นตารางว่างที่อ่านจบแล้ว ไม่ใช่ยังไม่ได้ capture ห้ามสร้าง GroupID หรือ pool-to-group mapping โดยเอาค่า enum 1–4 มาใช้เป็น IDs
## 4. การเพิ่มตู้มีสองกรณี
### กรณี A: มี config และ asset ของตู้จริงครบใน Client
1. ใช้แถว `GachaBasicInfoConfigRow` และ group/type ที่มี provenance ตรงรุ่น ปัจจุบัน group table อ่านครบแล้วเป็น 0 แถว จึงไม่มี original group mapping ให้เปิดใช้ และยังต้องอ่าน type data ที่จำเป็นให้ครบ
2. ตรวจ prefab, tab icon ทั้งสองสถานะ และ dependency ที่ controller ใช้ ให้มีจริงใน installation
3. ประกาศตู้ผ่าน resource catalog และ verified policy ไม่ใส่ game ID/path เจาะจงลง handler
4. ส่ง GetGachaInfo ให้ใช้ ID เดียวกับแถวที่ Client resolve ได้ และ prize/detail data ตรงกับตัวที่หน้าตู้แสดง
5. ให้ DoGacha ใช้ banner mapping เดียวกัน ตรวจ request/count และจัดการ grant/sync/persistence ให้ครบ
6. ตรวจ entry/exit และ animation state จาก callback จริง ไม่แก้ด้วยการปิด Canvas หรือกล้องทุกตัว
**กรณีนี้ยังทำไม่ได้กับ limited 4 แถวปัจจุบัน เพราะผลตรวจยืนยันว่า prefab ไม่มี**
### กรณี B: ไม่มี original banner asset — ต้องทำ custom presentation
นี่เป็นทางพัฒนาที่ตรงคำขอได้ แต่ยังไม่มี implementation สำเร็จใน source ปัจจุบัน:
1. กำหนด extension catalog แยกจาก raw captured tables โดยระบุว่าเป็น custom presentation ไม่ปลอมว่าเป็น original Client data
2. ใช้ avatar/item metadata และภาพที่ตรวจว่ามีจริงเป็นรายตัว ต้องแสดงชื่อ/ภาพตรงกับผล draw ห้ามใช้ภาพ Standard ค้างไว้แต่สุ่มเป็นตัวอื่น
3. ทำ UI/controller/binder ที่ใช้ asset ที่มีจริง อาจประกอบจากส่วนย่อยที่ตรวจแล้ว หรือทำ presentation ใหม่ที่เข้ากับระบบ UI; ไม่ใช่เพียงเปลี่ยน `Row.PrefabPath` เป็น Standard แล้วคาดว่า limited binder จะทำงาน
4. ต่อ pool/group/tab data และ selection state เข้ากับ Client โดยใช้ชนิด/enum/schema ที่ยืนยันแล้ว เก็บ custom ID mapping ใน resource ที่ตรวจความถูกต้องได้
5. ให้ Client และ server resolve ตู้เดียวกันจาก catalog เดียวกัน ก่อนรับการสุ่ม
6. ส่งผล Item/GachaItem/duplicate materials ให้ครบ และคืน transition กลับโลกเมื่อปิด
การส่ง GachaID ใหม่ที่ Client ไม่มี config **ไม่พอ**: Client ต้องสร้าง/resolve pool, type และ group ได้ด้วย การส่ง GachaID 1001 ซ้ำหลายแถวจะชน key ไม่ได้กลายเป็นตู้แยกทุกตัวละคร
ห้ามใช้สูตร `bannerID = avatarID + ค่าคงที่` หรือเดา path ของทุกตัวละครขึ้นเอง แล้วอ้างว่าเป็นตาราง Beta ให้กำหนด custom extension อย่างชัดเจนถ้าจำเป็นต้องสร้าง namespace ใหม่
## 5. สิ่งที่ Client ใช้สร้างหน้า — มีหลักฐานแล้ว
`battle_diagnostics/gacha-main-page.json` เป็นผลอ่าน bytecode ที่ไม่ execute ของ:
```text
@BakedLua/Ui/Gacha/GachaMainPage.bytes
```
### `_create_pools_panel` — prototype 26 / source line 308
ลำดับชื่อที่พบใน bytecode:
```text
GetSortedGachaGroupDatas
IsValid / IsFeatureClosed / IsSinglePoolGachaGroup
DefaultGachaPoolData.PrefabPath
sync_load_prefab
_gachaType2tabItem
create_panel / set_tab_data
```
แยกสองเส้นทาง:
- Single-pool group: โหลด `DefaultGachaPoolData.PrefabPath` แล้วสร้าง tab item ด้วย panel/binder ตาม `GachaType`
- Group: เลือกจาก `_groupID2GroupPrefab` / `_groupType2GroupPrefab` และ `_groupID2TabItem` / `_groupType2TabItem` พร้อม binder ของ group
ไม่ควรดูเพียง GetGachaInfoScRsp แล้วมองข้าม group data ที่หน้า UI ใช้จริง
### ฟังก์ชันสำคัญอื่น
- `_init_type2tab_table` prototype 8: ผูก `Normal`, `AvatarUp`, `WeaponUp`, `Newbie` กับ tab item/binder
- `_init_group_tab_prefab` prototype 9: กำหนด group prefab/controller/binder maps
- `_get_group_tab_prefab_config` prototype 10: เลือก override ด้วย GroupID แล้วจึง GroupType
- `_on_group_tab_change` prototype 31 และ `_on_tab_change` prototype 32: cache selected pool และ setup main page
- `_setup_main_page` prototype 33: setup draw/decide/top bar และ `Row.PoolName` ผ่าน `SafeSetTextID`
### Native/data types ที่ตรวจพบ
`BaseGachaPoolData` มี:
- `Row` getter/setter ชนิด `GachaBasicInfoConfigRow`
- `TypeBasicInfoRow`, `PrizeItemDatas`, `DetailItemDatas`
- `SingleDrawData`, `MultiDrawData`, `GachaTokenData`, `DecideData`
- `SyncGachaPoolData`, `_InitPrizeItemsRow`, `_InitDetailItemsRow`, `IsValid`, `IsFeatureClosed`, `PrefabPath`
`BaseGachaGroupData` มี:
- `_GachaGroupDataRow`, `_GachaPoolDataList`, `GroupID`, `GroupType`
- `AddGachaPoolData`, `GetSortedGachaPoolData`, `Sort`, `IsValid`, `IsFeatureClosed`, `HasGachaPool`
Capture ล่าสุดยืนยัน **shape** ของ `RPG.GameCore.GachaGroupDataRow`:
```text
PoolLabelIcon System.String
PoolLabelIconSelected System.String
GachaIDList System.UInt32[]
GroupType RPG.GameCore.GachaGroupType
GroupID System.UInt32
FromBinary(reader, GachaGroupDataRow byref)
```
ต่อจาก metadata ได้ตาม native chain และอ่าน flat GetAll ของตารางนี้ครบแล้ว:
```text
GachaGroupDataRow.FromBinary RVA 0x1e853750
-> wrapper RVA 0x1e853700
-> Add dictionary RVA 0x1e853950
-> flat GetAll RVA 0x1e852f20
BEGIN count=0
END count=0
```
หลักฐาน `ev_551674df9f28f4fc92485a8b8f3490795a8296564ee586fe356b16bca00e0b8b`, ข้อมูล `battle_diagnostics/glm-gacha-groups-current.json` และ assembler files `glm-gacha-group-add.asm`, `glm-gacha-group-dictionary.asm`, `glm-gacha-group-flat-getall.asm` ผูกกับ SHA ปัจจุบัน
**ตาราง group ที่ตรวจนี้ว่างจริง ณ capture** ไม่ได้แปลว่า Lua/UI ไม่มีโค้ดรองรับ groups แต่ไม่มี GroupIDs หรือ GachaIDList ให้ใช้เป็น original mapping อย่าอ่านค่า enum เป็น GroupID หรือเอาข้อมูลของ reference รุ่นเก่ามาเติมแล้วเรียกว่า Beta ปัจจุบัน
RVAs ข้างบนใช้บันทึกเส้นทางหลักฐานของ assembly hash นี้เท่านั้น ไม่ใช่ค่าที่ให้ฝังใน production MethodHandle/addresses ใน log ใช้ได้เฉพาะโปรเซสที่ capture ห้ามนำ pointer เดิมกลับไปใช้หลังเปิดเกมใหม่
`GachaTypeBasicInfoRow` มี `GachaTypeID`, `GachaBar`, `DiamondID`, `ItemPrice`, `ItemCosume`, `UpPropability`, `BuyPos` ต้องอ่านค่าจริงของ type ที่ใช้ ไม่เดาค่า currency/token หรือราคา
### Lua modules ที่ควรอ่านต่อแบบเจาะจง
- `Ui.Gacha.GachaPool.DefaultGachaPoolTabItem` และ binder
- `Ui.Gacha.GachaPool.DefaultGachaAvatarGroupTabItem` และ binder
- `Ui.Gacha.GachaPool.GachaSubAvatarGroupPanel`
- `Ui.Gacha.GachaPool.GachaSubAvatarItemIconPanel`
- `Ui.Gacha.GachaPool.DefaultGachaAvatarPanel`
- `Ui.Gacha.GachaPool.DefaultGachaUpAvatarPanel`
UpAvatarPanel มี `_init_imgs`, `_setup_up_avatar_img`, `setup_view`, `_on_load` แต่การมีชื่อ module ไม่ได้พิสูจน์ว่ามี prefab ที่ใช้งานได้
## 6. Protocol fields ที่ใช้อ้างอิงได้
ต้นฉบับ `protocol/proto/StarRail.proto` แถวประมาณ 20415 เป็นต้นไป:
| Message | Field ที่มีชื่อชัด | Wire tag |
| --- | --- | ---: |
| GachaInfo | end_time / gacha_id / gacha_ceiling / begin_time | 1 / 2 / 3 / 5 |
| GachaInfo | prize_item_list / item_detail_list | 10 / 11 |
| GetGachaInfoScRsp | retcode / gacha_info_list | 1 / 15 |
| DoGachaCsReq | gacha_id / gacha_num | 4 / 15 |
| DoGachaScRsp | retcode / gacha_item_list / gacha_num / gacha_id | 1 / 2 / 6 / 13 |
| GachaItem | transfer_item_list / is_new / token_item / gacha_item | 5 / 7 / 10 / 15 |
`GachaInfo` ยังมี fields obfuscated และ GetGachaInfoScRsp มี `AKMDBPNEHDE` ชนิด `NEIMLKNMDBM` อย่าอ้างว่าเป็น group payload แน่นอนหรือเติม tag ตามการคาดเดา ต้องตาม native consumer ก่อน
ตาราง command ที่เช็กใน source อยู่ที่ `protocol/proto/upstream_cmdids.go`:
```text
CommandSourceRevision = 005d2c12db4781071f4b5b68e8f364587886a710
GetGachaInfoCsReq 1974 -> GetGachaInfoScRsp 1919
DoGachaCsReq 1931 -> DoGachaScRsp 1987
```
เลขนี้ให้เป็นหลักฐานอ้างอิงในเอกสารเท่านั้น implementation ต้องใช้ named resolver ของโปรเจกต์ ห้ามฝังตัวเลขแทนชื่อหรือรับ aliases หลายรุ่น และ source revision ไม่ใช่หลักฐานว่า native schema .54 ทุก field ยืนยันครบแล้ว
## 7. โค้ด backend ปัจจุบันและการแก้ต่อ
### จุดอ่าน catalog
`internal/common/gacha_catalog.go`:
- `LoadBrowsableGachaBanners` ใช้ verified prefabs สำหรับ GetInfo
- `LoadFeaturedGachaBanners` ยอมรับเฉพาะ basename `AvatarGacha_<avatarID>.prefab` ที่อยู่ใน policy
- ไม่สร้าง GachaID หรือ prefab paths เพิ่มเอง
- ปัจจุบันพบ Standard ได้ แต่มี `AvatarID=0` จึงไม่เปิด featured draw
ข้อควรระวังสำหรับ custom presentation: logic ที่อนุมาน avatar จาก basename ใช้กับ extension catalog ใหม่ไม่ได้เสมอไป ต้องออกแบบ explicit mapping พร้อมตรวจ provenance/asset availability แทนการเปลี่ยน regex ให้รับทุกชื่อ
### จุดตอบ GetInfo/Draw
`internal/gameserver/handlers_gacha.go`:
- GetInfo ใช้ activity schedule จาก runtime config ส่ง non-null `GachaCeiling`
- ถ้ามี featured avatar จึงส่ง prize/detail lists
- DoGacha ตรวจ banner/count และ reject ระหว่าง Battle
- ต้องมี avatar ใน imported roster และมี Eidolon resource ที่ตรง
- duplicate ให้ material ตาม configured first Eidolon cost ไม่ใช่ตัวละคร/ไอเท็มสลับมั่ว
- ส่ง material delta ใน PlayerSync และ GachaItem ตามจำนวน draws
### Persistence ที่ต้องรักษา
`GrantGachaDuplicate` อ่าน latest `freesr-data.json` ใต้ shared process/file locks แล้ว merge เฉพาะ materials ไม่สร้าง avatar ใหม่ ไม่เปลี่ยน rank/EX/Traces ไม่เขียน inventory ทับทั้งก้อน
Sandbox policy ปัจจุบัน:
```text
allowed_draw_counts: 1, 10
charge_currency: false
duplicate_reward: configured_first_eidolon_cost
```
นี่ไม่ใช่ official probability/price model หากจะเปิด acquisition ของ avatar ที่ยังไม่มี ต้องทำ valid avatar/item sync และ targeted persistence เพิ่ม ยังไม่มีเส้นทางนั้นในโค้ดนี้
ไม่ควรเปลี่ยน DoGacha ให้ตอบ success พร้อมผลว่างเพื่อให้ spinner หยุด เพราะจะไม่ตรงจำนวน draws และ state ของ Client
## 8. อ่าน bytecode ต่ออย่างไร
Client นี้ใช้ `xluau.dll` มี Luau v4/type1 bytecode ไม่ใช่ LuaJIT:
- `string.dump` ไม่มี และ `jit.util` ใช้ไม่ได้
- มี `debug.getupvalue`, `debug.getinfo`, `debug.info`, `package.loaders`
- รอบที่เก็บ GachaMainPage ใช้ package loader เพื่อรับ closure โดย **ไม่ execute closure และไม่แทน package.loaded** แล้ว passive hook `xluaL_loadbuffer` เก็บ bytes
- อย่าเอา callback/module execution ไปปนกับการอ่านข้อมูล หรือ reload หน้าขณะผู้ใช้สู้
เก็บไว้แล้ว:
```text
battle_diagnostics/gacha-main-page.luau
battle_diagnostics/gacha-main-page.hex
battle_diagnostics/gacha-main-page.json
tools/inspect_luau_v4.py
```
ตัวอย่างอ่านไฟล์ capture offline จาก root โปรเจกต์:
```text
python tools/inspect_luau_v4.py battle_diagnostics/gacha-main-page.luau --output battle_diagnostics/gacha-main-page.json
```
Parser อ่าน version/type ที่รองรับเท่านั้น และตรวจว่าใช้ bytes ครบ ไม่ execute chunk เป็นเครื่องมือวิเคราะห์ ไม่ใช่ gameplay test และไม่ใช่ decompiler ที่ยืนยันความหมายทุกคำสั่ง
Layout reference: Luau upstream `VM/src/lvmload.cpp`, `Common/include/Luau/Bytecode.h` สำเนาอยู่ใน diagnostics ประกอบการตรวจ format
REA evidence ของ capture: `ev_57f147cb094af2060be82f5110e378d25ff2179f0390c56348368a855e7658b8` ขนาด GachaMainPage 23630 bytes ไม่มี message truncation ใน capture นี้
ทุก `.lua` ใน `scripts/` ถูกส่งเข้า Client อัตโนมัติ temporary probes ต้องอยู่ใน `tools/` เมื่อไม่ได้ใช้งาน จำกัดเฉพาะ types/functions ที่ระบุและ pause ระหว่าง Battle ห้ามสแกนทุก assembly type/method บน main thread
ณ จุดส่งต่อ probes ที่ใช้รอบนี้ถูกถอดจาก `scripts/` และ Frida sessions ปิด/detach แล้ว ไม่ได้ kill Client
## 9. เช็กลิสต์รับงานต่อ
- [ ] อ่าน package/manifest คู่กับ GLM-BETA-DATA เพื่อไม่ปน .53 และ .54
- [ ] ตัดสินทาง custom presentation โดยยอมรับว่า limited และ generic group prefabs ที่เช็กทั้งหมดไม่มีใน installation นี้
- [ ] ใช้ผล group table ที่อ่านจบแล้ว 0 แถวเป็นข้อจำกัดของ original config; อ่าน type data และ consumer ของ fields obfuscated ที่ยังจำเป็น ก่อนออกแบบ custom mapping
- [ ] ทำ explicit banner/avatar/presentation mapping ให้ Client และ backend ตรงกัน
- [ ] ตรวจ selected portrait/tab/icon/material dependencies เป็นราย resource ไม่เดาชื่อไฟล์
- [ ] รองรับ 1/10 draws และ duplicate/acquisition ตามขอบเขตที่ประกาศ
- [ ] รักษา progression/EX false/material delta และป้องกัน stale session ทับ API
- [ ] ทำ close/exit ให้คืน world/UI transition ไม่ค้างดำ
- [ ] ตามคำสั่งผู้ใช้ล่าสุด: ไม่เพิ่มหรือรัน tests และไม่วนให้ผู้ใช้ลองทีละ handler; ระบุส่วนที่ยังไม่มี Client confirmation ตามจริง
**จุดสรุปให้ GLM:** Backend ส่วนหนึ่งพร้อมแล้ว แต่การเปิดตู้ตัวละครจริงใน Beta นี้ติด presentation/config mapping และ assets ที่ไม่อยู่ใน installation การมี GachaInfo response หรือเพิ่ม allowlist อย่างเดียวไม่ใช่การทำฟีเจอร์เสร็จ
+35
View File
@@ -0,0 +1,35 @@
# Recovery checkpoint — 2026-10-24
## Confirmed findings
- No tracked files were deleted at the initial audit. Missing menus alone do not prove missing assets.
- Latest captured Player.log reports missing sub-mission `104020220`, followed by `MainMissionData.AddSubMission` / `_OnCmdGetMissionDataScRsp` sorting failure. Mission initialization failure is a plausible cause of incomplete unlock/menu state; Client recovery is not yet confirmed.
- Added only this observed exclusion to MissionCompatibility.json for the existing client revision entries, retaining previous exclusions. Copied the resource to `for ship/resources/` as well. No executable was rebuilt or replaced.
- The current persistent file had lost whole sections. Restored only absent sections; comparison against the checkpoint confirms every preexisting field is semantically unchanged.
## Restored sections
`team_presets` (8 saved teams), `active_team_preset`, `tierce_progress`, `player_outfits`, `scene_group_properties`, `profile`, and `currency_wars` (configured account only).
Source: `.runtime/before-cw-grants-25691022-130022/persistent`, dated 2026-10-22. CW envelope revision 529, route 2801, chapter 1, section 5. This is the best located backup, not proof of the latest state before loss.
Source SHA256: `0a2c9cc2d065f1a5f5f42142e6c28136e0fe92da7d25de4f45fc0fab35d383d0`
Recovered persistent SHA256: `eee9771994ef931d4710b6c0b6f7dad241c7d0f556fec76b67ebf21aeab34398`
Current lineup, position, scene, EX values, food stock and existing flags were preserved. No queued grants were restored. Missing Aha Help level was not guessed: no exact saved value was located in the inspected backups.
## Private rollback checkpoint
`.local-checkpoints/restore-ui-20261024T124147Z/before-recovery.zip` contains the pre-recovery persistent, local configuration, changed files, executable copies and Player.log evidence. It contains private local data; do not publish it. The adjacent manifest records hashes.
## Unresolved
- The writer responsible for dropping persistent sections is not established. Do not attribute it to one command without evidence.
- Further missing mission configs may surface after the current failure is removed. Do not claim the entire mission catalog is compatible from this single correction.
- Two AA source paths disappeared during the audit while replacement round-selection files were present. Both original paths are preserved in the checkpoint; do not blindly restore them over concurrent work.
- No gameplay tests, build, server restart or runtime probe was performed for this recovery. Client/menu behavior remains unverified. Existing executables read the external corrected resource on a fresh launch.
## Next check
Open the normal walking screen and phone menu on a fresh launch, then inspect the new Player.log for mission initialization errors. Stabilize restored menus and saves before continuing gacha or event injection. Avoid simultaneous writers from another coding session.
+549
View File
@@ -0,0 +1,549 @@
# ส่งต่องาน GaC-hkrpg-go ให้ Zcode
> Boss continuation: live logs confirm Tea Break take and preparation now pass,
> saved run is 1-6 revision545. Boss request was blocked by requiring nonzero
> Level/HardLevelGroup from an envelope that legitimately omits both. Corrected
> helper preserves proven wire zeros, validates formation and all saved enemy
> identities. See `currency-wars-route-factory.md` current Boss correction.
> 2026-10-26 late correction: the current Client's Bonfire selected phase is 2,
> not FFGO's 1. Native `_UpdateHasSelected` proves phase>=2. Earlier 22:49 build
> still failed because it used phase1. New build includes read-only legacy phase
> projection from same-node effect evidence and idempotent matching choice sync.
> See `cw-bonfire-phase-contract.md`. No rewards or saves changed by research.
> Latest CW deployment — 2026-10-26 22:49 Bangkok: Tea Break take-drop/heal,
> generated Boss/CampMonster layers and preparation/settlement integration are
> now built and deployed. This supersedes historical “take-drop unsupported”.
> Root Game/SDK visible consoles restarted; no Client take/Boss result observed
> yet. Existing run remains revision531,1-5,phase1 until user resumes; no save
> migration/reward was performed outside an actual request. See
> `currency-wars-ffgo-workflow-20261026.md` and `currency-wars-route-factory.md`.
> Pending: full augment effects, ordinary Monster/EliteBranch/nonenemy factories,
> finalization, companion synthesis, extra difficulty and weighted Orb offers.
> Both standard and shipping binaries compiled; no tests run. Maintained Lua
> scripts count is five, including ping_rainbow.lua; no probe is staged.
> อ่านหัวข้อ **Latest continuation — 2026-10-26** ท้ายไฟล์ก่อน:
> สถานะกาชา/AA/CW และ dump FFGO ใหม่ในหัวข้อนั้นแทนสถานะเก่าด้านล่าง
อัปเดต: 24 ตุลาคม 2026 (Asia/Bangkok)
## 1. เป้าหมายและคำสั่งล่าสุดจากผู้ใช้
ผู้ใช้ต้องการให้แก้ปัญหาที่แจ้งทั้งหมด งานล่าสุดที่ยังค้างคือ:
1. กาชา: เลือกตู้ตัวละครได้ โดยแต่ละตู้มีตัวเด่นหนึ่งตัว และสุ่มได้ตรงกับตัวที่แสดงบนตู้
2. กิจกรรม: เพิ่มรายการในหน้ากิจกรรม และเข้าไปดู/เล่นบางส่วนได้ ไม่จำเป็นต้องจำลองครบ 100%
3. Stella Jump: มินิเกมกระโดดด้านข้าง ต้องเข้าเล่นและเลือกด่านที่ยังล็อกได้
4. CW: แก้ปุ่มหน้าเข้าโหมดที่ทับกัน และออกจากโหมดแล้วโลกจอดำแต่ยังกดควบคุมได้
5. แต้มเทคนิคก่อนเข้าสู้ Endgame: ต้องเริ่มเต็มตามเพดานของทีม ไม่ติดอยู่ที่ 5
6. เมื่อส่วนข้างบนเรียบร้อย จึงกลับไปต่อ CW ให้เล่นต่อเนื่องได้ทั้งโหมด รวม Tea Break, Orb และคำสั่งเสก
ผู้ใช้บอกแล้วว่า **ไม่ต้องเทส/ไม่ต้องให้ลองซ้ำ ให้ทำงานต่อ** อย่ารันหรือเพิ่ม tests และอย่าให้ผู้ใช้ลองใหม่ทีละ handler โดยไม่มีเหตุจำเป็น หากต้องตรวจ gameplay เพิ่มจริง ให้ระบุว่าขาดหลักฐานอะไร การ compile ผ่านไม่ใช่หลักฐานว่าเล่นได้
คำขอปัจจุบันคือทำเอกสารส่งต่อ ยังไม่ได้สั่ง commit/push รอบนี้ และยังไม่ได้ส่งข้อความหาแชต Zcode
## 2. อ่านก่อนเริ่มทำงาน
- อ่าน `AGENTS.md` ที่ root; กฎมีผลกับทุกงานด้านล่าง
- ใช้ checkout ปัจจุบันต่อ มีงานแก้และไฟล์ใหม่จำนวนมากจากหลายรอบ **ห้าม reset/clean/ทับงานเดิม**
- อ่าน `git status --short` และ diff ก่อนแก้ อย่าเหมารวมว่าทุก diff เป็นงานของรอบล่าสุด
- เอกสารเก่าบางส่วนเป็นบันทึกตามเวลาและมีสถานะที่ถูกแทนที่แล้ว เอกสารนี้สรุปสถานะล่าสุดเพื่อส่งต่อ โดยเฉพาะ Aha, กาชา, กิจกรรม และ Client revision
- งานก่อนหน้าหลายส่วนยังไม่ยืนยันกับ Client ต้องแยกคำว่า “มีโค้ด”, “build แล้ว”, “วางไฟล์แล้ว” และ “ผู้ใช้ยืนยันแล้ว”
- อย่ารีสตาร์ต Game server ขณะผู้ใช้สู้ ผู้ใช้เคยอนุญาต rebuild/restart แล้ว แต่ต้องตรวจสถานะรอบปัจจุบันก่อน
- อย่าสั่งปิดคอมตามข้อความเก่า ผู้ใช้กลับมาใช้งานต่อแล้ว
### กฎสำคัญจาก repository
- ค่าตั้งระบบต้องมาจาก `server.json` + `server.local.json`/environment ห้ามฝัง path/IP/port/เวอร์ชัน Client ของเครื่องนี้ใน source หรือ startup scripts
- Game ID, floor, group, buff, level, unlock และกฎต่าง ๆ ต้องมี resource/Client evidence รองรับ ห้ามเดาตัวเลขเพื่อให้ผ่าน
- Resolve CmdID ด้วยชื่อจากตาราง protocol ที่ระบุ revision ห้ามส่งหลายเลขเพื่อเดา callback
- ถ้า schema obfuscated ให้บันทึก tag/ชนิดข้อมูล/สิ่งที่ยืนยันได้และสิ่งที่ยังไม่ทราบ
- ตัวอ่าน persistent ห้ามเขียนกลับ เซฟจาก session เก่าห้ามทับ API update; เก็บ EX false ได้ และ sync เฉพาะ avatar/material ที่เปลี่ยน
- ห้ามโหลด/สแกนทั้ง assembly บน main thread ระหว่างเล่น ใช้ named types และจำกัดงานต่อ heartbeat/frame
- ทุก `.lua` ใน `scripts/` ถูกส่งเข้า Client อัตโนมัติ Temporary probes ต้องเก็บที่ `tools/` และถอดจาก `scripts/` เมื่อเสร็จ
- SDK/Game server ต้องมีคอนโซลกับ log ให้เห็น
## 3. สถานะ build และ Client ณ จุดส่งต่อ
### Executables
อัปเดต 24 ต.ค. 2026 ~16:00: **rebuild + deploy + restart รอบสุดท้ายแล้ว** (root + `for ship`) ชุดนี้รวม: CW role compatibility, Endgame technique เริ่มเต็ม (`handlers_challenge_flow.go:287` Mp=MaxMp ยืนยันใน source), activity preview ขยาย 121 schedules, Srtool custom monsters ใน AA, MissionCompatibility 4 IDs, GetCurBattleInfo ไม่ null, และ probe scripts 3 ตัว ผู้ใช้ relogin กลับมาเองหลังแต่ละรอบ (ไม่ใช่การยืนยันระบบอื่น) **ยังไม่มี Client ยืนยันชุดแก้ใหม่นี้**
### กลไก probe ที่ตรวจสอบแล้ว (สำคัญต่องานต่อ)
- ไฟล์ใน `scripts/` ถูกแนบไปกับ **PlayerHeartBeat ทุกครั้ง** (`handlers_player.go`) และ Client **re-parse + execute ต่อ heartbeat จริง** (ยืนยัน 24 ต.ค. ~15:40: probe จิ๋วที่เขียนหลัง Client boot ก็รัน) — แต่ blob หนัก (เช่น probe ที่ฝัง ID หลายพันตัว ทำ 500 reflection calls/beat) จะกิน main thread จนโหลดฉากหมุนค้าง ใช้ chunk ไม่เกิน ~50/beat
- ตรวจ syntax ทุกสคริปต์ด้วย `pip install luaparser; ast.parse(...)` ก่อนวาง — สคริปต์พังทำ blob ทั้งก้อนเงียบหมด
- อ่าน output จาก Player.log ต้องใช้ `grep -a` (log มี byte ผสม binary)
- กับดัก xLua: `typeof(CS.RPG.Client[tn])` แบบ string index คืน lazy placeholder ไม่ใช่ type — เช็ค type ต้องใช้ `CS.System.Type.GetType('RPG.Client.Name, Assembly-CSharp')`
- ผล probe 24 ต.ค.: `FiveDimModule` มี `EnterChenLingGameBoy(UInt32,KFELGAIGHAP×4,GameEntity,Transform,Transform)`, `RequireChenLingGameBoyData(UInt32)` และ **ไม่มี** `_OnGetChenLingDataScRsp` (ChenLingGetData 9612 ถูกจัดการโดย module อื่น) `GridFightModule` มีแค่ `_ClearBonfireShownEventIds()` + `_OnGridFightHandlePendingActionScRsp` — ไม่มี bonfire page/ส่ง request ในตัว module และ `GlobalVars` ไม่มี field mission/gridfight — MissionModule/GridFightModule singleton ยังหา access path ไม่เจอ (รอบถัดไป: ไล่ static fields ของ MissionModule เอง หรือจับ page class จริงจาก stack trace ตอนผู้ใช้กด Tea Break)
- ชื่อ `GridFightBonfirePage`/`GridFightTeaBreakPage`/`GridFightBackstageTeaBreakPage` ฯลฯ **ไม่มีจริง** ใน Assembly-CSharp (ตรวจด้วย Type.GetType แล้ว) — ห้ามใช้ชื่อพวกนี้อ้างอีก
- Probe ทั้งหมดถอดจาก `scripts/` แล้วเมื่อจบรอบ สภาพปัจจุบันคือไฟล์ runtime ปกติ 5 ตัว
### ชุดข้อมูล GLM handoff (24 ต.ค. เย็น)
ผู้ใช้ส่ง `.runtime/glm-beta-handoff-20261024.zip` พร้อมเอกสาร `docs/GLM-BETA-DATA.md`, `GLM-BETA-EVENTS.md`, `GLM-GACHA-GUIDE.md` — ชุดข้อมูล event (181 panels/361 activities + derived index) และกาชา (6 แถวจริง, group table ว่าง 0 แถว, limited/group prefab ไม่มีใน installation) พร้อมกติกา: ห้ามเดา ID/สร้าง namespace ปลอม แยก provenance ทุกชั้น
ผลงานเพิ่มเติมจากชุดนี้ (24 ต.ค. ค่ำ, ยังไม่แก้ production code):
- ตรวจ schema ของ 4 event ที่มีชื่อ command ชัด: `PixAirGetData`(9812), `GetChenLingFesData`(9942), `StartFinalityBattleLevel`(10027), `BlindBoxGetData`(10052) — ทุกตัวต้องมี config table ของระบบตัวเองก่อนตอบได้ปลอดภัย (ตอบว่าง = ผิดกฎ) และ ChenLingFes อยู่ใน danger family ปัจจุบัน
- โพรบ TextID (ถอดออกแล้ว): `TextID` มี ctor `(String)` ที่**แฮช key เอง** และ `()`; field `hash` เซ็ตตรงผ่าน xLua ได้ (ยืนยัน hash ตรงเป้าครบ 10 panel) แต่ `ToString()` ไม่ resolve ข้อความ `LocalizationManager` เป็นแค่ language config; text-table lookup service ยังไม่พบ (รอบหน้า: enumerate TextID instance methods, หา UiText service ต่อ หรือแกะ DesignData pack) — localized ชื่อ event ใหม่ทั้ง 10 ยังไม่ได้
- กับดัก xLua เพิ่มเติม: string→ตัวเลขใหญ่ถูก coerce ผ่าน double เสียค่า; byte-array SetValue ติด widening; C# property (เช่น `IsStatic`) อ่านแบบ field ไม่ใช่ call; state ของ probe ต้องเปลี่ยนชื่อ variable ทุกครั้งที่แก้เพื่อบังคับรอบใหม่
### กาชา sandbox draw — ใช้ได้จริงแล้วใน build 24 ต.ค. ~16:4x
`GachaSandboxPolicy.json` เปิด `sandbox_draw_pool.source = "imported_roster"` และเพิ่ม `NoviceGacha_4001.prefab` เข้า verified prefabs (ผลตรวจ asset เช้านั้นยืนยัน novice = true อยู่แล้ว) `handlers_gacha.go` เพิ่มเส้นทาง `drawSandboxPool`: DoGacha บน banner ที่มี asset จริง (1001/4001) สุ่ม uniform จาก roster ใน freesr-data.json ณ ตอน draw (ไม่ฝังรายชื่อ) ตัดตัวที่ไม่มี first-rank Eidolon cost ออก แล้ว grant เป็น duplicate material ตาม first Eidolon cost ต่อ avatar (กลไก `GrantGachaDuplicate` เดิม) พร้อม PlayerSync ฝั่ง materials และ GachaItem ต่อครั้งที่สุ่ม
**ขอบเขตจริง:** ทุกผลสุ่มเป็นตัวละครที่มีใน roster แล้วเสมอ (duplicate) — การได้ตัวใหม่ที่ยังไม่มี (first acquisition) ยังไม่รองรับและยังถูก reject นี่คือ sandbox pool เพื่อให้ตู้ที่มี asset กดได้จริง ไม่ใช่ official probability/price และไม่ใช่ตู้เลือกตัวละคร (ยังติด custom presentation ตาม GLM-GACHA-GUIDE กรณี B) ยังไม่มี Client ยืนยันการกดสุ่มจริง
### ตู้ต่อตัวละคร — ผล RE รอบถอด handler (24 ต.ค. ดึก)
ตามคำสั่ง "ถอด `_CmdGetGachaInfoScRsp`": ยืนยัน binary hash ตรง .54 แล้ว disassemble สอง RVA ที่ dumper ผูกกับ `GetGachaInfoScRsp` (`0xCFDC1C0` 1515 instructions, `0xCFD46B0` 107) ลง `battle_diagnostics/gacha-info-handler-{1,2}.asm`
ผลที่ยืนยันเพิ่ม:
- **Concrete pool type จริง = `RPG.Client.StandardGachaPoolData`** (subclass ของ BaseGachaPoolData) — อ่านจาก live pool ด้วย `GetType().FullName` (แก้ตามข้อเสนอ: หยุดเดา BaseGachaPoolData ตรง ๆ) ไม่มี constructor ใด ๆ (รวม non-public)
- `DefaultGachaPoolData` ที่ bytecode หน้าอ้าง **ไม่ใช่ C# type ที่ xLua เห็น** (lazy placeholder) — อย่าใช้ชื่อนี้อ้างอีก
- เขียน `Row` บน derived pool ต้องใช้ reflection บน **BASE type**: `BaseGachaPoolData.GetField('<Row>k__BackingField', Instance|NonPublic)` (derived-type lookup เจอ nil)
- `_AddGachaPoolDataToGroupDict` โยน `InvalidCastException (BindingFlags)` ทั้งกับ Base และ Standard uninitialized instance — ยังไม่ระบุสาเหตุชั้นใน (การอ่าน asm ต้อง resolve metadata slot → type name ซึ่ง dumper static ไม่มี: slot `0x963af58` อยู่นอกช่วง method RVA ของ cs-type-infos)
**ขั้นต่อไปที่เจาะจง (รอบ RE ใหม่):**
1. Resolve metadata slots ใน handler-1 ด้วย runtime symbolication (Frida อ่าน type-info จากโปรเซสจริง ตามแบบ asm capture เดิม) เพื่อชี้จุด: โรงงานสร้าง pool, จุด lookup config, และ branch ที่ข้าม ID ไม่รู้จัก
2. ทางเลือกขนาน: hook ที่ `0xCFDC1C0` ตอน Client ประมวลผล response จริง เพื่อดู arg/return ของ pool construction สด ๆ
3. เมื่อเจอ factory/projection แล้ว ออกแบบตามหลัก "config projection ก่อนประมวลผล response" (ตามข้อเสนอ) — Row ที่เติมทีหลังไม่มีทางช่วยเพราะ Client ข้าม ID ตั้งแต่ก่อนสร้าง pool (พิสูจน์แล้ว)
**ตรวจ asset art:** `AvatarCutinImgPath = SpriteOutput/AvatarDrawCard/<id>.png` เป็น path จริงจาก config แต่ **ยังไม่ได้ตรวจ existence รายตัว** — ต้องผ่าน AssetMgr.Exists probe ก่อนใช้เป็นภาพตู้ (ตามข้อเสนอ: path จาก config อย่างเดียวไม่พอ)
ผลพิสูจน์สะสมจากเส้นทาง `_gacha_module` upvalue (หลักฐาน `gameplay-lua-upvalues.log`): module method surface ครบ (`GetSortedGachaPoolDatas/GetGachaPoolData(id)/_CmdGetGachaInfoScRsp/_AddGachaPoolDataToGroupDict/GetGachaNormalPoolID=1001`); pools สร้างจาก server response rows join local config (ID ไม่รู้จักถูกข้ามเงียบ — server ส่ง 3 ได้ pool 2 ไม่ crash); `GachaBasicInfoConfigRow()` สร้างใหม่ + เขียน field ได้ครบ; proto response class ไม่ถูก bridge เข้า xLua (baked Lua ส่ง request ผ่าน C# sender ทั้งหมด)
### UI regression 18 ต.ค. ช่วงเย็น — กู้ก่อนต่องานกาชา (24 ต.ค. 18:16)
ผู้ใช้รายงาน: เมนูโทรศัพท์เหลือ 4 ปุ่ม (Navigation/Missions/Bookshelf/Account Settings) และแถบด้านบนตอนเดินหาย พร้อมแก้ข้อสรุป: (ก) `DefaultGachaPoolData.PrefabPath` ใน bytecode เป็นการเข้าถึง property ไม่พิสูจน์ชื่อ C# class (ข) InvalidCastException ไม่พิสูจน์ว่าขาด field — ต้องอ่านชนิดจริงกับ stack (ทำแล้วบางส่วน: concrete type จริงคือ `StandardGachaPoolData` จาก GetType() ไม่ใช่การเดาชื่อ)
**การย้อนที่ทำแล้ว (bisect step 1):** ถอน ComicDessert (50142) ออกจาก ActivityPreviewPolicy ทั้ง panel entry และ allow_display_item_panels (จาก 163 schedules เหลือตามเดิม) เพราะเป็น delta ก่อนอาการรายงาน การ publish กิจกรรมที่ยังไม่มี handler คือการละเมิดกฎตัวเอง — ต้องมี data path ก่อน publish เสมอ
**ตรวจแล้วว่าไม่ใช่:** โปรไฟล์ถูกต้อง (server.json player_uid=52022 ไม่มีการสลับ), mission data ส่งครบตามดีไซน์ (14779 sent / 5 excluded), ไม่มี incomplete object ค้างใน Client (ทุก insertion ของ probe ล้มเหลวก่อนถูกเก็บ — POOL_COUNT ยังเป็น 2 ก่อน/หลัง, SETTEST เขียนค่าเดิมใส่ตัวเอง, relogin หลัง deploy สร้าง module state ใหม่จาก server response แล้ว)
**จุดตรวจถัดไป (ถ้าเมนูยังไม่กลับ):** bisect ถัดไปคือถอน mission exclusion 5 IDs (ยอมให้ NRE กลับมาชั่วคราวเพื่อพิสูจน์สาเหตุ) แล้วจึงตรวจ function unlock ที่อ้าง sub-mission เหล่านั้น — ห้ามสรุปแทนการทดสอบแบบมีจุดตรวจ
**สถานะงานกาชา (รายงานตรง):** ตู้ใหม่ยังไม่ขึ้นในหน้า Warp, การสุ่มผ่าน UI ยังไม่ผ่าน, การออกหน้าไม่จอดำหลังเพิ่มตู้ยังไม่ยืนยัน — งาน pool creation พักตามลำดับใหม่จนกว่า UI เดิมจะกลับมา
### สรุปสถานะงานกาชา ณ 24 ต.ค. ดึก
| รายการ | โค้ด | build+deploy | Client ยืนยัน |
| --- | --- | --- | --- |
| Standard (1001) / Novice (4001) สุ่ม sandbox roster | ✅ | ✅ | รอผู้ใช้กด |
| Mapped per-character banners (mapping 94 → ต้อง regenerate แบบ ID คงที่ด้วย tools/build_gacha_banner_mapping.py ที่แก้ให้ preserve) | ✅ backend | ✅ (GetGachaInfo ปิด preview ไว้) | ❌ ค้างที่ pool creation |
| ตู้ limited ดั้งเดิม | ❌ | ❌ | asset ไม่มี 12 path |
**หมายเหตุ mapping (ตามข้อเสนอแก้ไข):** `tools/build_gacha_banner_mapping.py` ปัจจุบัน regenerate ตามลำดับ roster แล้ว **ยังไม่ได้แก้ให้ preserve ID เดิม** — ต้องแก้ก่อนใช้จริง: อ่าน mapping เดิม คง (gacha_id → avatar_id) เดิม จัดสรรเฉพาะ avatar ใหม่ด้วย ID สูงสุด+1 และแยกรายงาน limited/standard/ขาด config (ปัจจุบัน 94 = ทุกตัวใน roster ที่มี Eidolon cost ไม่ได้แปลว่า limited ครบ)
### สิ่งที่แก้แล้ว (deployed, มีหลักฐาน log) vs ข้อสันนิษฐาน
**แก้แล้ว + หลักฐาน:**
- Mission NRE: `GetMissionDataScRsp` มี sub-mission ที่ Client .54 ไม่มี config ทำ `MainMissionData.AddSubMission` NRE ตอน sort — พบ 4 IDs (103380210, 104010267, 104010268, 104020209→216) ใส่ exclusion ครบใน `MissionCompatibility.json` พร้อม provenance หลัง relogin 15:09 ยังเจอตัวใหม่ (104020216) แสดงว่ายังไม่ครบจนกว่า probe จะไล่ครบ — **ยังไม่ประกาศว่าหาย**
- GetCurBattleInfo NRE: ตอบ `SceneBattleInfo{}` ว่างแต่ไม่ null ตามแบบ reference (Player.log NRE หายใน login 15:09)
**มี source ใน build แต่ยังไม่มี Client ยืนยัน:**
- Srtool custom monsters ใน AA: `setChallengeBattleConfigWithLimit` รับมอนจาก tool เมื่อ lease active และ `BattleConfig.Monsters` ถูกแก้จากค่า default เท่านั้น เฉพาะ `BattleTypeAS` โหมดอื่น/เล่นปกติยังใช้มอน resource จริง กฎโหมด/รอบ/คะแนนไม่ถูกแตะ
- Activity preview ขยาย: policy เพิ่ม 11 family (RoleTrial 32 panels รวม) → **121 schedules** (จาก 12) ทุกตัวมี prefab+icon จริงและไม่มี DisplayItemList dependency ตรวจ conflict แล้วเป็นศูนย์ กลไก QuestState คือกลไกเดียวกับ 8 family ที่ผู้ใช้เห็นแล้ว
- CW role compatibility + projection, Endgame technique เต็มเพดาน, Aha, Stella handlers
**ข้อสันนิษฐาน/ยังขาดหลักฐาน — ห้ามรายงานว่าเสร็จ:**
- CW Tea Break (EnterBonfire): โครงสร้าง reference (node types: None/Monster/CampMonster/EliteBranch/Boss/Supply) **ไม่มี TeaBreak node และไม่มี EnterBonfire handler เลย** จึงห้ามเดา pending arm ต้องรอ `[GAC_TEA_PROBE]` จาก Client boot ถัดไป
- Stella Jump toast: ยังไม่รู้ condition จริง, warning GroupProperty ยังไม่ใช่หลักฐาน — รอ `[GAC_STELLA_PROBE]`
- Aha ไม่มีอนิเมชั่น/Cyrene ไม่มีโดม: server รับ cast ถูกต้องแล้ว (log) แต่เป็น config ฝั่ง Client ของ custom avatar — ยังไม่มี probe; ต้องหา avatar ID ของ Aha/Cyrene จาก Client ก่อน (roster ฝั่ง server ไม่มีตัวนี้)
- ชุด sub-mission ที่หายยังไม่ครบจนกว่า `[GAC_MISSION_PROBE]` จะรายงาน END
- กาชา custom presentation: ยังไม่เริ่มทำรอบนี้ Standard อย่างเดียวยังไม่ใช่เสร็จ; อาการออกแล้วแมพดำยังเป็นเหตุ prefab หาย (index=-1)
### Revision และ provenance
Client ที่ตรวจ runtime ล่าสุดเป็น 4.6.54 และ `GameAssembly.dll` SHA-256:
```text
4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6
```
CW base capture/เซฟเดิมมาจาก 4.6.53:
```text
c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144
```
ห้ามเปลี่ยน label ให้ทั้ง catalog กลายเป็น .54 เพราะ recapture แค่บางตาราง และห้ามใช้ native RVA/MethodHandle ของ .53 กับ .54 หรือใช้ pointer เก่าหลังปิดเปิดเกม
`server.local.json` ยังมี launcher client_path ชี้ installation เก่า ขณะที่โปรเซสจริงล่าสุดเป็น installation .54 ให้ตรวจ path ของโปรเซสจริงใหม่ก่อนผูกเครื่องมือ อย่าเดาจากชื่อโฟลเดอร์ และอย่า commit path เครื่องนี้
`battle_diagnostics/` และ `.runtime/` ถูก ignore หลักฐานส่วนมากอยู่เฉพาะเครื่อง ถ้าจะส่งให้ Zcode บนอีกเครื่องต้องแนบไฟล์หลักฐานที่อ้างถึงด้วย ไม่ใช่ส่งแต่ Git diff
### Cleanup ที่ทำแล้ว
- ถอด temporary probes จาก `scripts/` แล้ว
- Frida session ที่ใช้ดึง GachaMainPage ปิด/detach แล้ว ไม่ได้ kill เกม
- รายการ script ณ จุดส่งต่อ: `client_unstuck_request.lua`, `damage_analyst_live.lua`, `freecam.lua`, `hide_ui.lua`, `navigation_profiles.lua`
- `client_unstuck_request.lua` เป็นไฟล์ runtime ที่ถูก ignore อย่าสับสนว่าเป็น probe ที่ควรถอดเอง
## 4. งานด่วน A — CW ปุ่มทับและออกแล้วจอดำ
### หลักฐานที่พบ
Player.log มี NRE ตามลำดับ:
```text
GridFightRoleConfig..ctor(GridFightRoleConfigRow)
GridFightModule.GetRoleConfig
GridFightRole.set_ID / Team.AddRole / Team.Initialize
GridFightGameSession._SyncInternal
GridFightModule._OnGridFightGetDataScRsp
GridFightGuideBook.get_CompletedChapterCnt
GridFightS2EntrancePage._refresh_big_guide_book_btn / _refresh_all_status
UITransition GridFightDivisionStartPage -> GridFightS2EntrancePage
```
เซฟเดิมมี role `151102` (avatar 1511) แต่ flat role table ปัจจุบันไม่มี ID นี้ จาก 140 แถวที่อ่านครบ พบ family ใหม่ และ Client handbook default ของ avatar นี้คือ `151112` ไม่ใช่การเลือกจากเลข ID ต่ำสุด
การ init ที่ล้มกลางทางเป็นเหตุที่มีหลักฐานรองรับสำหรับหน้า CW ผิดสถานะ ส่วนความสัมพันธ์กับจอดำหลังออก **ยังเป็นข้อสันนิษฐานที่ต้องแยกตรวจ** อย่ารายงานว่าจอดำหายแล้วจากแค่แก้ role
### โค้ดที่ทำแล้ว แต่ยังไม่ได้ deploy ล่าสุด
- `internal/common/currency_wars_role_compatibility.go`
- เชื่อม loader ใน `currency_wars_catalog.go`, `currency_wars_roles.go`, `currency_wars_variants.go`
- `internal/gameserver/currency_wars_role_projection.go`
- ใช้ projection ใน `currency_wars_save.go` และส่ง CW response/notify บางกลุ่มใน `session.go`
- `resources/CurrencyWarsCurrentRoles.json`: flat role table ปัจจุบัน 140 แถว
- `resources/CurrencyWarsRoleCompatibility.json`: overlay มี provenance แยกจาก base catalog
- `tools/build_cw_role_compatibility.py`: สร้าง overlay จาก capture
Projection แปลงเฉพาะ field ที่ยืนยันว่าเป็น role reference ได้แก่ `role_id`, `CDEAABODKCP.id`, `JJOBHGFOGHP.BGFFICLCKHE` ใน nested messages ไม่เปลี่ยน matching integers ทั้งก้อน และข้าม protobuf maps
รักษา UID/star/equipment/position/run progress เดิม ตัวอ่านเซฟเปลี่ยนเฉพาะ detached message ไม่เขียน persistent กลับ การเซฟเกิดในเส้นทาง transaction ปกติ
### ต้องทำต่อ
- [x] ตรวจทุกเส้นทาง role reference (audit 24 ต.ค.): ไม่มี map ใดใน proto บรรจุ role-reference message แม้ transitive จึงข้าม maps ได้ปลอดภัย `GridFightEnterBattleStageScRsp`, `GridFightEndBattleStageNotify`, `GridFightGetArchiveScRsp` เข้าถึง role refs ผ่าน SceneBattleInfo/BHBAILHMCOI แต่เดิมไม่อยู่ใน Send switch ของ projection แล้วเพิ่มแล้ว (no-op ตอนนี้เพราะ in-memory run ถูก project ตอนอ่านเซฟแล้ว) `GridFightGetArchiveScRsp` ยังไม่มี handler ส่งจริง เพิ่มไว้เป็นเกราะ ข้อสรุปใน `session.go` Send switch
- [ ] ตรวจ scope เปิดใช้ overlay ให้สัมพันธ์กับ target Client/provenance จริง อย่าใช้เพียงเปลี่ยนข้อความเวอร์ชัน
- [ ] ปัจจุบัน replacement star variants มี `SaleQuoteKnown:false` โค้ดปัจจุบัน reject การขายถูกต้องแล้ว (`CapturedSalePrice` คืน error ไม่เดาราคา) ต้อง capture ราคาขายจาก Client จึงจะปลดขายตัวนี้ได้ ห้ามเติมราคาเดา
- [x] Rebuild Game/SDK แล้ว deploy 14:07 ขณะไม่มีโปรเซสใดรัน (ดู §3) — ยังรอ Client ยืนยัน
- [ ] ถ้ายังมี GuideBook NRE หลัง role ถูกต้อง ให้ตรวจ book/chapter config แยก ไม่ซ่อนปุ่มเพื่อกลบ exception
- [ ] ตรวจเส้นทาง exit และ UI transition/camera restoration จากต้นเหตุ อย่าเปิด/ปิดกล้องหรือ Canvas ทุกตัวแบบ blanket
- [ ] `GridFightQuitLeaveGamePlay` ปัจจุบันเพียงตั้ง `currencyWarsOpen=false` และตอบกลับ โดยรักษา run ให้ Resume; อย่าเพิ่ม abandon run/teleport โดยไม่มี callback evidence
หลักฐาน: `cw54-current-defaults.log`, `cw54-role-replacement.log`, `cw54-role-constructor.asm`, `cw54-get-role.asm`, `cw54-role-flat-get.asm`, `cw54-guide-count.asm`, `cw54-guide-sync.asm` ใน `battle_diagnostics/`
### Tea Break ที่จบรอบไม่ได้ — สถานะ 24 ต.ค. บ่าย
ผู้ใช้ติดที่ Tea Break (route 2801 chapter 1 section 5) ตั้งแต่ rev 512: ack round-begin 22 → return-prep 23 → preparing แล้ว run ไม่มี pending แต่ยืนอยู่ที่โหนด Tea Break กด Continue แล้ว Client ส่ง `GridFightEnterBonfireCsReq` ×3 (14:19) server ตอบ retcode 0 ตาม schema (retcode-only) แต่ไม่มีอะไรตามมา Client จึง retry แล้วผู้ใช้กดออก
สิ่งที่ capture ได้จาก reference (`.runtime/march_cw_teabreak_capture.go`, `march_cw_next_after_teabreak.go`, ไฟล์ `march-cw-teabreak*`/`march-cw-next-*` ใน battle_diagnostics):
- Queue ของ pending เป็น cursor ต่อ run ที่เพิ่มทีละ action (16→17, 17→18, 19→20) และ Client รับค่า jump ไม่ต่อเนื่องได้ (เคย 16→20 ผ่าน)
- Entry ใน CurrencyWarsNodeTransitions หมายถึง transition FROM section N TO N+1: next_pending_wire = round-begin ของ N+1, round_pending_wire = pending หลัง ack round-begin ที่ N+1 ปัจจุบันมี 1-4 ห้ามตีความว่าครอบคลุม route
- section 6 (1-6) มี round-begin 19 → ack → return-prep 20 → preparing แต่ยังไม่มี level wire (IMPNAHBCADN) ของ 6 ใน sync ที่ capture ได้ จึงยังสร้าง entry 5→6 ไม่ได้
**ข้อจำกัดสำคัญ:** โค้ดอ้างอิง March7 (`.runtime/march-source`) **ไม่มี handler ของ GridFightEnterBonfire เลย** และมี state machine เต็มรูป (GridFightSession Phase/PrepareCurrentNode/AdvanceToNextNode/GetNextNode จาก route config) แต่ไม่ implement Tea Break การ capture จาก reference จึงผลิต choice arm ของ Tea Break ไม่ได้ สิ่งที่ขาดคือหลักฐานว่า Client คาดหวัง pending arm ใดหลัง EnterBonfire ต้องโพรบฝั่ง Client (bounded, named types) หรือหา reference ที่ implement ห้องนี้ **ห้ามเดา arm/เติม pending มั่ว**
งานต่อไปที่ชัด: โพรบ Client หา expected arm หลัง EnterBonfire; ศึกษา GridFightSession ของ March7 เป็นแบบแผน implement node advance จริง (แทน captured wires) เพื่อจบ route; หรือ reset บัญชีอ้างอิง (admin gameplay/reset) แล้ว replay ทั้ง route เพื่อ capture level wire ของ section ถัด ๆ ไป
## 5. งานด่วน B — กาชาเลือกตัวละครได้จริง
### สถานะจริง
- ผู้ใช้เห็นเฉพาะ Stellar Warp/Standard จึงยังไม่ตรงคำขอ
- `AssetMgr.Exists` ยืนยัน Standard และ Novice prefab มีจริง แต่ limited character/lightcone ทั้ง 4 path ใน captured table ไม่มีจริง
- การส่ง Seele limited prefab เคยทำให้ `UIPrefabLoader` ArgumentNullException ระหว่าง `GachaMainPage._create_pools_panel` แล้วกลับแมพดำ
- ปัจจุบัน policy เปิดแค่ Standard สำหรับดูหน้า ส่วน `DoGacha` ของ Standard ตอบ NOT_SUPPORT นี่เป็น mitigation ไม่ใช่ฟีเจอร์เสร็จ
- Captured GachaBasicInfo มี 6 แถวและ character candidates 2 แถว ไม่ใช่ตู้ครบทุกตัวละคร
- ห้ามนำ limited paths กลับมา enable เพียงเพราะมีแถวในตาราง
### ไฟล์หลัก
- `internal/common/gacha_catalog.go`
- `internal/gameserver/handlers_gacha.go`
- `resources/GachaSandboxPolicy.json`
- `resources/PreviewGameplayCatalog.json`
- หลักฐาน `battle_diagnostics/gacha-asset-exists-20261024.log`
Backend grant ที่เตรียมไว้ให้ตัวเด่นของ banner และ duplicate material ตาม first Eidolon cost จริง โดย merge latest import ใต้ shared lock ไม่เปลี่ยน rank/EX/Traces และยัง reject first acquisition ของ avatar ที่ไม่มีใน imported roster ต้องทำ acquisition ให้ครบถ้าจะรองรับกรณีนั้น
### จุดที่เพิ่งอ่านได้ เพื่อไม่ต้องเริ่มใหม่
Client ใช้ **Luau** (`xluau.dll`) ไม่ใช่ LuaJIT:
- `string.dump` ถูกถอด ไม่มี `jit.util`
- มี `debug.getupvalue`, `debug.getinfo`, `debug.info` และ `package.loaders`
- ใช้ `package.loaders[3]('Ui.Gacha.GachaMainPage')` อ่าน loader closure ได้ **โดยไม่ execute closure และไม่แทน package.loaded**
- Passive hook ที่ `xluaL_loadbuffer` ได้ bytecode ของ `@BakedLua/Ui/Gacha/GachaMainPage.bytes` ขนาด 23630 bytes
- REA evidence: `ev_57f147cb094af2060be82f5110e378d25ff2179f0390c56348368a855e7658b8`
- เก็บ `gacha-main-page.luau`, `gacha-main-page.hex`, `gacha-main-page.json` ใน `battle_diagnostics/`
- `tools/inspect_luau_v4.py` อ่าน Luau v4/type1 และ export prototypes/constants/locals โดยไม่ execute bytecode
- Layout reference คือ upstream Luau `VM/src/lvmload.cpp` และ `Common/include/Luau/Bytecode.h`; สำเนาอยู่ใน diagnostics การ parse สำเร็จไม่เท่ากับถอดความ behavior ทุก opcode แล้ว
`_create_pools_panel` prototype 26 / line 308 อ่าน group data ผ่าน `GetSortedGachaGroupDatas` แล้วใช้ `DefaultGachaPoolData.PrefabPath`, `sync_load_prefab`, `_gachaType2tabItem`, `create_panel`, `set_tab_data` มีแยก single-pool/group path
`BaseGachaPoolData.Row` มี getter/setter และ `GachaModule.GetGachaPoolData` / `GetSortedGachaPoolDatas` มีจริง แต่ **ยังไม่มี production patch เปลี่ยน prefab/สร้างตู้เพิ่ม** การใช้ Standard prefab แทน limited ยังไม่ได้พิสูจน์ binder/controller compatibility อย่าเปลี่ยนแบบสุ่ม
Loaded presentation modules มี `DefaultGachaAvatarPanel`, `DefaultGachaUpAvatarPanel`, `DefaultGachaPoolTabItem` โดย UpAvatarPanel มี `_init_imgs`, `_setup_up_avatar_img`, `setup_view` อาจเป็นทางต่อ generic presentation ที่ต้องอ่านเพิ่ม
### ต้องทำต่อ
- [ ] หาวิธีแสดงตู้ตามตัวละครด้วย asset ที่มีจริง และ bind controller ได้ถูกต้อง
- [ ] ถ้าทำ custom presentation ต้องมีตัวละคร/ชื่อ/ภาพตรงกับผล draw และแยกจากการอ้างว่า official prefab ใช้งานได้
- [ ] ให้ catalog ที่ UI แสดงกับ catalog ที่ backend รับ draw เป็นชุดเดียวกัน
- [ ] รองรับ 1/10 draws ตาม policy และ duplicate/material persistence โดยไม่ทำลาย progression
- [ ] ตรวจ acquisition ถ้า avatar ยังไม่มีใน import
- [ ] แก้ entry/exit ให้คืนโลกปกติ ไม่ทิ้ง pending transition
- [x] แก้ note ใน GachaSandboxPolicy แล้ว (24 ต.ค.): asset_verification_note ปัจจุบันระบุว่าตรวจครบ 6 path แล้ว ตามหลักฐาน `gacha-asset-exists-20261024.log`
## 6. งานด่วน C — กิจกรรมกลับมาและเข้าไปดูได้
### สถานะ
ผู้ใช้เห็นแค่ CW กับ Anomaly Arbitration กิจกรรมที่เคยเพิ่มหายไป เพราะปิด policy หลังพบ ActiveActivity invalid item และ RaidCollection missing reward icon
ล่าสุดอ่าน `AssetMgr.Exists` ครบ 290 panel/icon paths โดยไม่ load asset แล้ว เก็บผลใน `resources/PreviewAssetAvailability.json` ใช้ source/provenance ปัจจุบัน
### ทำแล้วใน source / ยังไม่ deploy
- `ActivityPreviewPolicy.json` เพิ่ม 8 prefab families ที่มี asset หน้าและ TabIcon และไม่มี explicit DisplayItemList dependency
- `activity_preview.go` ตรวจ availability ก่อนประกาศ schedule
- กลุ่ม `QuestState` ใช้ handlers quest/mission เดิม
- เพิ่ม `GetMultipleDropInfo` typed response มี panel entries และ zero counters เป็น preview ไม่ใช่สิทธิ์ double/triple drop ที่แต่งขึ้น
- ActiveActivity/RaidCollection ที่มี error ยังไม่เปิดกลับ
- `GetFiveDimMiniGameData` ยังตอบ empty list ไม่ใช่การทำมินิเกมสำเร็จ
### ต้องทำต่อ
- [x] ตรวจ module-ID/panel-ID association และ dedup (24 ต.ค.): พบ conflict จริงตามข้อสันนิษฐานเดิม โมดูล `1002101` ถูกอ้างใน 14 กิจกรรมรีรัน ข้าม panel 10021 และ 10113 แต่ทั้งคู่เป็น prefab เดียวกัน (`QuestFarmMultipleDropPanel`) และ handler เดียวกัน จึงเผยแพร่รายการเดียวถูกต้องอยู่แล้ว `activity_preview.go` ถูกแก้จาก first-match เงียบ ๆ เป็น: รวม candidate panels ต่อโมดูล เรียง deterministic แล้ว error ทันทีถ้า panels ใด handler/prefab ไม่ตรงกัน ผลลัพธ์กับข้อมูลปัจจุบันเหมือนเดิม 12 schedules (10 drop + 2 quest) fallback `PanelID==0 -> ActivityID` มีใช้จริงเฉพาะกิจกรรม 10054 และสอดคล้อง pattern module = panelID*100+1 ของทุกแถว explicit
- [ ] เลือกกิจกรรมที่มี dependencies ครบและ handler entry/data จริง เพิ่มเป็นรายระบบ ไม่ publish ทุกแถวพร้อม success ว่าง
- [ ] ตรวจเวลาตาม activity schedule config ไม่ hardcode deployment time (ตอนนี้ schedules ใช้ `cfg.ActivitySchedule` ร่วมกับ Endgame แล้ว แต่ยังไม่ได้ตรวจว่าตรง schedule config ของกิจกรรมแต่ละตัว)
- [ ] แยก preview/reward/gameplay support ในเอกสารให้ชัด
- [x] Rebuild/deploy ทั้งคู่จาก source ล่าสุดแล้ว 14:07 (ดู §3) — README ที่บอก previews withheld ยังต้องอัปเดตเมื่อมี Client ยืนยัน
- [ ] ยังไม่มี Client confirmation ว่ากิจกรรม 8 families ชุดนี้แสดง/เข้าได้จริง
## 7. งานด่วน D — Stella Jump ด้านข้าง
### สิ่งที่ผู้ใช้เห็น
หน้าเดิน Starfroster ตรง gateway รูปโดนัท/เครื่องเล่น กด F Investigate แล้วขึ้น **There's still more to do…** ยังไม่เข้าเกม การมี GetCase handler จึงยังไม่แก้จุดเข้าที่ถูกปฏิเสธอยู่ก่อน
### ส่วนที่มีแล้ว
- `resources/StellaJumpConfig.json`: ChenLingGameBoyCaseRow ปัจจุบันครบ 16 แถว มี group/instance/entity/challenge/cheat quest ตาม capture
- `internal/common/stella_jump.go`: separate persistent records; read-only reads และ targeted locked writes
- `handlers_stella_jump.go`: GetData, Finish, Ranking, Settings และ cheat requests ที่ยังเป็น obfuscated names
- response มี case payload ไม่ null และ expose challenge packs โดยไม่เก็บเวลาปลอมเพื่อปลดล็อก
- Handler path และข้อมูล GameBoy ไม่ได้พิสูจน์ว่า gateway ในภาพใช้ GameBoy entry เดียวกัน ต้องตรวจ actual caller
### ต้องทำต่อ
- [ ] ระบุ condition/scene task ที่ gateway ตรวจแล้วแสดง toast จากข้อมูลจริง อย่า complete ทุก mission/ตั้งทุก condition เป็น true — **audit จาก gameserver.log/server_debug.log 24 ต.ค.:** การ Investigate ที่ขึ้น toast คือ prop entity 1035 และ 1012 ด้วย interact_id2=1100 (server ตอบ real prop state=1 ถูกต้องแล้ว) มีรอบหนึ่ง Client เปิด UI GameBoy เองโดยไม่ผ่าน InteractProp (SetClientPaused + `GetChenLingGameBoyDataCsReq` case 16) แล้วปิดเอง ไม่มี request เริ่มเกมตามมา toast จึงเป็นเงื่อนไขฝั่ง Client ที่ยังไม่ถูก capture **สิ่งที่ขาด:** โครงสร้าง `ChenLingGetDataScRsp` (CmdID 9612) ที่มีข้อมูลจริง — Client ส่ง `ChenLingGetDataCsReq` ทุกครั้งโหลด floor และ server ปล่อย drop (danger family "ChenLing" + ไม่มี typed handler, log ขึ้น "Unknown command ID: 9612") GameBoy อยู่ในระบบ ChenLing Fes และ `BDOEDOEBFAJ` เป็น Fes board state เต็มรูป (stage/hp/entity_list/pending) การตอบว่างเคยทำ NRE จึงต้องมี capture จากเซิร์ฟเวอร์ทางการหรือ runtime ก่อน ห้ามเดาโครงสร้าง ที่ `.runtime/march-source/.../sc-packet-handlers.json` มีแค่ RVA ของ client callbacks ไม่ใช่ตัวอย่างข้อมูล
- [ ] Player.log 24 ต.ค. มี warning `[FiveDim] Group 12 的GroupProperty LG_110001__262_MapIconState_Auto 不存在!` ตอน CartographyFiveDim init จาก GetSceneMapInfoScRsp — เป็น warning ฝั่ง config ของ FiveDim instance 110001 (Stella Jump case 1) ยังไม่พิสูจน์ว่าเกี่ยวกับทางเข้าล็อคโดยตรง ต้องแยกตรวจก่อนอ้าง
- [ ] แยก ordinary FiveDim entrance/transfer/minigame กับ ChenLingGameBoy ให้ถูก ไม่เอา Parkour/รถแข่งมาปน
- [ ] อ่าน FiveDim enter/transfer/leave/update schema consumers และต่อ state/position callbacks ให้ครบสำหรับทางเข้าเป้าหมาย
- [ ] ปลด stage/challenge ตาม case/config ที่ตรง Client และเปิดเข้าเล่นได้จริง
- [ ] บันทึกผล/เวลา/challenge จริง รักษาเซฟ CW และส่วนอื่น
- [ ] cheat response extra boolean ยังมี label ไม่ยืนยัน ต้องเก็บข้อจำกัดไว้
### ข้อมูลสำหรับวิเคราะห์ต่อ
`FiveDimModule` ปัจจุบันมี `RequestEnterGame`, `RequestTransfer`, `RequestLeaveGame`, `RequireChenLingGameBoyData`, `EnterChenLingGameBoy`, `FinishFiveDimMiniGame`, `_OnGetFiveDimMiniGameDataScRsp` และ `_GameConfig`
`GetFiveDimGameDataScRsp` callback ที่อ่าน native ล่าสุด sync jump-energy scalar ไม่ได้ sync nested state ทุก field จึงอย่าเพิ่ม nested payload โดยหวังว่าจะปลดทางเข้าเอง
`_GameConfig` มี Scroll/Player/Camera/Physics/Avatar/Level/Audio/MiniGameCollection/Achievement/Misc config การ Serialize PlayerConfig ทั้งก้อนเคยติด self-referencing vector.normalized loop ต้องอ่านเฉพาะ primitive/named fields
Starfroster floor 20571001 มี scene entry Town/Story แยกกัน `res.json.scene_config` เป็น list ใช้ key `entryID` ไม่ใช่ map/entry_id มี props 151 ตัวต่อ entry เก็บ Prop ID/JsonPath เดิมไว้ใน `battle_diagnostics/prop-source-rows.json` แต่ capture นี้เป็น revision เก่า ต้องตรวจความตรงรุ่น
**ห้ามใช้ broad LoadRtLevelFloorInfo probe เดิมเพื่อไล่ graph ใหม่** เคยทำ Client crash แล้ว ใช้ข้อมูลที่โหลดอยู่หรือ exact named config ที่รู้วิธีอ่านปลอดภัย
เครื่องมือที่เตรียม: `tools/preview_minigame_metadata.lua`, `preview_gameboy_metadata.lua`, `fivedim_config_metadata.lua`, `fivedim_minigame_config.lua` และ logs `preview-gameboy-current.log`, `preview-minigame-current.log`, `gameplay-regression-metadata.log`
## 8. แต้มเทคนิค Endgame และ Aha's Help
### แต้มเทคนิค — แก้ source แล้ว ยังไม่ยืนยัน/ยังไม่ deploy ล่าสุด
- ผู้ใช้หมายถึง **แต้มเทคนิคปุ่ม E ตอนเดินก่อนสู้** ไม่ใช่ skill points ใน Battle
- `lineupInfoFromAvatars` สร้าง Endgame lineup เริ่ม Mp ตาม MaxMp
- `Session.techniqueLineup` ใช้ MaxMp เป็นค่าเริ่ม session เมื่อมี ChallengeRun; overworld และหักแต้มต่อ cast ยังคงเดิม
- เพดานทีมที่ตรวจจาก resource เป็น 7 ขณะที่ผู้ใช้บอก 8 ไม่ได้เพิ่มเลข 8 ตายตัว ต้องรองรับเพดานที่ rule/team คำนวณได้จริง
- ไฟล์หลัก `handlers_challenge.go`, `technique.go`
### Aha — ผู้ใช้ยืนยันแล้วว่าแสดงใน combat
- Frontend envelope เคยอ่าน `/api/persistent` ผิด field; แก้เป็น `persistent` และโหลด selector แยกจาก character cache
- เลือก LV 1–3, explicit off และ FreeSR fallback ได้
- custom Corruption battle เดิมไม่เข้า branch ที่ผูก ChallengeStageID; เปลี่ยนให้ตรวจ Corruption buffs ใน outgoing battle จริง
- บันทึกระดับที่เลือกมีผลตอนสร้าง Battle ถัดไป ไม่แก้ battle ที่กำลังเล่น
- ผู้ใช้ยืนยัน “ขึ้นแล้ว” ห้ามรายงานว่ายังรอเลือก LV ตามเอกสารเก่า
- หลักฐาน `AHA_HELP ... selected=3 ... support=3034013 level=3` และ `battle_diagnostics/aha-help-web-20261024.png`
- ไฟล์ `aha_help.go` ทั้ง common/gameserver, SDK `api_aha_help.go`, `AhaHelpConfig.json` และ GaC-srtool ฝั่ง Save Manager
## 9. หลังแก้ regressions: ทำ CW ต่อให้ครบ
### ผู้ใช้ยืนยันผ่านมาก่อนแล้ว (เฉพาะเส้นทางที่ลอง)
- Standard เข้าเกม/ซื้อหนึ่งตัว/จัดตัว/เริ่ม Battle ห้องแรก
- ซื้อ EXP และขายตัวที่ไม่ได้ติดอุปกรณ์
- รวมตัว 3 ตัวอัปดาว และติดตามอุปกรณ์
- Plot Armor เลือก Protagonist และ Battle หลังเลือก
- Encounter combat/settlement ไปห้อง 1-5
การยืนยันเหล่านี้เกิดก่อนพบ Client revision เปลี่ยน จึงต้องรักษาเส้นทางเดิมและระวัง schema/config ต่างรุ่น ไม่ใช่หลักฐานว่าห้องทุกแบบและ Overclock ครบแล้ว
### ยังต้องทำ
- [ ] Backstage Tea Break: choices/effects/queue acknowledgement/next room
- [ ] Automatic Orb drops ตาม killed instance/node/talent rule จริง ไม่ให้ Orb ทุก Battle แบบตายตัว
- [ ] เปิด Orb และ resolve reward ด้วยตาราง combination/basic bonus ที่ตรงรุ่น
- [ ] Consumable effects/stack/use/consume quantity ให้ครบ
- [ ] Forge/equipment crafting/dressing และ returned equipment state ให้ตรง Client
- [ ] Supply, Encounter alternate branches, Spotlight, Trial, Boss และ transition ต่อห้องสำหรับ Standard/Overclock
- [ ] Completion/settlement/rank/weekly/season rewards ตามข้อมูลจริง ไม่แต่งคะแนน
- [ ] Pending-action oneof ทุก arm ที่ผู้ใช้เข้าได้ ต้อง mutation + notify + ack ถูกต้อง ไม่ตอบ null success เพื่อดับ spinner
- [ ] เติม commands/handlers ที่ยังไม่รองรับจาก inventory โดยดู semantics ไม่ใช่นับ registration ว่าครบแล้ว
- [ ] Resume/leave/abandon/unstuck ไม่ทำ run หาย ไม่หัก/แจกซ้ำเมื่อ resend และไม่ทำ stale session ทับ API command
### คำสั่งเสกที่มีแล้ว
```text
/cw status
/cw list role|equip|orb|consumable|forge
/cw gold <total>
/cw hp <total>
/cw exp <gain>
/cw equip|orb|consumable|forge <itemID> [count]
/cw role <roleID> <star> [count]
```
ผ่าน SDK command queue, ผูก UID/run และ apply ใน Preparation เท่านั้น คิวกับ snapshot ใช้ revision/atomic persistence สิ่งที่ยังไม่มีจริงอย่าแสดงว่าคำสั่งรองรับครบแล้ว แยกการ “เสกเข้ากระเป๋า” จาก “กดใช้แล้ว effect สำเร็จ”
### เอกสารและ reference
- `docs/currency-wars-coverage.md`: request registration และ pending arms ที่ยัง missing เป็น snapshot ไม่ใช่หลักฐาน gameplay
- `docs/currency-wars-6900-audit.md`: 6900 คือ RET_GRID_FIGHT_CONF_MISS ไม่ใช่ CmdID; อ่านส่วน Subsequent recovery ที่แก้ blocker เก่าแล้ว
- `docs/currency-wars-investigation.md`
- Reference ที่ผู้ใช้ให้คือ March7 PS ใต้ `E:\beta hsr\server` (ตำแหน่งเฉพาะเครื่องสำหรับงานวิเคราะห์ ไม่ใส่ลง source/startup)
- มี isolated reference/captures ใต้ `.runtime/` เทียบได้ แต่ห้าม promote ทุกค่าจาก reference เก่าเป็น Client ปัจจุบัน
- Orb data: current capture 529 Orb, 18 consumable, 11 Forge, 478 combination; เทียบ reference ได้ตรงแค่บางส่วน (347/478 combination, 276/529 Orb มี direct basic-row match)
## 10. Backlog เก่าที่ต้อง audit สถานะ ห้ามบอกว่าเสร็จหมดจากความทรงจำ
รายการนี้เก็บจากคำขอในแชต มีบางส่วนเคยแก้แล้ว แต่ไม่ครบทุกเรื่องที่มีผลยืนยันล่าสุด ให้ตรวจ code/evidence ก่อนเปิดงานซ้ำ:
- [ ] ทุก Endgame: เซฟทีม/คะแนน/เลือกห้องต่อโดยไม่เริ่มห้องแรกทุกครั้ง และ PF/Starward/MoC/AA/AS ไม่ค้างเปลี่ยนห้อง
- [ ] Traces แสดงระดับใน Client และ GaC-Srtool ตั้ง/เซฟได้
- [ ] บัฟ/แต้มเทคนิคจากตัวละครก่อนสู้, อาหารเติมแต้มและ auto-use
- [ ] Acheron E ฆ่ามอนข้างทางได้ตามกฎ, debuff technique ไม่ fail to use ability
- [ ] มอนข้างทางใช้ monster/stage/version ตรงตัวที่ตีหรือถูกตี Custom monster เฉพาะเมื่อใช้ Srtool ตามคำขอ
- [ ] prop ข้างทางที่ตีแตกให้แต้ม/บัฟตามชนิดจริง
- [ ] animation/effect E ของ Aha และโดม Cyrene ผู้ใช้บอกว่าไม่เกี่ยวกับ Freecam
- [ ] Freecam หันด้วยเมาส์ได้ แต่ขณะต่อสู้ mouse click ไม่ trigger attack/เปลี่ยนสกิล; Q/E ใน Battle ไม่ขยับกล้องขึ้นลง ใช้ PageUp/PageDown แทน และคืน input เมื่อปิด
- [ ] Hide UI: ซ่อน UI ตัวละคร/หลอดอัลติ/action bar ใน Battle และ character/EX Eidolon UI แต่ไม่ซ่อนภาพ EX/ทำพื้นหลังเบลอ; **ต้องรักษาชื่อเซิร์ฟเวอร์ ชื่อ PS และ UID**
- [ ] Preset ทีม 20 slots/การนำทีมที่เคยจัดมาใช้ และการเซฟหลังสลับ
- [ ] UID 52010, ชื่อ login AFN -> GaCy และบอกผู้ใช้ว่าแก้ตรงไหน; ห้าม hardcode user identity เพิ่มเพื่อกลบ config
- [ ] ของแต่งตัวผู้บุกเบิกต้องปลดตามตาราง
- [ ] run.bat/startup เช็ค Go/requirements ดาวน์โหลดตาม config, SDK/Game/launcher ใช้ค่าเดียวกัน และ consoles มองเห็น
- [ ] ก้อน Eidolon ยังคงอยู่ในกระเป๋าแม้ E6/EX เต็มแล้ว ตามคำยืนยันผู้ใช้
- [ ] Unstuck ใน GaC-Srtool ใช้ได้โดยไม่ต้องออกเข้าเกม ไม่ลบ run/progression
- [ ] Story/Town ในหน้า M: ผู้ใช้ยืนยันแล้วว่าแยกปลายทางและภาพฉากได้ รักษา `navigation_profiles.lua` กับ entry override; ยังต้อง audit เสาวาร์ป/ห้องภายใน/รถไฟ Starfroster ตามข้อร้องเรียนเก่า
- [ ] มีคำขอ git ในอดีต แต่รอบส่งต่อนี้ยังมีงานค้างจำนวนมากและไม่ได้อนุญาตให้ commit/push งานปัจจุบันโดยอัตโนมัติ
## 11. วิธีรับงานต่อที่แนะนำ
1. อ่าน AGENTS, git diff และเอกสารนี้ ตรวจ process/module/config ที่เป็นปัจจุบันอีกครั้ง
2. แยก source-ready fixes จาก deployed fixes อย่าขอให้ผู้ใช้ลอง build ที่ยังไม่ได้วาง
3. ทำกาชา/กิจกรรม/Stella กับ regressions CW ตาม sections 4–8 โดยใช้หลักฐานที่เก็บแล้ว
4. ถ้าใช้ REA หรือ runtime probe ให้ตรวจ identity ใหม่ ใช้เฉพาะ target ที่ระบุ จำกัดงานต่อ frame และ cleanup เสมอ
5. Rebuild ทั้ง Game และ SDK หลังแก้ source/resource ครั้งสุดท้าย สำรองและ deploy ตอนนอก Battle เมื่อจำเป็น (build/deploy รอบ 14:07 24 ต.ค. ทำแล้ว แต่ถ้าแก้ต่อต้อง rebuild ใหม่)
6. ไม่รัน tests/ไม่วนขอ gameplay retry ตามคำสั่งล่าสุด รายงานสิ่งที่ยังไม่มี Client confirmation ตรง ๆ
7. อัปเดตเอกสารสถานะให้ตามจริง แล้วจึงเดิน CW progression ต่อ ไม่บอก “ครบทุก handler/ทุกกิจกรรม” จากการมี success response หรือ build ผ่าน
### ขอบเขตที่ยังไม่ได้เสร็จ ณ จุดส่งต่อ
**ตู้ตัวละครที่เลือกสุ่มได้, Stella Jump gateway, การเล่นกิจกรรมทุกตัวที่ต้องการ, CW exit black-screen confirmation และ CW เต็มโหมด ยังไม่เสร็จ**
CW role compatibility, event preview families, Endgame technique initialization และงาน audit รอบ 24 ต.ค. (projection ชื่อเพิ่มเติม, activity loader, policy note) รวมอยู่ใน build/deploy 14:07 แล้ว แต่ **ไม่มี gameplay confirmation สำหรับทั้งชุด** เซิร์ฟเวอร์ยังไม่ได้สตาร์ตหลัง deploy ไม่ควรเริ่มใหม่จากศูนย์หรืออ้างว่าวางครบแล้ว
# Latest continuation — 2026-10-26
### Ping colors and CW Go follow-up
Ping colors is now user-confirmed: all bars and real latency digits animate,
colors match, and digit changes do not flicker. `scripts/ping_rainbow.lua`
uses white-RGB/original-alpha masks for the single-sprite signal icon and
colors the native TextGenerator glyph mesh at the canvas boundary. No rich
text is written over the native ping value. Current `10ms` capture contains
16 populated vertices, without an extra unused quad. See `docs/ping-colors.md`.
CW Go's current captured panel exists (71101) but is PreGuide2. Its actual
ActivityPanelConditionRow requires FinishMainMission8047206; the old initial
mission response omitted it. Common Go consequently chooses GuideGoto6417
instead of ActivityGoto6418. `resources/CurrencyWarsActivityConditions.json`
retains that exact current row/provenance; `LoadCurrencyWarsGuideMissions`
validates it and adds only its declared guide missions to the shared mission
unlock view. Expected GetMissionData main count:149 instead of148. It does not
finish all2205 imported main missions or force Lua state. See
`docs/cw-book-entry-recovery.md`.
The combined standard/shipping Game+SDK build passed and both root servers
were restarted after this fix. All temporary probes were removed from scripts/
and the passive Frida capture session was detached. Fresh GetMissionData
logged149 main missions; actual EnterScene resolved CW entry2032202, and the
user confirmed teleport works after relogin. This closes the reported silent
Go entry failure, not the still-incomplete gameplay inside the CW run.
This section supersedes older deployment/feature status below; historical
investigation details are retained.
- The overworld loading recovery was confirmed by the user. A separate AA
entry failure then reported `CreateNPCMonster Invalid ID 4015011`.
- The updated FFGO reference was inspected offline, never executed. Complete
CmdID/protobuf/function/direct-call/resource dumps are under
`battle_diagnostics/ffgo-20261026/`; reproducible tools and interpretation are
documented in `docs/FFGO-CW-REFERENCE-20261026.md` and
`docs/ffgo-cw-resource-reference.md`.
- AA scene correction now uses an explicit provenance-backed 44-row resource.
Peak 204 maps to NPC 4015010 / entry 3013701 / group 10. All 44 NPCs also
occur in the reference's extracted NPC Excel table. The last eight scene
placements still require supplementary data or reject before EnterScene.
Actual current Client acceptance remains unverified until the new build is
exercised. See `docs/aa-scene-npc-recovery.md`.
- Gacha: enabled native registration of 71 eligible five-star banners is
confirmed by Client logs. The user confirmed the prototype art/panel fix.
Latest 80/10 pity, three four-star portraits and atomic reward persistence
were deployed previously but not Client-confirmed after that change. The
old OFF gate in historical notes no longer describes current policy. See
the current-status section of `docs/GACHA-NATIVE-ADAPTER.md`.
- ComicDessert GetData preview now has a real four-cycle/fifteen-level catalog
and sends initial cycle 1. Starting/finishing cooking remains unfinished.
- CW reference extraction closes the old missing-table gap: 72 tables,
including bonus pools, basic bonuses and bonfire options. Reference custom
recipes are labelled implementation evidence, not original Client JSON.
The current route's Tea Break can be a PetPal override of a static Monster
node; never replace the active run with the reference route/player save.
- Active source work in this continuation: Tea Break creation/selection and
persistent PetPalStarDown effect; scoped real Orb payout and current packet
translation. Pending-next-node construction still needs a broader port;
existing captured transitions cover only the first four nodes. Do not claim
CW complete from menu success or a successful compile.
- Still carry forward: Stella Jump portal/condition unlock, missing activity
gameplay and previews, CW remaining route/reward/effect progression and exit
black-screen confirmation, Aha/Cyrene presentation issues, and earlier UI/
cosmetics/interaction reports where no Client confirmation exists.
Deployment: `run.ps1 -Action build` completed for standard and self-contained
Game/SDK binaries, then `run.ps1 -Action servers` started both root servers in
visible consoles. A private predeployment checkpoint retains saves, local
settings and previous root executables. No research probe was staged; scripts/
contains only the four maintained scripts. No tests were run. The new AA scene,
Tea Break and Orb paths have not yet been confirmed in the Client.
Integrated Tea Break scope: resource-backed menu and option selection, phase-1
sync, atomic saved PetPalStarDown rule and one-time future-layer star reduction.
Heal and take-drop/advance remain explicit unsupported operations. Integrated
Orb scope: current named handler, atomic removal/rewards, native notification
and grouped context for supported fixed/declarative recipes. Ordinary Orb100's
weighted bonus pool and general effect hooks remain unfinished. See
`docs/currency-wars-ffgo-workflow-20261026.md` and
`docs/currency-wars-ffgo-orbs.md` before claiming broader completion.
+32
View File
@@ -0,0 +1,32 @@
# AA round selection sync — 2026-10-25
## Confirmed path and defect
The Srtool AA dropdown posts `peak_group_id` to `/api/monster-settings/aa-round`; the SDK writes `persistent.aa_round_selection`. A read-only check returned group 2 with the configured Client version. The running Game executable contains the selection reader.
Before this change, the selected group affected only `GetChallengePeakDataScRsp.CurrentPeakGroupId` when the Client happened to request AA data. Saving from Srtool did not invalidate cached Client module state. `StartChallengePeak` continues to consume the actual requested PeakID; it does not consult the UI selector and must not silently substitute a different room.
The protocol's `ChallengePeakGroupDataUpdateScNotify` contains one `ChallengePeakGroup`, with no current-group field. Sending that notification is not proof that the selected current group changed. No numeric command alias or unsolicited response was added.
## Source changes
- `internal/gameserver/aa_round_sync.go` builds a resource-validated desired group and selected-group/version digest. The default comes from the same loaded Peak groups as the data handler. It reads selection without writing saves.
- `aa_round_sync.lua` uses the actual current Client's `ChallengePeakModule.SendGetChallengePeakDataRequest()` and observes `CurrentPeakGroupID`. It sends one outstanding request and waits for the native value to match. It does not fabricate a response, alter private state, close a page, change scene, start a Battle, or remap a PeakID.
- Server gating defers while `CURRENT_BATTLE`, `ChallengeRun`, or CW is active; the Client also checks `BattleGamePhase`. Existing native login initialization (`CurrentPeakGroupID == 0`) is allowed to finish without issuing a duplicate request.
- `GetChallengePeakData` retains the existing Peak run's group until that run is left. It logs the actual selected group, number of groups and active-run state. Missing Peak resources now produce a typed error rather than a fabricated group/room list.
- Server README and Thai/English Srtool copy describe deferred native refresh rather than claiming that reopening the page necessarily causes a data request.
## Evidence and validation boundaries
The current process metadata in Player.log, `[GAC_AA_ROUND_META]`, reports:
```
UInt32 get_CurrentPeakGroupID()
Void SendGetChallengePeakDataRequest()
```
This evidence establishes the named native API, not its successful execution or UI refresh. Runtime pointers in the log are process-local and are not shipped or reused.
`go build ./internal/gameserver` and `node --check ../GaC-srtool/js/i18n.js` passed. No tests, save mutations, executable replacement, restart or Lua staging were performed for this source change. Root must wire `loadAARoundRefreshLua(s)` into heartbeat, build/deploy, and confirm the real request/reply plus `[GAC_AA_ROUND_SYNC] applied` and the displayed round before reporting Client success.
There is intentionally no timeout retry while an in-flight request cannot be distinguished from an unchanged result. A changed native group proves completion; new desired choices can then be requested. Reconnect/module replacement resets local request tracking. All activity schedules and resource room/boss definitions remain intact.
+74
View File
@@ -0,0 +1,74 @@
# AA scene NPC recovery
## Observed loading failure
The current Client reports `CreateNPCMonster Invalid ID 4015011` while entering
Peak 204 from selected group 2. The source resource row supplies entrance
3013501, maze group 8, event 30502021 and NPC 4015011. This is a scene actor
creation failure, separate from refreshing the selected AA group.
`loadPeakResources` in `handlers_challenge.go` copies `NpcMonsterIDList` into
`PeakStageData.MonsterID`. `loadChallengeScene` in
`handlers_challenge_scene.go` forwards that value directly into
`SceneNpcMonsterInfo.MonsterId`; no current Client config lookup validates it.
The battle wave monster is a different identifier namespace and cannot be
converted into an adventure NPC by truncating digits.
## Evidence boundary
The existing `WorldBattleConfig.json` NPC catalog is a partial capture of 153
NPCs, from assembly SHA-256
`c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144`.
An offline comparison finds that 42 of the 44 Peak rows refer to at least one
NPC outside that partial catalog. Absence from it is therefore insufficient
to declare an AA room invalid. Using it as a mandatory allow-list would disable
most AA rooms, including ones not demonstrated to fail.
The reported Client error establishes that this particular NPC failed in the
actual session. It does not establish a replacement NPC or prove that all
other Peak rows are invalid. No replacement ID, arbitrary fallback monster,
save migration was justified by the old partial catalog alone.
## Reference-backed correction prepared
The FFGO update inspected on 2026-10-26 contains an explicit
`challenge_peak_extra_data` JSON object at binary file offset `0x114c212`,
decoded length 9101 bytes, binary SHA-256
`235f5c3567f281cc99613ed84694ef23f492c15298dc868a8e78e6529f0cda86`.
Its Peak 204 mapping is NPC **4015010**, entrance **3013701**, maze group
**10**. These values come from the reference object, not ID arithmetic.
The full reference extraction is retained in
`battle_diagnostics/ffgo-20261026/challenge_peak_extra_data.json`.
`resources/ChallengePeakSceneOverrides.json` retains all 44 explicit mappings
and their provenance. `peak_scene_overrides.go` applies only the scene NPC,
entrance and maze group after loading canonical Peak group memberships.
Battle event IDs, waves, buffs, targets and saved/active runs are unchanged.
The loader validates provenance, duplicate/unknown IDs, group membership and
merged resource scene placements. A missing mapping or unusable placement
is stored as a configuration error. `StartChallengePeak` rejects it before
creating battle/run state or sending EnterScene; unknown Peak IDs also now
return the existing typed challenge-not-exist error instead of empty success.
The first 36 reference mappings have monster placements in raw `res.json`.
The last eight (Peak 1001–1104) require supplementary placements or further
capture; no placement is invented when the merged loader cannot supply one.
The resource is labeled reference evidence, not a captured Client table.
`go build ./internal/gameserver` succeeded; no tests were run, no deployment
was performed by this subtask, and actual Client NPC/scene acceptance remains
unverified.
## Next bounded capture
`tools/aa_npc_config_metadata.lua` is prepared outside `scripts/` and passes
Lua syntax parsing. It inspects only six named candidate types, at eight
members per heartbeat, to locate `NPCManager.CreateNPCMonster` and the
NPC/Peak flat config entry points. Missing candidate types are logged rather
than treated as proof that config is absent. It does not enumerate assembly
types, call getters, create actors, load scene graphs or send gameplay packets.
The Client process was not open during this offline inspection, so this probe
has not been staged or run. Once current native/config lookup evidence is
available, capture the relevant Peak row and each referenced NPC config to
verify or supersede the reference mapping. Client battle/scene success remains
unverified.
+64
View File
@@ -0,0 +1,64 @@
# ComicDessert current Client contract
## Proven data and preview entry
`ComicDessertCatalog.json` retains all four Cycle rows and fifteen Level rows
captured from the current Client assembly. The catalog preserves 64-bit TextID
hashes, requires a complete two-table capture, rejects duplicate IDs, and checks
that each cycle references existing levels. It includes the ordinary cycle
levels and the Greedy Feast and Long Tail configuration paths; those paths alone
do not prove that their gameplay is implemented.
Current assembly SHA256:
`4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6`.
The native GetData consumer at `0xd4dbc60` reads response offset `+0x3c` into
`_SetUpProgress` (`0xd4dbcf0`). The protobuf getter for `FNIAAEAFGDE` reads that
same offset (`0x1fc3dcd0`). Progress synchronization at `0x16c8dab0` writes the
cycle ID at `+0x18`; the actual `CurrentCycleId` getter (`0x16c8d980`) reads
`+0x18`. `HNOCFELOAFJ` supplies the completed-level collection.
The root implementation responds to GetData with the resource's first cycle,
without fabricated completed levels, upgrades, currency or rewards. This is
preview state, not a working cooking-run implementation. A zero cycle ID led to
the Date dialog view-model failure observed before this response existed.
## Request family
These are the actual current command-table names, paired from the live concrete
NetworkService method signatures. Numeric IDs are documentation of the current
table, not aliases to register in source.
| Operation | Request | Response | Current IDs |
|---|---|---|---|
| GetData | `MGCJKEEOPEC` | `LPLCFFGANFC` | 10215 → 10208 |
| StartLevel | `MECNLNGKDHA` | `CIDKLLMAIGP` | 10204 → 10220 |
| FinishLevel | `CBMLONMBLNE` | `PEFBGOANFHP` | 10216 → 10209 |
| UpgradeDevice | `DONCOCHMEBC` | `NLJOCMODADF` | 10207 → 10206 |
| ChangeCycle | `JLBJPLGJBFF` | `NBIBDLLLCLH` | 10213 → 10212 |
| StartLongTail | `FHJMEFOOOAB` | `PIGILFCALBA` | 10211 → 10218 |
| FinishLongTail | `CGHKNHAJBGL` | `CMHFBLDNPGB` | 10219 → 10210 |
The concrete NetworkService has `OFHMHPKEECI(UInt32)` returning
`IPromise<CIDKLLMAIGP>` and `<StartLevelAsync>b__2_0(CIDKLLMAIGP)`.
`StartLevel` request carries `level_id` at tag 4. Its response additionally has
`HOGEMAHFFEF` (uint32, tag 1) and `NLMEEEKBPKO` (string, tag 2), plus retcode at
tag 12. The purpose and required values of the uint/string have **not** been
proven. A retcode-only success must not be advertised as working gameplay.
## Next bounded capture
`tools/comic_level_start_metadata.lua` is inactive outside `scripts/`. It reads
the already constructed NetworkService and LevelStartFlowService, plus the
actual Start response type obtained from the NetworkService return type. It
records at most eight methods/properties per non-battle heartbeat and invokes
no gameplay or scene methods.
After capture, resolve current-process MethodHandles through record `+8`, verify
the resulting entry lies inside the current GameAssembly, and disassemble the
StartLevel consumer and response getters. Handles from an exited Client cannot
be reused. Map the string/uint consumers before implementing a successful Start
response or persistent cooking run.
No Start/Finish/Upgrade/ChangeCycle/LongTail implementation, deployment, runtime
draw, save mutation or gameplay confirmation was performed by the entry audit.
+60
View File
@@ -0,0 +1,60 @@
# Currency Wars `RET_GRID_FIGHT_CONF_MISS` audit
In the current checked-in protocol, `RET_GRID_FIGHT_CONF_MISS` is retcode `6900`. It is a configuration/state failure response, not a command ID. This audit covers all current source references found by searching `internal/gameserver` on 2026-10-22. It does not claim that every CW flow is implemented or Client-verified.
## Client provenance correction (2026-10-22)
The target Client is the Beta 4.6.53 OS installation explicitly identified by the user. Its root `GameAssembly.dll` SHA-256 is `c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144`, matching the active-CW capture/resource identity. An earlier static lookup against the D: main-game installation was the wrong source and is excluded from this audit. The saved `[GAC_CW_ACTIVE_TABLE_ROWS]` runtime capture is the Beta run at route 2801 / section 4 / stage 70000006. The live process path was verified with `QueryFullProcessImageName` and resolves to the user's Beta installation. The attempted `GridFightStageRouteConfigExcelTable.GetData` and `GridFightEnemyDifficultyLvConfigExcelTable.GetData` lookups returned an empty row and `No such type`, respectively; this only shows those exact Lua type/API lookups did not resolve the expected data in this Beta runtime, not that the underlying game data is absent.
| Handler | Condition returning 6900 | Current status |
| --- | --- | --- |
| `GridFightStartGamePlay` — `handlers_currency_wars.go` | CW catalog or saved snapshot cannot be read, or initial run data cannot be built | Fails closed; log includes the setup failure. |
| `GridFightHandlePendingActionScRsp` — `currency_wars_entry_choice.go` | Pending oneof is unsupported, does not match the active queue, or action processing fails | Known missing pending arms remain incomplete; current handler logs unsupported arms and validation errors. |
| `GridFightEnterBattleStage` — `currency_wars_battle.go` | Preparation state or battle envelope is invalid, or the selected node has no matching captured enemy recipe | This is the user's current failure. The branch is now selected from the saved one-based choice, but stage 70000006 / penalties 91113 and 91114 have no captured recipes. |
| `GridFightBuyExp` — `currency_wars_experience.go` | Required `GridFight_LevelUpExp` catalog rule is missing or outside the supported range | Returns 6900; catalog rule is required for a safe purchase. |
| `GridFightSpotLightEnter` — `currency_wars_spotlight.go` | Preparation/config is missing or a Spotlight offer cannot be built | Returns 6900 with a diagnostic log. |
| `GridFightRecycleRole` — `currency_wars_transactions.go` | No captured sale quote exists for the selected role/star | Returns 6900 and logs the missing quote. |
| `GridFightBuyGoods` — `currency_wars_transactions.go` | Party property scales disagree or the offered role/star variant is absent from captured resources | Returns 6900; no transaction is committed. |
| `PVEBattleResult` CW settlement — `handlers_battle.go` | Settlement validation or persistence fails | Returns 6900 and logs the settlement error. |
| `GridFightQuitSettle` — `currency_wars_quit.go` | Saving the abandoned-run state fails | Returns 6900 and logs the save error. |
## Encounter blocker
The active saved run is Standard Gambit, route 2801, chapter 1, section 4, stage 70000006. A read-only capture from the running Client 4.6.53 confirms stage level 90, HardLevelGroup 1, StageExcel EliteGroup 0, and base/current/all difficulty deltas 0. The two branch records are:
| Branch | Option | Penalty | Wave | Monsters as `id:role_star` |
| --- | ---: | --- | --- | --- |
| 1 (selected) | 11303 | 91113 | 1 | `200203009:1, 200201014:1, 202302016:2, 200201014:1, 201201013:1, 200201014:1, 200201014:1, 201201013:1, 200203009:1, 201301103:3, 200201014:1, 201302014:2` |
| 2 | 11304 | 91114 | 1 | `201201013:1, 200203009:1, 200201014:1, 200201014:1, 201302014:2, 201201013:1, 201201013:1, 200201014:1, 200203009:1, 200201014:1, 201302014:3, 201301103:2` |
The only saved recipe in `CurrencyWarsEnemyPlans.json` still covers stage 70000003 / penalty 92013. The builder correctly resolves the chosen branch and fails closed when its recipe is absent. The new capture does not prove the `SceneMonsterWaveParam.EliteGroup` or `CPHIINKIDEB` formation value: StageExcel has no monster list, and the saved branch message contains wave ID, monsters, stars, option and penalty but no formation-wave ID. The direct Lua API lookup for the expected formation/elite tables was unavailable. Therefore stage 70000006 is still not safe to add to the recipe resource; no battle values were guessed.
### Subsequent Encounter entry recovery
The preceding missing-recipe finding describes the state before recovery. A typed MemoryPack BattlePlan was subsequently recovered from the isolated reference run for route 2801 / chapter 1 / section 4 / penalty 91114: elite group 1802, difficulty 0, one wave, formation 5, twelve monsters. The reference BuildEncounterBattlePlan chooses elite group and formation at node scope, independently of option quality. This supports the same wave parameters for saved option 91113; its penalty and monsters remain those from the player's selected branch.
The matching Beta formation consumer at RVA f0c9d50 calls the flat getter at RVA 1e33bb30 with the selector carried by SceneMonsterWaveParam tag 6. A bounded read on a managed handbook callback verified row 5: MaxTeammateCount 5, empty ParamList/Ability, ClearPreviousAbility false. Evidence: ev_ac0ddf4c7244887fe99edcde069382c076d0f5f96f887bbc44a4bb34b2ab85fc. The active StageRow was captured again for level 90 / hard group 1. These values are now resource entries with per-entry provenance; no game-value literals were added to the battle builder. The saved branch supplies every monster ID and star.
The staged Game server compiled and was copied to the root, hash-checked, and restarted visibly. The user confirmed Encounter combat now works. Own logs confirm stage 70000006 Battle 357 entered and PVEBattleResult arrived; settlement then rejected the absent next-node recipe, producing a blank Client result popup.
The selected penalty row 91113 was subsequently read from the active Beta node. The isolated reference was moved from Encounter 1-4 to the next ordered route node 1-5 and RoundBegin was captured. Only its next layer/action were imported, with queue counters rebased after existing captured actions using sequential-counter semantics. The selected-penalty settlement fix and these resource rows were built/deployed. The user's team/balances are preserved. Settlement/room-1-5 Client verification is pending; alternate option 91114 settlement and subsequent combat recipes remain incomplete. This is not complete CW progression.
`tools/cw_active_encounter_capture.lua` contains the bounded read-only capture used for the current encounter. `tools/cw_active_wave_table_methods.lua` inspects only the named 4.6.53 wave and elite table types. Both are kept in `tools/`; temporary copies were removed from `scripts/` after collection. The probe reads reflected fields observed from this Client and depends on the current client schema; it is not a general Client-independent decoder.
The other 6900 sites are also fail-closed guards. Returning success while omitting their purchase, settlement or saved-state changes would leave the Client and server inconsistent. Unimplemented CW commands and pending arms are inventoried separately in `currency-wars-coverage.md`.
## Combined handler and grant continuation
- User confirmed selected Encounter Battle and settlement proceed to room 1-5; this supersedes the earlier pending Client check for that path only.
- Added Tea Break entry response, equipment dressing/crafting and battle equipment forwarding. Compilation is confirmed; Client gameplay for these additions remains unverified.
- Current Client `_ProcessUpdateInfo` dispatch evidence establishes equipment Add/Update/Remove as LMOLELDIKMA/DDBKEOPKPFI/PENGEDECBNF. Supply now sends Add instead of Remove.
- `/cw role`, `/cw equip`, `/cw exp` and read-only catalog commands use captured resources and the existing Preparation transaction path. Additive grants and queue acknowledgement share the snapshot CAS/atomic file replacement. No adventure inventory is replaced.
- Reference `GridFightSession.AddKilledMonsterOrbs` awards configured Orb drops for verified killed monster instances in Monster nodes; Boss talent Orb rewards have a separate path. This is evidence for comparison, not proof that the current Beta always gives an Orb after every fight. Current Go automatic Orb grant/opening is still missing, as are current-revision Orb/Consumable/Forge catalog captures.
- Dispatcher inventory now contains 22 registration names, including equipment Forge use. Neither this count nor compilation proves a complete CW run; see the missing request/action arms in `currency-wars-coverage.md`.
Current-revision reward captures now include 529 Orb, 18 consumable, 11 Forge and
478 combination rows. Grant commands are implemented; opening Orbs and applying
consumable effects remain incomplete. Offline comparison found only 347 matching
combination rows in the older reference, so its entire bonus table cannot be
treated as current Client data.
+87
View File
@@ -0,0 +1,87 @@
# CW dispatcher and source comparison
Generated by `tools/inventory_cw.py` from the current revision table and source registrations.
**Registration is not gameplay verification.** A registered pending dispatcher still needs each action implemented.
Reference source names are evidence for comparison only; they are not protocol aliases.
| Current request | Go registration | Reference same name |
| --- | --- | --- |
| `GridFightBuyExpCsReq` | `internal/gameserver/currency_wars_experience.go:47` (handle) | Yes |
| `GridFightBuyGoodsCsReq` | `internal/gameserver/currency_wars_transactions.go:127` (handleNamed) | Yes |
| `GridFightDestroyWeeklyRewardCsReq` | Missing | Not matched |
| `GridFightEnterBattleStageCsReq` | `internal/gameserver/currency_wars_battle.go:210` (handle) | Yes |
| `GridFightEnterBonfireCsReq` | `internal/gameserver/currency_wars_bonfire.go:13` (handle) | Not matched |
| `GridFightEquipCraftCsReq` | `internal/gameserver/currency_wars_craft.go:120` (handle) | Yes |
| `GridFightEquipDressCsReq` | `internal/gameserver/currency_wars_equipment.go:113` (handle) | Yes |
| `GridFightFinishTutorialCsReq` | Missing | Yes |
| `GridFightGetArchiveCsReq` | Missing | Not matched |
| `GridFightGetDataCsReq` | `internal/gameserver/handlers_currency_wars.go:181` (handle) | Yes |
| `GridFightHandleBonfireHealHpCsReq` | `internal/gameserver/currency_wars_entry_choice.go:131` (handleNamed) | Not matched |
| `GridFightLockShopCsReq` | `internal/gameserver/currency_wars_transactions.go:255` (handle) | Not matched |
| `GridFightPermanentTalentEnableCsReq` | Missing | Not matched |
| `GridFightPermanentTalentResetCsReq` | Missing | Not matched |
| `GridFightQuitLeaveGamePlayCsReq` | `internal/gameserver/handlers_currency_wars.go:161` (handle) | Yes |
| `GridFightQuitSettleCsReq` | `internal/gameserver/currency_wars_quit.go:119` (handle) | Yes |
| `GridFightRecycleItemCsReq` | Missing | Not matched |
| `GridFightRecycleRoleCsReq` | `internal/gameserver/currency_wars_transactions.go:71` (handle) | Yes |
| `GridFightRefreshShopCsReq` | `internal/gameserver/currency_wars_transactions.go:275` (handle) | Yes |
| `GridFightResumeGamePlayCsReq` | `internal/gameserver/handlers_currency_wars.go:102` (handle) | Yes |
| `GridFightSeasonTalentEnableCsReq` | Missing | Not matched |
| `GridFightSeasonTalentResetCsReq` | Missing | Not matched |
| `GridFightSpotLightEnterCsReq` | `internal/gameserver/currency_wars_spotlight.go:169` (handle) | Not matched |
| `GridFightSpotLightReplaceCsReq` | Missing | Not matched |
| `GridFightStartGamePlayCsReq` | `internal/gameserver/handlers_currency_wars.go:45` (handle) | Yes |
| `GridFightSummonProjectionCsReq` | Missing | Not matched |
| `GridFightTakeWeeklyRewardCsReq` | Missing | Not matched |
| `GridFightTraitUpdateCsReq` | Missing | Not matched |
| `GridFightUpdateEliteBranchSelectCsReq` | `internal/gameserver/currency_wars_encounter.go:44` (handle) | Yes |
| `GridFightUpdateEquipTrackCsReq` | `internal/gameserver/currency_wars_tracking.go:19` (handle) | Not matched |
| `GridFightUpdateEquipTrackPriorityCsReq` | `internal/gameserver/currency_wars_tracking.go:83` (handle) | Not matched |
| `GridFightUpdatePosCsReq` | `internal/gameserver/currency_wars_preparation.go:273` (handle) | Yes |
| `GridFightUpdateSpotLightTrackCsReq` | Missing | Not matched |
| `GridFightUseForgeCsReq` | `internal/gameserver/currency_wars_forge.go:101` (handle) | Yes |
## Pending action arms
“Referenced” means the dispatcher inspects the field; it does not prove the entire action/effect works.
| Schema arm | Dispatcher |
| --- | --- |
| `MFFCPLBNHCF` | Referenced |
| `OKPMJOCEKBC` | Missing |
| `JACEOLDFKDD` | Missing |
| `DKDFDGJGIHM` | Referenced |
| `HOKCPPPLJIO` | Missing |
| `IOHJGOENAPF` | Missing |
| `LFIDNOAECMN` | Missing |
| `DCPHLHNLNKF` | Missing |
| `KEBDKGKEJDD` | Missing |
| `BAKAKODKECM` | Referenced |
| `IACBCOBMGJB` | Missing |
| `JLPOPEAJHMF` | Missing |
| `FIKAGBAEOAP` | Referenced |
| `PLJBPFHFAHL` | Missing |
| `HHNHGJMOGDD` | Missing |
| `MHBGJCOIMPA` | Missing |
| `DAJDBBEPMMA` | Missing |
| `NNDGEJFLGGF` | Referenced |
| `EMMPHLKJAJN` | Missing |
| `KDGAJCHDFOK` | Missing |
| `GEPGMIEPBMB` | Missing |
| `PKHJLKNGCGH` | Missing |
| `IBCHMBNIPLK` | Referenced |
| `DPKFJEEJABC` | Missing |
| `EJHBPFJOBKB` | Missing |
| `LAJGNNBOLDG` | Missing |
| `JMJOAOCJAAG` | Missing |
| `HHNPEHMBDKD` | Missing |
| `PFEBKFJOGKO` | Missing |
| `IIDBLCFAAPC` | Missing |
| `LGNPHHBGKFH` | Referenced |
| `FKEAHOKGDPO` | Missing |
| `DPBFGOMKGMB` | Missing |
| `ENMJFJGIOEM` | Missing |
| `FMHPKKDEHNC` | Missing |
| `NFBJINKLLLK` | Missing |
| `CFDIPFKBFJB` | Missing |
| `PBEJCFAJLGE` | Missing |
@@ -0,0 +1,114 @@
# CW current consumer evidence — 2026-10-25
Target assembly SHA256:
`4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6`.
These observations belong to this target; the older base catalog/reference has
not thereby been recaptured in full.
## Tea Break
The bounded read-only `tools/cw_teabreak_runtime.lua` capture confirms that the
current Client session sees route 2801, chapter 1, section 5 as a Bonfire node.
Its `BonfireEventIds` contains 10200601. The live node parameter itself already
contains this list. Thus missing Bonfire flags/event IDs are not the blocker at
this particular node. Do not add guessed node data to fix it.
`GridFightGameEventData` is a set of change collectors, not the Bonfire choice
processor. Its captured methods are Reset/Dispatch/GetCollector/RegisterCollector
and initialization; no missing game-event protobuf component was established.
Focused native disassembly of `_RefreshBonfireEventIds` at RVA `0xdc635b0`
(AMD64 exception-table bounds) copies the event list from the node parameter into
the cached list. It does not resolve event configuration. The direct caller at
`0xdc631f0` copies the Bonfire flag from the node parameter. Leaf getters at
`0xdc64be0` and `0xdc64c00` independently read the cached flag/list; those two
artifacts use explicit ranges because leaf getters have no unique unwind entry.
Artifacts: `battle_diagnostics/cw54-teabreak-runtime-20261025.log`,
`cw54-bonfire-refresh.asm`, `cw54-bonfire-refresh-caller.asm`,
`cw54-is-bonfire.asm`, and `cw54-bonfire-ids.asm`.
The unresolved step is the actual EnterBonfire caller/callback and its expected
choice/action/effect state. The reference has no EnterBonfire implementation.
The existing retcode-only success does not establish functioning Tea Break.
## Entrance and exit
Passive exact-name loadbuffer capture, requested through package loader closures
without executing those closures, produced the current S2 entrance and season
router chunks under `.runtime/named-baked-capture/`.
The S2 entrance's `_on_btn_start` names the actual next module:
`Ui.GridFight.Division.Start.GridFightDivisionStartPage`.
Its `_on_dispose` only stops the CW menu audio state; no blanket camera/Canvas
restoration is justified by that function. The button-overlap screenshot belongs
to the Division Start screen, so its status/continue/end callbacks are the next
required consumer, not a reason to move arbitrary buttons.
The season router selects Legacy/Latest presentation using
`GridFightModule.Instance.IsCurSessionLatest`. It supplies real prefab paths,
not a Bonfire event module path. No invented Bonfire page names were loaded.
## Orb boundary
Grant/list commands already cover captured Orb IDs, consumables and Forge items.
That is separate from dropping/opening Orbs. Current resources retain 529 Orb
display rows and 478 combination rows, but lack a complete matching basic bonus
pool plus the current open-Orb sender/callback mapping. The older reference's
custom basic-Orb rewards are not a complete current-revision reward table.
The current runtime capture now includes MethodHandle values for
`GridFightOrbServerData`. Resolving the native entry at MethodHandle + 8 and
disassembling against the assembly hash above establishes the following:
- `GetOrb(List<uint>, bool)`, RVA `0xdbe3c50`, forwards to the network sender
at `0xe3ff8f0`. That sender puts the list at request offset `0x18`, the bool
at `0x20`, and sends command `0x21af` (8623).
- The current protocol table names 8623 `IKMOCJBMGOJ`; its current schema is
repeated uint32 field 4 plus `is_get_all` field 9. This agrees with the native
argument layout. Historical reference names for its response/notification
are leads only: no new response pair is registered from historical IDs.
- The nested `<>c__DisplayClass11_0` is a count/filter closure, **not** the
GetOrb response callback. Its method is `<GetOrbCountByType>b__0` and its
captured field is `GridFightOrbType`.
- The actual nested `OrbSummarizer` consumes the sync update context. At RVA
`0xdbe5370`, `IsConcernedWith` accepts enum value 1. At `0xdbe5520`,
`UpdateBefore` requires the same value and uses the first context uint as the
Orb UID; it looks up or creates the result for that UID. `UpdateRemoveOrb`
at `0xdbe58a0` records removed UIDs. `PreUpdateDone` at `0xdbe5bb0` dispatches
accumulated results only for UIDs included in the removed set.
Accordingly, an eventual proven Orb payout must use one
`ABPLALCHNFA` group per Orb UID, with `grid_update_src` enum value 1,
`OOEOCGLLHFO = [orbUID]`, and the actual removal/loot updates in
`JKPJFKCBIEM`. Sending ungrouped updates under the default context cannot
construct the Client's Orb result through this consumer. This establishes the
consumer context, not the missing reward rolls or the response callback.
The live session's `Bonus` is `RPG.Client.GridFightBonusServerData`, a bonus
distributor with trait/initial-supply results and a distributor queue. It is
not evidence for a random bonus-pool config repository. Four previously
recorded candidate row names are absent from the inspected current config
assembly; this is not proof that the data itself is absent or cannot be
resolved under other names.
Artifacts: `cw54-get-orb-sender.asm`, `cw54-get-orb-network-sender.asm`,
`cw54-orb-consumer-rvas-20261025.json`, and `cw54-orb-context-{filter,before,
remove,complete}.asm` under `battle_diagnostics/`. Native resolution was a
read-only, bounded Frida attachment, with the current process and module range
checked first; no hooks, native gameplay calls, or memory writes were used.
## Pending current consumer capture
`tools/cw_teabreak_current_consumer.lua` is prepared outside `scripts/`. It
exports only three established live Preparation callback functions, their
source/upvalue names, and eight fields per heartbeat from the actual session
and Stage types. It skips Battle and sends no gameplay requests. It has not
yet been staged or captured. This can identify the real loader/service path
before attempting any Tea Break pending action implementation.
The captured Division Start `_setup_btn_state` already uses mutually exclusive
start/continue visibility: continue follows `_is_in_game`, start follows its
negation. The settle button uses `_should_show_settle_btn`. The overlap report
therefore requires observing the live visibility/state application; moving
buttons arbitrarily would not fix the proven state consumer.
+88
View File
@@ -0,0 +1,88 @@
# CW Orb implementation from the updated reference
The reference binary SHA-256 is
`235f5c3567f281cc99613ed84694ef23f492c15298dc868a8e78e6529f0cda86`.
The original binary was read without execution. Its embedded protobuf
descriptor, Excel tables and authored declarative configs were extracted under
`battle_diagnostics/ffgo-20261026/`.
`tools/export_ffgo_orb_recipes.py` reproducibly creates
`resources/CurrencyWarsOrbRecipes.json` from the explicitly selected extracted
Excel/custom JSON files and reference binary digest. The resource retains both
input JSON hashes and separates native table identities from the reference's
authored reward recipes. It does not claim captured official reward odds.
## Proven protocol contract
The current Client sender and reference descriptor agree on the request:
| Current name | Reference name | CmdID | Fields |
|---|---|---:|---|
| IKMOCJBMGOJ | GridFightUseOrbCsReq | 8623 | repeated UID tag4, get-all bool tag9 |
| PNHDGCBLPGD | GridFightUseOrbScRsp | 8659 | retcode tag3 |
| GDHFMHKFEAL | GridFightUseOrbNotify | 8745 | UID tag14, DropList tag5 |
The implementation registers only the current named request. It introduces no
numeric alias or fallback response. The reference handler at RVA `0xca4740`
replies through 8659; the called `gfItemUseOrbs` (`0xca2a40`) sends 8745 before
the reward sync. The reference's `gfRewardDropProto` (`0xcd3640`) does not set a
drop ID for coin/EXP/refresh drops. It writes a role/item ID for those types.
Role-star presentation maps exactly to `AOHKKFHDALO.role_star` tag101; the other
ChooseParam arm is unused.
The current native OrbSummarizer proof in
`currency-wars-current-consumer-notes.md` establishes source enum1 and the first
context uint equal to the opened Orb UID. Each opened Orb has its own grouped
sync containing the actual reward changes and the remove-Orb arm tag1503
(`GOHHJLAPMBB`).
## Implemented scope
Opening one or all selected owned Orbs uses a detached snapshot and saves the
removal and actual rewards in one revision-checked transaction. Duplicate or
unowned UIDs, stale revisions, malformed recipes, exhausted pools and unsupported
bonuses do not consume an Orb. Network errors after a committed payout are
reported as send failures; reconnect restores the saved result.
Sixteen reference recipes are identified among 532 native Orb rows:
102, 103, 197, 199, 203–208, 120031, 200001, 200005, 200013, 200015 and 200027.
The effect dispatcher supports gold, EXP, free refresh, lineup HP, captured
equipment/consumable/forge items, random captured equipment categories and
random available captured role rarities/stars. Random role rewards reserve
owned copies and unsold shop cards using captured merge rules, reject disabled
full-star roles, and use existing acquisition/merge/property projection paths.
Equipment categories require all reference category entries to exist in the
captured equipment catalog; no silently reduced category pool is substituted.
Inventory/effect prerequisites can still reject a particular identified recipe.
Orb opening is currently restricted to Preparation without another pending
action or active Battle, using the same revision guard as purchases. Native
bonus-pool budget/weighted recursion, role modifiers and general `OnOrbOpened`
trait/effect hooks remain separate work. For example ordinary Orb100's bonus
20001 has no supported fixed recipe yet, and returns a configuration error
without removal. The handler must not be described as complete coverage of all
532 Orbs or original game odds.
No unit tests, live probes or deployment were performed for this change.
`go build ./internal/gameserver` passed; Client Orb presentation and gameplay
acceptance remain unverified.
## Post-battle drops audit
The reference workflow includes `gfRouteRewardNodeOrbs` (RVA `0xce0c00`),
which calls `gfRouteRandomCreepOrbs` (`0xcdf4a0`) and `gfPoolRandomOrb`
(`0xccaec0`). Its `gfBattleTraitDrops` also calls `gfBattleDropReward`
(`0xc63e80`), which checks the configured Orb row before processing an Orb
drop. These are separate paths; the reference dump does not itself establish
the current Client's complete wire or success behavior.
The current settlement reads progress and damage but does not generate
post-battle Orb drops. `MGMJOPHJCNL.ODMCMPIDJNH` is a repeated drop-shaped
field in the current protocol; its relationship to a server-issued battle's
drop list and the matching reference fields has not been demonstrated.
Accepting it as a grant without that validation would trust unverified Client
input. Likewise, restricting random rewards to the small set of implemented
recipes would change the reference distribution. A complete implementation
still needs the current Client's battle drop contract, the reference pool
membership and selection parameters, and usable implementations for the
resulting Orb recipes. The audited save and server were not modified.
@@ -0,0 +1,119 @@
# FFGO CW workflow comparison, 2026-10-26
Reference binary SHA256: `235f5c3567f281cc99613ed84694ef23f492c15298dc868a8e78e6529f0cda86`.
Embedded revision: `440df54730ba64935e9ad7ecae9147e55ad279a9`.
This is compiled implementation evidence, not recovered original source or proof
that every reference handler succeeds in the current Client.
## Tea Break entry and selection
The recovered Go pclntab contains a complete Bonfire entry path, closing the
earlier reference's missing-handler gap. Direct calls agree with coherent
disassembly boundaries and Go runtime helpers; the PE pclntab's zero on-disk
textStart is resolved to the `.text` section virtual address.
| Reference function | RVA | Observed behavior |
|---|---:|---|
| OnGridFightEnterBonfireCsReq | `c697e0` | Current run, Bonfire entry, sync notification, persistence, response |
| gfBonfireEnter | `c69940` | Resync current pending type 11, or create a new Bonfire pending action from the current node's event list |
| gfPendingAddBonfire | `cbc3c0` | Roll options for every event; capture basic/interest/streak income and node Orb rewards; sync queue head |
| gfPendingBonfireProto | `cb1760` | Convert offered options, income, drops and selected phase to the pending payload |
| gfPendingHandleBonfire | `cbb740` | Select option or heal first; separate take-drop step grants income/EXP/rewards, finishes pending, advances node |
| gfPendingMarkBonfireSelected | `cbc0a0` | Mark selected, serialize the same pending action, sync it again |
| gfRouteLowerEnemyStars | `cde100` | For every enemy above one star: roll integer 1..100; at configured threshold decrement one star |
`OnGridFightEnterBonfireCsReq` sends reference command 8582 after its sync. The
implementation here resolves `GridFightEnterBonfireScRsp` by the repository's
named protocol table, rather than importing a numeric alias.
The specific Bonfire subset agrees with our existing schema:
| Reference meaning | Current generated field | Wire tag |
|---|---|---:|
| Bonfire pending arm | CHCHAJIANIM.IIDBLCFAAPC | 1920 |
| Bonfire request arm | GridFightHandleBonfireHealHpCsReq.IIDBLCFAAPC | 1659 |
| Pending queue identifier | CHCHAJIANIM.QueuePosition | 6 |
| Coin basic / interest / streak | NCEPOLNLNKH.EIFICNFGGHI / AHJJJNBOMPG / DANCNIMJOLE | 14 / 11 / 5 |
| Options / phase / drops | NCEPOLNLNKH.KFNMIEMBJGD / Phase / DJOBNPIAEJP | 13 / 9 / 6 |
| Option event / selected option | MHCOIBONODA.EventId / HAFOKMHCGFM | 11 / 13 |
| Select event / option request | LDJOCEMPFBJ.EventId / HAFOKMHCGFM | 1 / 14 |
The full reference sync/pending messages contain additional arms absent from
our revision. Only this scoped verified subset is used; reference response
bytes are never copied directly into current packets.
## Imported implementation reference and current scope
`tools/export_ffgo_bonfire.py` reproducibly projects the extracted reference
tables into `resources/CurrencyWarsBonfire.json`: 38 events, 72 options, three
chapter heal rows and 17 declarative TeaBreakOption recipes. The resource
records binary and extraction hashes. Its target identity is a compatibility
gate against our existing catalog, explicitly **not** a claim of a new Client
capture. The selected event must also occur in the active Client node.
Current event 10200601, option 1, uses reference recipe
`petpal/bonfire/GridFightBonfire102006011.json`: SetRule `PetPalStarDown`,
parameter `#1 = 40` from the Excel option. The native reference's string
cross-reference proves this rule lowers **enemy stars**, not shop stars.
Implemented source now creates and persists the real menu before acknowledging
entry, resumes an existing Bonfire pending action, and validates the selected
event/option against the saved offer. Selecting this supported option persists
the rule with phase 1 and syncs the updated pending action. Future enemy layers
created through pending-action transitions apply the rule once per node;
the changed enemy stars and the application marker commit atomically.
Server rule state lives beside the protocol payload under snapshot `runtime`,
scoped by run ID. Normal same-run writes inherit it under the existing revision
CAS and file lock; new runs cannot inherit old rules. Unknown envelope/runtime
fields and unknown protobuf fields remain intact. Snapshot readers never write.
Only supported effects execute. Opening/selecting does not pay income. The
later continuation below supersedes the initial healing/take-drop boundary;
unsupported option effects still preserve the active offer.
## Remaining node-factory boundary
Our transition resource contains captured steps 1-1 through 1-4; it has no
current 1-5 -> 1-6 LevelWire/next pending/enemy recipe. The reference's static
route 2801 section 5 is a Monster node, while the active Client node is a
dynamic Tea Break. Its PetPal effect can replace that static node type. Copying
the static reference route or a saved reference run would therefore be wrong.
Continue from reference `gfPendingAdvanceNode`, `gfRouteCreateNode`,
`gfRouteFillEliteBranch`, and the PetPal dynamic-node override. The factory must
resolve the active route section, dynamic Tea Break replacements, layer-specific
parameters, actual enemy waves/camp, penalty, queue, shop and reward updates.
The generated factory described below now supplies the current next Boss node.
Validation performed: Go compilation and a read-only catalog load confirming
38/72/17/3 rows and supported event 10200601/1 -> PetPalStarDown 40. No unit tests
were added or run, no saves were changed by the checks, and no Client menu or
selection success is claimed until observed after deployment.
## Take-drop continuation (2026-10-26)
The saved live run was inspected without writing it: revision 531, route 2801,
chapter 1 section 5, pending queue 530, Bonfire phase 1. Its offer contains basic
gold 10, interest 5, streak gold 2 and no Orb drops. The old phase-0-only guard
rejected take-drop before reaching its branch, explaining the repeated 6900.
`cwSelectBonfire` now distinguishes selection/healing from take-drop. Healing
uses the chapter row and caps at maximum HP. Take requires phase 1, pays the
saved income and resource-defined wave EXP, applies any already-offered Orb
items, and constructs the next saved route node. The caller commits the entire
detached result using the existing revision CAS before sending notifications.
Failure leaves income/inventory/coordinates unchanged; retrying a completed
queue cannot award again. It does not invent missing Orb rewards for the legacy
offer. Weighted generation of ordinary node Orb offers remains separate work.
New enemy rounds use typed RoundBegin -> ReturnPreparation instead of replaying
the initial shop capture. Battle settlement retains proven captured transitions
and otherwise calls the generated node factory with a monotonic revision-based
queue. Reference penalty rows (114) are stored separately with provenance;
current-Client captured rules take precedence. Enemy-star rules and their
once-per-node markers commit with the newly generated layer.
See `currency-wars-route-factory.md` for destination-family limits. This change
does not claim complete CW finalization, all augment effects or all node types.
Compilation is distinct from live Client acceptance.
+55 -1
View File
@@ -288,7 +288,7 @@ An isolated native administrative move to the next route node followed by RoundB
The user reports that this node presents the Protagonist button, not ordinary Battle. Requests include `GridFightSpotLightEnterCsReq` and `GridFightUpdateSpotLightTrackCsReq`, both previously unhandled. The old reference lacks this current Spotlight implementation. The reconstructed normal second-battle path above is not verified as the appropriate current route. Moreover, the imported old layer's camp must not be treated as a generated member of the current run's active camps. Selection, actual effects and the appropriate enemy layer remain unfinished.
Bounded current Client captures now contain 84 initialized Spotlight rows, exported by `tools/export_cw_spotlights.py` to `resources/CurrencyWarsSpotlights.json`. These are real configurations and suitable-role lists, not evidence of selection weights, offer count, costs or grant policy. Do not substitute arbitrary offers or a success-only response for those missing rules.
Bounded current Client captures now contain 84 initialized Spotlight rows, exported by `tools/export_cw_spotlights.py` to `resources/CurrencyWarsSpotlights.json`. These are real configurations and suitable-role lists, not evidence of original-server selection weights, offer count, costs or grant policy. `CurrencyWarsSpotlightPolicy.json` explicitly defines the current server's uniform compatible selection policy (three options, no rerolls); it must not be described as captured original weighting. No success-only response replaces selection state.
Named MethodHandle +8 reads and bounded PE disassembly establish `GridFightSpotLightSelectAction._SyncFromProto` at RVA `0xdc00cd0`. Isolated protobuf setters encoded to bytes establish the field tags independently. Assembly SHA256 is `c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144`. Evidence is retained in `battle_diagnostics/cw-spotlight-selection.asm`, `cw-getter-native.json`, `cw-spotlight-wire.log` and `cw-spotlight-getters.log` (ignored diagnostics).
@@ -305,6 +305,10 @@ Named MethodHandle +8 reads and bounded PE disassembly establish `GridFightSpotL
ActionID comes from the enclosing pending QueuePosition. The protobuf arm is EEKMIAMGHFL (1817), not the ordinary Battle arm. `SelectCandidate` dispatches role and selected Spotlight ID through `Select`; this still needs a server-owned offered-choice/role validation path. FMBACDOFCAL mappings independently encoded: IHHNLLAJAGB (1) SpotlightID, UniqueId (2), MDNAGANGNKK (9), ELBPNDIENDL (11), RoleId (13). Meanings of fields 9/11 and special effects are not inferred merely from their types.
Further named native inspection resolves fields 9/11: AddOrUpdate at RVA `0xdbfb3f0` shuffles the proto scalars into its ACNDKIFJLJC record. GetActiveSpotLightBindingByRoleId at `0xdbfb9a0` and binding constructor at `0xdbf6380` place that record into RoleUniqueID/RoleID/SpotLightID/UniqueID/IsLoss. Thus MDNAGANGNKK is RoleUniqueID and ELBPNDIENDL is IsLoss. New grants bind an owned role UID and use IsLoss=false; merges move the UID binding when the selected card is consumed. See `cw-spotlight-add.asm`, `cw-spotlight-binding-get.asm`, `cw-spotlight-binding-ctor.asm` in ignored diagnostics.
The implemented Enter handler validates preparation and the current node flag, persists an offered pending choice, then sends pending sync before the typed response. Selection validates the saved offer, suitability, ownership and duplicate binding; it saves a run-owned Spotlight, updates the route node, finishes the pending action and unlocks preparation. Start/entry transitions preserve an empty Spotlight component, and explicit Resume migrates old runs so Client Sync marks the manager valid. Snapshot reads remain read-only. The build compiles; UI selection/resume is still awaiting current Client proof. Battle projection/effect execution and subsequent route fidelity are unfinished; do not claim the complete mode works yet.
### Basic merges and equipment tracking
`CurrencyWarsCatalog.json` now contains 219 actual native star rows, identity checked against the requested role/star (no clamped rows accepted). `tools/import_cw_role_stars.py` preserves earlier configurations and imports only observed rows. Ordinary sale quotes use the current rarity table only when the captured default quote agrees with that table; unestablished special quotes are rejected.
@@ -314,3 +318,53 @@ ActionID comes from the enclosing pending QueuePosition. The protobuf arm is EEK
Current tracking handlers bind names from the current command table: GridFightUpdateEquipTrack and GridFightUpdateEquipTrackPriority. Tracks persist in the player component MIIDIMOCPEB; KFNCAIHIHCM.BMGFDIKDOBE carries the complete updated list. Native `CreateServerTrackUpdateInfo` at RVA `0xda5afa0`, `RemoveEquipTrack` at `0xda63a30` and `_AddTrackToLastAndSend` at `0xda628d0` prove BJDOINAHDLN is **enabled**: add passes true, removal false. It is not a deletion flag. Priority is NALMBOOCCIN; the source protocol comparison also names it priority, but old source tags/opcodes are not used. Equipment IDs are checked against the 142 current initialized handbook equipment rows. This implements tracking persistence/display, not equipping, crafting or combat item effects.
The merge/tracking build compiles; no automated tests were added or run. Client confirmation of these new changes remains pending. Finished research scripts have been removed from scripts/; their source remains under tools/.
### Protagonist selection confirmed; CW trial blocker found
The user confirms selection works. Current logs prove Enter offered three choices at queue 215/revision 215 and DKDFDGJGIHM selection finished at revision 216 with preparation restored. An initial validation error was our incorrect requirement that every native Spotlight row contain JsonPath; fifteen real rows have an empty path and must be retained, not replaced with guessed paths. The validator now accepts their native shape.
The subsequent EnterBattle failure is distinct: `CW role avatar 6042 not owned; trial resolver required`. The captured role row marks this as a fake CW avatar and supplies SpecialAvatarID. The current native flat SpecialAvatar table supplies its identity, world level, level, promotion, rank, enhancement and equipment values. `CurrencyWarsTrialAvatars.json` retains this complete native row and capture hash; `cwTrialBattleAvatar` builds an isolated trial battle avatar with the special ID and Trial enum. It never adds the fake avatar or trial gear to Adventure/persistent inventory. The native reference's ResolveBattleAvatar / SpecialAvatarInfo.ToBattleProto corroborate this special-ID serialization and do not create relics for this fake avatar. Only captured trial profiles/world levels are supported; others still fail explicitly.
Native `BattleGridFightAvatarData.get_SpotLightID` at RVA `0xefae920` reads BattleExtInfo +0x18 then that object's +0x18. Isolated ABJGLPCOMMK setters encode tag 2 as `10-01`, whose accessor at `0x1eea9f00` reads +0x18; tag 1 reads +0x1c. The old captured role envelope independently has tag 1 Mode=2. Runtime retains that mode and injects only the selected run binding's SpotlightID at tag 2. It does not inherit the reference avatar's Spotlight. Server-side economic/difficulty/trait-specific Spotlight effects remain unfinished; the presence of this projection is not proof of all effects.
Current trial/Spotlight projection build compiles and is deployed at root. Actual node-1-2 combat after the trial fix is awaiting Client confirmation. No automated tests were added or run. Research captures are outside scripts/ after completion. Future probes should wrap their whole body in a local function: a top-level return in one concatenated script can skip later scripts in the same heartbeat.
### Supply selection and second-node Client confirmation (2026-10-21)
The user now confirms node 1-2 Battle works after the fake-avatar resolver. The server records battle 247, a completed settlement with progress 100, followed by Supply queue 16 at revision 248. This supersedes earlier pending-verification statements for this particular fight only.
The Supply 6900 was a missing FIKAGBAEOAP request branch. The new handler validates the saved queue, exact selection count, one-based indices, offered role/star and item identities against current resources. It grants the selected equipment and role with fresh run-owned UIDs, merges eligible triplets, and saves once before sending equipment/role/merge groups and the pending acknowledgement. A rejected transaction sends no grants and writes no partial changes. Paid selections and rerolls remain unimplemented rather than inventing prices. The acquisition Source=9 discriminator is corroborated by the native Supply selection captures and the reference SupplyEquipmentSource definition.
The captured Standard Supply transition advances the existing party to section 1-4. It imports only the next level/pending recipe from march-cw-supply-next stage 17/18/19, never another account's balances or inventory. The later EliteBranch action and current-camp procedural encounter generation are unfinished; the captured branch layer is a reference recipe, not proof of correctly generated encounters for every selected camp. Do not claim a complete CW run or use it as proof of later Battle fidelity. Current Supply selection still awaits Client confirmation. Build only; no automated tests added or run.
### CW flow audit and staged Encounter work (2026-10-21)
The current Client/server trace confirms Supply queue 16 succeeds, advances to RoundBegin 20 and Encounter 21 (revision 250). The next 6900 is the unimplemented BAKAKODKECM arm, not a Supply failure. The user explicitly requests completing connected CW flows in batches instead of repeatedly requesting one-button Client checks.
`tools/inventory_cw.py --reference-root <source-checkout> --markdown <output>` now compares all current command names, Go registrations and reference source handlers, plus every pending-action arm. `docs/currency-wars-coverage.md` is the current static audit. Registration is deliberately not labeled gameplay success, and old reference names are not registered as aliases. Missing equipment, consumable, progression and pending actions remain visible.
A staged Encounter implementation validates the offered one-based branch, saves SelectedEliteBranchId, emits the mapped FGODNPLCECH selection sync, and queues ReturnPreparation; it also implements changing the selected branch during preparation. It compiles but has not replaced the root Supply build. It must not be presented as a complete Encounter combat/settlement implementation: wave recipes, difficulty, penalties, rewards and the following transition still require the connected work.
Native Create(UInt32,...) method handles identify RVA 0xdb7d780. Its bounded PE disassembly calls the monster row getter at 0x1dee0820 before constructing MonsterData; the capture invokes only that flat getter and the previously established serializer at 0x1d3efb60, on the initialized handbook getter thread, four rows per call. Current assembly hash matches the catalog. REA observations ev_6de4d1e2da5ceaf24244fb3effc43b0a9ed5122a6edc252a912fd7397b051311, ev_a5ea1ccc45442bcd8550983f294080ecb6cca0ea2d39f28828f17094433fe8ce and ev_2e7d90ac354eaf31406ddb077b68e18b2dccc0b1dbefb3d5f764136de324219d plus the retained getter disassembly establish 42 identity-checked monster rows covering this run's camps and the imported branch camp. No monster/scene/level-graph constructor executes. Finished probes are outside scripts/.
`CurrencyWarsMonsters.json` retains native tiers and all four star elite-group fields, with a complete plan/capture digest. Its coverage is partial, not the complete game table. The staged compatibility sampler selects a compatible active camp uniformly and replaces imported branch monsters with current native monsters of the same tier while preserving stars, wave layout, penalties and rewards. This is an explicit server compatibility policy, not a claim about original-server random weights. Explicit Resume reconciles an old pending Encounter once and saves before GetData; readers remain read-only. No Adventure inventory or party is changed. The root build is still cw-supply-gameserver; do not request another Client retry until the connected Encounter flow is ready.
### Quit/abandon active run request (2026-10-21)
The first handler only cleared the saved run and returned `GridFightQuitSettleScRsp`. The screenshot's “Currently unable to manually end and finalize” showed that was insufficient: the Client also expects `GridFightSyncKeepWinCntNotify` followed by `GridFightSettleNotify` before the success response. The handler now builds those notifications from the active run and current catalog, commits only the removal of `DHFOFLFCLAH`, sends the notifications in that order, then lets the dispatcher send the typed response. It does not award victory rewards or change Adventure inventory.
The packet names and wire layout come from the checked-in current protocol; the older reference is used only to confirm the required packet order and Quit reason, not its old CmdIDs or field tags. Settlement rank and completed-battle count are not present in the saved run/catalog mapping yet, so their protobuf defaults remain unset. The UI flow still needs confirmation in a connected Client after rebuilding/restarting the server.
### Encounter battle returns 6900 (2026-10-22)
`RET_GRID_FIGHT_CONF_MISS` is protocol retcode 6900. The current log attributes the Encounter failure to a missing enemy plan. The saved run is Standard, route 2801, chapter 1, section 4, stage 70000006. The Encounter layer offers two branches, with branch 1 selected; its saved enemy payload has one wave containing 12 monsters and penalty 91113. The second offer has penalty 91114. These live saved values do not include the battle's level, hard-level group, elite group, formation wave or complete difficulty modifiers.
`CurrencyWarsEnemyPlans.json` has a captured recipe only for stage 70000003 / penalty 92013, so it cannot construct either current Encounter branch. The builder previously also rejected every multi-branch layer and looked up a recipe using the node's penalty instead of the chosen branch's penalty. It now resolves the saved one-based selected branch, looks up that branch's penalty and logs the route/section/stage/selection when no recipe exists. Unit tests verify first/second branch selection and reject absent, empty or out-of-range choices. This avoids starting the wrong branch once its exact recipe is available.
The connected Client 4.6.53 capture confirms stage level 90, HardLevelGroup 1 and zero difficulty deltas. It records both one-wave branches, their 12 monster IDs and stars, and penalties 91113/91114. StageExcel's EliteGroup is 0; a separate monster row reports EliteGroup 1, but the current capture does not establish which value belongs in `SceneMonsterWaveParam.EliteGroup`. The saved branch message has no formation-wave ID, and the expected formation/elite table classes were not resolved through the direct Lua API. Do not fill these fields from the older reference or infer them from monster identities. The Encounter still fails closed until the current Client's exact formation and elite configuration values are captured. `tools/cw_active_encounter_capture.lua` is the bounded read-only probe; it uses reflected fields from this current Client, so it is not a general decoder. The full retcode audit is in `docs/currency-wars-6900-audit.md`.
Current 6900 paths elsewhere include missing gameplay catalog/snapshot, unsupported pending-action arms or failed action validation, missing EXP/Spotlight config, unavailable sale/role variants, mismatched party property scales on purchase, battle settlement validation, and save failure during quit. These are reported in their handlers; they do not justify returning success without state changes. CW equipment/forge, many pending-action arms, talents and later route recipes remain incomplete as listed in `docs/currency-wars-coverage.md`.
### Beta scan source correction (2026-10-22)
The user clarified that the target is the Beta 4.6.53 OS installation. The previous static lookup using the D: main-game assets was invalid and must not inform this Encounter. The retained runtime capture has the Beta `GameAssembly.dll` SHA-256 `c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144` and records the current run as route 2801 / section 4 / stage 70000006. The live process path was independently verified with `QueryFullProcessImageName` and resolves to the user's Beta installation. `GridFightStageRouteConfigExcelTable.GetData` returned an empty row for the attempted key, while `GridFightEnemyDifficultyLvConfigExcelTable.GetData` failed to resolve that exact type; these are incomplete lookups, not proof that the data is missing. Continue only against this Beta runtime and its matching assets.
+43
View File
@@ -0,0 +1,43 @@
# CW typed response boundary
## Source correction, 2026-10-25
The shared typed dispatcher sends its response only when the registered function
returns nil (or the handler has already sent the response explicitly). Several CW
paths returned resource, validation or save errors directly. Those paths therefore
left the Client waiting instead of receiving the revision's typed error response.
CW registrations now use `cwHandle` / `cwHandleNamed`, which still resolve request
and response IDs by their names through the existing protocol table. When a CW
operation returns an application error, the wrapper preserves a nonzero retcode
already selected by that handler, or assigns `RET_GRID_FIGHT_CONF_MISS` if it was
still zero. It logs the error and returns control to the dispatcher to send exactly
one typed response. It never converts an unsupported operation into success or
replays a failed transaction.
Every explicit packet send within these registered handlers uses `cwSend` to mark
any send error, including serialization or projection failures. The wrapper
propagates that error, network/EOF/closed-connection errors, and
`errResponseAlreadySent` unchanged. It does not attempt an additional packet in
those cases. The former pending-action-specific error defer was removed because
it swallowed send errors as though they were application failures.
`GridFightUpdatePos` also rejects position changes while `CURRENT_BATTLE` is
active, matching the existing Preparation-only mutation boundary used by shop,
equipment and grants. This does not remove or settle the active battle.
## Validation and limits
- `go build ./internal/gameserver` succeeded. No tests were run.
- No executable was replaced, no server restarted, no live save changed and no
probe was staged by this change.
- This closes a source-level missing-response path. Client behavior is not yet
verified, and Tea Break choices, automatic Orb drops/opening and later route
recipes are still incomplete.
- The existing `GridFightEnterBonfire` handler's success-only navigation response
is not proof of a working Tea Break. Its game-event consumer and the associated
current revision's choices/effects still need runtime evidence before new
pending state can be implemented.
The static inventory scanner recognizes both CW wrappers, so registration reports
continue to distinguish present handlers from actual gameplay support.
+63
View File
@@ -0,0 +1,63 @@
# Currency Wars generated route continuation
The route continuation uses the extracted FFGO `gfPendingAdvanceNode` ->
`gfFxHEnterNode` flow and `gfRouteCreateNode` configuration. Reference executable
and Excel-dump hashes are recorded in `CurrencyWarsReferenceNodes.json`; its 493
normalized templates are data, not snapshots of another player's run.
`cwAdvanceRouteNode` operates only on the caller's detached run. It finds the
next ordered chapter/section in the catalog, retains the run's existing route
display (including dynamic Tea Break replacements), and asks the reference
enemy factory to construct the destination layer using that run's saved
chapter boss/camp. It validates the destination before changing the source.
It then emits finish-old-queue, level change, and typed RoundBegin updates.
It neither awards rewards nor writes a save. The caller commits rewards and
continuation together with its existing revision/CAS check.
`cwNextRound` keeps the existing captured transitions and uses typed generated
pending actions when a new enemy node has no captured RoundWire. It refreshes
the finite-pool shop and creates ReturnPreparation, Spotlight, or Encounter
selection through the existing handlers. Queue values increase from the
active queue; battle settlement must seed that queue from its persisted
revision before calling the factory when no pending action remains.
Current integration target is the dynamic Tea Break at 1-5 followed by the
saved route's Boss at 1-6. General augment effects, non-enemy layer creation,
and end-of-route finalization require their own state handlers; this module
does not claim to implement all run effects or replace those handlers.
Validation: Go compilation only. No unit tests, live probes, deployment or
player-save writes were performed by this implementation task. Client
continuation and combat remain to be checked after the parent integration.
## Current Boss entry correction
Live logs now confirm take-drop, RoundBegin and ReturnPreparation succeeded:
the user's run reached 1-6, revision 545, without resetting the run. Boss start
was rejected by the new helper's `CW validated battle scalar parameters missing`.
That guard incorrectly required Level and HardLevelGroup to be nonzero. Decoding
the proven first-node BattleTemplates wire shows both are omitted/zero, while
formation is 5. Updated FFGO `gfBattleMonsterWave` (RVA 0xc62b00) initializes its
wave param with formation and elite only, independently confirming omission.
The helper now preserves those captured zero values and validates the required
formation. It does not replace them with older recipes' explicit 90/1 constants.
Saved boss/camp, wave ordinals, stars, penalty and mode identity still validate.
No claim of live Boss entry is made until the patched request is observed.
## Monster and EliteBranch battle projection
The reference battle projection also accepts a previously created Monster or
EliteBranch layer: it validates the saved camp membership and wave ordering,
and EliteBranch's selected penalty against the extracted penalty table. This
does not generate those layers or establish that the Client accepts the fight.
The reference `gfRouteCreateNode` uses a run-specific neutral camp for Monster
nodes. `gfRoutePlanForRun` reads that camp from an internal FFGO run field; it
is not represented by the saved Client stage's boss camp list. The captured
first battle's monster IDs match more than one native season camp, so they do
not uniquely recover the saved run's neutral camp. The reference uses one wave
of three monsters for the first Monster node and five thereafter, filtering by
the captured maximum tier; determining the run camp is still required before
constructing that layer. EliteBranch generation additionally needs its option,
difficulty and reward contract. No player save was modified by this audit.
+39
View File
@@ -0,0 +1,39 @@
# Bonfire phase correction — 2026-10-26
The deployed FFGO-derived selected phase was wrong for the current Client.
The user's video showed the initial option cards after resume, despite the
server rejecting both option and heal requests as already selected. Saved
revision 531 has phase 1 and the already-applied same-node PetPal rule marker.
Read-only runtime evidence from the active Client:
- Exact type: `RPG.Client.GridFightBonfirePendingAction`.
- `HasSelected=false` with the server's phase 1; queue 530, income 10/5/2.
- `GridFightBonfireDialog._setup_view` reads `HasSelected` to choose between
initial option cards and final rewards. Its current baked closure was captured
without executing that closure.
- `_UpdateHasSelected(KMJMHDPPAKH)` resolves to RVA `0xda53360`.
- Native instructions `cmp esi,2; setge byte ptr [rdi+0x6c]` prove selected
means phase >= 2. See private `cw54-bonfire-hasselected.asm`.
- GameAssembly SHA256:
`4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6`.
The FFGO factory writes selected=1. Matching scalar wire layout did not prove
matching enum semantics. The earlier Tea Break integration incorrectly assumed
that semantic match; this document supersedes its phase-1-selected statements.
The server now sends choosing=1, selected=2, and accepts old phase-0 offers for
selection. A read-only projection repairs legacy selected=1 only when the
same-run/same-node effect marker and exactly one offered option's saved rule
values prove the old selection. A bare phase 1 is never automatically selected.
Readers do not write persistent or replay effects. The actual next transaction
persists the repaired phase together with its ordinary revision CAS.
New selections record the event/option (or heal) in the same-run sidecar. A
duplicate matching request resynchronizes the selected action without applying
the effect/heal again; changing a completed selection is rejected. Take-drop
still grants and advances once in the existing single commit.
Probes remain under tools/. All temporary script copies were removed and both
Frida sessions were detached. Compilation is not Client acceptance; the patched
resume/take flow still needs observation after deployment.
+93
View File
@@ -0,0 +1,93 @@
# CW Go button recovery — 2026-10-26
## Current evidence
The user reports Go from both the handbook and activity page does nothing,
with no outgoing teleport command. Current Client identity is assembly SHA256
`4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6`.
Two exact named baked modules were captured passively without executing their
returned loader closures:
- `Ui.DailyMission.Rogue.GridFight.HandbookRogueGridFightTabItem`
- `Ui.DailyMission.Rogue.HandbookRogueGotoBtnBehaviour`
The common superclass was also captured:
`Ui.Activity.CommonComponents.CommonActivityGotoBtnBehaviour`.
Raw chunks and parsed Luau v4 representations are in
`.runtime/named-baked-capture/cw-{handbook,handbook-goto,common-goto}-current.*`.
`string.dump` is absent in this Client; that failed probe is not evidence that
the named callbacks are missing. `debug.getupvalue` is available.
The handbook's `_on_click_go` calls
`ActivityModule:GetPanelData(_GRID_FIGHT_CONSTANTS.ActivityID)`, passes the
result to its behaviour and calls `on_btn_go`. Read-only current observations:
- ActivityID and PanelID: 71101.
- ContentID: 171002.
- Panel type: `RPG.Client.GridFightActivityData`; panel/state are present.
- `IsSkipSwitchStoryLine=false`.
- `StateData.CurState=PreGuide` (enum value 2).
This disproves the earlier-session nil-panel explanation for the present
failure. The unrelated missing Tourn Rogue resident-panel warning is not used
as proof of the CW cause.
## Missing native guide prerequisite
The exact live `ActivityPanelConditionRow` is retained in
`battle_diagnostics/cw-book-entry-20261026/condition-row.json`:
- PreConditions: level 21 and FinishMainMission 1034109.
- GuideConditions: FinishMainMission 8047206.
- GuideGoto: 6417; ActivityGoto: 6418; GuideTakeMission: 0.
The current common Go behaviour dispatches a PreGuide panel through its guide
path, rather than its InProgress ActivityGoto path. This server's initial
GetMissionData advertises the 148 function-unlock missions from the older
export. Its list contains 1034109 and the older CW introduction 8037100, but
omits 8047206. The latter is present in `resources/MainMission.json`. Publishing
all 2,205 imported main missions is unnecessary and is not part of the fix.
## Source correction
`resources/CurrencyWarsActivityConditions.json` retains the captured condition
row, named condition enum mapping, capture digest and the explicit older-base
to-current-activity-capture provenance. It declares the scoped freeplay policy
`complete_declared_guide_finish_main_missions`.
`LoadCurrencyWarsGuideMissions` reads this resource without modifying a save.
It validates source/target identity, active CW panel membership, supported
condition kind and mission existence. `getMissionUnlocks` appends only these
validated guide prerequisites, deduplicated, to its existing function-unlock
view. GetMissionData and GetMissionStatus therefore agree. The expected initial
finished-main count becomes 149. No Client CurState field is forced, no scene
or callback is invoked, and unrelated missions/inventory/progression are not
rewritten.
`go build ./internal/gameserver` passed. No tests or deployment were performed
by this subtask. Actual native transition to InProgress and successful Go
teleport require confirmation after the updated mission view reaches the
Client.
## Integrated validation
The parent built and deployed standard/shipping Game and SDK binaries and
restarted the root servers. Fresh GetMissionData logged 149 finished main
missions, with the existing 14,716 sub-missions and 68 exclusions preserved.
The user then confirmed Go teleport works. Server evidence records an actual
EnterScene request and resolved CW entry 2032202, rather than a success-only
button response. This confirms the tested entry path; it does not establish
completion of CW's remaining Tea Break/route/reward gameplay.
All temporary probe copies were removed from scripts/ and the passive Frida
session was detached. Ping colors was also independently user-confirmed in
this build: matching bar/digit colors and no flashing on digit changes.
## Diagnostic cleanup notes
Research tools remain under `tools/`. The parent owns removal of intentionally
staged `cw_book_condition_row.lua` and the metadata/panel-state probe copies
from `scripts/`. A finished top-level Lua probe must never use a bare `return`
inside an outer `do` block: that returns from the entire concatenated heartbeat
chunk. Use a local function/tick boundary for early returns instead.
+40
View File
@@ -0,0 +1,40 @@
# Currency Wars route continuation audit
The captured route 2801 contains these node types after the first boss:
| Chapter | Sections in order |
| --- | --- |
| 2 | CampMonster, Supply, EliteBranch, Monster, Boss |
| 3 | CampMonster, Supply, EliteBranch, Monster, Boss |
These names are joined from `CurrencyWarsCatalog.json` stage routes and
`CurrencyWarsReferenceNodes.json` templates. They describe the template, not
necessarily a run's dynamically substituted node display.
`cwAdvanceRouteNode` currently calls `cwGenerateReferenceEnemyLayer` for every
destination. That factory accepts only Boss and CampMonster; it rejects Supply,
EliteBranch, and Monster. `cwSelectSupply` also requires an exact captured
transition. Consequently a successful 2-1 battle does not establish that 2-2
or later rooms can be played. Constructing the remaining node layers, pending
actions and rewards needs their corresponding native/reference rules and a
current-Client check; copying the first Supply's randomized inventory would not
prove the later rooms correct.
`cwCapturedSupplyLayer` derives the empty Supply node container from the
revision-bound transition capture and validates that it has no camp or enemy
branches. It neither copies the captured option list nor modifies a run. It is
not yet connected to route advancement: FFGO's `gfPendingSupplyOf` and
`gfPendingFillSupplyOptions` also choose a chapter/state-dependent offer,
including distinct roles and random equipment. That pending offer remains
unmapped; advancing without it would strand the player in Supply.
After the final node, `cwAdvanceRouteNode` returns `CW route has no next node`.
At zero HP, `finishCurrencyWarsBattle` returns `CW defeat settlement requires
terminal-run handler`. Neither path currently settles the run. FFGO's extracted
descriptor names settlement reasons Quit=1, HpZero=2, and Finish=3; the current
Client's obfuscated enum has matching numeric slots, but only Quit=1 has been
confirmed for the current implementation. The reference `gfSettleSend` builds
and archives a settlement record before sending the settlement notification.
The names and fields of its rank/reward/archive components must be mapped to
the current Client before a completion handler can safely persist rewards and
clear the active run. No saved run has been modified by this audit.
+94
View File
@@ -0,0 +1,94 @@
# FFGO CW resource reference, 2026-10-26
The updated reference executable was inspected offline. It was not launched,
and its saves/configuration were not modified. Its SHA256 is
`235f5c3567f281cc99613ed84694ef23f492c15298dc868a8e78e6529f0cda86`.
## Reproducible extraction
`tools/export_ffgo_embedded_resources.py --binary <reference executable>
--output <evidence directory>` extracts bounded gzip members and decodes the
Excel resource through the executable's own generated protobuf descriptors.
It requires Python protobuf and the sibling `dump_embedded_proto.py`.
No executable code from the reference is run.
Evidence is retained under `battle_diagnostics/ffgo-20261026/`:
- `resource-manifest.json`: binary identity, descriptor identities, exact gzip
offsets/lengths, compressed and uncompressed hashes.
- `excel-data.json`: full decoded `excel.ExcelData`, including NPC monsters,
challenge/Peak data, activities, shops and CW tables.
- `gridfight-excel-data.json`: CW-only subset, 72 tables.
- `gridfight-custom-data.json`: 1,253 reference-authored config files and two
action schemas. These are **not original Client level JSON**.
- `resource-inventory.json`: table counts and the exact currently blocked Tea
Break event/options/custom rule.
- `challenge_peak_extra_data.json`: separate embedded JSON supplement,
11 groups/44 Peak entries, file offset `0x114c212`, 9,101 decoded bytes.
- `load-excel.asm`: static loader evidence. `LoadExcel` at RVA `0xb79160`
reads embedded `resources/excel.gz`, creates a gzip reader, reads all bytes,
and unmarshals the protobuf into the global Excel data object.
The Excel gzip member starts at file offset `0x11c9fef`, compressed size
962,600 bytes, uncompressed size 6,008,625. The CW custom JSON gzip member
starts at `0x1153105`, compressed size 25,684, uncompressed size 267,251.
The extractor preserves protobuf int64 values as decimal strings in JSON.
## New usable CW evidence
The extracted tables include 38 Bonfire events, 72 Bonfire options, 3 Bonfire
heal rows, 110 bonus pools, 1,120 basic bonuses, 480 combination bonuses,
532 Orbs, 493 node templates/routes, 629 special avatars and 411 augments.
This supplies the previously missing reference bonus-pool recipes. It does
not by itself establish current Client response bindings or packet order.
For the blocked event `10200601`, the reference Excel row states PetPalID 2
and DialogID `1020060101`. Its option 1 states:
- JsonPath: `Config/Level/GridFight/petpal/bonfire/GridFightBonfire102006011.json`
- DialogID: `1020060102`
- EffectParamList: `[40]`
- OptionShowType: `None`
The corresponding reference-authored custom rule is
`petpal/bonfire/GridFightBonfire102006011.json`: `TeaBreakOption`, immediate
`SetRule` action, rule name `PetPalStarDown`, value `#1` (the parameter 40).
It must not be replaced with a generic healing reward. Separate Bonfire heal
rows specify 20 for each of chapters 1, 2 and 3.
Basic bonus, random pool and combination bonus IDs are separate lookup
namespaces. For example basic BonusID 1 is Gold with amount parameter 1;
there is no random pool row with RandomBonusID 1. The existing captured Orb
197 points to BonusID 1, so trying to resolve every Orb through the random
pool table would fail for this legitimate direct basic bonus.
## Saved state is supporting evidence, not reusable configuration
The reference's external `data-in-game.json` contains an active season 2,
route 1800 run at node 1-2, 23 pregenerated nodes and one completed battle.
Its first two nodes retain per-monster `drop_orb_ids`, and its saved effect
state contains `OrbsOpened = 5`. This shows the reference persists those
concepts, but does not capture the packets that awarded/opened them.
That run must not replace this project's route 2801 run or player save.
No avatar snapshots or player inventory from the reference were imported.
The reference's static route 2801 chapter 1 section 5 points to node template
280115, whose row is `Monster`, StageID 70000008, ParamList `[902]`, penalty
92204 and basic gold 10. The captured live Client run is instead a Tea Break
with event 10200601 at that position. A PetPal/dynamic node override may explain
this; static route data must not overwrite the active run. The reference does
explicitly link PetPal 2 to effect 102006, whose parameter is event 10200601.
## Compatibility and limits
The reference supports multiple Client revision dispatches; a table's presence
in its embedded Excel is not independent proof that it matches the connected
Client's revision. Compare relevant rows with captured Client data and retain
this binary's provenance before importing a compatible subset. Resolve CmdIDs
through the current named command table; never transplant historical numbers.
The custom files label 822 entries `Implemented`, 42 `Partial`, 116
`NotImplemented`, 93 `BattleOnly`, 129 `Code` and 51 `Excel`. These are labels
inside the reference's own authored data, **not verification that those
features work in this project or even a runtime verification of the reference**.
Gameplay integration and Client verification remain separate work.
+198
View File
@@ -0,0 +1,198 @@
# Offline continuation and acceptance requirements
> Latest handoff: [ZCODE-HANDOFF.md](ZCODE-HANDOFF.md), 2026-10-24. This file
> retains chronological findings; some statuses below are superseded, including
> the user's confirmation of Aha Help, newly staged event previews and the CW
> role compatibility overlay. Use the handoff for current priorities/deployment.
The full CW objective remains active. Additional requests do not replace it.
The user subsequently specified that Stella Jump, activities, gacha and Aha's
Help must be handled before returning to CW. Preserve that order.
## Offline audit round, 2026-10-24 afternoon
With no server or game process running, both servers were rebuilt from the
latest source and deployed at 14:07 (root and `for ship`), then documented in
[ZCODE-HANDOFF.md](ZCODE-HANDOFF.md). Three source/resource changes went into
that build: the CW role-ID projection in `session.go` now also covers
`GridFightEnterBattleStageScRsp`, `GridFightEndBattleStageNotify` and
`GridFightGetArchiveScRsp` (the proto audit found no map transitively carrying
role references, and in-memory run state was already projected, so this is
defense in depth); `activity_preview.go` replaced silent first-match module
dedup with verified panel equivalence (module 1002101 legitimately spans
rerun panels 10021/10113 with an identical prefab; the published schedules are
unchanged at 12); and the stale `asset_verification_note` in
`GachaSandboxPolicy.json` now states all six captured prefab paths were
checked. No Client confirmation exists for any of this.
Stella Jump gateway analysis from `gameserver.log`/`server_debug.log`: the
"There's still more to do…" toast attempts are InteractProp on prop entities
1035/1012 with interact_id2=1100, answered with the real prop state; the
GameBoy UI itself opened once without an interaction (case 16 data request)
and closed without a start request, so the block is a client-side condition.
`ChenLingGetDataCsReq` (9612) is sent every floor load and still dropped by
the ChenLing danger family; a populated `ChenLingGetDataScRsp` capture is the
missing evidence before it can be answered safely.
## Latest steering and staged technique fix
The user confirmed Aha Help appears in combat. Their next report concerned
technique points before combat, not combat skill points: Endgame rooms start
with only five usable points despite a larger team capacity. Both the initial
Endgame lineup projection and session initialization used overworld initial_mp.
Endgame lineup construction now starts at its resource-derived MaxMp, and a new
room's session technique counter uses that same capacity. Overworld initialization
and per-cast deductions are unchanged. The inspected team's existing resource cap
is seven; the reported eight-point capacity has not been independently established,
and no new cap was invented. gameserver-go.next.exe compiled with this change.
It has not replaced the live Game server, whose last log still showed an active
Battle. The user explicitly said not to run more tests or ask for another gameplay
retry, and to continue the remaining work. Do not interrupt their active Battle
to deploy this staged binary.
## Aha Help follow-up, 2026-10-24
The user reported missing support in combat and a stuck web selector. Browser
inspection confirmed the open tab still ran the earlier JavaScript, and its
local static server was no longer listening. The existing local page service was
restarted, the tab reloaded, and its live Save Manager now shows enabled LV 1–3
options. The selector now explicitly shows `FreeSR (off)` when the legacy
`enable_invasion_support` is false; the API previously returned level null, and
no override had been saved. Aha Global is a separate passive setting.
The imported custom battle contains a Corruption buff matching the resource
invasion mapping, but the old support branch required ChallengeStageID. Support
selection now checks the outgoing battle's actual Corruption buffs after the
existing official-challenge injection. It does not inject Corruption from a
custom stage ID. Selecting a level removes other support levels before adding
one selected buff; explicit zero removes support for that Corruption battle.
Null follows the existing FreeSR switch. Selection is read afresh at battle
creation, and AHA_HELP diagnostics record the decision and sent IDs. Game and
SDK compiled and were restarted with visible consoles. The new web state is
confirmed; the user still needs to choose a level and verify the next battle.
## Current Client capture and staged work
### Client regression after deployment, 2026-10-24
After the user reopened the Client, its assembly hash was rechecked and a
bounded `AssetMgr.Exists` query checked all six captured prefab paths, without
loading them. Standard and novice returned true; all four limited character and
lightcone paths returned false. The research scripts were removed from scripts/
after capture. Evidence is retained in
`battle_diagnostics/gacha-asset-exists-20261024.log`. Standard is now the sole
verified browsable entry in the resource policy. It has no invented featured
avatar or prize list, and its draw request returns NOT_SUPPORT. Featured draws
remain unavailable pending real installed presentation assets. The rebuilt Game
server was restarted; actual Standard page entry/exit still awaits Client retry.
The user reported an empty Warp page followed by a black map on exit. Player.log
proves the captured Seele prefab is absent from the installed asset manifest
(`index=-1`), followed by `UIPrefabLoader._HandleLoadResult` ArgumentNullException
inside `GachaMainPage._create_pools_panel`. The earlier statement that two
captured paths represented usable banners was too strong: they are candidates,
not verified installed assets. Gacha entry now returns `RET_GACHA_NOT_SUPPORT`
when the resource policy has no verified banner prefab; DoGacha uses the same
verified set. No alternative prefab path or banner ID was invented.
The same log contains repeated ActiveActivity ItemFactory null references and
missing RaidCollection reward icons. Additional preview schedules are withheld
through their resource policy until each dependency is validated. Existing
non-preview schedules and saves were not changed. The guarded Game executable
was built and deployed; SDK was started with its visible console as well.
Recovering a Client already stuck in the failed UI transition requires a fresh
login. The user was asked to open the Client at the normal walking screen to
check available assets; no game process was present during this repair. Neither
safe rejection in the Client nor replacement banners have been verified yet.
The running Client was verified at runtime as a different assembly from the old
CW capture: SHA-256 `4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6`.
The module path identified the user's current installation as 4.6.54. No old
native RVAs were reused against it. Exact named FromBinary methods, their flat
dictionary consumers, and bounded getters were traced and captured separately.
`PreviewGameplayCatalog.json` contains 6 gacha basic rows, 13 Parkour rows, 181
activity panels and 361 activity configurations. Original JSON number strings
were retained when exporting so 64-bit text hashes are not rounded.
Stella Jump is the side-view ChenLing GameBoy game, not Parkour. All 16 case rows
are retained in `StellaJumpConfig.json`. New handlers respond with a non-null
case payload, expose its configured challenge packs, and save actual best times
and submitted completions under a separate persistent key. No synthetic best
time is stored to unlock the menu. The request CmdID for RequireChenLingGameBoyData
was independently checked in current Client native code and matches the named
revision-tagged command table. The two cheat requests still have obfuscated table
names: ANDPLLAKCLE/CDJKLJDMJHO and EMDKLICDPKK/JHEHACPKKBL. Their case-ID and
case-ID/boolean shapes are mapped to the named Client sender methods; the exact
meaning of the extra response boolean still needs Client verification.
The gacha implementation now derives featured characters from actual captured
avatar-prefab basenames and returns that same character for each draw. The
captured basic table currently provides two character banners. This does not
establish support for a banner for every avatar. Sandbox draw counts/pricing and
duplicate handling are explicit resource policy. For the existing fully owned
roster, duplicate materials use the avatar's configured first Eidolon cost and
merge into the latest import under the common file lock. Rank, EX and Traces are
preserved. First-time acquisition for an avatar absent from the imported roster
is still rejected rather than constructing an incomplete avatar.
Activity preview policy currently exposes two captured panel types, minigames
and ActiveActivity, with their typed data callbacks. Mini-game scores are empty
unless provided by a dedicated subsystem; this does not claim full event gameplay.
ActiveActivity's module-ID to data-ID association is an initial mapping requiring
Client confirmation. Remaining event-specific actions/rewards are incomplete.
Aha's Help's loading bug was a frontend envelope mismatch: `/api/persistent`
returns `persistent`, but the page read `data` and returned before loading levels.
The level loader now runs independently, shows offline/API errors explicitly,
and reloads on a connection change. The actual API was observed returning LV 1–3.
The regression check exercises the real envelope, empty character cache, explicit
off and API failure; it passes. Frontend script/style cache keys were updated.
On 2026-10-24 the user explicitly authorized rebuilding and restarting both
servers. Both builds succeeded, previous root executables were backed up under
`.runtime/before-preview-*`, and the new root Game/SDK executables were started
with visible consoles. Both processes remained running and the SDK Aha endpoint
returned LV 1–3. Focused store tests for Aha, Stella Jump and duplicate gacha
grants pass. Client unlocks, event screens and gacha animations remain unverified.
## Implemented, awaiting Client verification
Aha's Help has a resource-backed level selector, independent persistent setting,
SDK endpoint and GaC-Srtool control. Values are from the user's supplied screenshot,
not a claim of a freshly captured Client table. Existing stage-invasion detection
gates the buff. Explicit off and resetting to the FreeSR setting are supported.
Reads do not write, and targeted writes preserve other persistent sections.
The focused persistence test passes, both executables compile, and srtool JavaScript
passes syntax checking. The broader common and SDK test packages pass. The game
server package has failures resolving resources in relic, scene and smoke tests;
there is no claim that the whole test suite passes or that Client gameplay works.
CW equipment Forge use and grants for Orb/consumable/Forge are implemented.
Automatic Orb drops, opening Orbs, consumable effects, Tea Break choices and full
later-room progression remain incomplete.
## Offline findings and remaining requests
- Reward comparison: 347 of 478 captured Client combination rows match the older
reference by ID and both arrays. The reference has 372 combination rows and 966
basic bonus rows; only 276 of 529 captured Orbs point directly to those basic
rows. Do not promote the entire older reward table as current Client data.
- Stella Jump: all stages should be selectable and playable. No current stage
catalog was located in this repository. Parkour request schemas exist, but that
alone does not prove Stella Jump uses that subsystem or identify unlock fields.
- Activities: expose event pages and enough entry/data handlers for preview;
complete reward/gameplay simulation was not requested. The current schedule
handler deliberately exposes only Endgame/CW, and there is no generic event
data implementation. Avoid publishing every ActivityConfig row with empty
replies that leave the Client waiting.
- Gacha: one character per selectable banner, with each draw matching the displayed
character. Current code hardcodes a standard banner and alternates unrelated
result IDs. A matching Client banner-to-character table is still required;
the older reference's Banners.json is not proof of current banner assets.
- Aha's Help: verify LV 1/2/3, off, legacy fallback, challenge-only application,
and that changing the setting during battle affects the next battle only.
Keep all research probes outside scripts while the game is not being inspected.
No Client gameplay confirmation has been requested during this offline work.
+34
View File
@@ -0,0 +1,34 @@
# Ping colors
Maintained script: `scripts/ping_rainbow.lua`; included in the self-contained
Game/SDK builds through `assets_ship.go`. Root servers read the external script
on heartbeat, so a live fix does not require restarting the server or game.
## Current behavior and confirmation
The user confirmed on 2026-10-26 that signal/text colors now match and changing
ping digits no longer flicker. The initial three-slice version was confirmed
to show all signal bars, but its original tinted texture darkened the colors
and writing rich text caused a flash whenever native latency changed.
The maintained version uses a tiny white-RGB mask with the signal sprite's
original alpha. It crops only the named NetStatusPanel signal icon from its
atlas once on creation, not the whole UI. Three UV slices color each bar
independently. The background and native connectivity state remain unchanged.
Text keeps the real Client latency string. The canvas callback colors the
native TextGenerator glyph vertices instead of replacing the string with
color tags. This removes the native-setter/rich-text race. Current Client
capture proves `10ms` has sixteen populated vertices; no presumed trailing
quad is discarded. CanvasRenderer.GetMesh is unavailable in this engine, so
the current path uses the retained native generator and SetMesh.
Only the named walking/Battle latency widgets are targeted. No global Canvas,
world camera, server-name watermark or unrelated UI is modified. Lifecycle
cleanup restores owned components and disposes generated textures/meshes.
Research capture scripts stay in `tools/`, not `scripts/`.
Runtime evidence is retained under `battle_diagnostics/ping-colors-20261026/`.
The walking widget is Client-confirmed; Battle has the existing exact path
but was not separately exercised during this confirmation. Lua syntax checking
and shipping compilation are separate from that visual confirmation.
+6 -4
View File
@@ -1,9 +1,11 @@
# Endgame team recommendations
`GetFriendRecommendLineup` (CmdID 2985 from the checked-in 4.6.53 command table) now returns three recommended teams for the current MoC floor-12 snapshot. The response uses the `OJJJDPNOKHG.lineup_list` shape because its repeated `ChallengeLineupList` entries match the three stage rows in the referenced Client page. Each external character slug is resolved through the current `resources/AvatarConfig.json`; the server does not embed AvatarIDs in its handler.
`GetFriendRecommendLineup` (CmdID 2985 in the checked-in Client 4.6.53 command table) serves current Prydwen team snapshots for Memory of Chaos, Pure Fiction, Apocalyptic Shadow, and Anomaly Arbitration. Each source slug is resolved through this Client's `resources/AvatarConfig.json`, with source-name aliases kept beside the snapshot. The AA response uses the Peak-lineup protocol variant and obtains Peak IDs from `ChallengePeakGroupConfig.json`; it does not embed the current game's IDs in the handler.
The bundled snapshot is dataset revision 4.6.2, collected 2026-10-14, for MoC cycle 4.6.1 “Crossing the Afterlife”. The files identify the first-ranked Prydwen team for stages 12-1, 12-2, and 12-3. The dataset repository declares MIT and asks users to credit LvlUrArti; its README says it contains processed data shown on Prydwen. Attribution and source metadata are kept in `resources/PrydwenEndgameTeams.json`.
The bundled data is revision 4.6.2, collected 2026-10-14. Each mode retains its own challenge version/name because their cycles do not necessarily advance together. Data is processed from the MIT-licensed [LvlUrArti/MocDataProcessed dataset](https://huggingface.co/datasets/LvlUrArti/MocDataProcessed), which describes its contents as processed Prydwen data and requests credit to LvlUrArti.
To refresh for another floor and the newest published snapshot, run `python tools/update_prydwen_endgame_teams.py --floor 12 --stage-count 3`. The updater validates every slug against this Client's AvatarConfig before replacing the snapshot; add a source-slug-to-AvatarVOTag alias in the resource if a name differs.
Refresh all modes from the latest dataset snapshot with `python tools/update_prydwen_endgame_teams.py`. To refresh only one mode, use `--mode moc`, `--mode pf`, `--mode as`, or `--mode aa`. The updater selects the highest-ranked team whose four character slugs resolve against this Client's `AvatarConfig`; this avoids emitting avatar IDs that the running Client does not define.
Protocol limitation: the current proto retains an obfuscated `JFNJKAPPNOF` enum and obfuscated response oneof names. The handler echoes the request `type` and `key`, and uses the lineup-list variant based on the visible three-row MoC UI and the message's repeated lineup schema. The exact numeric type-to-mode relationship and the meaning of response field `ALDBIIIGLOM` are not established. This first implementation does not discriminate modes using `type` or `key`, so it is limited to the illustrated MoC page and needs in-Client verification before claiming support for other Endgame modes or the friend-cleared tab.
Protocol limitation: `GetFriendRecommendLineupCsReq.type` is the obfuscated `JFNJKAPPNOF` enum in this Client's protobuf. The mapping 2=MoC, 3=PF, 4=AS, and 5=AA is an explicit implementation assumption; the checked-in schema does not reveal the enum names, and we do not have packet captures from each Client page to confirm those values. The mapping is centralized in `resources/PrydwenEndgameTeams.json`, and unknown values receive an empty response with the request context preserved instead of MoC data. The handler logs the received type/key to support Client-side verification. AA `key` matching also remains an assumption: known Peak resource IDs are matched directly, and otherwise the latest configured group is paired with the bundled current AA snapshot.
The response shapes follow the checked-in protobuf: the current three-stage MoC/PF/AS pages use `OJJJDPNOKHG.lineup_list`; AA uses `MJMGDLJAJCM` entries with `peak_id` and avatar lists. These server tests verify resource conversion and protobuf round trips; a successful build does not confirm the live Client accepted every mode's obfuscated route or UI response.
+290
View File
@@ -0,0 +1,290 @@
# Ungrouped.proto — คู่มือจัดกลุ่ม message
## อ่านไฟล์นี้อย่างไร
นี่คือ schema ของ Protobuf ที่ใช้กำหนดรูปแบบข้อมูลระหว่าง Client กับ Server ไม่ใช่ไฟล์ config และไม่ได้บอกวิธีทำงานของ handler เอง
- `CsReq` คือคำขอจาก Client, `ScRsp` คือคำตอบจาก Server, `ScNotify` คือข้อความแจ้งจาก Server; `Rsp` คือ response เช่นกัน
- เลขหลัง `=` คือ Protobuf field tag; คอมเมนต์ `offset:` เป็น metadata จาก dump ไม่ใช่ CmdID
- `Ungrouped.proto` ไม่มี CmdID และไม่มีป้าย protocol revision จึงห้ามใช้ไฟล์นี้เดาเลข route/handler
## ผลเทียบกับ GaC
- ไฟล์ต้นทางมี 203 top-level messages และ 5 enums
- ชื่อ message 141 รายการมีอยู่แล้วใน `StarRail.proto`; เพิ่ม schema ที่ขาด 62 รายการกับ enum ที่ขาด 1 รายการไว้ใน `protocol/proto/ungrouped.proto`
- เพิ่ม `KVP` (uint32 value (tag 3), uint32 key (tag 9)) ซึ่งไฟล์ต้นทางอ้างผ่าน `Common.proto` แต่ dependency นั้นไม่ได้แนบมา
- schema ที่เพิ่มไม่มี CmdID comment และยังไม่ได้ผูก packet handler; การเทียบกับ source อื่นพบว่า body/field tags ใช้ตรวจโครงสร้างได้ แต่ CmdID ต่างกันได้
ตรวจ signature ของ 203 message กับ `AstralOS/crates/morax/src/StarRail.proto` ที่ checkout revision `abf2fd8fc07711432bac878d44f151f041311f24` แล้ว field types/tags ตรงกันทั้งหมด อย่างไรก็ตาม revision ของไฟล์ต้นทางที่แนบมาไม่ระบุ จึงใช้ reference นี้ยืนยันรูปร่าง schema เท่านั้น ไม่ใช้ย้าย CmdID
ตัวอย่างความต่างของ CmdID: `B51RacingGetDataCsReq` ในตาราง GaC ปัจจุบันเป็น 9995 แต่ source AstralOS revision ข้างต้นระบุ 9990 จึงไม่คัดลอก ID ข้ามตาราง
## กลุ่มที่อ่านความหมายได้จากชื่อ
### B51 Racing (37 messages)
ชุดข้อมูลและคำสั่งของกิจกรรมแข่งรถ: รถ/ลายรถ/คนขับ/ชิ้นส่วน/การพัฒนา/รอบแข่ง.
- `B51RacingAgendaInfo` — เพิ่ม schema แล้ว
- `B51RacingCarDisplay` — เพิ่ม schema แล้ว
- `B51RacingCarLivery` — เพิ่ม schema แล้ว
- `B51RacingCarLiveryCsReq` — เพิ่ม schema แล้ว
- `B51RacingCarLiveryScRsp` — เพิ่ม schema แล้ว
- `B51RacingChallengeCarData` — เพิ่ม schema แล้ว
- `B51RacingChallengeData` — เพิ่ม schema แล้ว
- `B51RacingChallengeEndMatchCsReq` — เพิ่ม schema แล้ว
- `B51RacingChallengeEndMatchScRsp` — เพิ่ม schema แล้ว
- `B51RacingChallengeStartMatchCsReq` — เพิ่ม schema แล้ว
- `B51RacingChallengeStartMatchScRsp` — เพิ่ม schema แล้ว
- `B51RacingChallengeUpdateCarCsReq` — เพิ่ม schema แล้ว
- `B51RacingChallengeUpdateCarScRsp` — เพิ่ม schema แล้ว
- `B51RacingCycleData` — เพิ่ม schema แล้ว
- `B51RacingDevelopmentInfo` — เพิ่ม schema แล้ว
- `B51RacingDriverUnlockScNotify` — เพิ่ม schema แล้ว
- `B51RacingEndMatchCsReq` — เพิ่ม schema แล้ว
- `B51RacingEndMatchScRsp` — เพิ่ม schema แล้ว
- `B51RacingGetDataCsReq` — มี schema เดิมใน `StarRail.proto`
- `B51RacingGetDataScRsp` — มี schema เดิมใน `StarRail.proto`
- `B51RacingMatchInfo` — เพิ่ม schema แล้ว
- `B51RacingMatchStats` — เพิ่ม schema แล้ว
- `B51RacingMissionChangeAgendaScNotify` — เพิ่ม schema แล้ว
- `B51RacingPartInfo` — เพิ่ม schema แล้ว
- `B51RacingPreMatchTrackInfo` — เพิ่ม schema แล้ว
- `B51RacingReplacePartScRsp` — เพิ่ม schema แล้ว
- `B51RacingSelectDevelopActionCsReq` — เพิ่ม schema แล้ว
- `B51RacingSelectDevelopActionScRsp` — เพิ่ม schema แล้ว
- `B51RacingSelectDevelopPartCsReq` — เพิ่ม schema แล้ว
- `B51RacingSelectDevelopPartScRsp` — เพิ่ม schema แล้ว
- `B51RacingSetDriverCsReq` — เพิ่ม schema แล้ว
- `B51RacingSetDriverScRsp` — เพิ่ม schema แล้ว
- `B51RacingStartCycleCsReq` — เพิ่ม schema แล้ว
- `B51RacingStartCycleScRsp` — เพิ่ม schema แล้ว
- `B51RacingStartMatchCsReq` — เพิ่ม schema แล้ว
- `B51RacingStartMatchScRsp` — เพิ่ม schema แล้ว
- `B51RacingStatInfo` — เพิ่ม schema แล้ว
### Expedition Battle (16 messages)
ข้อมูลแผนที่ เส้นทาง ทีม เริ่มต่อสู้ และสรุปผลของ Expedition Battle.
- `ExpeditionBattleAvatarDamage` — เพิ่ม schema แล้ว
- `ExpeditionBattleAvatarInfo` — เพิ่ม schema แล้ว
- `ExpeditionBattleEndScNotify` — เพิ่ม schema แล้ว
- `ExpeditionBattleFunRecord` — เพิ่ม schema แล้ว
- `ExpeditionBattleLevelRecord` — เพิ่ม schema แล้ว
- `ExpeditionBattleLineup` — เพิ่ม schema แล้ว
- `ExpeditionBattleMapData` — เพิ่ม schema แล้ว
- `ExpeditionBattleRouteRecord` — เพิ่ม schema แล้ว
- `ExpeditionBattleRouteSettleInfo` — เพิ่ม schema แล้ว
- `ExpeditionBattleSetLineupCsReq` — เพิ่ม schema แล้ว
- `ExpeditionBattleSetLineupScRsp` — เพิ่ม schema แล้ว
- `ExpeditionBattleSettleScNotify` — เพิ่ม schema แล้ว
- `ExpeditionBattleStartCsReq` — เพิ่ม schema แล้ว
- `ExpeditionBattleStartScRsp` — เพิ่ม schema แล้ว
- `GetExpeditionBattleDataCsReq` — เพิ่ม schema แล้ว
- `GetExpeditionBattleDataScRsp` — เพิ่ม schema แล้ว
### Blind Box (7 messages)
อ่าน/เปิด/รีเซ็ตตำแหน่งกล่อง และการแจ้งการแลกเปลี่ยน.
- `BlindBoxGetDataCsReq` — มี schema เดิมใน `StarRail.proto`
- `BlindBoxGetDataScRsp` — มี schema เดิมใน `StarRail.proto`
- `BlindBoxOpenBoxCsReq` — มี schema เดิมใน `StarRail.proto`
- `BlindBoxOpenBoxScRsp` — มี schema เดิมใน `StarRail.proto`
- `BlindBoxResetPoolPositionCsReq` — เพิ่ม schema แล้ว
- `BlindBoxResetPoolPositionScRsp` — เพิ่ม schema แล้ว
- `BlindBoxTradeChangeScNotify` — มี schema เดิมใน `StarRail.proto`
### Badge (2 messages)
ข้อมูลและการแจ้งเปลี่ยน Badge.
- `BadgeInfoScNotify` — มี schema เดิมใน `StarRail.proto`
- `GetBadgeInfoScRsp` — มี schema เดิมใน `StarRail.proto`
### Social Play (15 messages)
ข้อมูลห้อง เจ้าของห้อง ผู้เยี่ยมชม แชต การเคลื่อนไหว และ operation ในห้อง.
- `SocialPlayGameplayOperationScNotify` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayGetDataCsReq` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayGetDataScRsp` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayGetOnlineRoomDataCsReq` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayGetOnlineRoomDataScRsp` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayGetOwnerRoomDataCsReq` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayGetOwnerRoomDataScRsp` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayPreCheckEnterRoomCsReq` — เพิ่ม schema แล้ว
- `SocialPlayPreCheckEnterRoomScRsp` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayQueryRecentVisitorsCsReq` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayQueryRecentVisitorsScRsp` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayRoomPlayerMoveScNotify` — มี schema เดิมใน `StarRail.proto`
- `SocialPlaySettingInfoScNotify` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayTalkCsReq` — มี schema เดิมใน `StarRail.proto`
- `SocialPlayTalkScRsp` — มี schema เดิมใน `StarRail.proto`
### Pet Marble (6 messages)
ข้อมูลเกม Pet Marble, trial และเริ่ม/ซิงก์ด่าน.
- `PetMarbleGetCycleTrialPetsCsReq` — มี schema เดิมใน `StarRail.proto`
- `PetMarbleGetCycleTrialPetsScRsp` — มี schema เดิมใน `StarRail.proto`
- `PetMarbleGetDataCsReq` — มี schema เดิมใน `StarRail.proto`
- `PetMarbleGetDataScRsp` — มี schema เดิมใน `StarRail.proto`
- `PetMarbleLevelBeginScRsp` — มี schema เดิมใน `StarRail.proto`
- `PetMarbleSyncDataScNotify` — มี schema เดิมใน `StarRail.proto`
### Pet Park (2 messages)
คำขอปรับแต่ง Pet Park.
- `PetParkDiyCsReq` — มี schema เดิมใน `StarRail.proto`
- `PetParkDiyScRsp` — มี schema เดิมใน `StarRail.proto`
### Finality Battle (2 messages)
คำขอเริ่มด่านต่อสู้ Finality และผลตอบกลับ.
- `StartFinalityBattleLevelCsReq` — มี schema เดิมใน `StarRail.proto`
- `StartFinalityBattleLevelScRsp` — มี schema เดิมใน `StarRail.proto`
### Voracity Invasion (3 messages)
อ่านข้อมูลและรับ notification ของ Voracity Invasion.
- `GetVoracityInvasionDataScRsp` — มี schema เดิมใน `StarRail.proto`
- `VoracityInvasionChangeScNotify` — มี schema เดิมใน `StarRail.proto`
- `VoracityInvasionGetDataCsReq` — เพิ่ม schema แล้ว
### Private Order (2 messages)
คำขอประกาศ private order และผลตอบกลับ.
- `PublishPrivateOrderCsReq` — มี schema เดิมใน `StarRail.proto`
- `PublishPrivateOrderRsp` — มี schema เดิมใน `StarRail.proto`
### Enum ที่เพิ่ม
- `GGLMGBPOCOP`: ค่า `GGLMGBPOCOP_BMKFIMEJPOM=0`, `GGLMGBPOCOP_MLOGJAKGHHD=1`, `GGLMGBPOCOP_ILMKHLENPNI=2`; ชื่อสมาชิกยัง obfuscated จึงยังบอกความหมายเชิงเกมไม่ได้
## ข้อความที่ยัง obfuscated
เหลือ 111 message ที่ชื่อเป็นรหัส ไม่มีชื่อ feature ที่ยืนยันได้ใน schema จึงไม่ตั้งชื่อความหมายเอง รายการด้านล่างบอกเฉพาะโครงสร้างและชนิดที่ message อื่นอ้างถึง:
- `AAOAEMOHCEP` — fields: OHMBEPHEBDJ:uint32#2, progress:uint32#8; ถูกอ้างจาก: `FOEPMKFEJMK`
- `ABGMGHNOONM` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `ADDMKOIFOEF` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `AFAIGBNOCJB` — fields: info:FOEPMKFEJMK#12; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `AFKFJCPELEM` — fields: NGPBPFKGNLI:uint32#4, retcode:uint32#11; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `AHBLKPAJDPI` — fields: CHILKFNAINA:uint32#13, LBMGKCMHKLN:uint32#14, HEMOHFJJMJG:uint32#15; ถูกอ้างจาก: `BlindBoxOpenBoxCsReq`
- `ALAMOHABJIP` — fields: ILBFMJKABFO:uint32#4, JPPMEKJGJFD:uint32#10, LLNNOPDLLED:uint32#11, GNFDFIIKJHI:uint32#14; ถูกอ้างจาก: `HPJONNDENCB`, `PPFAMGCOOFP`
- `AOBDHCFGGBH` — fields: design_level:uint32#3, DLDELBKOMDK:uint32#4, retcode:uint32#7, AFMDPIAFPNF:uint32#8, EIFICNFGGHI:uint32#9, LAOPAGMAAHD:uint32#11, OOIMHIJFHDI:uint32#12, PDNHGNDAHBA:uint32#14, FDGKBOIEHBD:uint32#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `BACPIBIJPPH` — fields: retcode:uint32#13; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `BDOBLDOOICE` — fields: EPENKGKBOAP:uint32#7, end_time:int64#8; ถูกอ้างจาก: `PetMarbleGetCycleTrialPetsScRsp`
- `BHJEBMOOJED` — fields: KJPFENPNFBP:ItemList#12; ถูกอ้างจาก: `BlindBoxOpenBoxScRsp`
- `BMJHNDBOPLC` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `BNKDEHGIJMH` — fields: LLCHGCNFOJJ:JCAHAPMBCOC#15, IKMADODLNJD:PACMGHKKGKN#2, EPLGOGFAHDM:ONJIANLPDBE#9, PPNNPIGCHOL:FJEMMEGKKHE#11; ถูกอ้างจาก: `HMLFGDFLIBP`
- `BODEMOLDHAA` — fields: teleport_id:uint32#10; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `BPMFHIHNEHH` — fields: ENGHMIAMPLG:ItemList#9, retcode:uint32#12, info:FOEPMKFEJMK#13; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `CCLIGKFAHJI` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `CDLFFHOHAIH` — fields: FIEOPKNBHKJ:uint64#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `CEAPCHBBOFN` — fields: MBIAIMKHNDB:bool#2, uid:uint32#11; ถูกอ้างจาก: `MIECIEKKIMJ`
- `CHNMJPLALEC` — fields: retcode:uint32#3, MJNENEAAOAE:uint64#5; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `CJIFMPGCOOC` — fields: AALLJKILLKM:DLDPJEILCDB#13; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `COPLCPBANMD` — fields: FODBOPBEALE:PDFEPMMIKDF#13; ถูกอ้างจาก: `PetMarbleGetDataScRsp`, `PetMarbleSyncDataScNotify`
- `CPCHHBHCGOO` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `DCNIDBKPPCK` — fields: IKJOGIDIBPK:uint64#1, retcode:uint32#6, order_list:NMEGIPHFFDA#9; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `DJIHNCHDFED` — fields: retcode:uint32#5; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `DLDPJEILCDB` — fields: HJAMPKPCKEB:string#1, KMGONPNDONA:string#2, DHPIFLNBLNM:string#3, ACLHGDDNNLK:string#4, CAGPHEEGOAC:string#5, DNDHBFOKAEA:string#6, ACMLHNNMBBN:string#7, FFCDKLBFKJM:string#8, DALMLLPIFNP:string#9, EFGMHCEIJGO:string#10, PFDNBIDFDMH:string#11, BLBAIBEBIAL:string#12, KNAKEKLCFDH:string#13, GECJPIMLHIM:string#14, JHKJKKGLAHE:string#15, GOOLPABLPBF:string#1297, LOKOLODKAAM:string#1369; ถูกอ้างจาก: `CJIFMPGCOOC`
- `DNHFLGJJKHN` — fields: order_list:NMEGIPHFFDA#10, IKJOGIDIBPK:uint64#11; ถูกอ้างจาก: `OIJOHMLIEII`
- `DPOGMNFCMNN` — fields: order_list:NMEGIPHFFDA#5, retcode:uint32#7; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `EBGAMBKHDBO` — fields: IAJHCHOJHNN:uint32#14, type:uint32#3, NLIHHAKFEDB:bool#607, GGBGEJIIKFN:BEGIDCPIPBG.MDNMHBPMJFD#155; ถูกอ้างจาก: `GetVoracityInvasionDataScRsp`
- `ELNAIJEFGMK` — fields: NMELIDCDKAK:uint32#5; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `FAKNKCAOHON` — fields: FIEOPKNBHKJ:uint64#14; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `FDCJIIKHHHB` — fields: retcode:uint32#10; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `FGLAJHMCJLL` — fields: expire_time:int64#10, EIKLMFPMJJD:uint32#12; ถูกอ้างจาก: `JEGMGPOFHGG`
- `FIJJHJADLLM` — fields: retcode:uint32#5, DODHMIDBNHC:NPLMMCGAJDF#10; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `FJEMMEGKKHE` — fields: KIEBAPFGCCN:uint32#7; ถูกอ้างจาก: `BNKDEHGIJMH`
- `FJKEGMEPLDI` — fields: CPPBNJLABGE:HKHKEMHCHEB#8; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `FKPKLHICPFO` — fields: LENMCGCGBOA:uint32#7, retcode:uint32#14; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `FMOEINGLFGG` — fields: FLKIEILIBJA:PGLBKDELHJK#4, OGOCOFPHIIK:FODAGGODIJM#1; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `FODAGGODIJM` — fields: FLBOPEJIGJF:uint32#5, DGONPFLCOMO:uint32#7; ถูกอ้างจาก: `FMOEINGLFGG`
- `FOEPMKFEJMK` — fields: LNLDJDODOIL:uint32#5, available_count:uint32#7, CLGMOPPOGGC:uint32#8, OMNDNGDEEGL:AAOAEMOHCEP#11; ถูกอ้างจาก: `AFAIGBNOCJB`, `BPMFHIHNEHH`, `OMEAEOLPGGM`
- `GNBOBLNFEHI` — fields: FIEOPKNBHKJ:uint64#9; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `HAHEOGIBNHL` — fields: MJNENEAAOAE:uint64#10, retcode:uint32#11; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `HAIFIDAHGJG` — fields: JIPPNPILKDJ:HHCNMGNAIBG#14; ถูกอ้างจาก: `SocialPlayGetDataScRsp`
- `HFHGPMCHDGL` — fields: BHBJFFMACFD:uint32#1, OLGCOBHGDCD:HIMPJFMPEPA#2; ถูกอ้างจาก: `HHCNMGNAIBG`
- `HHCNMGNAIBG` — fields: DANNIDIPFAL:HFHGPMCHDGL#1; ถูกอ้างจาก: `HAIFIDAHGJG`, `LLKIFBFCMLK`, `PetParkDiyScRsp`, `SocialPlayGameplayOperationScNotify`
- `HHJLCGGEHPB` — fields: PLPPPCEPBDO:uint32#1, KFACPOBAAGM:int64#7, CILGIDDHODG:PlayerSimpleInfo#14; ถูกอ้างจาก: `SocialPlayQueryRecentVisitorsScRsp`
- `HKHKEMHCHEB` — fields: NECCJMBJNEN:uint32#4, HECCOBFBJFI:uint32#5; ถูกอ้างจาก: `FJKEGMEPLDI`
- `HLJINHODOPP` — fields: order_list:NMEGIPHFFDA#3, retcode:uint32#6; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `HMACEHDGGHB` — fields: BJPHDKEBOBK:IKAHKMNCFDN#1, HBKEPFKDAMI:uint32#2, CMHKFNFKGOI:int64#3; ถูกอ้างจาก: `SocialPlayGameplayOperationScNotify`
- `HMLFGDFLIBP` — fields: DGNGMJMPFGK:BNKDEHGIJMH#8; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `HPJONNDENCB` — fields: EEFLBHGIAAN:ALAMOHABJIP#4, OFNDFACDNOC:uint32#11; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `IAKKHBENIOL` — fields: retcode:uint32#9; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `IFEEMEAJMEJ` — fields: ODNGMIJLKKA:uint32#1, ENGJIMIHCHJ:PFNJCDINMLA#2, EGECDHIHFHF:OELLEKNNEMK#3; ถูกอ้างจาก: `JBJNJPAOCDA`
- `IKBDJLNEPBH` — fields: HFLOPHNBKGN:PEEEEGAPCOK#1; ถูกอ้างจาก: `SocialPlayGameplayOperationScNotify`
- `ILBLJAFMBBK` — fields: FIEOPKNBHKJ:uint64#6; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `IMDEBPDKCAJ` — fields: MJNENEAAOAE:uint64#5, retcode:uint32#8; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `IOPNJIOPAFI` — fields: filter:MMBIBKFEFNG#13, ADPEKIOPFKG:GGLMGBPOCOP#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `JBJNJPAOCDA` — fields: uid:uint32#1, OJPDDAOJJKC:bool#2, NJDCPMENIFG:JOLAHHGIFHA#3, AIMNJIMDIKM:int64#4, AJIPBLCIONL:PlayerSimpleInfo#5, DCFKJCMODKJ:IFEEMEAJMEJ#6, LHLKJIDFLIN:CBPDACMBHGL#7; ถูกอ้างจาก: `POBLGKIGINE`, `SocialPlayGameplayOperationScNotify`, `SocialPlayGetDataScRsp`
- `JCAHAPMBCOC` — fields: EJHKAHEGCDC:uint32#8; ถูกอ้างจาก: `BNKDEHGIJMH`
- `JCIPKHCJLBM` — fields: retcode:uint32#11; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `JDNHIMDLIHH` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `JEGMGPOFHGG` — fields: CPMCCCODGAB:FGLAJHMCJLL#3; ถูกอ้างจาก: `BadgeInfoScNotify`, `GetBadgeInfoScRsp`
- `JGAMELLGLGE` — fields: NJDCPMENIFG:JOLAHHGIFHA#7; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `JKILAALMFIB` — fields: retcode:uint32#7; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `JLMKPMCDOKC` — fields: CLGMOPPOGGC:uint32#13; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `JNDBILOGFAF` — fields: FBDIGGDLDCP:MNGADDFICJF#1, FLBOPEJIGJF:uint32#10; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `JOLAHHGIFHA` — fields: pos:Vector#1, rot:Vector#2, ICNANKMDJIC:float#3, GHMKFMBDKNE:Vector#4, GHEMGLKGKLC:float#5, FPHBEHJJBIA:uint32#6, MGIOLDGHPMA:bool#7, time_stamp:int64#8; ถูกอ้างจาก: `JBJNJPAOCDA`, `JGAMELLGLGE`, `MHNNEFBOPIE`
- `JPAOIPLDKHB` — fields: BJPHDKEBOBK:IKAHKMNCFDN#1, NLJBJMDPBGN:BFAKMCIJFCB#2, DBIKJPDBMOE:int64#3, CMHKFNFKGOI:int64#4, HBKEPFKDAMI:uint32#5, GAEKEFEKCBD:uint32#6; ถูกอ้างจาก: `PBMDEBCGNMD`
- `JPPCNOGIMFD` — fields: DHAKONBPFMC:uint32#7; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `KKACLNNMMAM` — fields: EIHOECKBDOH:uint32#7, BPAOGJPLENJ:uint32#14, JMAODNEONPF:bool#15; ถูกอ้างจาก: `KPBCIIFIAGI`
- `KPBCIIFIAGI` — fields: CMHKFNFKGOI:int64#1, KABGCGENKLK:CGLJLBDFNBK#2, NIELDCLPOLA:JOFHMCJPBCE#4, BJPHDKEBOBK:IKAHKMNCFDN#5, NLJBJMDPBGN:BFAKMCIJFCB#6, CEMFBJPOLNP:PJFIMFJPMCN#7, NAIFOMCLGLN:ONAADAJBLEB#8, JIELLGELABA:KKACLNNMMAM#9, KBEGMPBAJIL:uint32#11; ถูกอ้างจาก: `SocialPlayGetDataScRsp`
- `LLKIFBFCMLK` — fields: JIPPNPILKDJ:HHCNMGNAIBG#1; ถูกอ้างจาก: `POBLGKIGINE`
- `LMOILOPJKCB` — fields: retcode:uint32#2; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `LNAAACICHPG` — fields: pet_id:uint32#1, NDMHOKEGOAP:uint32#11, ONMDDKGCEHK:uint64#13; ถูกอ้างจาก: `NMEGIPHFFDA`
- `LPJFNJAJIGM` — fields: FIEOPKNBHKJ:uint64#13, ONMDDKGCEHK:uint64#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `MENCBJMOEML` — fields: FIEOPKNBHKJ:uint64#12; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `MFCCCIMGMFL` — fields: pool_id:uint32#1, POONFMJAFDH:uint32#3, end_time:int64#7, GOJBGCEEEHK:string#11, JPLIJJFCAOO:int64#14; ถูกอ้างจาก: `BlindBoxGetDataScRsp`
- `MGFJDLIBABO` — fields: JPPKLEIPKAN:BattleEndStatus#6, PLAPNCJJAOP:NPLMMCGAJDF#11, ELHJAMKKKLH:bool#12; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `MHNNEFBOPIE` — fields: op_uid:uint32#1, JENKGODEIOM:JOLAHHGIFHA#2; ถูกอ้างจาก: `SocialPlayRoomPlayerMoveScNotify`
- `MIECIEKKIMJ` — fields: retcode:uint32#2, CAFBDEDFBOL:CEAPCHBBOFN#3; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `MIKGMGBHLEN` — fields: message_text:string#1, extra_id:uint32#2; ถูกอ้างจาก: `SocialPlayGameplayOperationScNotify`, `SocialPlayTalkCsReq`, `SocialPlayTalkScRsp`
- `MKGODFLGEAM` — fields: level:uint32#2, LLKGDLAFODJ:string#5, head_icon:uint32#6, AGABADPIGGK:bool#8, uid:uint32#15; ถูกอ้างจาก: `NMEGIPHFFDA`
- `MLNNHJKKMNC` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `MMBIBKFEFNG` — fields: FMHBALCGMFF:bool#3, PODLFMBEKEG:uint32#9; ถูกอ้างจาก: `IOPNJIOPAFI`
- `MNGADDFICJF` — fields: ENPNDBIBPLE:uint32#1, PANMEBACIBF:bool#2, rotation:uint32#3, x:uint32#8, y:uint32#11; ถูกอ้างจาก: `JNDBILOGFAF`, `NPMOBJOCIAF`, `PGLBKDELHJK`
- `MNGELOJBJGC` — fields: retcode:uint32#7, FMACGJBHLPF:uint32#10, order_list:NMEGIPHFFDA#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `MNLLCNFNKKP` — fields: IMGDMDDKHDL:uint32#1, LALKFADHJJL:uint32#5, FMCCHBBIJKF:ODLEEMAALIP#6, GBJEALNCMJC:uint32#7, HCMKEFPFEDH:bool#8, IIIAGPNGPJM:ODLEEMAALIP#9, mode:uint32#12, OFNINJLHHDE:ODLEEMAALIP#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `NLBAOLFBEGB` — fields: retcode:uint32#3, LLLOIIKOCEN:PPELMHMMCHP#8; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `NMEGIPHFFDA` — fields: AMGLECMANAH:LNAAACICHPG#1, LFOIKMFLNKJ:PEHEBABHPBH#2, EFKJFADLLIA:MKGODFLGEAM#6, FIEOPKNBHKJ:uint64#7, expire_time:uint64#8, NDHBAFMMFBC:OHAPBJANBDE#10, KDBMGCMEOFL:uint64#11, DCKKGALHFNO:uint64#12, DAMCKNHKDOA:LNAAACICHPG#13, DFAACJDIFBL:MKGODFLGEAM#15; ถูกอ้างจาก: `DCNIDBKPPCK`, `DNHFLGJJKHN`, `DPOGMNFCMNN`, `HLJINHODOPP`, `MNGELOJBJGC`
- `NPLMMCGAJDF` — fields: DFFPHJJIHFJ:uint32#2, LAPLGJOBGAN:uint32#4, remaining_round:uint32#12, level_id:uint32#14; ถูกอ้างจาก: `FIJJHJADLLM`, `MGFJDLIBABO`
- `NPMOBJOCIAF` — fields: DGONPFLCOMO:uint32#11, FBDIGGDLDCP:MNGADDFICJF#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `OAOONIMHKLA` — fields: retcode:uint32#1; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `ODHFCEALPFN` — fields: IIIAGPNGPJM:ODLEEMAALIP#1, JJPLIMAENEB:uint32#3, JNBIALMKFCL:uint32#5, FMCCHBBIJKF:ODLEEMAALIP#7, OFNINJLHHDE:ODLEEMAALIP#9, LLMLOGNFFCD:bool#10, mode:uint32#13; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `ODLEEMAALIP` — fields: AOLIEDBCNBN:uint32#1, hp:sint32#4, KNDIIBJEIDG:uint32#6, NDMHOKEGOAP:uint32#7, OLANKLPCBEG:uint32#9, atk:uint32#10, AGKNBANFLIB:KVP#11, MDKFLGDEJCN:uint32#12; ถูกอ้างจาก: `MNLLCNFNKKP`, `ODHFCEALPFN`
- `OELLEKNNEMK` — fields: OLGCOBHGDCD:HIMPJFMPEPA#1, CGBJOAJEMKN:uint32#2; ถูกอ้างจาก: `IFEEMEAJMEJ`
- `OIJOHMLIEII` — fields: EPHIIBNCCJG:DNHFLGJJKHN#15; ถูกอ้างจาก: `BlindBoxTradeChangeScNotify`
- `OKCAJHKCJDE` — fields: JDFJJOKDIKC:uint32#2, OBLOEMJOFEE:uint32#4, AFFLDMFBGEH:uint64#13; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `OMEAEOLPGGM` — fields: HNFFFDEGOEB:FOEPMKFEJMK#8, retcode:uint32#13; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `ONAADAJBLEB` — fields: DBIKJPDBMOE:int64#11, ONOHPMDGNNH:uint32#14; ถูกอ้างจาก: `KPBCIIFIAGI`
- `ONJIANLPDBE` — fields: LEJEBBCKPCI:uint32#9; ถูกอ้างจาก: `BNKDEHGIJMH`
- `PACMGHKKGKN` — fields: IEOAHLNBBBB:uint32#13; ถูกอ้างจาก: `BNKDEHGIJMH`
- `PBMDEBCGNMD` — fields: IKJNIKIGFLF:MNCBEDBDDHL#1, PKHFMJDNKOE:JPAOIPLDKHB#2, KABGCGENKLK:CGLJLBDFNBK#4; ถูกอ้างจาก: `POBLGKIGINE`
- `PDFEPMMIKDF` — fields: KOMOGINENAC:uint32#1, AIJPKJICFDJ:uint32#6, mode:uint32#8; ถูกอ้างจาก: `COPLCPBANMD`
- `PEEEEGAPCOK` — fields: PLPPPCEPBDO:uint32#1, op_uid:uint32#2, OOCPKIGPEHP:uint32#3, CMIEOOODDIA:int64#4, AALDPOAKJBK:string#5; ถูกอ้างจาก: `IKBDJLNEPBH`
- `PEMMJHDFOLM` — fields: ไม่มี field; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `PGLBKDELHJK` — fields: FLBOPEJIGJF:uint32#1, status:uint32#5, DGONPFLCOMO:uint32#7, FBDIGGDLDCP:MNGADDFICJF#9; ถูกอ้างจาก: `FMOEINGLFGG`
- `PHIMNIFMBMI` — fields: MJNENEAAOAE:uint64#2, retcode:uint32#14; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `PMBMFHMKBNC` — fields: retcode:uint32#4; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `POBLGKIGINE` — fields: room_owner_uid:uint32#1, player_info:JBJNJPAOCDA#2, DLKOEIANIMK:uint32#3, LNMGOFCOMED:PBMDEBCGNMD#100, MAGDHGMLLKG:LLKIFBFCMLK#101; ถูกอ้างจาก: `SocialPlayGameplayOperationScNotify`, `SocialPlayGetOnlineRoomDataScRsp`, `SocialPlayGetOwnerRoomDataScRsp`
- `PPELMHMMCHP` — fields: KLOJONBEJKJ:uint32#1, ONMDDKGCEHK:uint64#4; ถูกอ้างจาก: `NLBAOLFBEGB`
- `PPFAMGCOOFP` — fields: GALBOLNODBB:uint32#1, LENMCGCGBOA:uint32#2, EEFLBHGIAAN:ALAMOHABJIP#3, NGPBPFKGNLI:uint32#4, IEOAHLNBBBB:uint32#5, EJHKAHEGCDC:uint32#6, LEJEBBCKPCI:uint32#8, design_level:uint32#9, OOIMHIJFHDI:uint32#10, DEJOLCEPDCF:uint32#11, retcode:uint32#12, OFNDFACDNOC:uint32#13, KIEBAPFGCCN:uint32#14, LAOPAGMAAHD:uint32#15; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
- `PPOPABLIHNI` — fields: count:uint32#10, offset:uint32#14; ถูกอ้างจาก: ไม่มีการอ้างถึงจาก message ในไฟล์นี้
## ข้อจำกัดก่อนใช้ทำ handler
- การมี Go message type ไม่ได้แปลว่ามี CmdID, request/response pairing หรือ handler แล้ว
- ใช้ `protocol/proto/cmdid.go`/ตารางที่อ้าง revision ตรงกันเท่านั้น; ถ้าชื่อยัง obfuscated ให้บันทึกความไม่แน่นอนแทนการเดา
- schema ที่เพิ่มครั้งนี้เป็นการเติม definitions ที่ไม่มีใน `StarRail.proto` เท่านั้น ไม่ได้ยืนยันว่า Client รุ่นใดส่ง message เหล่านี้หรือว่า feature เล่นได้ครบ