The synthetic 1000-60000 ranges filled the Travel Log with entries the client cannot resolve. Replaced with the 147 real (activityId, panelId) rows dumped from the March7th PS ActivityConfig (matches the 4.6.51 client), keeping the Apocalyptic Shadow panel 21001 block that the AS tab requires
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):
- ตอนโหลดฉาก server เก็บรายการ monster entity จริง ไว้ใน
Session.MonsterEntities(entity_id → event_id) SceneCastSkillยอมรับเฉพาะ hit target ที่เป็น monster จริงเท่านั้น- ถ้าไม่มี monster จริงถูกตี → ตอบ
retcode 0 + cast_entity_idเฉยๆ ไม่เข้า battle client เล่นแอนิเมชันตีปกติ กล้องค้างกับตัวละคร - ตีโดน 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 ทำงานเหมือนเดิม)