การซิงก์ไคลเอนต์ปริมาณการใช้งานต่ำกับเซิร์ฟเวอร์ใน MMO


22

ฉันใช้ MMO ที่ผู้เล่นบินไปในอวกาศบนยานอวกาศของเขาควบคุมด้วยปุ่มลูกศรและร่วมมือกับผู้เล่นคนอื่น ๆ

ฉันต้องการใช้มันเพื่อให้ผู้เล่นสามารถหลบเรือของเขาจากจรวดหรืออย่างอื่นดังนั้นฉันจึงพยายามทำนายสถานะเกมทั้งหมดในฝั่งไคลเอ็นต์โดยใช้อัลกอริทึมจำลองโลกแบบเดียวกับการใช้เซิร์ฟเวอร์ โลกของเกมนั้นเขียนขึ้นบน C # และจะถูกเรียกภายในไคลเอนต์โดยตรง (มันเขียนบน Unity3D) และผ่าน CLR บนเซิร์ฟเวอร์ C ++ (ภายใต้ Linux) การเชื่อมต่อผ่าน UDP

ปัญหาคือวิธีการดูแลรักษาผู้เล่น 1,000 คนในแผนที่เดียว (ไม่รวมวัตถุเกมอื่น ๆ mobs ... ): สมมติว่าฉันจะ:

  • ซิงโครไนซ์เซิร์ฟเวอร์กับไคลเอนต์ 50 ครั้งต่อวินาที
  • ส่งไปยังแต่ละไคลเอนต์ของวัตถุเกม (และผู้เล่น) ซึ่งเขาสามารถมองเห็นได้ (ภายในรัศมี)
  • ต้องส่ง 100 วัตถุไปยังผู้เล่นแต่ละคนภายในรัศมีมุมมองของเขา
  • จะต้องส่งค่าเฉลี่ย 50 ไบต์ต่อวัตถุเกม (มันเป็นรหัส, x, y coords, การหมุน, สถานะ ... )

ดังนั้นมันจะต้องมีเครือข่ายแบนด์วิดท์เช่น: 1,000 (ไคลเอนต์) * 50 (ครั้งต่อวินาที) * 100 (วัตถุที่ส่งไปยังผู้เล่นแต่ละคน) * 50 (ไบต์ต่อวัตถุ) = 250 000 000 ไบต์ต่อวินาที! มันเป็นไปไม่ได้!

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

อย่างไรก็ตามมีการตั้งโปรแกรมเกมดังกล่าวในลักษณะทั่วไปอย่างไร? ขอขอบคุณ.


1
ฉันส่งข้อมูลเชิงตรรกะเกี่ยวกับวัตถุ (ตำแหน่งโลกสถานะปัจจุบัน (ซึ่งเป็นหนึ่งไบต์) และอื่น ๆ ) - ไม่มีกราฟิก
ชาวสลาฟ

1
@Slav: ดี! การขยับบิตนั้นทำให้ฉันนึกถึงวันที่เขียนโปรแกรม ASM ของฉัน
Randolf Richardson

1
ทำไมไม่ "วันนี้วัน"? :) เมื่อฉันเขียน AS3, Java, Lua, C # และเผชิญกับประสิทธิภาพที่แย่เช่นนั้นฉันคิดถึง C ++ และจดจำเกี่ยวกับ ASM
ชาวสลาฟ

1
@Slav: Heheh ฉันไม่ได้ทำ ASM มากเมื่อเร็ว ๆ นี้ สิ่งส่วนใหญ่สำหรับฉันอยู่ใน Java และ Perl (mod_perl2 ส่วนใหญ่) วันนี้ แต่ฉันก็สนุกกับภาษาเหล่านี้ด้วยเช่นกัน
Randolf Richardson

2
@Slav คุณเขียนว่า: "เมื่อฉันเขียน AS3, Java, Lua, C # และพบกับประสิทธิภาพที่แย่เช่นนี้ฉันคิดถึง C ++ และจดจำเกี่ยวกับ ASM" คุณควรเรียนรู้วิธีการใช้ Lua และ C # อย่างถูกต้องบางทีคุณอาจพบว่าประสิทธิภาพการใช้งานต่ำลง นอกจากนี้การบ่นเกี่ยวกับภาษาสคริปต์ที่เร็วที่สุด (ที่ถูกกล่าวหา) นั้นมีเอกพจน์ที่ดีที่สุด ... นี่เป็นเกมเกี่ยวกับการวิเคราะห์จีโนมมนุษย์แบบเรียลไทม์หรือไม่?
เรน

