CAtlas0784 91ee027eb7 fix(gameserver): answer UI-gating cmds the 4.6.51 client stalls on
First real-client session (2026-10-07 01:00) showed the client walking and
attacking but UI interactions stalling: ~120 CsReq dropped with no reply.

- auto-empty responder: any unknown CsReq with a Cmd-enum ScRsp pair now
  gets an empty ScRsp, except the danger families (GridFight/ChessRogue/
  EvolveBuild/ChimeraDuel/Jukebox/CycleScore) which must stay dropped
  (client Sync(nil) NREs on empty, per the Rust lessons)
- GetUnreleasedBlockInfo: the Endgame entry waits on this - 4.6.51 wire is
  CsReq 4190 -> ScRsp 4112 retcode tag 14 (the Rust build answered 4130,
  an id this client never sends)
- SetClientPaused acked (client pauses itself when opening menus/map)
- explicit handlers: TakeQuestReward, GetFirstTalkNpc, QuitBattle,
  GetMapRotationData (Amphoreus teleport pillars), GetPamSkinData,
  GetAllServerPrefsData/UpdateServerPrefsData, GetHeartDialInfo, GetPetData,
  GetShopList
- SendRaw now logs (dummy/raw replies were invisible in gameserver.log)
- cmdpairs.go: req->rsp id pairs generated from the Cmd enum (865 pairs),
  stable across message renames
- smoke test extended: 4190->4112 and SetClientPaused ack verified
2026-10-07 01:19:56 +07:00

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 ทำงานเหมือนเดิม)
S
Description
No description provided
Readme
7.9 MiB
0 Stars 1 Watchers 0 Forks
Languages
Go 94.7%
Lua 3.7%
Python 1.4%
JavaScript 0.1%
PowerShell 0.1%