การทำนายฝั่งไคลเอ็นต์ทำงานอย่างไร


33

ฉันได้อ่าน Valve + Gafferon และอีกหลายร้อยหน้าจาก Google แต่ด้วยเหตุผลใดก็ตามที่ฉันไม่สามารถคาดเดาลูกค้าได้

เพื่อความเข้าใจของฉันปัญหาพื้นฐานคือ:

  • ลูกค้า A ส่งอินพุตที่ T0
  • เซิร์ฟเวอร์รับอินพุตที่ T1
  • ลูกค้าทั้งหมดได้รับการเปลี่ยนแปลงเวลา T2

T2อย่างไรก็ตามเมื่อใช้การคาดการณ์ของลูกค้าลูกค้า A อยู่ในตำแหน่งที่เหมาะสมT4แล้ว

คุณจะมั่นใจได้อย่างไรว่าลูกค้า A เมื่อคาดการณ์ว่าเซิร์ฟเวอร์จะยอมรับคำขอการเคลื่อนไหวจะไม่นำหน้าเซิร์ฟเวอร์ เห็นได้ชัดว่าทุกครั้งที่พวกเขาอยู่ข้างหน้าผลนี้ในการหักกลับไปที่เซิร์ฟเวอร์ครั้งล่าสุดเห็นพวกเขา ด้วยการแก้ไขทั้งหมดที่ฉันได้ลองสิ่งนี้ยังคงเห็นได้ชัดเจนเมื่อคุณหยุดเพราะเซิร์ฟเวอร์หยุดตามคุณ

คำตอบ:


35

ฉันเขียนบทความเกี่ยวกับเรื่องนี้ มันขึ้นอยู่กับความคิดเดียวกันกับที่คุณอ่านที่อื่น แต่อธิบายอย่างละเอียดและ (ฉันหวังว่า) วิธีที่เข้าถึงได้

โดยเฉพาะอย่างยิ่งบทความเกี่ยวกับการทำนายฝั่งไคลเอ็นต์คือคนนี้


บทความที่ยอดเยี่ยม :-) ฉันชอบที่จะดูส่วนที่สี่ของซีรีส์ เป็นข้อเสนอแนะเล็ก ๆ ลิงก์ไปยังส่วนถัดไปในตอนท้ายของบทความแต่ละบทความจะปรับปรุงการนำทางอย่างแน่นอน
หรือผู้ทำแผนที่

5
@ORMapper - ในที่สุดฉันก็เขียนบทความที่ 4! gabrielgambetta.com/fpm4.html
ggambett

ความรุ่งโรจน์สำหรับซีรี่ส์บทความของคุณ :-) มีประโยชน์มากขอบคุณ :-)
หรือผู้ทำแผนที่

บทความทั้งหมด (ฉันหาได้) ที่พูดถึงการสร้างอดีตโดยใช้สแนปชอตที่เก็บไว้ถ่ายภาพเป็นตัวอย่าง สิ่งนี้ใช้ได้กับการเคลื่อนไหวด้วยหรือไม่? ฉันนึกภาพได้ว่าการกระตุ้นการเคลื่อนไหวอาจทำให้เกิดความแตกต่างใหญ่สำหรับผู้เล่นอื่นหากพวกเขาสามารถปะทะกัน สมมติว่าผู้เล่นสองคนเคลื่อนที่ต่อกันและหนึ่งในนั้นหยุดการขยับ "ขั้นตอน" เพียงไม่กี่จุดจากนั้นจะเป็นจุดปะทะกัน คำสั่งหยุดนี้มาถึงล่าช้าเนื่องจากความล่าช้าดังนั้นหากเราปรับโลกผู้เล่นสองคนจะอยู่ในตำแหน่งที่แตกต่างกันมาก
Lope

นั่นเป็นคำถามที่น่าสนใจ น่าเสียดายที่ฉันไม่มีคำตอบที่ชัดเจน ฉันเดาว่ามันขึ้นอยู่กับว่าการเคลื่อนไหวมีความสำคัญต่อเกมอย่างไร คุณเพิ่งชนคนอื่นและไม่มีอะไรเกิดขึ้น? ในกรณีที่เซิร์ฟเวอร์อาจไม่สนใจก็ถูกมองว่าเป็นความผิดพลาดในการทำนาย (เราทุกคนเห็นว่ามันเกิดขึ้นในจุดที่ทำให้หายใจไม่ออกใช่มั้ย) คุณฆ่าผู้เล่นคนอื่นเมื่อสัมผัสหรือไม่? ในกรณีนี้การทำให้ถูกต้องมีความสำคัญมากกว่าและอาจคุ้มค่ามากขึ้นโปรดทราบว่าในบางจุดคุณจำเป็นต้องทิ้งแพ็กเก็ตบางอันว่าเป็น "เก่าเกินไป" มิฉะนั้นคุณจะต้องปรับขนาดอาจจะเป็น t = 0 ได้ตลอดเวลา
ggambett

4

ฉันยังไม่ได้ใช้งานจริง (ดังนั้นอาจมีปัญหาบางอย่างที่ฉันไม่เห็นทันที) แต่ฉันคิดว่าฉันจะพยายามช่วย

