110 lines
7.8 KiB
Markdown
110 lines
7.8 KiB
Markdown
# GaC hkrpg GO — StarRail 4.6.51 Private Server (ภาษา Go)
|
|||
|
|
|
||
|
|
โอนย้าย (port) จากโปรเจกต์ Rust `GaC-hkrpg-ps` มาเป็นภาษา Go ทั้งหมด
|
||
|
|
พร้อม **แก้บัคกล้องหลุดจากตัวละครตอนกดตี (SceneCastSkill)** ตั้งแต่ต้นทาง
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ทำไมต้อง Go (ที่มาของการแปลง)
|
||
|
|
|
||
|
|
- Firefly Shelter (`firefly-go`) ซึ่งพิสูจน์แล้วว่าเข้าเกมได้กับ client 4.6.51 เป็น server ภาษา Go
|
||
|
|
(ไม่มี public source — สำรวจจาก binary จริงด้วย `tools/firefly_dump` ใน repo เดิม)
|
||
|
|
- โค้ด Rust ล่าสุดใน commit `ebc27a1` แตกตัวกับ proto ใน repo (ใช้ชื่อ message เก่าอย่าง
|
||
|
|
`PveBattleResultCsReq` / `QuickStartCocoonStageCsReq` ที่ไม่มีใน proto 4.6.51 อีกต่อไป)
|
||
|
|
การพอร์ตใหม่จึงผูกกับ **proto 4.6.51 จริง** ตั้งแต่ต้น
|
||
|
|
|
||
|
|
## บัคกล้องหลุด (SceneCastSkill) — สาเหตุและวิธีแก้
|
||
|
|
|
||
|
|
อาการ: กดตีใน overworld แล้วกล้องหลุดออกจากตัวละคร
|
||
|
|
|
||
|
|
สาเหตุ (จาก `gameserver/src/net/handlers/battle.rs` เดิม):
|
||
|
|
handler ของ `SceneCastSkillCsReq` ตอบ `battle_info` + `monster_battle_info` ให้ client
|
||
|
|
เข้าสู่การต่อสู้กับ target ที่ผ่าน filter แบบหลวม:
|
||
|
|
|
||
|
|
```
|
||
|
|
filter เดิม: id > 30_000 (monster) || id < 1_000 (avatar entity ของผู้เล่นเอง!)
|
||
|
|
```
|
||
|
|
|
||
|
|
เมื่อ client ส่ง hit target เป็น prop / NPC / ตัวผู้เล่นเอง server จะสั่งเข้า battle
|
||
|
|
กับ "monster" ที่ไม่มีอยู่จริง → battle transition โหลดไม่สำเร็จ → กล้อง battle
|
||
|
|
ไม่มี target ให้ตาม → กล้องหลุดจากตัวละคร นอกจากนี้ถ้าอยู่ใน arena
|
||
|
|
(entry >= 3000000) โค้ดเดิมยัง "หลอก" target เป็น 30001 เสมอ
|
||
|
|
|
||
|
|
วิธีแก้ (ใน `internal/gameserver/handlers_battle.go`):
|
||
|
|
1. ตอนโหลดฉาก server เก็บรายการ **monster entity จริง** ไว้ใน `Session.MonsterEntities`
|
||
|
|
(entity_id → event_id)
|
||
|
|
2. `SceneCastSkill` ยอมรับเฉพาะ hit target ที่เป็น monster จริงเท่านั้น
|
||
|
|
3. ถ้าไม่มี monster จริงถูกตี → ตอบ `retcode 0 + cast_entity_id` เฉยๆ **ไม่เข้า battle**
|
||
|
|
client เล่นแอนิเมชันตีปกติ กล้องค้างกับตัวละคร
|
||
|
|
4. ตีโดน monster จริง (รวมบอสใน arena 30001) → เข้า battle ตามปกติ
|
||
|
|
|
||
|
|
ยืนยันด้วย test อัตโนมัติ: `internal/gameserver/smoke_test.go`
|
||
|
|
(จำลอง client เต็มรูปแบบ: handshake → login → กดตี ทั้งกรณี ผ่าน UDP จริง)
|
||
|
|
|
||
|
|
## สถาปัตยกรรม
|
||
|
|
|
||
|
|
```
|
||
|
|
cmd/gameserver เกมเซิร์ฟเวอร์ (UDP :23301, KCP)
|
||
|
|
cmd/sdkserver dispatch + login + SRTools (HTTP :21000)
|
||
|
|
protocol/proto StarRail.pb.go — generate จาก proto 4.6.51 (4,932 messages)
|
||
|
|
protocol/proto/cmdid.go — ตาราง CmdID (2,114 ids) generate จาก "// CmdID:" comments
|
||
|
|
pkg/kcp KCP สาย mihoyo (header 28 ไบต์: conv+token) — port จาก kcp.rs 1:1
|
||
|
|
internal/common FreesrData / persistent / res.json / teleports.json + proto converters
|
||
|
|
internal/gameserver gateway, packet framing, session, dispatch, handlers ทั้งหมด
|
||
|
|
internal/sdkserver query_dispatch / query_gateway / auth / srtools / versions.json
|
||
|
|
```
|
||
|
|
|
||
|
|
ไฟล์ข้อมูลใช้ชุดเดิมกับ Rust PS ทุกไฟล์ (freesr-data.json, persistent, res.json,
|
||
|
|
teleports.json, challenge_data.json, mission_unlocks.json, versions.json) — save เดิมใช้ได้ทันที
|
||
|
|
|
||
|
|
## การใช้งาน
|
||
|
|
|
||
|
|
```
|
||
|
|
run_go.bat เมนู 1/2/3/4 เหมือนเดิม
|
||
|
|
gameserver-go.exe เกมเซิร์ฟเวอร์
|
||
|
|
sdkserver-go.exe SDK/dispatch
|
||
|
|
```
|
||
|
|
|
||
|
|
ต้องแก้ hosts ของเครื่อง client แบบเดียวกับ Rust PS (หรือใช้ Fiddler/proxy เดิม)
|
||
|
|
|
||
|
|
## Build จากซอร์ส
|
||
|
|
|
||
|
|
ต้องมี Go 1.27+ และ protoc + protoc-gen-go (เฉพาะตอนแก้ proto):
|
||
|
|
|
||
|
|
```
|
||
|
|
go build -o gameserver-go.exe ./cmd/gameserver
|
||
|
|
go build -o sdkserver-go.exe ./cmd/sdkserver
|
||
|
|
go test ./... # รวม smoke test จำลอง client จริง
|
||
|
|
```
|
||
|
|
|
||
|
|
## สิ่งที่พอร์ตครบแล้ว
|
||
|
|
|
||
|
|
- Network: mihoyo KCP (conv+token), NetOperation handshake (0xFF/0x145/0x194),
|
||
|
|
packet framing (0x9D74C714/0xD7A152C8), freesr-data.json hot-reload watcher
|
||
|
|
- Login flow ครบ (GetToken/PlayerLogin/GetBasicInfo/PlayerLoginFinish + ContentPackage)
|
||
|
|
- ฉาก: GetCurSceneInfo/EnterScene (โหลด props/NPCs/monsters จาก res.json, teleport
|
||
|
|
resolution, fallback จุดเกิด), SceneEntityMove (บันทึกตำแหน่ง), InteractProp,
|
||
|
|
GetNpcTakenReward, GetSceneMapInfo, GetEnteredScene, GetUnlockTeleport
|
||
|
|
- ทีม: GetAllLineupData/GetCurLineupData/JoinLineup/ReplaceLineup/SwapLineup/
|
||
|
|
SwitchLineupIndex/ChangeLineupLeader + SceneGroupRefresh/SyncLineup notify
|
||
|
|
- ตัวละคร/ไอเทม: GetAvatarData (+skin), สวม/ถอด lightcone/relic, RankUpAvatar, GetBag
|
||
|
|
- ภารกิจ: GetMissionStatus (curversion finished), GetMissionData, GetQuestData,
|
||
|
|
GetMainMissionCustomValue, UpdateTrackMainMission (จาก mission_unlocks.json)
|
||
|
|
- บทเรียน: ปดล็อคครบ 1249 tutorials + 855 guides (กันกล้อง/อินพุตค้าง)
|
||
|
|
- ต่อสู้: SceneCastSkill (**แก้บัคกล้องหลุดแล้ว**), StartCocoonStage,
|
||
|
|
StartQuickCocoonStage, SceneEnterStage, PVEBattleResult, GetCurBattleInfo,
|
||
|
|
SceneCastSkillCostMp, บัฟ global (Castorice/SW/Aha 151104)
|
||
|
|
- Challenge: GetChallenge, GetCurChallenge, GetChallengePeakData, GetCurChallengePeak,
|
||
|
|
GetActivityScheduleConfig, StartChallengePeak (cmd 8948 → arena 3000101),
|
||
|
|
StartChallenge → 1787 layout 4.6.51, Tierce (8973) + ทุก raw reply ที่ตอบค้าง
|
||
|
|
(1708/1716/1781/1704/8997/8999/8923/8920/... ครบตาม packet.rs เดิม)
|
||
|
|
- Dummy ปลอดภัย: ตอบว่างเฉพาะรายการที่ปลอดภัย ที่เหลือ drop เงียบ
|
||
|
|
(บทเรียนจาก Rust: ตอบว่างมั่วทำให้ client NRE จอดำ)
|
||
|
|
|
||
|
|
## ต่างจาก Rust ที่ควรรู้
|
||
|
|
|
||
|
|
- นาฬิกา KCP เป็นมิลลิวินาที (Rust ใช้วินาที — ทำให้ RTT/เวลา retransmit เพี้ยน)
|
||
|
|
- มี ticker ขับ KCP ทุก 50ms ต่อ session (retransmission ทำงานจริง)
|
||
|
|
- ชื่อ message ใช้ตาม proto 4.6.51 จริง (แก้ปัญหาชื่อเก่าที่หายไป)
|
||
|
|
- StartChallenge ยังไม่รองรับ challenge_id ที่อยู่นอก challenge_data.json
|
||
|
|
(fallback arena 3014101 ทำงานเหมือนเดิม)
|