คำตอบ:


20

คุณต้องการการอัพเดตประมาณ 30 ครั้ง (หรืออาจน้อยกว่า 10 หรือ 20) ต่อวินาที สอดแทรกตำแหน่งของการเคลื่อนย้าย objectts ฝั่งไคลเอ็นต์ โดยทั่วไปคุณควรส่งข้อมูลเมื่อจำเป็นจริงๆเท่านั้น ใน WoW คุณอาจได้รับการอัปเดตเพิ่มเติมจากผู้เล่นที่คุณอยู่ในกลุ่มที่มีมากกว่าจากผู้เล่นที่อยู่ในสถานที่เดียวกัน นอกจากนี้หากผู้เล่นอื่นอยู่ห่างจากคุณคุณจะไม่ได้รับการอัปเดตเกี่ยวกับเขาต่อวินาทีมากนัก

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

จากนั้นใช้ประโยชน์จาก BitVectors อย่างหนักหรือคุณอาจเรียกมันว่าอะไรก็ตามเพื่อลดปริมาณข้อมูลที่ไม่จำเป็น! ตัวอย่าง: คุณยังสามารถลองเขียน float โดยใช้เพียงหนึ่งไบต์ (ในช่วงตั้งแต่ 0 ถึง 1 หรือ -1 ถึง 1) ดังนั้นคุณจึงมีค่าต่างกัน 256 หรือ 128 เท่านั้น แต่ผู้เล่นจะไม่สังเกตเห็นการเคลื่อนไหวกระตุกเนื่องจากการแก้ไข

ดูตัวอย่างนี้กับ LidgrenLibrary เกี่ยวกับวิธีบีบอัดข้อมูล: http://code.google.com/p/lidgren-network-gen3/wiki/Optimization

ถัดไป: ลองลดรัศมีการดูของผู้เล่นขณะที่เคลื่อนที่และส่งเฉพาะข้อมูลสำคัญในเวลานั้น จากนั้นเมื่อพวกเขาหยุดเพิ่มรัศมีการมองของพวกเขาอีกครั้ง คุณสามารถใช้ระบบแฮชเชิงพื้นที่หรือต้นไม้ bsp เพื่อลดค่าใช้จ่ายในการค้นหาวัตถุที่ "อยู่ในช่วง" นี่เป็นการอ่านที่ดีสำหรับหัวข้อ: http://en.wikipedia.org/wiki/Collision_detection

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

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

แก้ไข (เพราะความคิดเห็น):

วิธีการเพิ่มเติมเพื่อลดจำนวนบิตเฉลี่ยต่อวินาทีให้กับผู้เล่นแต่ละคน:

  1. คุณเขียนว่าคุณส่ง "วัตถุไม่เปลี่ยนแปลง" ไม่มีเหตุผลที่จะทำเช่นนี้ หากคุณกังวลเกี่ยวกับการสูญหายของแพ็กเก็ต (และทำให้การจำลองของคุณไม่ตรงกันเนื่องจากสิ่งนี้) ให้พิจารณาสิ่งต่อไปนี้: ในแต่ละการประทับเวลาคงที่ (เช่น 100, 200, 300, 400 ... ) แฮชสถานะจำลองและส่งไปยังเซิร์ฟเวอร์ . เซิร์ฟเวอร์ยืนยันหรือส่งสแน็ปช็อตที่สมบูรณ์ของข้อมูลทั้งหมดกลับ

  2. สำหรับสิ่งต่าง ๆ เช่นจรวดหรือแม้แต่ผู้เล่นคุณสามารถใช้การแก้ไขไม่เพียง แต่การประมาณค่า แต่ยังรวมถึงการคาดการณ์เพื่อให้การจำลองสมจริงยิ่งขึ้น ตัวอย่าง 'Rocket': แทนที่จะอัปเดตด้วยข้อความเช่น "ตอนนี้อยู่ที่ตำแหน่ง x" เพียงส่งข้อความเมื่อมีสิ่งต่อไปนี้: "Rocket Spawned: ตำแหน่ง (เวกเตอร์), เวลา (ซึ่งขั้นตอนการจำลองจรวดถูกวางไข่), ความเร็ว ( เวกเตอร์)" ดังนั้นคุณไม่จำเป็นต้องรวมการหมุนเพราะปลายจะอยู่ในทิศทาง "ความเร็ว" เสมอ

  3. รวมหลายคำสั่งในข้อความเดียวและไม่เคยส่งข้อความที่เล็กกว่า 16-20bytes เพราะส่วนหัวของ udp จะใหญ่กว่าตัวข้อความเอง อย่าส่งแพ็กเกจที่ใหญ่กว่า MTU ของโปรโตคอลของคุณเพราะการแตกแฟรกเมนต์จะทำให้ความเร็วในการส่งช้าลง


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

