- พบ บั๊กประหลาด ในฉากช่วงต้นของ Half-Life 2 ที่ทำให้ประตูไม่เปิดและเกมดำเนินต่อไม่ได้
- สาเหตุคือเมื่อประตูเปิด ปลายเท้าของยามที่ยืนอยู่ด้านในชนกับเส้นทางการเคลื่อนที่ของประตู ทำให้ประตูปิดกลับและล็อกอีกครั้ง
- แม้ในโค้ดต้นฉบับจะมีการชนกันแบบเดียวกันอยู่แล้ว แต่ผลลัพธ์กลับต่างกันเพราะความต่างของความแม่นยำระหว่าง การคำนวณเลขทศนิยมลอยตัวแบบ x87 ในปี 2004 และ การคำนวณแบบ SSE ในปี 2013
- ในสภาพแวดล้อม x87 จะเกิดการหมุนเล็กน้อยทำให้เท้าถูกดันออกไปและการชนหายไป แต่ใน SSE ปริมาณการหมุนไม่พอ จึงลงเอยด้วยการที่ประตูปิด
- กรณีนี้เป็นตัวอย่างเด่นที่แสดงให้เห็นว่า ความแม่นยำของเลขทศนิยมลอยตัวและความต่างของคอมไพเลอร์ ส่งผลต่อพฤติกรรมจริงของเกมได้อย่างไร
บั๊กที่พบระหว่างการพอร์ต Half-Life 2 ไปยัง VR
- ระหว่างการทดลองพอร์ต Team Fortress 2 ไปยัง VR ที่ Valve ในปี 2013 เกมที่ใช้เอนจินเดียวกันอย่าง Half-Life 2 และ Portal 1 ก็สามารถรันบน VR ได้ด้วย
- Portal 1 ทำให้เวียนหัวจนแทบเล่นใน VR ไม่ได้ เพราะมุมมองบิดเบือน
- Half-Life 2 กลับทำงานได้ค่อนข้างดี และฉากเรือ การเรียงกล่อง รวมถึงการต่อสู้กับ manhack ก็ยิ่งเพิ่มความสมจริงแบบ VR
- ระหว่างการทดสอบ นักพัฒนาเล่นเกมใน VR ตั้งแต่ต้นจนจบ และพบว่า ติดค้างเล่นต่อไม่ได้ในฉากสถานีรถไฟช่วงต้นเกม
การวิเคราะห์สาเหตุที่ประตูไม่เปิด
- ในเหตุการณ์ตามปกติ ยามคนหนึ่ง (จริง ๆ แล้วคือ Barney) จะเคาะประตูแล้วพูดว่า “เข้าไปสิ” จากนั้นเมื่อผู้เล่นเข้าไปในห้อง เกมจะดำเนินต่อด้วยสคริปต์ถัดไป
- แต่ในกรณีบั๊ก ประตูจะ กระตุกแล้วล็อกจนปิดสนิท ยามยังคงชี้ไปที่ประตู และผู้เล่นก็ติดอยู่ข้างนอก
- เมื่อนำซอร์สโค้ดต้นฉบับของ Half-Life 2 มาสร้างใหม่ก็ยังเกิดปัญหาเดียวกัน ทำให้ดูเหมือนเป็น บั๊กที่เหมือนเกิดขึ้นจากการย้อนเวลา จนสร้างความสับสน
ต้นตอที่แท้จริง: การเปลี่ยนวิธีคำนวณเลขทศนิยมลอยตัว
- ตอนที่ Half-Life 2 วางจำหน่ายในปี 2004 เกมใช้ ชุดคำสั่งคณิตศาสตร์ x87 ซึ่งเป็นโครงสร้างที่มีความแม่นยำปะปนกันทั้ง 32, 64 และ 80 บิต
- ในบิลด์หลังปี 2013 มีการใช้ ชุดคำสั่ง SSE เป็นค่าเริ่มต้น ทำให้ความแม่นยำของการคำนวณถูกจำกัดไว้อย่างชัดเจนที่ 32 หรือ 64 บิต
- ทั้งสองสภาพแวดล้อมต่างก็มีการชนกันระหว่างประตูกับปลายเท้าของยาม แต่ ความต่างเล็กน้อยในการคำนวณของฟิสิกส์เอนจิน ทำให้ผลลัพธ์ไม่เหมือนกัน
- ใน x87 เมื่อเกิดการชน ยามจะหมุนเพียงเล็กน้อยจนเท้าหลุดพ้นจากประตู ทำให้ประตูเปิดได้
- ใน SSE ปริมาณการหมุนนั้นน้อยลงอีกนิด ทำให้เท้ายังแตะประตูอยู่ และประตูก็ปิดกลับพร้อมล็อก
การแก้ไขและการแก้ปัญหา
- หลังระบุปัญหาได้แล้ว ก็แก้ได้ด้วยการปรับง่าย ๆ คือ ขยับตำแหน่งของยามถอยหลังประมาณ 1 มม.
- ระหว่างดีบักยังต้องกลับไปเรียนรู้วิธีใช้เครื่องมือเก่า ๆ ใหม่อีกครั้ง ทำให้ใช้เวลาไม่น้อย
- กรณีนี้แสดงให้เห็นว่า ความต่างของความแม่นยำและการเปลี่ยนค่าการตั้งคอมไพเลอร์ สามารถทำให้พฤติกรรมของโค้ดเก่าเปลี่ยนไปได้
ปฏิกิริยาจากชุมชน
- นักพัฒนาหลายคนเห็นพ้องว่า “สุดท้ายปัญหาก็มักจะเป็นเรื่อง ความแม่นยำของเลขทศนิยมลอยตัว”
- บางคนยกตัวอย่างกรณีการเปลี่ยนการคำนวณการชนในรีเมกของ Sonic 1·2·3 ว่าคล้ายกัน
- หลายความเห็นมองว่านี่เป็นบทเรียนว่า “โค้ดเหมือนเดิม แต่คอมไพเลอร์ไม่เหมือนเดิม” และเป็นตัวอย่างที่เตือนถึง ความยากในการดูแลโค้ดแบบเลกาซี
- นักพัฒนาคนอื่น ๆ ยังเชื่อมโยงไปถึงเหตุผลที่เกมอย่าง Fallout 4 ออกแบบไม่ให้ NPC เดินผ่านประตูได้ เพื่อหลีกเลี่ยงปัญหาแบบนี้
- โดยรวมแล้ว หลายคนมองว่านี่คือ “หนึ่งในเรื่องเล่าบั๊กที่น่าสนใจที่สุด”
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
สมัยก่อนตอนที่ทำพัฒนาเกม เคยจำได้ว่ามีกรณี assert ล้มเหลวจาก ข้อผิดพลาดการคำนวณของ FPU ที่เกิดขึ้นเฉพาะบนพีซีบางเครื่อง
สาเหตุคือซอฟต์แวร์รับลายมือเขียนได้ฉีด DLL เข้าไปในทุกโปรเซส และ รีเซ็ต โหมด FPU กลับเป็นค่าเริ่มต้น
สุดท้ายก็เลยย้ายโค้ดตั้งค่า FPU จากขั้นตอนเริ่มต้นระบบไปไว้ใน event loop เพื่อหลีกเลี่ยงผลกระทบจาก DLL ของบุคคลที่สาม
หนึ่งในเป้าหมายของฉันคือทำให้ Valve หันมาใช้ Nix
คิดว่าตอนนี้น่าจะน่าสนใจขึ้นเพราะกำลังมีการรองรับ Windows
ถ้าเป็นแบบนั้น ก็จะสามารถจำลองซ้ำได้ครบถ้วนไม่ใช่แค่ซอร์สต้นฉบับ แต่รวมถึง toolchain และ dependency ในยุคนั้นด้วย เลยคิดว่าน่าจะช่วยหาสาเหตุรากของบั๊กแบบนี้ได้ง่ายขึ้นมาก
ทำให้นึกถึงมีม “DOOR STUCK”
วิดีโอที่เกี่ยวข้อง
สงสัยว่า “Half-Life 2 VR เบตา” เล่นได้จริงหรือเปล่า
ถ้าเล่นได้ก็สงสัยว่าทำไมฉันไม่เคยรู้มาก่อน แต่ถ้ายังเล่นไม่ได้ก็สงสัยว่าทำไมถึงยังไม่ทำ
อยากลอง Portal VR มากเหมือนกัน หลายคนบอกว่าเวียนหัวหนัก แต่ฉันแทบไม่เมา VR เลย น่าจะลองได้
คุณภาพดีจนทำให้อยากกลับไปเล่น HL2 อีกรอบเลย
ตอนย้ายจาก x87 ไป SSE แล้วการคำนวณบางส่วนพัง เป็นเรื่องที่เกิดขึ้นได้บ่อย
ใน TF2 ก็เคยเกิดแบบเดียวกัน โดยบิลด์บน Linux ใช้ SSE ทำให้การคำนวณกระสุนต่างออกไปเล็กน้อย
กล่องเล็กจะให้ +40 หรือ +41 แล้วแต่ OS ของเซิร์ฟเวอร์
ทุกครั้งที่เข้าเซิร์ฟเวอร์ใหม่ก็สนุกดีที่จะเดาว่าเป็น OS อะไร
แค่เปลี่ยนจาก x87 ไปเป็น SSE เกมก็พังแล้ว เลยยิ่งน่าทึ่งที่ การแปลง x86→ARM ทำงานได้ดีขนาดนั้น
มันใช้รีจิสเตอร์ 80 บิต จึงมีความแม่นยำสูงกว่า แต่ก็มีพฤติกรรมประหลาดอย่างเช่นสูญเสียความแม่นยำเมื่อ spill ลงหน่วยความจำ
ตอนก่อนหน้านี้ที่ฉันดีบักซอฟต์แวร์ซินธิไซเซอร์ ก็เคยเจอ บั๊กด้านความแม่นยำ คล้าย ๆ กัน
การจำลองวงจร RC ต้องให้ค่าเข้าใกล้ 0 มากพอถึงจะเปลี่ยนสถานะได้ แต่บน CPU บางตัว ค่า denormal ไม่ถูก flush เลยไม่เข้าเงื่อนไข
ท้ายที่สุดก็ปรับค่า threshold แบบคร่าว ๆ เป็นประมาณ 0.7 กับ 0.01 แล้วมันก็ทำงานได้ดีบนทุกแพลตฟอร์ม
พูดแบบเมตา ๆ หน่อย ฉันกำลังจะทำ ทวิตเตอร์โคลน และคิดจะใส่ฟีเจอร์แบนทันทีถ้าใครโพสต์บล็อกยาวหลายย่อหน้า