ฉันจะกำหนดรหัสเอนทิตีในวิธีที่แข็งแกร่งในเกมเครือข่ายได้อย่างไร


17

ฉันกำลังทำงานกับระบบเอนทิตีสำหรับเกมบนเครือข่ายและฉันกำหนดรหัสประจำตัวจำนวนเต็ม 32 บิตที่ไม่ซ้ำกันซึ่งฉันสามารถใช้เพื่ออ้างอิงการอ้างอิงไปยังเอนทิตีและเอนทิตีเองได้

ขณะนี้ฉันเพิ่งเพิ่มตัวนับทุกครั้งที่มีการสร้างเอนทิตี ฉันเดารหัสในที่สุดจะหมด แต่ฉันไม่คาดหวังว่าจะมี 4 พันล้านหน่วย นอกจากนี้สิ่งนี้จะช่วยหลีกเลี่ยงปัญหาหากเอนทิตี # 5 ถูกทำลายและเราได้รับ id 5 มันหมายถึงการอ้างถึง # 5 ใหม่หรือเก่าที่ถูกลบ # 5 หรือไม่

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

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

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

อีกทางเลือกหนึ่งคือการใช้บางอย่างที่มีโอกาสสูงกว่าในการเป็นเอกลักษณ์เช่น 128- บิต GUID แต่ดูเหมือนว่าหนักมากสำหรับเกมที่พยายามลดปริมาณการใช้เครือข่าย นอกจากนี้ในความเป็นจริงฉันจะไม่ต้องการเอนทิตีเพิ่มเติมในคราวเดียวจากนั้นจะพอดีกับจำนวนเต็ม 32- บิตหรือ 24 บิต

ขอบคุณ!


1
ทำไมลูกค้าทุกคนไม่มีเอนทิตีเดียวกัน ลูกค้าไม่ได้ทำข้อมูลให้ตรงกันหรือไม่? หรือเป็นโลกขนาดใหญ่ที่ลูกค้าไม่ได้เล่นเกมเดียวกันทั้งหมด
ฟิลิป

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

1
ฉันคิดว่าอย่างที่คุณพูดมันควรได้รับการจัดการโดยเซิร์ฟเวอร์เท่านั้นหากเป็นไปได้ในสถาปัตยกรรมของคุณ จากนั้นเก็บรหัสเอนทิตีฟรีที่มีอยู่แยกต่างหากกับรายการ / แผนที่เอนทิตีเพื่อให้คุณรู้ว่ามี ID ใดที่พร้อมใช้งาน การล้มเหลวโมเดลเซิร์ฟเวอร์ที่มีสิทธิ์ดังนั้นวิธีการเรียงลำดับของคุณควรใช้งานได้ในแง่ของช่วง สี่พันล้านนั้นมากแม้ว่าจะแบ่งผู้เล่น 4,000 คนใน MMO จากนั้นใช้วิธีการเดียวกันเพื่อติดตาม ID ที่มีอยู่เช่นเดียวกับการรับรองความถูกต้อง เซิร์ฟเวอร์
วิศวกร

@Lucas ลิงก์ของคุณบอกว่า "เซิร์ฟเวอร์ระบุชุดของนักแสดง" ที่เกี่ยวข้อง "สำหรับลูกค้าแต่ละราย" สิ่งนี้บอกเป็นนัยถึงเซิร์ฟเวอร์รู้เกี่ยวกับเอนทิตีทั้งหมดและอยู่ในฐานะที่จะแจกแจง
Kylotan

1
แน่นอน แต่ถ้าลูกค้าสร้างเอนทิตีใหม่ A แต่ก่อนที่จะได้รับข้อความการสร้างเซิร์ฟเวอร์สร้างเอนทิตีใหม่ B พวกเขาทั้งสองจะได้รับรหัส "ฟรี" เดียวกัน
ลูคัส

คำตอบ:


13

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

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

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


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

สำหรับรหัสเฉพาะลูกค้า (จำเป็นสำหรับการคาดการณ์ในขณะที่รอเซิร์ฟเวอร์) คุณสามารถใช้คำนำหน้าบน id
danijar

6

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

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

แนวทางที่แปลกใหม่น่าจะเป็นข้อความ "Object with GUID 'n' ตอนนี้คือ Object ด้วย GUID 'm'" ข้อความสำหรับทุกวัตถุที่มีอยู่ แต่ในกรณีของฉันมันไม่น่าจะเกิดขึ้นจริงและฉันไม่คิดว่าผู้คนจะนึกถึงวัตถุระยะไกลที่หายไปจากโลกครึ่งวินาทีหลังจากห้าวันไม่หยุดเล่นในเครือข่ายเซสชันเดียว ;)


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

4

หากลูกค้าของคุณสามารถวางไข่เอนทิตีของตัวเองฉันเดาว่าคุณมีเกมแบบผู้เล่นหลายคน

หากเป็นเช่นนั้นคุณอาจมีลูกค้าไม่มากเกินไป ไม่เกิน 256 แน่นอนและรหัสนิติบุคคลของคุณรับประกันว่าจะพอดีกับ 24 บิต (เอนทิตี 16000000+ นั้นเพียงพอสำหรับทุกคน!) ดังนั้นเพียงทำให้ไบต์สูงสุดของ ID ของคุณเท่ากับ id ของลูกค้า

entityId = clientId<<24 + (maxEntityIn++)

หรือบางสิ่งบางอย่าง.

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


1

ฉันใช้วิธี 'ไร้เดียงสาที่สุด' (เพิ่มจำนวนเต็มสำหรับแต่ละ ID ใหม่) ในเกมที่มีผู้เล่นหลายคนแบบถาวรและทำงานได้ดีเพราะฉันไม่อนุญาตให้ลูกค้าสร้าง ID ใหม่

ถ้าคุณปล่อยให้ลูกค้าตัดสินใจ (โดยใช้เทคนิคการจัดเรียงของ GUID อธิบาย) ลูกค้ายังสามารถแนะนำข้อบกพร่องต่าง ๆ ด้วยการกำหนด Old ID ให้กับรายการใหม่ อาจมีช่องโหว่อื่น ๆ โหลด)

เหมือนอย่างเคย, เพื่อป้องกันการโกงเซิร์ฟเวอร์ควรทำการสร้างและตรวจสอบความถูกต้องทั้งหมด

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