Đồng bộ hóa máy khách lưu lượng truy cập thấp với máy chủ trong MMO


22

Tôi đang triển khai MMO nơi người chơi bay vào vũ trụ trên con tàu không gian của mình điều khiển nó bằng các phím mũi tên và hợp tác với những người chơi khác.

Tôi muốn triển khai nó để người chơi có thể tránh tàu của mình khỏi tên lửa hoặc thứ gì khác, vì vậy tôi đang cố gắng dự đoán toàn bộ trạng thái trò chơi ở phía máy khách bằng thuật toán mô phỏng thế giới giống như sử dụng máy chủ. Thế giới trò chơi đó được viết trên C # và sẽ được gọi trực tiếp trong máy khách (nó được viết trên Unity3D) và thông qua CLR trên máy chủ C ++ (trong Linux). Kết nối thông qua UDP.

Vấn đề là làm thế nào để duy trì, ví dụ, 1000 người chơi trong một bản đồ (loại trừ tất cả các đối tượng trò chơi khác, mob ...): Hãy nói rằng tôi sẽ:

  • đồng bộ hóa máy chủ với khách hàng 50 lần mỗi giây
  • gửi cho mỗi trạng thái khách hàng của chính các đối tượng trò chơi đó (và người chơi) mà anh ta có thể nhìn thấy (trong một số bán kính)
  • phải gửi 100 đối tượng cho mỗi người chơi trong bán kính xem của mình
  • phải gửi trung bình 50 byte cho mỗi đối tượng trò chơi (đó là id, x, y coords, rotation, state ...)

vì vậy, nó sẽ cần phải có băng thông mạng như vậy: 1000 (máy khách) * 50 (lần mỗi giây) * 100 (đối tượng để gửi cho mỗi người chơi) * 50 (byte mỗi đối tượng) = 250 000 000 byte mỗi giây! Điều đó là không thể!

Có thể giảm giá trị này bằng cách nào đó? Ví dụ: để khách hàng mô phỏng hoàn toàn thế giới trò chơi của họ (trong một khoảng thời gian dài) và gửi cho họ chỉ là đầu vào của các khách hàng khác và đồng bộ hóa thế giới trò chơi, giả sử, cứ sau vài giây, nó sẽ gây ra các vấn đề đồng bộ hóa kỳ lạ khi xích vì tính toán nổi .

Dù sao, làm thế nào các trò chơi như vậy được lập trình theo cách phổ biến? Cảm ơn bạn.


1
Tôi chỉ gửi thông tin logic về các đối tượng (vị trí của thế giới, trạng thái hiện tại (là một byte), v.v.) - không có đồ họa.
Slav

1
@Slav: Đẹp quá! Tất cả sự thay đổi bit đó nhắc nhở tôi về những ngày lập trình ASM của tôi.
Randolf Richardson

1
Tại sao không "ngày hôm nay"? :) Khi tôi viết trên AS3, Java, Lua, C # và đối mặt với hiệu suất kém như vậy, tôi nhớ C ++ và nhớ về ASM.
Slav

1
@Slav: Heheh, tôi đã không thực hiện nhiều ASM gần đây. Hầu hết mọi thứ đối với tôi là ở Java và Perl (chủ yếu là mod_perl2), nhưng tôi cũng rất thích những ngôn ngữ này.
Randolf Richardson

2
@Slav, bạn đã viết: "Khi tôi viết trên AS3, Java, Lua, C # và đối mặt với hiệu suất kém như vậy, tôi nhớ C ++ và nhớ về ASM". Bạn nên tìm hiểu cách sử dụng Lua và C # đúng cách, có thể bạn sẽ thấy hiệu suất ít tệ hơn. Ngoài ra, phàn nàn về ngôn ngữ kịch bản nhanh nhất (được cho là) ngoài kia là tốt nhất ... Đây có phải là một trò chơi về phân tích bộ gen người thời gian thực?
Raine

Câu trả lời:


20

Bạn chỉ cần khoảng 30 cập nhật (hoặc thậm chí ít hơn có thể 10 hoặc 20) mỗi giây. nội suy các vị trí của đối tượng di chuyển phía khách hàng. Nói chung, bạn chỉ nên gửi dữ liệu khi thực sự cần thiết. Trong WoW, bạn có thể nhận được nhiều cập nhật hơn từ những người chơi mà bạn ở trong một nhóm so với những người chơi ở cùng địa điểm. Ngoài ra, nếu một người chơi khác ở xa bạn, bạn sẽ không nhận được nhiều cập nhật mỗi giây về anh ta.

Sau đó, chỉ gửi một ảnh chụp nhanh hoàn chỉnh cho mỗi người chơi khi anh ta kết nối. Sau đó chỉ gửi những thay đổi của các đối tượng trò chơi. Nếu không có thay đổi xảy ra, đừng gửi nó.

