diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..40d5264 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,131 @@ +--- +name: hkrpg-ps-version-update +description: คู่มือ Honkai Star Rail Private Server (GaC-hkrpg-go ภาษา Go + GaC-hkrpg-ps Rust ตัวเก่า) บทเรียนอัปเดตข้ามเวอร์ชัน client และกับดักที่พิสูจน์แล้ว ใช้เมื่อ client อัปเดตแล้วเซิร์ฟเวอร์มีอาการ จอดำ/ค้าง/กล้องหลุดตอนกดตี/packet Unknown/dialogue ค้าง/crash +--- + +# คู่มือ HSR Private Server — บทเรียนที่พิสูจน์แล้ว (อัปเดตล่าสุด: 2026-10-07) + +> **สถานะปัจจุบัน:** เซิร์ฟเวอร์หลักคือ **`C:\Users\Phitchayut\Desktop\GaC-hkrpg-go` (ภาษา Go, client 4.6.51)** +> โปรเจกต์ Rust `GaC-hkrpg-ps` เป็นตัวต้นทาง/reference — โค้ด Rust ล่าสุดแตกตัวกับ proto ใน repo (ดูหัวข้อ 10) +> เอกสารฉบับเต็มของตัว Go อยู่ที่ `GaC-hkrpg-go/README.md` + +--- + +## 1. ลำดับการวินิจฉัยเมื่อ client ใหม่เข้าไม่ได้ + +อ่าน log ตามลำดับนี้ **ก่อนแก้โค้ด** เพราะอาการเดียวกันมีหลายต้นเหตุ: + +| อาการ | แหล่งข้อมูล | สิ่งที่มองหา | +|---|---|---| +| ค้างก่อนหน้า login | client hook log | URL ที่ถูก redirect/block | +| จอดำหลังกด login | `Player.log` (LocalLow/Cognosphere/Star Rail) | `NullReferenceException` + ชื่อ handler `_CmdXxxScRsp` + **offset** (offset ต่างกัน = field คนละตัวใน handler เดียวกัน) | +| จอดำ/ค้างหลัง login finish | `Player.log` + log หน้าต่าง Game Server | packet ที่ client ส่งต่อแต่เซิร์ฟ "Unknown command ID" | +| ค้างหน้าโหลดฉาก | `Player.log` | `CreateMemberEntityLeader FAILED`, `LuaException` (GotoMapParam ฯลฯ), ExcelTable FAILED | +| กล้องหลุดจากตัว/ค้างหลังกดตี | `Player.log` + `server_debug.log` (บรรทัด `SCENE_CAST_SKILL`) | battle transition จาก target ที่ไม่ใช่ monster (ดูหัวข้อ 11) | +| เกมดับ | `Temp/Cognosphere/Star Rail/Crashes` | crash report | +| จุดวาป/คุยผิดปกติ | `server_debug.log` ในโฟลเดอร์เซิร์ฟ | บรรทัด `ENTER_SCENE` / `INTERACT_PROP` (บันทึก entry_id/teleport_id/prop จริง) | + +กฎสำคัญ: **`Player.log` ถูกเขียนทับทุกครั้งที่เปิดเกม** — ต้องอ่านทันทีหลังทดสอบ และอย่าสรุปจาก error ของ session เก่าที่จำ offset ไว้ + +## 2. Checklist สิ่งที่ต้องอัปเดตต่อเวอร์ชัน client + +1. **Proto/cmd dump ใหม่** — dump จาก client ด้วย Morax หรือใช้ dump จาก AstralOS รุ่นใหม่ (ตัว Go: `protocol/proto/StarRail.proto` + generate ใหม่ด้วย protoc-gen-go) +2. **`cmd_ids_.json`** — mapping cmd ทั้งหมดของรุ่นนั้น (ตัว Go generate cmdid map จาก `// CmdID:` comments ใน proto อัตโนมัติ) +3. **Data files จาก AstralOS dump** (ใช้ได้ — เป็น data จาก client ไม่ใช่โค้ด): `challenge_data.json`, `res.json`, `teleports.json`, `mission_unlocks.json`, `freesr-data.json` +4. **`BASE_AVATAR_IDS`** — เพิ่ม avatar ตัวใหม่ (ตัว Go: `internal/gameserver/dispatch.go` — 89 ตัวใน 4651 มี 1511/1512/1513) +5. **`versions.json`** — hotfix URLs ต่อเวอร์ชัน (ดูหัวข้อ 5) +6. **Tutorial ID lists** — ตัว Go generate จาก Rust tutorial.rs แล้ว (`handlers_tutorial_ids.go` 1249+855 ids) + +## 3. Cmd ID และ response layout เปลี่ยนทุกรุ่น + +- **ScRsp id เลื่อนตำแหน่ง**: `StartChallengeScRsp` เคยเป็น 1775 → 4.6.51 กลายเป็น **1787** และ 1775 ไปเป็น `GetChallengeGroupStatisticsCsReq` — ส่ง response ผิด id = client รอไม่ได้ หมุนค้างตลอด +- **Field tag เลื่อน**: `StartChallengeCsReq.challenge_id` tag 12 → **tag 14** — decoder มือต้องอัปเดต +- **Response body layout เปลี่ยน**: tag ของ retcode/scene/lineup ใน ScRsp ต้องแกะใหม่จาก proto ทุกรุ่น +- cmd ที่ไม่มีใน dump (เช่น 1452, Anomaly Arbitration) = เนื้อหาหลัง beta build ที่ client ถือ — ทำไม่ได้จนกว่าจะมี dump ใหม่ +- **ชื่อ message เปลี่ยนทุกรุ่น**: 4.6.51 เปลี่ยน `PveBattleResultCsReq → PVEBattleResultCsReq`, `QuickStartCocoonStageCsReq → StartQuickCocoonStageCsReq/StartQuickCocoonStageRsp`, `GateServer → Gateserver`, `GetGachaInfoCsReq/DoGachaCsReq หายไป` — **โค้ดต้องผูกกับ proto ของรุ่นนั้นจริงๆ เสมอ** + +## 4. Optional message fields — สาเหตุจอดำที่ไล่ยากที่สุด + +`_CmdGetBasicInfoScRsp` NRE วนซ้ำเพราะ `PlayerSettingInfo` มี optional message ซ่อนหลายตัว (`ojpaodihaje` Tag 13, `ankidjjinei` Tag 1171, `cmfcooeeecb` Tag 1552) — ปล่อย None แล้ว client unwrap → NRE → จอดำ + +วิธีไล่: NRE offset ใน Player.log ต่างกัน = field คนละตัว ใส่ทีละตัวจนหมด ใช้ `field_overrides_.json` ช่วยแปลชื่อ + +## 5. Design data CDN — ต้นเหตุ "ตารางพัง/ค้างหน้าโหลด" + +- `query_gateway` response (message `Gateserver`) มี `asset_bundle_url` / `ex_resource_url` / `lua_url` — มาจาก `versions.json` (sdkserver fetch จาก CDN จริงผ่าน proxy) +- client beta **hot-update design data** จาก URL เหล่านี้ — ถ้า CDN push ชุดใหม่กว่า GameAssembly ที่ติดตั้ง → ExcelTable โหลด FAILED → ค้างหน้าโหลด (ดู D number: 4.6.51 ติดตั้ง = D16700702 ≠ D16706787) +- **แก้**: `ex_resource_url` ต้องชี้ `design_data/BetaLive/output_` (ตัวอย่าง: `https://autopatchcn.bhsr.com/design_data/BetaLive/output_16700702_...`) — **ห้ามชี้ /no_update** เพราะ client beta ไม่ fallback ใช้ local +- ไฟล์ที่โหลดมาแล้วพังค้างใน `StreamingAssets/DesignData/Windows/` — restore จาก `.bak` หรือ re-verify + +## 6. กับดักที่พบจริงใน 4.6.51 (เก็บไว้เจอซ้ำ) + +- **ทีมเกิน 4 ตัว**: client ส่งทีม 2 ช่องทาง (`avatar_lineup_first` + `first_lineup`) รวมได้ 8 ตัว → `TeamManager` IndexOutOfRange ตอนเข้า arena — แก้ด้วย dedupe + truncate(4) +- **InteractProp**: เก็บ mapping entity_id → prop ตอนโหลดฉาก แล้วตอบ `prop_state` **จริงจาก config** — ห้ามตอบ `interact_id2` (มันคือ interaction id เช่น 1100 ไม่ใช่ state) +- **GetNpcTakenReward (2174)**: client ถามก่อนคุย NPC — ไม่ตอบ = dialogue ไม่มีตัวเลือกและค้าง +- **Tutorial**: mark ทุก id ว่าดูแล้ว (`GetTutorial`/`GetTutorialGuide` status enum `Oekdmamgidc`=2) ไม่งั้น popup เด้งวนและ**บล็อก input**; `FinishTutorial/UnlockTutorial*` ต้องตอบพร้อม Tutorial/TutorialGuide message +- **GetMissionStatusScRsp ต้องส่ง `finished_main_mission_id_list` + `curversion_finished_main_mission_id_list` (tag 13)** — ตอบเปล่า = client Lua NRE → บล็อก input + client ส่ง cmd 1204 ซ้ำรัวๆ +- **GetSwitchHandData**: 4.6.51 CsReq 8115 → ตอบ ScRsp **8104** (tag 3 retcode 0) +- **arena ใหม่ไม่มีใน client เก่า**: challenge phase ใหม่ (เช่น 5312) ใช้ arena 3014101 ซึ่ง client build เก่าไม่มี MapEntrance → Lua `GotoMapParam: attempt to index nil with 'ID'` — fallback ไป arena มาตรฐาน 3000101 +- **Scene ไม่มี teleport**: ฉาก arena ไม่มี teleport ใน res — fallback จาก `teleports.json` หรือ spawn ใกล้ prop แรกหันหน้าเข้าหา +- **full coverage ตอบ ScRsp ว่างทุก cmd = อันตราย!** — client modules (`GridFight`, `ChessRogue`, `EvolveBuild`, `ChimeraDuel`, `Jukebox`) รับว่างแล้ว `Sync(nil)` → NRE วน → **จอดำ** — cmd ไม่รู้จักต้อง **drop เงียบๆ** ตอบว่างได้เฉพาะ dummy list ที่ทดสอบแล้ว +- **BASE_AVATAR_IDS ห้ามใส่ตัวที่ client build นี้ไม่มี** (เช่น id จาก reference รุ่นใหม่กว่า) → พังตอน init โลก; ขาดตัวที่มีจริงก็ crash ตอน battle เช่นกัน +- **freesr-data.json ฟอร์แมตใหม่** (จาก SRTools): avatars 99 ตัว ไม่มี key leader/lineups — parser ต้อง tolerate ฟิลด์แปลก (Go: `LoadFreesrData` รองรับแล้ว) + +## 7. เครื่องมือและแหล่งข้อมูล + +- **AstralOS dump**: `C:\Users\Phitchayut\Downloads\New folder` (bin/*.json = data 4651, tools/reference/* = proto/cmdids/**field_overrides 4651** แปล obfuscated → ชื่อจริง) — ห้ามก็อปโค้ดทั้งดุ้น ใช้ data ได้ +- **`field_overrides_.json`** — ดัชนีแปลชื่อ field obfuscated → ชื่อจริงของทุก message +- **Firefly Shelter** (`C:\Program Files\Firefly Shelter\server\firefly-go`) — PS ภาษา Go ที่เวิร์กกับ client นี้ **ปิด source** — สำรวจได้จาก `tools/firefly_dump` (symbols: handlers/pb fields/cmds) และ data dir ของมัน (ใช้ freesr-data.json / data-in-game.json / version.json ฟอร์แมตเดียวกับ FreeSR) +- **`server_debug.log` / `gameserver.log`** — บันทึก ENTER_SCENE/INTERACT_PROP/SCENE_CAST_SKILL + log ทุก cmd +- **Dimbreath Game Data**: `https://gitlab.com/Dimbreath/turnbasedgamedata` (ExcelOutput แม่นยำ) +- **robinsr reference**: `https://git.neonteam.dev/amizing/robinsr` (อ่านเทียบได้ ห้ามก็อปทั้งดุ้น) + +## 8. กระบวนการทำงานที่พิสูจน์แล้วว่าเร็ว + +1. ทดสอบ 1 อย่าง → อ่าน log ทันที → แก้ 1 จุด → build → ทดสอบซ้ำ (อย่าแก้หลายจุดโดยไม่มี log ยืนยัน) +2. Reference จาก PS อื่น: **อ่านเทียบได้ ห้ามก็อปโค้ดทั้งดุ้น** — ดึงเฉพาะ data dump และค่า config +3. **commit ทุกครั้งที่แก้เสร็จ** — ไฟล์เคยถูกย้อนกลับโดยไม่ทราบสาเหตุ 2 ครั้ง +4. แก้ path hardcode ใน .bat ทุกครั้งที่ย้าย/rename โฟลเดอร์ +5. เปลี่ยน versions.json ทีละ field ด้วย script — อย่าแก้มือตอนเซิร์ฟเวอร์กำลังรัน + +## 9. สถานะที่รู้ว่ายังไม่สำเร็จ (ณ 4.6.51) + +- Anomaly Arbitration — ไม่มี cmd ใน dump ของ client รุ่นนี้ +- Currency War (ตระกูล Rogue 101 cmd) — ตอบ default ครบ แต่เล่นได้จริงต้อง implement state เฉพาะ +- Gacha (GetGachaInfo/DoGacha) — proto 4.6.51 เปลี่ยนชื่อ message → ตัว Go skip handler ไว้ (log "handler skipped") ต้องหาชื่อใหม่จาก dump +- StartChallenge กับ challenge_id ที่ไม่มีใน challenge_data.json — ใช้ fallback arena 3014101 +- ยังไม่ได้ทดสอบกับ client จริงแบบเต็ม session หลังพอร์ต Go (รอ user ทดสอบ: login → Parlor Car → เดิน → กดตี → วาป → เข้า endgame) + +## 10. โค้ด Rust แตกตัวกับ proto ใน repo (บทเรียนสำคัญ) + +commit สุดท้ายของ Rust (`ebc27a1`) อ้างชื่อ message ที่ **ไม่มีใน** `proto/StarRail.proto` ของตัวเองแล้ว: +`PveBattleResultCsReq`, `QuickStartCocoonStageCsReq`, `GateServer`, `GetGachaInfoCsReq`, `GroupRefreshInfo`, `LineupSlot` +→ สาเหตุ: proto ถูกแทนด้วย dump 4.6.51 ใหม่ (ชื่อ obfuscated พิมพ์ใหญ่) แต่ handler ไม่ได้ตาม +→ **กฎ:** หลังแทน proto ต้อง compile ทันทีและแก้ชื่อให้ตรง ก่อนปล่อย build ให้ user ทดสอบ +→ ตัว Go แก้ครบโดยผูกทุก handler กับชื่อจริงใน proto (handler ไหน proto ไม่มีจะ log+skip ไม่ panic) + +## 11. บัคกล้องหลุดตอนกดตี — SceneCastSkill (แก้แล้วในตัว Go) + +**อาการ:** กดโจมตีใน overworld แล้วกล้องหลุดออกจากตัวละคร + +**ต้นเหตุ (Rust battle.rs):** handler ตอบ `battle_info` + `monster_battle_info` ให้เข้า battle กับ target ที่ผ่าน filter หลวม `id > 30000 || id < 1000` — ซึ่งรวม **avatar entity ของผู้เล่นเอง** (1-4); ถ้าอยู่ arena (entry >= 3000000) ยังหลอก target เป็น 30001 เสมอ → client เริ่ม battle transition กับ "monster" ที่ไม่มีจริง → กล้อง battle ไม่มี target ให้ตาม → หลุด + +**วิธีแก้ (Go `internal/gameserver/handlers_battle.go`):** +1. ตอนโหลดฉาก เก็บ monster entity จริง (entity_id → event_id) ไว้ใน `Session.MonsterEntities` +2. `SceneCastSkill` ยอมรับเฉพาะ hit target ที่เป็น monster จริง +3. ไม่มี monster จริง → ตอบ `retcode 0 + cast_entity_id` **ไม่เข้า battle** (client เล่นแอนิเมชันตีปกติ กล้องค้างกับตัว) +4. ตีโดน monster จริง (รวมบอส arena 30001) → เข้า battle ปกติ +5. ยืนยันด้วย `internal/gameserver/smoke_test.go` (จำลอง client เต็มรูปแบบผ่าน UDP จริง) + +**บทเรียน:** อย่าตอบ battle/transition ให้ client จาก target ที่ server ไม่ได้ spawn เอง — ตรวจกับ entity registry ของฉากปัจจุบันเสมอ + +## 12. Go server (GaC-hkrpg-go) — สถาปัตยกรรมและข้อควรรู้ + +- **mihoyo KCP header 28 ไบต์**: `conv(4) + token(4) + cmd(1) + frg(1) + wnd(2) + ts(4) + sn(4) + una(4) + len(4)` Little-Endian — standard KCP lib อ่านไม่ได้; Go port อยู่ `pkg/kcp` (port จาก kcp.rs 1:1, UDP loopback test ผ่าน) +- **นาฬิกา KCP ต้องเป็นมิลลิวินาที** — Rust เดิมใช้วินาที (session_time secs) ทำ RTT/resend เพี้ยนทั้งระบบ +- **Handshake**: 20-byte NetOperation — client `head=0xFF, tail=0xFFFFFFFF`, server ตอบ `head=0x145, tail=0x14514545` (param1=conv, param2=token), ตัดการเชื่อมต่อ `head=0x194, tail=0x19419494` +- **Packet framing ใน KCP stream**: `HEAD 0x9D74C714 + cmd(u16 BE) + headLen + bodyLen + head + body + TAIL 0xD7A152C8` — ไม่มี XOR encryption ใน build นี้ +- **cmdid map** generate จาก `// CmdID:` comments ใน proto → `protocol/proto/cmdid.go` (regenerate ตอนเปลี่ยน proto) +- **ใช้ data files Rust PS ได้ทันที** (freesr-data.json / persistent / res.json / teleports.json / challenge_data.json / mission_unlocks.json / versions.json) — ฟอร์แมต JSON ตรงกัน รวม enum string อย่าง `main_character: "FemaleHarmony"` +- **Build**: `go build -o gameserver-go.exe ./cmd/gameserver` + `./cmd/sdkserver`; ทดสอบ: `go test ./...`; เปิดด้วย `run_go.bat` (UDP 23301 + HTTP 21000 เหมือนเดิม) +- **ที่ตั้ง skill library**: `tools/AI TOOLBOX/` (ทั้งสองโปรเจกต์มี copy — อัปเดตต้นฉบับที่เดียวแล้วก็อป) diff --git a/tools/AI TOOLBOX/MEMORY.md b/tools/AI TOOLBOX/MEMORY.md new file mode 100644 index 0000000..449e54b --- /dev/null +++ b/tools/AI TOOLBOX/MEMORY.md @@ -0,0 +1,42 @@ +# AI TOOLBOX - Project Long-Term Memory + +## Project Overview +Honkai Star Rail Game Server (.NET / C# and Rust Architecture & Protocol Simulation). + +## Core Directives & User Preferences +1. **Approval Automation**: Group tasks into single automated commands or use subagents; avoid asking repetitive approval prompts. +2. **FreeCam System**: Preserve live-reloading of `scripts/freecam.lua` via `PlayerHeartBeatScRsp.download_data` (CmdID: 62). Maintain user's exact controls and rainbow watermark. +3. **Challenge Unlocks**: Keep stages unlocked (`hgpkmhfpmbj: true` / `is_unlock: true`) across Forgotten Hall (Jarilo-VI 15, Xianzhou Luofu 6), MoC (12 floors), Pure Fiction (4 stages), and Apocalyptic Shadow (4 difficulties). +4. **Hotfix Sync**: Hotfix URLs are stored in `versions.json`. SDK server delivers hotfix payloads for target client versions (e.g. `OSBETAWin4.5.51`, `OSBETAWin4.5.52`, `CNBETAWin4.3.51..55`). +5. **No Code Overwrites**: Never blindly wipe or revert user source code without explicit verification. +6. **External Reference**: `https://git.neonteam.dev/amizing/robinsr` (Third-party repo used only as an external reference to inspect when game updates break server compatibility). +7. **No Vanity / Slop Logs**: Never output fake or vanity console logs pretending handlers or systems are registered/functional when they are placeholders. Only log real operations that actually execute. +8. **Dimbreath Game Data**: `https://gitlab.com/Dimbreath/turnbasedgamedata` (Primary source for exact game tables: ExcelOutput, ChallengeMazeConfig, stages, etc.). +9. **Daily Memory Logging (Continuous)**: Maintain daily logs in `tools/AI TOOLBOX/memory/YYYY-MM-DD.md`. Update this file continuously throughout active sessions to ensure all technical discoveries, reverse engineering findings, and architectural shifts are persistently saved across chat resets. +10. **Open Source & Mod-Friendly Data**: Do NOT compress or pack game tables into opaque binary blobs like March7th's `Resource.bin`. Keep resources open, transparent, and moddable in standard JSON directories (`resources/Config`, `ExcelOutput`, `TextMap`). +11. **MhyKcp Protocol (28-byte Header)**: HoYoverse games modify standard KCP by inserting a 4-byte `token` after `conv`: `conv(4) + token(4) + cmd(1) + frg(1) + wnd(2) + ts(4) + sn(4) + una(4) + len(4)` (Little-Endian). Standard KCP libraries cannot read this; use the native C# `MhyKcp.cs`. +12. **Login Security (login_random)**: In `PlayerLoginCsReq` (CmdId: 34), client sends a 64-bit random number (`login_random`, Tag 6). The server MUST echo this exact value in `PlayerLoginScRsp` (CmdId: 25, Tag 14). Failing to do so triggers Error 1001_3. +13. **Dispatch HTTP Server**: Must use ASP.NET Core Kestrel on port 21000 to prevent raw TCP `StreamReader` buffer hangs (which triggers Error 1001_1). +14. **MoC & Endgame Unlock Protocol**: + - MoC floors 11–12 require matching actual `RewardID`s in `ChallengeHistoryMaxLevel.reward_display_type` (`101201..=101212` for level 12). + - Apocalyptic Shadow tab requires active schedule in `GetActivityScheduleConfigScRsp` (CmdID: 2616) with `panel_id: 21001` and `activity_id: 21001..=21030`. + - Total challenge stages: 790 stages across 101 groups. +15. **Exact Command IDs (4.5.52)**: + - `PlayerGetToken`: CsReq: 60 -> ScRsp: 16 + - `PlayerLogin`: CsReq: 34 -> ScRsp: 25 + - `PlayerLoginFinish`: CsReq: 87 -> ScRsp: 63 + - `PlayerHeartBeat`: CsReq: 44 -> ScRsp: 62 + - `GetCurSceneInfo`: CsReq: 1458 -> ScRsp: 1456 + - `GetChallenge`: CsReq: 1734 -> ScRsp: 1725 + - `GetCurChallenge`: CsReq: 1715 -> ScRsp: 1742 + - `GetBasicInfo`: CsReq: 80 -> ScRsp: 67 + - `GetActivityScheduleConfig`: CsReq: 2625 -> ScRsp: 2616 +16. **Dependency & Pip Installation Tracking**: + - Whenever any script, tool, or component requires installing packages via `pip install`, ALWAYS record the package and its version in `requirements.txt` and note it in `tools/AI TOOLBOX/memory/YYYY-MM-DD.md`. + - This ensures friends or other users who receive the project can simply run `pip install -r requirements.txt` and execute all scripts/tools without encountering missing module errors. +17. **Skill & Knowledge Crystallization**: + - Whenever a complex protocol mechanism, reverse engineering pattern, build pipeline, or operational workflow is solved, ALWAYS immediately create/update a dedicated Skill in `tools/AI TOOLBOX/skills//SKILL.md` and write the exact findings into memory. + - Never rely on memory alone or re-search from scratch in subsequent sessions; consult and maintain the skill library first. +18. **Primary Server is Now Go (`C:/Users/Phitchayut/Desktop/GaC-hkrpg-go`)**: As of 2026-10-07 the active server is the Go port (commit 59ea97b). The Rust `GaC-hkrpg-ps` code drifted out of sync with its own proto (old message names like `PveBattleResultCsReq`/`GateServer` no longer exist in 4.6.51 proto) - treat Rust as reference only. Data files (freesr-data.json, persistent, res.json, teleports.json, challenge_data.json, mission_unlocks.json, versions.json) are shared between both. +19. **SceneCastSkill Camera Fix (solved)**: Never reply `battle_info`/`monster_battle_info` for hit targets that are not real scene monsters. The server tracks real monster entities per session (`Session.MonsterEntities` in `internal/gameserver/handlers_battle.go`); attacking props/NPCs/player avatars must return `retcode 0` with NO battle, or the client's battle camera detaches from the character. +20. **Skill File Single Source**: The living lessons doc is `SKILL.md` at each repo root; a synced copy lives in `tools/AI TOOLBOX/skills/hkrpg-ps-version-update/SKILL.md`. Update the root file first, then copy to the toolbox (both projects). Session-scoped prompt docs (HANDOFF/PROMPT/GLM_FIX_PROMPT) were deleted 2026-10-07 - do not recreate them; extend SKILL.md instead. diff --git a/tools/AI TOOLBOX/memory/2026-10-07.md b/tools/AI TOOLBOX/memory/2026-10-07.md new file mode 100644 index 0000000..82b2c5a --- /dev/null +++ b/tools/AI TOOLBOX/memory/2026-10-07.md @@ -0,0 +1,49 @@ +# 2026-10-07 — พอร์ตเซิร์ฟเวอร์เป็นภาษา Go + แก้บัคกล้องหลุด (SceneCastSkill) + +## สรุปงานวันนี้ + +### 1. พบต้นเหตุจริงของบัค "กดตีแล้วกล้องหลุดจากตัวละคร" +- `SceneCastSkillCsReq` handler เดิม (Rust battle.rs) ตอบ `battle_info` + `monster_battle_info` + ให้ client เข้า battle กับ target ที่ผ่าน filter หลวม `id > 30000 || id < 1000` +- filter นี้รวม **avatar entity ของผู้เล่นเอง** (1-4) เข้าไปด้วย → client เริ่ม battle transition + กับ "monster" ที่ไม่มีอยู่จริง → กล้อง battle ไม่มี target → หลุดจากตัวละคร +- กรณี arena (entry >= 3000000) โค้ดเดิมยังหลอก target เป็น 30001 เสมออีกชั้น + +### 2. พอร์ตทั้งเซิร์ฟเวอร์เป็นภาษา Go → `C:\Users\Phitchayut\Desktop\GaC-hkrpg-go` (commit 59ea97b) +- สาเหตุที่เปลี่ยนภาษา: (1) คำแนะนำจากเพื่อนให้ใช้ GO แทน (Firefly Shelter ที่เวิร์กเป็น Go + แต่ปิด source) (2) พบว่าโค้ด Rust commit สุดท้าย **แตกตัวกับ proto ใน repo ตัวเอง** — + ใช้ชื่อ message เก่า (`PveBattleResultCsReq`, `QuickStartCocoonStageCsReq`, `GateServer`, + `GetGachaInfoCsReq`, `GroupRefreshInfo`, `LineupSlot`) ที่ไม่มีใน proto 4.6.51 แล้ว +- ตัว Go ผูกทุก handler กับชื่อจริงใน proto (handler ที่ proto ไม่มี → log+skip ไม่ panic) + +### 3. สิ่งที่สร้าง/พอร์ต +- `pkg/kcp` — mihoyo KCP (header 28 ไบต์ conv+token) port จาก kcp.rs 1:1 + ใช้นาฬิกา ms + (Rust ใช้วินาที ทำ RTT/resend เพี้ยน) + UDP loopback test ผ่าน +- `protocol/proto` — generate Go protobuf จาก proto 4.6.51 (4,932 messages) + + cmdid map 2,114 ids generate จาก `// CmdID:` comments +- gameserver ครบ: handshake 0xFF/0x145/0x194, packet framing 0x9D74C714/0xD7A152C8, + login flow, scene load (props/NPCs/monsters + MonsterEntities tracking), lineup, + avatar/skin, missions, tutorials (1249+855), bag/equip, challenge ครบ + (StartChallenge 1787 / Tierce 8973 / Peak 8948 / raw replies ทุกตัว) +- sdkserver: query_dispatch/query_gateway (Gateserver pb + base64), hotfix fetch, + auth endpoints, SRTools upload +- **FIX SceneCastSkill**: เก็บ monster entity จริงต่อ session (`Session.MonsterEntities`) + ตีไม่โดน monster จริง = ตอบ retcode 0 ไม่เข้า battle → กล้องไม่หลุด +- smoke test จำลอง client เต็มรูปแบบผ่าน UDP จริง: handshake → PlayerGetToken → + SceneCastSkill ทั้งสองกรณี — **PASS ทั้งหมด** +- ใช้ data files เดิมทุกไฟล์ (save ไม่พัง) — เปิดด้วย `run_go.bat` + +### 4. เครื่องมือที่ช่วย +- `tools/firefly_dump` (ที่ user เตรียมไว้) — symbol dump ของ Firefly binary ใช้ยืนยัน + สถาปัตยกรรม + ยืนยันว่า Firefly ปิด source ไม่มี code ให้ก็อป +- ติดตั้ง Go 1.27.0 (winget) + protoc-gen-go ใหม่ใน session นี้ + +### 5. การจัดการเอกสาร +- ลบ `GLM_FIX_PROMPT.md`, `PROMPT.md`, `HANDOFF.md` (หมดอายุ — เนื้อหาจำเป็นย้ายเข้า SKILL.md) +- อัพเดต `SKILL.md` (เพิ่มหัวข้อ 10-12: proto desync, บัคกล้อง, สถาปัตยกรรม Go) +- ก็อป SKILL.md → `tools/AI TOOLBOX/skills/hkrpg-ps-version-update/SKILL.md` ทั้งสองโปรเจกต์ + +## สิ่งที่ต้องทำต่อ +1. **ทดสอบกับ client จริง** — เปิด `run_go.bat` (GaC-hkrpg-go) แล้ว login ด้วย hosts/proxy เดิม +2. Gacha handlers ถูก skip (proto 4.6.51 เปลี่ยนชื่อ GetGachaInfoCsReq/DoGachaCsReq) — หาชื่อใหม่จาก dump +3. ถ้า client ฟ้อง cmd ไหน "Unknown" ให้เช็ค `gameserver.log` แล้วเติม handler ในตัว Go diff --git a/tools/AI TOOLBOX/skills/hkrpg-ps-version-update/SKILL.md b/tools/AI TOOLBOX/skills/hkrpg-ps-version-update/SKILL.md new file mode 100644 index 0000000..40d5264 --- /dev/null +++ b/tools/AI TOOLBOX/skills/hkrpg-ps-version-update/SKILL.md @@ -0,0 +1,131 @@ +--- +name: hkrpg-ps-version-update +description: คู่มือ Honkai Star Rail Private Server (GaC-hkrpg-go ภาษา Go + GaC-hkrpg-ps Rust ตัวเก่า) บทเรียนอัปเดตข้ามเวอร์ชัน client และกับดักที่พิสูจน์แล้ว ใช้เมื่อ client อัปเดตแล้วเซิร์ฟเวอร์มีอาการ จอดำ/ค้าง/กล้องหลุดตอนกดตี/packet Unknown/dialogue ค้าง/crash +--- + +# คู่มือ HSR Private Server — บทเรียนที่พิสูจน์แล้ว (อัปเดตล่าสุด: 2026-10-07) + +> **สถานะปัจจุบัน:** เซิร์ฟเวอร์หลักคือ **`C:\Users\Phitchayut\Desktop\GaC-hkrpg-go` (ภาษา Go, client 4.6.51)** +> โปรเจกต์ Rust `GaC-hkrpg-ps` เป็นตัวต้นทาง/reference — โค้ด Rust ล่าสุดแตกตัวกับ proto ใน repo (ดูหัวข้อ 10) +> เอกสารฉบับเต็มของตัว Go อยู่ที่ `GaC-hkrpg-go/README.md` + +--- + +## 1. ลำดับการวินิจฉัยเมื่อ client ใหม่เข้าไม่ได้ + +อ่าน log ตามลำดับนี้ **ก่อนแก้โค้ด** เพราะอาการเดียวกันมีหลายต้นเหตุ: + +| อาการ | แหล่งข้อมูล | สิ่งที่มองหา | +|---|---|---| +| ค้างก่อนหน้า login | client hook log | URL ที่ถูก redirect/block | +| จอดำหลังกด login | `Player.log` (LocalLow/Cognosphere/Star Rail) | `NullReferenceException` + ชื่อ handler `_CmdXxxScRsp` + **offset** (offset ต่างกัน = field คนละตัวใน handler เดียวกัน) | +| จอดำ/ค้างหลัง login finish | `Player.log` + log หน้าต่าง Game Server | packet ที่ client ส่งต่อแต่เซิร์ฟ "Unknown command ID" | +| ค้างหน้าโหลดฉาก | `Player.log` | `CreateMemberEntityLeader FAILED`, `LuaException` (GotoMapParam ฯลฯ), ExcelTable FAILED | +| กล้องหลุดจากตัว/ค้างหลังกดตี | `Player.log` + `server_debug.log` (บรรทัด `SCENE_CAST_SKILL`) | battle transition จาก target ที่ไม่ใช่ monster (ดูหัวข้อ 11) | +| เกมดับ | `Temp/Cognosphere/Star Rail/Crashes` | crash report | +| จุดวาป/คุยผิดปกติ | `server_debug.log` ในโฟลเดอร์เซิร์ฟ | บรรทัด `ENTER_SCENE` / `INTERACT_PROP` (บันทึก entry_id/teleport_id/prop จริง) | + +กฎสำคัญ: **`Player.log` ถูกเขียนทับทุกครั้งที่เปิดเกม** — ต้องอ่านทันทีหลังทดสอบ และอย่าสรุปจาก error ของ session เก่าที่จำ offset ไว้ + +## 2. Checklist สิ่งที่ต้องอัปเดตต่อเวอร์ชัน client + +1. **Proto/cmd dump ใหม่** — dump จาก client ด้วย Morax หรือใช้ dump จาก AstralOS รุ่นใหม่ (ตัว Go: `protocol/proto/StarRail.proto` + generate ใหม่ด้วย protoc-gen-go) +2. **`cmd_ids_.json`** — mapping cmd ทั้งหมดของรุ่นนั้น (ตัว Go generate cmdid map จาก `// CmdID:` comments ใน proto อัตโนมัติ) +3. **Data files จาก AstralOS dump** (ใช้ได้ — เป็น data จาก client ไม่ใช่โค้ด): `challenge_data.json`, `res.json`, `teleports.json`, `mission_unlocks.json`, `freesr-data.json` +4. **`BASE_AVATAR_IDS`** — เพิ่ม avatar ตัวใหม่ (ตัว Go: `internal/gameserver/dispatch.go` — 89 ตัวใน 4651 มี 1511/1512/1513) +5. **`versions.json`** — hotfix URLs ต่อเวอร์ชัน (ดูหัวข้อ 5) +6. **Tutorial ID lists** — ตัว Go generate จาก Rust tutorial.rs แล้ว (`handlers_tutorial_ids.go` 1249+855 ids) + +## 3. Cmd ID และ response layout เปลี่ยนทุกรุ่น + +- **ScRsp id เลื่อนตำแหน่ง**: `StartChallengeScRsp` เคยเป็น 1775 → 4.6.51 กลายเป็น **1787** และ 1775 ไปเป็น `GetChallengeGroupStatisticsCsReq` — ส่ง response ผิด id = client รอไม่ได้ หมุนค้างตลอด +- **Field tag เลื่อน**: `StartChallengeCsReq.challenge_id` tag 12 → **tag 14** — decoder มือต้องอัปเดต +- **Response body layout เปลี่ยน**: tag ของ retcode/scene/lineup ใน ScRsp ต้องแกะใหม่จาก proto ทุกรุ่น +- cmd ที่ไม่มีใน dump (เช่น 1452, Anomaly Arbitration) = เนื้อหาหลัง beta build ที่ client ถือ — ทำไม่ได้จนกว่าจะมี dump ใหม่ +- **ชื่อ message เปลี่ยนทุกรุ่น**: 4.6.51 เปลี่ยน `PveBattleResultCsReq → PVEBattleResultCsReq`, `QuickStartCocoonStageCsReq → StartQuickCocoonStageCsReq/StartQuickCocoonStageRsp`, `GateServer → Gateserver`, `GetGachaInfoCsReq/DoGachaCsReq หายไป` — **โค้ดต้องผูกกับ proto ของรุ่นนั้นจริงๆ เสมอ** + +## 4. Optional message fields — สาเหตุจอดำที่ไล่ยากที่สุด + +`_CmdGetBasicInfoScRsp` NRE วนซ้ำเพราะ `PlayerSettingInfo` มี optional message ซ่อนหลายตัว (`ojpaodihaje` Tag 13, `ankidjjinei` Tag 1171, `cmfcooeeecb` Tag 1552) — ปล่อย None แล้ว client unwrap → NRE → จอดำ + +วิธีไล่: NRE offset ใน Player.log ต่างกัน = field คนละตัว ใส่ทีละตัวจนหมด ใช้ `field_overrides_.json` ช่วยแปลชื่อ + +## 5. Design data CDN — ต้นเหตุ "ตารางพัง/ค้างหน้าโหลด" + +- `query_gateway` response (message `Gateserver`) มี `asset_bundle_url` / `ex_resource_url` / `lua_url` — มาจาก `versions.json` (sdkserver fetch จาก CDN จริงผ่าน proxy) +- client beta **hot-update design data** จาก URL เหล่านี้ — ถ้า CDN push ชุดใหม่กว่า GameAssembly ที่ติดตั้ง → ExcelTable โหลด FAILED → ค้างหน้าโหลด (ดู D number: 4.6.51 ติดตั้ง = D16700702 ≠ D16706787) +- **แก้**: `ex_resource_url` ต้องชี้ `design_data/BetaLive/output_` (ตัวอย่าง: `https://autopatchcn.bhsr.com/design_data/BetaLive/output_16700702_...`) — **ห้ามชี้ /no_update** เพราะ client beta ไม่ fallback ใช้ local +- ไฟล์ที่โหลดมาแล้วพังค้างใน `StreamingAssets/DesignData/Windows/` — restore จาก `.bak` หรือ re-verify + +## 6. กับดักที่พบจริงใน 4.6.51 (เก็บไว้เจอซ้ำ) + +- **ทีมเกิน 4 ตัว**: client ส่งทีม 2 ช่องทาง (`avatar_lineup_first` + `first_lineup`) รวมได้ 8 ตัว → `TeamManager` IndexOutOfRange ตอนเข้า arena — แก้ด้วย dedupe + truncate(4) +- **InteractProp**: เก็บ mapping entity_id → prop ตอนโหลดฉาก แล้วตอบ `prop_state` **จริงจาก config** — ห้ามตอบ `interact_id2` (มันคือ interaction id เช่น 1100 ไม่ใช่ state) +- **GetNpcTakenReward (2174)**: client ถามก่อนคุย NPC — ไม่ตอบ = dialogue ไม่มีตัวเลือกและค้าง +- **Tutorial**: mark ทุก id ว่าดูแล้ว (`GetTutorial`/`GetTutorialGuide` status enum `Oekdmamgidc`=2) ไม่งั้น popup เด้งวนและ**บล็อก input**; `FinishTutorial/UnlockTutorial*` ต้องตอบพร้อม Tutorial/TutorialGuide message +- **GetMissionStatusScRsp ต้องส่ง `finished_main_mission_id_list` + `curversion_finished_main_mission_id_list` (tag 13)** — ตอบเปล่า = client Lua NRE → บล็อก input + client ส่ง cmd 1204 ซ้ำรัวๆ +- **GetSwitchHandData**: 4.6.51 CsReq 8115 → ตอบ ScRsp **8104** (tag 3 retcode 0) +- **arena ใหม่ไม่มีใน client เก่า**: challenge phase ใหม่ (เช่น 5312) ใช้ arena 3014101 ซึ่ง client build เก่าไม่มี MapEntrance → Lua `GotoMapParam: attempt to index nil with 'ID'` — fallback ไป arena มาตรฐาน 3000101 +- **Scene ไม่มี teleport**: ฉาก arena ไม่มี teleport ใน res — fallback จาก `teleports.json` หรือ spawn ใกล้ prop แรกหันหน้าเข้าหา +- **full coverage ตอบ ScRsp ว่างทุก cmd = อันตราย!** — client modules (`GridFight`, `ChessRogue`, `EvolveBuild`, `ChimeraDuel`, `Jukebox`) รับว่างแล้ว `Sync(nil)` → NRE วน → **จอดำ** — cmd ไม่รู้จักต้อง **drop เงียบๆ** ตอบว่างได้เฉพาะ dummy list ที่ทดสอบแล้ว +- **BASE_AVATAR_IDS ห้ามใส่ตัวที่ client build นี้ไม่มี** (เช่น id จาก reference รุ่นใหม่กว่า) → พังตอน init โลก; ขาดตัวที่มีจริงก็ crash ตอน battle เช่นกัน +- **freesr-data.json ฟอร์แมตใหม่** (จาก SRTools): avatars 99 ตัว ไม่มี key leader/lineups — parser ต้อง tolerate ฟิลด์แปลก (Go: `LoadFreesrData` รองรับแล้ว) + +## 7. เครื่องมือและแหล่งข้อมูล + +- **AstralOS dump**: `C:\Users\Phitchayut\Downloads\New folder` (bin/*.json = data 4651, tools/reference/* = proto/cmdids/**field_overrides 4651** แปล obfuscated → ชื่อจริง) — ห้ามก็อปโค้ดทั้งดุ้น ใช้ data ได้ +- **`field_overrides_.json`** — ดัชนีแปลชื่อ field obfuscated → ชื่อจริงของทุก message +- **Firefly Shelter** (`C:\Program Files\Firefly Shelter\server\firefly-go`) — PS ภาษา Go ที่เวิร์กกับ client นี้ **ปิด source** — สำรวจได้จาก `tools/firefly_dump` (symbols: handlers/pb fields/cmds) และ data dir ของมัน (ใช้ freesr-data.json / data-in-game.json / version.json ฟอร์แมตเดียวกับ FreeSR) +- **`server_debug.log` / `gameserver.log`** — บันทึก ENTER_SCENE/INTERACT_PROP/SCENE_CAST_SKILL + log ทุก cmd +- **Dimbreath Game Data**: `https://gitlab.com/Dimbreath/turnbasedgamedata` (ExcelOutput แม่นยำ) +- **robinsr reference**: `https://git.neonteam.dev/amizing/robinsr` (อ่านเทียบได้ ห้ามก็อปทั้งดุ้น) + +## 8. กระบวนการทำงานที่พิสูจน์แล้วว่าเร็ว + +1. ทดสอบ 1 อย่าง → อ่าน log ทันที → แก้ 1 จุด → build → ทดสอบซ้ำ (อย่าแก้หลายจุดโดยไม่มี log ยืนยัน) +2. Reference จาก PS อื่น: **อ่านเทียบได้ ห้ามก็อปโค้ดทั้งดุ้น** — ดึงเฉพาะ data dump และค่า config +3. **commit ทุกครั้งที่แก้เสร็จ** — ไฟล์เคยถูกย้อนกลับโดยไม่ทราบสาเหตุ 2 ครั้ง +4. แก้ path hardcode ใน .bat ทุกครั้งที่ย้าย/rename โฟลเดอร์ +5. เปลี่ยน versions.json ทีละ field ด้วย script — อย่าแก้มือตอนเซิร์ฟเวอร์กำลังรัน + +## 9. สถานะที่รู้ว่ายังไม่สำเร็จ (ณ 4.6.51) + +- Anomaly Arbitration — ไม่มี cmd ใน dump ของ client รุ่นนี้ +- Currency War (ตระกูล Rogue 101 cmd) — ตอบ default ครบ แต่เล่นได้จริงต้อง implement state เฉพาะ +- Gacha (GetGachaInfo/DoGacha) — proto 4.6.51 เปลี่ยนชื่อ message → ตัว Go skip handler ไว้ (log "handler skipped") ต้องหาชื่อใหม่จาก dump +- StartChallenge กับ challenge_id ที่ไม่มีใน challenge_data.json — ใช้ fallback arena 3014101 +- ยังไม่ได้ทดสอบกับ client จริงแบบเต็ม session หลังพอร์ต Go (รอ user ทดสอบ: login → Parlor Car → เดิน → กดตี → วาป → เข้า endgame) + +## 10. โค้ด Rust แตกตัวกับ proto ใน repo (บทเรียนสำคัญ) + +commit สุดท้ายของ Rust (`ebc27a1`) อ้างชื่อ message ที่ **ไม่มีใน** `proto/StarRail.proto` ของตัวเองแล้ว: +`PveBattleResultCsReq`, `QuickStartCocoonStageCsReq`, `GateServer`, `GetGachaInfoCsReq`, `GroupRefreshInfo`, `LineupSlot` +→ สาเหตุ: proto ถูกแทนด้วย dump 4.6.51 ใหม่ (ชื่อ obfuscated พิมพ์ใหญ่) แต่ handler ไม่ได้ตาม +→ **กฎ:** หลังแทน proto ต้อง compile ทันทีและแก้ชื่อให้ตรง ก่อนปล่อย build ให้ user ทดสอบ +→ ตัว Go แก้ครบโดยผูกทุก handler กับชื่อจริงใน proto (handler ไหน proto ไม่มีจะ log+skip ไม่ panic) + +## 11. บัคกล้องหลุดตอนกดตี — SceneCastSkill (แก้แล้วในตัว Go) + +**อาการ:** กดโจมตีใน overworld แล้วกล้องหลุดออกจากตัวละคร + +**ต้นเหตุ (Rust battle.rs):** handler ตอบ `battle_info` + `monster_battle_info` ให้เข้า battle กับ target ที่ผ่าน filter หลวม `id > 30000 || id < 1000` — ซึ่งรวม **avatar entity ของผู้เล่นเอง** (1-4); ถ้าอยู่ arena (entry >= 3000000) ยังหลอก target เป็น 30001 เสมอ → client เริ่ม battle transition กับ "monster" ที่ไม่มีจริง → กล้อง battle ไม่มี target ให้ตาม → หลุด + +**วิธีแก้ (Go `internal/gameserver/handlers_battle.go`):** +1. ตอนโหลดฉาก เก็บ monster entity จริง (entity_id → event_id) ไว้ใน `Session.MonsterEntities` +2. `SceneCastSkill` ยอมรับเฉพาะ hit target ที่เป็น monster จริง +3. ไม่มี monster จริง → ตอบ `retcode 0 + cast_entity_id` **ไม่เข้า battle** (client เล่นแอนิเมชันตีปกติ กล้องค้างกับตัว) +4. ตีโดน monster จริง (รวมบอส arena 30001) → เข้า battle ปกติ +5. ยืนยันด้วย `internal/gameserver/smoke_test.go` (จำลอง client เต็มรูปแบบผ่าน UDP จริง) + +**บทเรียน:** อย่าตอบ battle/transition ให้ client จาก target ที่ server ไม่ได้ spawn เอง — ตรวจกับ entity registry ของฉากปัจจุบันเสมอ + +## 12. Go server (GaC-hkrpg-go) — สถาปัตยกรรมและข้อควรรู้ + +- **mihoyo KCP header 28 ไบต์**: `conv(4) + token(4) + cmd(1) + frg(1) + wnd(2) + ts(4) + sn(4) + una(4) + len(4)` Little-Endian — standard KCP lib อ่านไม่ได้; Go port อยู่ `pkg/kcp` (port จาก kcp.rs 1:1, UDP loopback test ผ่าน) +- **นาฬิกา KCP ต้องเป็นมิลลิวินาที** — Rust เดิมใช้วินาที (session_time secs) ทำ RTT/resend เพี้ยนทั้งระบบ +- **Handshake**: 20-byte NetOperation — client `head=0xFF, tail=0xFFFFFFFF`, server ตอบ `head=0x145, tail=0x14514545` (param1=conv, param2=token), ตัดการเชื่อมต่อ `head=0x194, tail=0x19419494` +- **Packet framing ใน KCP stream**: `HEAD 0x9D74C714 + cmd(u16 BE) + headLen + bodyLen + head + body + TAIL 0xD7A152C8` — ไม่มี XOR encryption ใน build นี้ +- **cmdid map** generate จาก `// CmdID:` comments ใน proto → `protocol/proto/cmdid.go` (regenerate ตอนเปลี่ยน proto) +- **ใช้ data files Rust PS ได้ทันที** (freesr-data.json / persistent / res.json / teleports.json / challenge_data.json / mission_unlocks.json / versions.json) — ฟอร์แมต JSON ตรงกัน รวม enum string อย่าง `main_character: "FemaleHarmony"` +- **Build**: `go build -o gameserver-go.exe ./cmd/gameserver` + `./cmd/sdkserver`; ทดสอบ: `go test ./...`; เปิดด้วย `run_go.bat` (UDP 23301 + HTTP 21000 เหมือนเดิม) +- **ที่ตั้ง skill library**: `tools/AI TOOLBOX/` (ทั้งสองโปรเจกต์มี copy — อัปเดตต้นฉบับที่เดียวแล้วก็อป)