10 KiB
Battle investigation — 2026-10-16
หลักฐานที่ใช้อ้างอิง
- Upstream: HonkaiSlopRail/pearl-sr
- ตรวจ remote ใหม่แล้วที่ commit
005d2c12db4781071f4b5b68e8f364587886a710 - ไฟล์หลัก:
gameserver/src/services/battle.zig,gameserver/src/manager/battle_mgr.zig,gameserver/src/data/game_config.zig,protocol/src/protocol.pb.zig - Client ล่าสุดยัง NRE ที่
CreateBattleServerCheckResultผ่านตัวแปลง BattleAvatar/รายการ relic และNMBMHCNGCFG.BDNFEMGIEIH - Payload ที่บันทึกเวลา 21:34 มีตัวละคร 4 ตัว แต่ละตัวมี relic 6 ชิ้นและ sub-affix 24 ค่า แม้เลิกส่ง inventory UniqueId ใน BattleRelic แล้ว Client ก็ยังล้ม
เทียบทีละส่วน
| ส่วน | สิ่งที่ตรวจพบ | ข้อสรุปที่ใช้ได้ |
|---|---|---|
| Quick Calyx response | Field numbers: retcode=1, battle_info=5, wave=8, cocoon_id=11 ตรง upstream | ยังไม่พบ field-number mismatch ใน wrapper |
| SceneBattleInfo | ตรวจชุด field numbers ของ 20 fields ตรงกัน | ชื่อ JAOIOKBBMFC ของ Go คือ field 7 ซึ่ง upstream เรียก monster_wave_length |
| BattleAvatar | ตรวจชุด field numbers ของ 18 fields ตรงกัน | ยังต้องดูค่าที่ parser ของ Client ถอดได้จริง |
| Relic/lightcone | BattleRelic, RelicAffix และ BattleEquipment มีชุด field numbers ตรงกัน | จำนวน sub-affix ฝั่ง Go อย่างเดียวไม่ยืนยันว่า Client ถอดได้ครบ |
| Monster/wave | SceneMonster, SceneMonsterWave, SceneMonsterWaveParam มีชุด field numbers ตรงกัน | ยังไม่มีหลักฐานให้สลับ WaveParam เป็น nil อีก |
| Buff | Go ใช้ชื่อ OwnerId แต่ upstream ใช้ owner_index บน field 3 เหมือนกัน | ชื่อ Go ไม่ใช่หลักฐานว่า field บน wire ผิด |
| แหล่งข้อมูล | Go ใช้ freesr-data.json/persistent; PearlSR ใช้ config.json/selected avatars | Payload ทั้งสองยังไม่เท่ากันในระดับค่าข้อมูล |
| EX rank | Upstream append รายการ ExRankAvatarID ให้ทุก battle avatar; Go ส่งรายการตามตัวละครที่ปลดล็อก | เป็นข้อแตกต่างที่บันทึกไว้ ยังไม่ชี้ว่าเป็นสาเหตุ NRE |
| Global/technique buffs | เจ้าของบัฟ, target list และ dynamic values บางตัวต่างกัน | ต้องตรวจแยกหลังระบุตำแหน่งที่ parser/ตัวตรวจล้ม |
การตรวจ field numbers ข้างต้นไม่ได้ยืนยัน default values, Client schema ของรุ่นที่รันจริง หรือผลการคำนวณค่าสถานะใน Client
ขั้นแรกที่เพิ่มในรอบนี้: เก็บ wire และอ่านกลับบน Client
บันทึกหลังส่ง response สำเร็จจาก Session.Send แทนการบันทึกระหว่างสร้าง battle:
battle_last_response.bin: protobuf body ของ response ที่ส่งจริงbattle_last.bin: bytes ของ nested battle_info ที่ตัดออกจาก response เดิมโดยตรง ไม่ marshal ใหม่battle_last.json: ข้อมูลสำหรับอ่านด้วยตาbattle_last_capture.json: CmdID, ชื่อ response, StageID, เวลา UTC และ SHA-256battle_diagnostics/: snapshot ของแต่ละรอบ เก็บทั้งข้อมูลเดิมและรอบต่อมา
เปิด read-only Client probe ด้วย battle_diagnostics.client_battle_type ใน local config ชื่อ class ต้องเอาจาก stack trace ของ Client รุ่นที่กำลังใช้งาน ไม่ฝังชื่อ class ที่เปลี่ยนตามเวอร์ชันใน Go/Lua
Probe ถูกส่งครั้งเดียวใน heartbeat หลัง response battle โดยใช้ protobuf parser ของ Client อ่าน bytes เดียวกับ capture จากนั้นเขียน [GAC_BATTLE_WIRE] ลง Player.log พร้อม decoded JSON และ descriptor field numbers ไม่แก้ตัวละคร relic บัฟ หรือ callback การต่อสู้
หาก parser/Reflection ไม่ถูกเปิดให้ Lua ใช้ จะมี probe_error ใน Player.log แทน ห้ามตีความว่า capture ฝั่ง Go ผ่านแล้วแปลว่า Client decode ผ่าน
ข้อสรุปที่ถอนออก
Stack trace เดิมเพียงอย่างเดียวไม่ได้พิสูจน์ว่า WaveParam=nil หรือ SceneMonster.ExtraInfo=nil เป็นสาเหตุ การใส่ ExtraInfo หรือการลบ UniqueId ยังไม่ได้ทำให้การเข้า battle สำเร็จ จึงไม่ถือเป็นการแก้ที่ยืนยันผลแล้ว
ผลตรวจรอบ 21:47: main affix ที่ไม่มีในตาราง
Calyx และ overworld ตายที่ stack เดียวกัน ส่วน probe รุ่นแรกทำงานแล้วแต่รายงาน protobuf parser property not found จึงไม่มี Client readback และยังใช้ผลของ probe ยืนยันการ decode ไม่ได้
แก้การอ่านตำแหน่ง exception: 0xc4eb77c เป็น return address หลังคำสั่ง call ที่ 0xc4eb777 เช่นเดียวกับ frame 0x166b23d2 ที่อยู่หลัง call 0xc4eb0c0 ดังนั้นจุดนี้มาจาก branch หลัง lookup main affix ไม่พบ (0xc4eb2b0–0xc4eb2b3) ไม่ใช่ branch ตรวจ sub-affix array ที่กระโดดไป 0xc4eb77c แล้วมี return address 0xc4eb781 การตีความ sub-affix array เป็น null ในรอบก่อนจึงถูกถอนออก
ตรวจ payload จริงและ inventory พบรายการนี้:
| Inventory UID | Avatar | Relic | main_affix_id เดิม | ผลตรวจ |
|---|---|---|---|---|
| 483 | 1213 (Dan Heng IL) | 63095 | 11 | ไม่มีใน main affix group 55 ของลูกแก้ว |
เทียบกับ relics.json และ relic_main_affixes.json: group 55 มี ID 1–10 โดย ID 10 คือ ImaginaryAddedRatio และ resources/AvatarConfig.json ระบุ Avatar 1213 เป็น Imaginary
แก้ ข้อมูล inventory เท่านั้น จาก 11 เป็น 10 ใน freesr-data.json ไม่มีเงื่อนไขพิเศษสำหรับ Avatar/Relic นี้ใน converter สำรองข้อมูลและ log ก่อนแก้ไว้ใน battle_diagnostics/main-affix-repair/ แล้ว และปิด probe ใน local config ขณะลองผลการแก้ข้อมูล
ข้อจำกัดของชุดข้อมูลอ้างอิง: ไม่พบ relic ใหม่ 63295/63296 ของ Avatar 1511 จึงไม่ได้รับรอง inventory ทุกชิ้น แต่ชิ้นที่อยู่ในทีมของ payload รอบนี้มีครบและพบ main affix ผิดหนึ่งชิ้นข้างต้น
ขั้นต่อไปหลังแก้ main affix
- เปิดเกมใหม่ให้ Client โหลด inventory ที่แก้แล้ว และลอง Calyx/overworld ด้วยทีมเดิม
- หากยังล้ม ให้เก็บ stack ใหม่และเทียบ capture ว่าส่ง main affix 10 แล้ว ก่อนเปลี่ยนส่วนอื่น
แนวทางตรวจเพิ่มเติมหากยังล้ม
- เทียบ SHA-256 ให้ตรงกับรอบที่ Client ล้ม
- เทียบ schema/ข้อมูล BattleAvatar และ nested relic ที่ Client ถอดได้กับ capture ฝั่ง Go
- หากข้อมูลตรงกัน ให้แยกตัวละครและอุปกรณ์ที่ทำให้ตัวตรวจค่าสถานะล้มโดยมี control payload ก่อนแก้ resource หรือสูตรบัฟ
- เปลี่ยนเฉพาะส่วนที่มีหลักฐาน แล้วตรวจ Calyx และ overworld battle แยกกัน
สถานะ: ยังไม่มีการยืนยันว่าเข้า fight ได้