Sau đó, hãy sử dụng BitVector thật nhiều hoặc tuy nhiên bạn có thể gọi cho họ để giảm lượng dữ liệu không cần thiết! Ví dụ: Bạn cũng có thể thử viết một float chỉ bằng một byte (trong phạm vi từ 0 đến 1 hoặc -1 đến 1) để bạn chỉ có 256 hoặc 128 giá trị khác nhau. Nhưng người chơi sẽ không nhận thấy bất kỳ chuyển động giật nào nhờ vào các phép nội suy.

Hãy xem ví dụ này với LidgrenL Library về cách nén dữ liệu: http://code.google.com.vn/p/lidgren-network-gen3/wiki/Optimization

Tiếp theo: Cố gắng giảm bán kính xem của người chơi khi họ di chuyển và chỉ truyền thông tin quan trọng trong thời gian đó. Sau đó, khi họ dừng tăng bán kính xem của họ một lần nữa. Bạn có thể sử dụng hệ thống băm không gian hoặc cây bsp để giảm chi phí tìm kiếm các đối tượng "trong phạm vi". Đây là một bài đọc tốt cho chủ đề: http://en.wikipedia.org/wiki/Collision_detection

Cũng nén dữ liệu YOURSELF chỉ có bạn biết về cấu trúc dữ liệu và sự kết hợp thời trong dữ liệu (có thể và nên được khai thác). Một thuật toán chung như Bzip2, Deflate, bất cứ điều gì, nên được sử dụng, nhưng chỉ là giai đoạn nén cuối cùng!

Ngoài ra, đối với thông tin không quan trọng trong trò chơi, bạn cũng có thể sử dụng các kỹ thuật P2P bổ sung. Ví dụ: Một người chơi phát hình động "xin chào". (Chỉ là hiệu ứng đồ họa) Người chơi gửi thông tin này đến máy chủ, nhưng máy chủ không chuyển thông tin đến những người chơi khác. Thay vào đó, hiệu ứng không quan trọng này được gửi bởi chính người chơi đến các máy khách khác trong phạm vi.

EDIT (vì nhận xét):

Các phương pháp bổ sung để giảm số bit trung bình mỗi giây cho mỗi người chơi:

  1. Bạn đã viết rằng bạn gửi "Đối tượng không thay đổi". Không có lý do để làm điều này. Nếu bạn lo lắng về việc mất gói (và không đồng bộ hóa mô phỏng vì điều này), hãy xem xét các vấn đề sau: Tại mỗi dấu thời gian cố định (ví dụ: 100, 200, 300, 400 ...) hãy băm trạng thái mô phỏng và gửi nó đến máy chủ . máy chủ xác nhận hoặc gửi một ảnh chụp nhanh hoàn chỉnh tất cả dữ liệu trở lại.

  2. Đối với những thứ như tên lửa hoặc thậm chí người chơi, bạn có thể sử dụng không chỉ nội suy mà còn ngoại suy để làm cho mô phỏng thực tế hơn. Ví dụ 'Rocket': Thay vì cập nhật với các tin nhắn như "Hiện đang ở vị trí x", chỉ gửi tin nhắn một lần có chứa thông tin sau: "Rocket Spawned: vị trí (vectơ), Thời gian (tại đó bước mô phỏng tên lửa được sinh ra), vận tốc ( vectơ) ". Vì vậy, bạn thậm chí không phải bao gồm vòng quay vì đầu sẽ luôn theo hướng "vận tốc".

  3. Kết hợp nhiều lệnh trong một tin nhắn và không bao giờ gửi tin nhắn nhỏ hơn 16-20byte vì tiêu đề udp sẽ lớn hơn chính tin nhắn. Cũng không gửi các gói lớn hơn MTU của giao thức của bạn vì phân mảnh sẽ làm chậm tốc độ truyền.


Ồ, đó là một ý tưởng tốt để cập nhật một số đối tượng thường xuyên hơn các đối tượng khác, sử dụng P2P, làm giảm độ chính xác của dấu phẩy động, chỉ gửi các thay đổi (điều này không tầm thường đối với tôi vì tôi dự định đồng bộ hóa các đối tượng theo định kỳ nhưng "đối tượng không thay đổi" là thông tin quá). Với tất cả những sửa đổi, toàn bộ bức tranh trông thực tế hơn!
Slav

1
Gửi thông báo loại "đối tượng không thay đổi" có thể là một kỹ thuật hữu ích cho mục đích thử nghiệm, nơi bạn muốn xem trò chơi của mình hoạt động như thế nào khi người chơi bận rộn vì nó có khả năng đưa ra yêu cầu xử lý cũng như mạng, nhưng vẫn còn những giải pháp tốt hơn thế này (chẳng hạn như tạo một daemon độc lập điều khiển một nhân vật trong trò chơi thực tế, sau đó chạy deamon đó nhiều lần từ các máy khác nhau).
Randolf Richardson

5

Đây là hai cách tiếp cận:

Đầu tiên:
Chuyển sang vật lý xác định, gửi lệnh của người chơi, ai hành động, đối tượng xuất hiện và bất cứ điều gì không thể được xác định phía khách hàng cho khách hàng. Điều này phải bao gồm các lệnh không, một xác nhận rằng đến một thời điểm nhất định không có gì ngoài các lệnh đã được gửi và nhận được áp dụng.