นี่คือสิ่งที่คุณพูดว่าเกิดขึ้น:

ลูกค้า A ส่งอินพุตที่ T0

เซิร์ฟเวอร์รับอินพุตที่ T1

ลูกค้าทั้งหมดได้รับการเปลี่ยนแปลงที่ T2

อย่างไรก็ตามที่ T2 โดยใช้การคาดการณ์ของลูกค้าลูกค้า A อยู่ในตำแหน่งที่เหมาะสมกับ T4

มันอาจจะเป็นประโยชน์ในการคิดในแง่ของเวลาเซิร์ฟเวอร์ (อาจ) คล้ายกันมากกับการแก้ไขการทำงาน

ทุกคำสั่งจะถูกส่งพร้อมกับเวลาของเซิร์ฟเวอร์ เวลาของเซิร์ฟเวอร์นี้จะถูกคำนวณเมื่อเริ่มต้นการแข่งขันโดยการสอบถามการทำเครื่องหมายเซิร์ฟเวอร์และชดเชยเวลา ping ในไคลเอนต์ที่คุณมีจำนวนท้องถิ่นของคุณและแต่ละคำสั่งที่คุณส่งจะถูกแปลงเป็นเห็บเซิร์ฟเวอร์ (เป็นการดำเนินการลบแบบง่าย)

นอกจากนี้ไคลเอนต์มักจะแสดงผล "ในอดีต" ดังนั้นคุณคิดว่าโลกที่ลูกค้าเห็นคือพูดว่าอยู่เบื้องหลัง 100ms เวลาของเซิร์ฟเวอร์จริง ๆ

งั้นลองใช้ตัวอย่างของคุณใหม่กับเวลาเซิร์ฟเวอร์ (กำหนดโดย S)

ไคลเอนต์ส่งอินพุตที่ T0 พร้อมเวลาเซิร์ฟเวอร์ S0 (ซึ่งฉันคาดเดาว่าจริงๆแล้วคือ "การแสดงไคลเอ็นต์ของเวลาเซิร์ฟเวอร์ลบด้วยเวลาการแก้ไข") ลูกค้าไม่รอการตอบสนองจากเซิร์ฟเวอร์และย้ายทันที

เซิร์ฟเวอร์รับอินพุตที่ T1 เซิร์ฟเวอร์คิดออกตำแหน่งที่มีสิทธิ์ของลูกค้าในเวลาเซิร์ฟเวอร์ S0 ที่กำหนดโดยลูกค้า ส่งให้กับลูกค้า

ลูกค้าได้รับตำแหน่งที่เชื่อถือได้ที่ T2 (ยังคงมีการกำหนดเวลาของเซิร์ฟเวอร์ S0) ลูกค้าติดตามมูลค่าเวลาที่ผ่านมาของเหตุการณ์ก่อนหน้า (อาจเป็นเพียงคิวของการทำนายที่ไม่ได้รับการยืนยันทั้งหมด)

หากตำแหน่ง / ความเร็วที่คาดการณ์ / สิ่งที่เซิร์ฟเวอร์ส่งกลับไปที่ S0 นั้นแตกต่างจากสิ่งที่ลูกค้าได้เก็บไว้ที่ S0 ลูกค้าจะจัดการกับสิ่งนี้ ไม่ว่าจะโดยการสลับผู้เล่นกลับไปยังตำแหน่งที่ผ่านมาหรือปรับขนาดอินพุตก่อนหน้าหรืออาจเป็นอย่างอื่นที่ฉันไม่ได้คิด


3
ทุกอย่างถูกต้องยกเว้นบิตเกี่ยวกับการเรนเดอร์ไคลเอ็นต์ในอดีต เมื่อเทียบกับเซิร์ฟเวอร์ลูกค้ากำลังแสดงผลในอนาคต! เซิร์ฟเวอร์รู้ว่าข้อมูลที่ได้จากลูกค้าแต่ละรายนั้นเก่าและลูกค้าแต่ละรายจะมีการเปลี่ยนแปลงตั้งแต่นั้นมา
Kylotan

2

ที่จริงแล้วมีการนำโอเพ่นซอร์สมาใช้ใน GitHub ซึ่งแสดงให้เห็นว่าการดำเนินการนี้เป็นอย่างไร ตรวจสอบLance.gg

repo github: https://github.com/lance-gg/lance

โค้ดการทำนายไคลเอ็นต์ถูกนำไปใช้ในโมดูลที่ชื่อ src/syncStrategies/ExtrapolateStrategy.js