1
การส่งประกาศ "วัตถุไม่เปลี่ยน" อาจเป็นเทคนิคที่มีประโยชน์สำหรับจุดประสงค์ในการทดสอบที่คุณต้องการดูว่าเกมของคุณทำงานอย่างไรเมื่อผู้เล่นเข้ามาในช่วงเวลาที่ยุ่งเพราะมีศักยภาพที่จะทำให้เกิดความต้องการในการประมวลผลเช่นเดียวกับเครือข่าย ยังมีวิธีแก้ปัญหาที่ดีกว่านี้ (เช่นการสร้าง daemon แบบสแตนด์อะโลนที่ควบคุมอักขระในเกมจริงจากนั้นเรียกใช้ deamon หลายครั้งจากเครื่องที่แตกต่างกัน)
Randolf Richardson

5

นี่คือสองวิธี:

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

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

หากการติดตามเร็วพอคุณสามารถปล่อยให้แตกต่างกันระหว่าง no 2 และ no 3 และเพียงแค่ปล่อยข้อมูลเก่าทันที

ที่สอง:
อย่าใช้ฟิสิกส์ที่กำหนดค่าได้ทำแบบเดียวกับข้างบน แต่ส่ง "ฟูลเฟรม" ทุกๆสองสามวินาที คุณสามารถออกจากการถ่ายโอนสิ่งชั่วคราวเช่นกระสุนได้อย่างง่ายดาย

ในทั้งสองกรณีคุณอาจต้องระวังเกี่ยวกับไคลเอนต์ที่ทำนายคนที่กำลังจะตายมันเป็นเรื่องโง่ที่เห็นฝ่ายตรงข้ามไม่ได้อธิบาย

และ +1 สำหรับการทำคณิตศาสตร์คนจำนวนมากเกินไปล้มเหลวในการประเมินการใช้ทรัพยากรอย่างง่าย


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

3
มันหมายถึงจำนวนเต็มและขั้นตอนเวลาคงที่ ในทางทฤษฎีคุณสามารถเยาะเย้ยจุดลอยตัวที่จะประพฤติ แต่ใช้จำนวนเต็มเป็นวิธีที่ง่าย คุณได้รับจุดที่มีตัวอย่างของขีปนาวุธที่หายไปถ้าคุณใช้ฟิสิกส์ที่ไม่ได้กำหนดไว้มันน่าจะดีที่สุดที่จะให้เซิร์ฟเวอร์จัดการกับความตายได้อย่างเต็มที่และส่งกรณีการตาย / การทำลายอย่างรวดเร็ว
aaaaaaaaaaaa

5

ไม่กี่คำถามแรก

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

โดยทั่วไปแม้ว่าจะไม่มีเหตุผลอะไรที่ค่อนข้าง: A) มีอัตราสัญญาณนาฬิกาที่ 50Hz ( นักกีฬาส่วนใหญ่หนีไปด้วย 15-20 และ MMO น้อยกว่านั้น) B) ส่งสถานะเต็มทุกเฟรม (การหมุนของขีปนาวุธในอวกาศมีความสำคัญหรือไม่หรือคุณแค่คิดว่ามันเป็น 'ด้านหน้า' ถูกปรับทิศทางไปตามเวกเตอร์ที่กำลังเคลื่อนที่?)

ใช้เวลาในการทำนายและแก้ไขและคุณจะเห็นแบนด์วิดท์ของคุณดิ่งลง โครงการที่ฉันทำงานมีอัตราการอัปเดตที่ 10Hz และการแทนค่าสถานะวัตถุของฉันคิดว่า 14 ไบต์ (บีบอัดทุกอย่างที่คุณทำได้! ฉันเชื่อว่าเราใช้ 6 บิตในการกำหนดการหมุนรอบระนาบ x จากนั้นอีก 6 บิตสำหรับการเอียงบน / ล่างระนาบนั้นมันดูไม่สามารถแยกแยะได้จากการส่งเมทริกซ์หมุน / quaternion จริง ๆ )

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

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.