Máy khách phải chạy hai hoặc ba mô phỏng đồng thời.
1: Dừng bất cứ khi nào thiếu dữ liệu cho bước tiếp theo.
2: Tiếp tục sử dụng dữ liệu đoán và cung cấp trạng thái được sử dụng để kết xuất. 3: Bất cứ khi nào số 1 dừng lại, mô phỏng này sẽ sao chép trạng thái của số 1, theo kịp thời điểm hiện tại và tiếp quản số 2, sau đó bị loại bỏ.

Nếu bắt kịp đủ nhanh, bạn có thể bỏ qua khác nhau giữa không 2 và 3 và chỉ cần bỏ dữ liệu cũ ngay lập tức.

Thứ hai:
Không sử dụng vật lý xác định, thực hiện tương tự như trên, nhưng gửi "khung hình đầy đủ" cứ sau vài giây. Bạn có thể dễ dàng hoàn toàn rời khỏi việc chuyển những thứ tạm thời như đạn.

Trong cả hai trường hợp, bạn có thể muốn cảnh giác về việc khách hàng dự đoán bất kỳ ai sẽ chết, thật là ngớ ngẩn khi thấy một đối thủ không giải thích được.

Và +1 để làm toán, quá nhiều người không thực hiện được ước tính sử dụng tài nguyên đơn giản.


2
"Vật lý xác định" có nghĩa là tôi không thể sử dụng các giá trị dấu phẩy động hoặc các bước mô phỏng khác nhau? Tôi tự hỏi rằng việc đồng bộ hóa quan trọng có thể xảy ra nếu, ví dụ, tên lửa sẽ vượt qua một tháp pháo của kẻ thù trên máy khách nhưng sẽ tấn công nó trên máy chủ (vì một số điểm không chính xác) sẽ khiến người chơi tiếp tục chiến đấu với tháp pháo cho đến khi gói đồng bộ hóa của máy chủ tiếp theo (vài giây).
Slav

3
Nó có nghĩa là số nguyên và bước thời gian cố định. Về mặt lý thuyết bạn có thể giả định các điểm nổi để hành xử, nhưng sử dụng số nguyên thì đơn giản hơn nhiều. Bạn đã có một điểm với ví dụ về tên lửa bị mất, nếu bạn sử dụng vật lý không xác định, có lẽ tốt nhất là để máy chủ xử lý hoàn toàn cái chết và truyền nhanh các trường hợp tử vong / hủy diệt.
aaaaaaaaaaaa

5

Vài câu hỏi đầu tiên.

Là 'tên lửa hoặc thứ gì khác' thông minh hay ngu ngốc? Nếu họ câm tất cả những gì bạn cần là dấu thời gian của lửa, nguồn gốc và vectơ để mô phỏng đường đi của họ. Nếu họ thông minh thì họ thông minh đến mức nào? Bạn có thể tính toán tại thời điểm hỏa hoạn mà họ sẽ bắn hoặc bỏ lỡ không? Nếu vậy bạn có thể mô phỏng toàn bộ đường dẫn trên máy khách. ("Tại T13, tên lửa sẽ tấn công con tàu vì vở kịch bị mất cuộn tránh / người bắn đã ghi được một đòn chí mạng.")

Nói chung, mặc dù không có nhiều lý do để: A) có tốc độ xung nhịp 50Hz, (Hầu hết các game bắn súng đều giảm đi với 15-20 và MMO ít hơn thế.) B) gửi toàn bộ trạng thái mỗi khung hình. (Việc quay vòng của một tên lửa trong không gian có vấn đề gì không? Hoặc bạn có thể cho rằng đó là 'mặt trước' được định hướng dọc theo vectơ mà nó đang di chuyển không?)

Dành thời gian với dự đoán và nội suy, và bạn sẽ thấy băng thông của mình giảm mạnh. Một dự án tôi đã làm việc có tốc độ cập nhật 10Hz và đại diện trạng thái đối tượng của tôi nghĩ là 14 byte. (Nén tất cả mọi thứ bạn có thể! Tôi tin rằng chúng tôi đã sử dụng 6 bit để xác định góc quay quanh mặt phẳng x và sau đó là 6 bit khác cho độ nghiêng trên / dưới mặt phẳng đó, nó trông không thể phân biệt được với việc gửi ma trận / bậc bốn thực tế.)

Một điều bạn có thể làm là ưu tiên các đối tượng. Hiển thị, có thể có 100 đối tượng trong tập hợp có liên quan, nhưng bạn có biết quan điểm của anh ấy trên máy chủ không? Nếu một cái gì đó không nằm trong tầm nhìn của anh ấy, bạn có thể giảm tần suất cập nhật theo một độ lớn không?

Ý tưởng chung không phải là tạo ra một mô phỏng hoàn hảo trên máy khách, điều đó là không thể, ý tưởng là tạo ra một trò chơi thú vị mà người chơi sẽ không nhận thấy rằng đó không phải là một mô phỏng hoàn hảo.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.