นอกจากการคาดการณ์มีสองแนวคิดที่ฉันไม่ได้เห็นดังกล่าวข้างต้นคือ:

  1. การดัดแบบเพิ่ม โดยทั่วไปแทนที่จะใช้การแก้ไขเซิร์ฟเวอร์ทั้งหมดในครั้งเดียวให้คุณใช้เดลต้าทีละน้อย ด้วยวิธีการนี้วัตถุระยะไกลจะค่อยๆปรับตำแหน่งของตนให้ตรงกับตำแหน่งเซิร์ฟเวอร์ มีตำแหน่งดัดความเร็วดัดมุมดัดและความเร็วเชิงมุมดัด นอกจากนี้คุณอาจต้องการปัจจัยการดัดที่แตกต่างกันสำหรับวัตถุที่แตกต่างกัน
  2. ขั้นตอนการออกกฎหมายอีกครั้ง ข้อเท็จจริงที่ว่าข้อมูลในอดีตหมายความว่าคุณสามารถย้อนเวลาเป็นเวลาข้อมูลเซิร์ฟเวอร์และรีสตาร์ทจากจุดนั้น แน่นอนคุณจะต้องโค้งงอไปยังตำแหน่งที่พบใหม่แทนที่จะข้ามไปที่ตำแหน่งนั้น

1

ลูกค้า A อยู่ข้างหน้าเซิร์ฟเวอร์เสมอ - แต่มันไม่สำคัญ คุณจะต้อง snap ลูกค้ากลับมาอีกครั้งหากเซิร์ฟเวอร์แจ้งว่ามีปัญหาเกี่ยวกับตำแหน่งที่รายงาน ณ จุดนี้ลูกค้าจะทำการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นใหม่เนื่องจากข้อผิดพลาดกับค่าที่แก้ไขแล้วเพื่อให้เข้ากันได้กับสถานะ กับเซิร์ฟเวอร์

ในการทำเช่นนี้ลูกค้าจำเป็นต้องจดจำการอัพเดตที่ผ่านมาและการอัพเดทที่ผ่านมา นี่อาจเป็นเพียงค่าง่ายๆไม่กี่อย่างเช่นตำแหน่ง, ความเร็ว, ทิศทาง, สิ่งนั้น เซิร์ฟเวอร์จะส่งการตอบรับเป็นระยะ ๆ ว่าการอัพเดทไคลเอนต์ต่างๆนั้นถูกต้องซึ่งหมายความว่าพวกเขาสามารถถูกลืมได้จากลูกค้า หากเซิร์ฟเวอร์รายงานว่าการอัพเดทไม่ถูกต้องสถานะไคลเอนต์จะย้อนกลับไปยังจุดนั้นและการเปลี่ยนแปลงในอนาคตจะถูกนำไปใช้กับสถานะที่แก้ไขนั้น

มีลิงก์พิเศษบางส่วนที่ด้านล่างของบทความ Valve ที่ควรค่าแก่การอ่าน - นี่คือหนึ่งในนั้น: https://developer.valvesoftware.com/wiki/Prediction


ดังนั้นฉันขวาในการคิดว่าลูกค้า (at t=4) ได้รับข้อมูลเกี่ยวกับการt=2จึงรีเซ็ตรัฐt=2แล้วการอัปเดตใหม่วิ่งที่จะนำวัตถุจากt=2ไปt=4?
George Duckett

ฉันยังไม่เข้าใจด้วยเหตุผลบางอย่าง เซิร์ฟเวอร์ไม่ได้รับการบอกตำแหน่งของผู้เล่นเฉพาะอินพุตเท่านั้น ดังนั้นผู้เล่นจะย้ายจากตำแหน่งสุดท้ายที่เซิร์ฟเวอร์บอกว่ามันเป็นที่ อินพุตถูกนำไปใช้ แจ้งเซิร์ฟเวอร์ เซิร์ฟเวอร์ยืนยันอินพุตให้ทุกคน สมมติว่ายอมรับคำสั่งทั้งหมดเซิร์ฟเวอร์จะยังคงอยู่หลังไคลเอ็นต์ A - ดังนั้นเมื่อไคลเอ็นต์ A หยุดอักขระของมันจะหยุดทันทีจากนั้นเลื่อนกลับไปที่ตำแหน่งเซิร์ฟเวอร์เมื่อได้รับการยืนยันการหยุด
Chris Evans

@GeorgeDuckett: ใช่ (แม้ว่าจะไม่จำเป็นต้องเป็น t = 4 แต่ก็อาจเป็นได้ทุกครั้งที่ตรวจพบความคลาดเคลื่อนและอาจมีการอัปเดตจำนวนมากที่นำไปใช้อีกครั้ง)
Kylotan

@ChrisEvans: สถานะที่เป็นที่รู้จัก + การเปลี่ยนแปลงโดยอิงจากอินพุตนั้นเทียบเท่ากับสถานะการส่งต่อไป สำหรับตัวอย่างการหยุดนั้นในตัวมันเองเป็นอินพุตและเซิร์ฟเวอร์ยังคงจำลองการเคลื่อนไหวจนกว่าจะได้รับอินพุตนั้น สมมติว่าเวลาแฝงคงที่เซิร์ฟเวอร์จะหยุดผู้เล่นเคลื่อนที่ในตำแหน่งเดียวกับที่ลูกค้าเห็นเมื่อเขาหยุดเคลื่อนไหวเนื่องจากลูกค้าอยู่ข้างหน้าเซิร์ฟเวอร์ (ในโลกแห่งความเป็นจริงความล่าช้าอาจแตกต่างกันดังนั้นคุณต้องแก้ไขเล็กน้อยเพื่อทำให้มันราบรื่น)
Kylotan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.