Files
GaCy-GO/docs/battle-investigation.md
T

10 KiB
Raw Blame History

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-256
  • battle_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

  1. เปิดเกมใหม่ให้ Client โหลด inventory ที่แก้แล้ว และลอง Calyx/overworld ด้วยทีมเดิม
  2. หากยังล้ม ให้เก็บ stack ใหม่และเทียบ capture ว่าส่ง main affix 10 แล้ว ก่อนเปลี่ยนส่วนอื่น

แนวทางตรวจเพิ่มเติมหากยังล้ม

  1. เทียบ SHA-256 ให้ตรงกับรอบที่ Client ล้ม
  2. เทียบ schema/ข้อมูล BattleAvatar และ nested relic ที่ Client ถอดได้กับ capture ฝั่ง Go
  3. หากข้อมูลตรงกัน ให้แยกตัวละครและอุปกรณ์ที่ทำให้ตัวตรวจค่าสถานะล้มโดยมี control payload ก่อนแก้ resource หรือสูตรบัฟ
  4. เปลี่ยนเฉพาะส่วนที่มีหลักฐาน แล้วตรวจ Calyx และ overworld battle แยกกัน

สถานะ: ยังไม่มีการยืนยันว่าเข้า fight ได้