Làm cách nào để giữ đồng hồ máy chủ-máy khách không đồng bộ cho các trò chơi được nối mạng chính xác như Quake 3?


15

Tôi đang làm việc trên một game bắn súng từ trên xuống 2D và cố gắng hết sức để sao chép các khái niệm được sử dụng trong các trò chơi nối mạng như Quake 3.

  • Tôi có một máy chủ có thẩm quyền.
  • Máy chủ gửi ảnh chụp nhanh cho khách hàng.
  • Ảnh chụp nhanh chứa dấu thời gian và vị trí thực thể.
  • Các thực thể được nội suy giữa các vị trí chụp nhanh để chuyển động trông trơn tru.
  • Do sự cần thiết, phép nội suy thực thể xảy ra hơi "trong quá khứ" để chúng ta có nhiều ảnh chụp nhanh để nội suy giữa.

Vấn đề tôi gặp phải là "đồng bộ hóa đồng hồ".

  • Để đơn giản, hãy giả vờ một chút rằng không có độ trễ bằng 0 khi chuyển gói đến và từ máy chủ.
  • Nếu đồng hồ máy chủ đi trước 60 giây so với đồng hồ máy khách, thì dấu thời gian chụp nhanh sẽ vượt 60000ms so với dấu thời gian cục bộ của máy khách.
  • Do đó, các ảnh chụp thực thể sẽ thu thập và ngồi trong khoảng 60 giây trước khi khách hàng thấy bất kỳ thực thể cụ thể nào thực hiện các bước di chuyển của mình, bởi vì phải mất nhiều thời gian để đồng hồ khách bắt kịp.

Tôi đã cố gắng khắc phục điều này bằng cách tính toán sự khác biệt giữa đồng hồ máy chủ và máy khách mỗi khi nhận được ảnh chụp nhanh.

// For simplicity, don't worry about latency for now...
client_server_clock_delta = snapshot.server_timestamp - client_timestamp;

Khi xác định khoảng cách nội suy của thực thể là bao xa, tôi chỉ cần thêm sự khác biệt vào thời gian hiện tại của khách hàng. Tuy nhiên, vấn đề với điều này là nó sẽ gây ra hiện tượng giật vì sự khác biệt giữa hai đồng hồ sẽ đột ngột dao động do ảnh chụp nhanh đến / chậm hơn so với các đồng hồ khác.

Làm cách nào tôi có thể đồng bộ hóa các đồng hồ đủ chặt chẽ để độ trễ duy nhất có thể nhận biết được là mã hóa cứng để nội suy và nguyên nhân gây ra bởi độ trễ mạng thông thường?

Nói cách khác, làm thế nào tôi có thể ngăn nội suy bắt đầu quá muộn hoặc quá sớm khi đồng hồ bị đồng bộ hóa đáng kể, mà không gây ra hiện tượng giật?

Chỉnh sửa: Theo Wikipedia , NTP có thể được sử dụng để đồng bộ hóa đồng hồ qua internet trong vòng vài mili giây. Tuy nhiên, giao thức có vẻ phức tạp và có lẽ quá mức cần thiết để sử dụng trong các trò chơi?


nó phức tạp như thế nào Đó là một yêu cầu và trả lời từng dấu thời gian của việc truyền và đến, sau đó là một chút toán học để có được đồng bằng
quái vật ratchet

@ratchetfreak: Theo ( mine-control.com/zack/timesync/timesync.html ), "Thật không may, NTP rất phức tạp và quan trọng hơn là chậm hội tụ trên đồng bằng thời gian chính xác. Điều này làm cho NTP không lý tưởng cho mạng chơi trò chơi trong đó người chơi mong đợi một trò chơi bắt đầu ngay lập tức ... "
Joncom

Câu trả lời:


9

Sau khi tìm kiếm xung quanh, có vẻ như đồng bộ hóa đồng hồ của 2 máy tính trở lên không phải là một việc nhỏ. Một giao thức như NTP thực hiện công việc tốt nhưng được cho là chậm và quá phức tạp để trở nên thiết thực trong các trò chơi. Ngoài ra, nó sử dụng UDP sẽ không hoạt động với tôi vì tôi đang làm việc với các ổ cắm web, không hỗ trợ UDP.

Tôi đã tìm thấy một phương pháp ở đây , tuy nhiên, có vẻ tương đối đơn giản:

Nó tuyên bố sẽ đồng bộ hóa đồng hồ trong vòng 150ms (hoặc tốt hơn) của nhau.

Tôi không biết liệu điều đó có đủ tốt cho mục đích của mình không, nhưng tôi không thể tìm thấy một sự thay thế chính xác hơn.

Đây là thuật toán mà nó cung cấp:

Một kỹ thuật đồng bộ đơn giản là cần thiết cho các trò chơi. Lý tưởng nhất, nó phải có các thuộc tính sau: chính xác hợp lý (150ms hoặc tốt hơn), hội tụ nhanh, đơn giản để thực hiện, có thể chạy trên các giao thức dựa trên luồng như TCP.

Một thuật toán đơn giản với các thuộc tính này như sau:

  1. Máy khách đóng dấu giờ địa phương hiện tại trên gói "yêu cầu thời gian" và gửi đến máy chủ
  2. Khi nhận được bởi máy chủ, máy chủ đóng dấu thời gian máy chủ và trả lại
  3. Khi khách hàng nhận được, khách hàng sẽ trừ thời gian hiện tại khỏi thời gian gửi và chia cho hai để tính độ trễ. Nó trừ thời gian hiện tại từ thời gian máy chủ để xác định delta thời gian của máy khách-máy chủ và thêm vào độ trễ một nửa để có được đồng hồ chính xác. (Cho đến nay algothim này rất giống với SNTP)
  4. Kết quả đầu tiên phải được sử dụng ngay lập tức để cập nhật đồng hồ vì nó sẽ đưa đồng hồ cục bộ vào ít nhất đúng sân bóng (ít nhất là múi giờ phù hợp!)
  5. Khách hàng lặp lại các bước từ 1 đến 3 năm lần trở lên, tạm dừng vài giây mỗi lần. Lưu lượng khác có thể được cho phép trong thời gian tạm thời, nhưng nên được giảm thiểu để có kết quả tốt nhất
  6. Kết quả của các biên lai gói được tích lũy và sắp xếp theo thứ tự độ trễ thấp nhất đến độ trễ cao nhất. Độ trễ trung bình được xác định bằng cách chọn mẫu điểm giữa từ danh sách được sắp xếp này.
  7. Tất cả các mẫu trên độ lệch chuẩn khoảng 1 so với trung vị đều bị loại bỏ và các mẫu còn lại được lấy trung bình bằng trung bình số học.

Sự tinh tế duy nhất của thuật toán này là các gói trên một độ lệch chuẩn trên trung vị bị loại bỏ. Mục đích của việc này là để loại bỏ các gói được truyền lại bởi TCP. Để hình dung điều này, hãy tưởng tượng rằng một mẫu gồm năm gói đã được gửi qua TCP và tình cờ không có sự truyền lại. Trong trường hợp này, biểu đồ độ trễ sẽ có một chế độ (cụm) tập trung xung quanh độ trễ trung bình. Bây giờ hãy tưởng tượng rằng trong một thử nghiệm khác, một gói duy nhất trong số năm được truyền lại. Việc truyền lại sẽ làm cho một mẫu này rơi xa về bên phải trên biểu đồ độ trễ, trung bình gấp đôi so với trung vị của chế độ chính. Bằng cách đơn giản là cắt bỏ tất cả các mẫu rơi ra nhiều hơn một độ lệch chuẩn so với trung vị, các chế độ đi lạc này dễ dàng được loại bỏ khi cho rằng chúng không bao gồm phần lớn các số liệu thống kê.

Giải pháp này xuất hiện để trả lời câu hỏi của tôi một cách thỏa đáng, bởi vì nó đồng bộ hóa đồng hồ và sau đó dừng lại, cho phép thời gian chảy tuyến tính. Trong khi phương pháp ban đầu của tôi cập nhật đồng hồ liên tục, khiến thời gian nhảy xung quanh một chút khi nhận được ảnh chụp nhanh.


Làm thế nào điều này đã chứng minh để làm việc cho bạn sau đó? Tôi đang ở trong tình trạng tương tự bây giờ. Tôi đang sử dụng khung máy chủ chỉ hỗ trợ TCP, do đó tôi không thể sử dụng NTP, nó gửi các datagram UDP. Tôi đấu tranh để tìm bất kỳ Thuật toán đồng bộ hóa thời gian nào tuyên bố sẽ thực hiện đồng bộ hóa thời gian đáng tin cậy qua TCP. Đồng bộ hóa trong vòng một giây sẽ đủ cho nhu cầu của tôi.
điện

@dynamokaj Hoạt động khá tốt.
Joncom

Mát mẻ. Có thể là bạn có thể chia sẻ việc thực hiện?
điện

@dynamokaj Có vẻ như tôi không thể tìm thấy một triển khai như vậy trong bất kỳ dự án nào tôi có thể nghĩ ra ngay bây giờ. Ngoài ra, những gì hoạt động đủ tốt đối với tôi là: 1) ngay lập tức sử dụng độ trễ mà bạn tính toán từ một yêu cầu / phản hồi ping và sau đó, 2) cho tất cả các phản hồi trong tương lai theo hướng dần dần về giá trị mới, không phải ngay lập tức. Điều này có hiệu ứng "trung bình" rất chính xác cho mục đích của tôi.
Joncom

Không vấn đề gì. Tôi đang chạy dịch vụ phụ trợ của mình trên Google App Engine, do đó trên cơ sở hạ tầng của Google, nơi các máy chủ được đồng bộ hóa bằng Google NTP Server: time.google.com ( developers.google.com/time ) Do đó, tôi sử dụng ứng dụng khách NTP sau cho máy khách Xamarin Mobile của mình để có được sự bù đắp giữa máy khách và máy chủ. thành phần.xamarin.com /view/rebex-time - Cảm ơn bạn đã dành thời gian trả lời.
điện

1

Về cơ bản, bạn không thể sửa chữa [toàn bộ] thế giới và cuối cùng, bạn sẽ phải vẽ đường thẳng.

Nếu máy chủ và tất cả các máy khách chia sẻ cùng một tốc độ khung hình, chúng chỉ cần đồng bộ hóa khi kết nối và đôi khi, sau đó, đặc biệt là sau một sự kiện trễ. Độ trễ không ảnh hưởng đến dòng thời gian hoặc khả năng của PC để đo lường nó, trong nhiều trường hợp, thay vì nội suy, bạn phải ngoại suy. Điều này tạo ra các hiệu ứng không mong muốn như nhau, nhưng, một lần nữa, đó là những gì nó là và bạn phải chọn ít nhất trong số các tệ nạn có sẵn.

Hãy xem xét rằng trong nhiều MMO phổ biến, người chơi bị tụt lại là điều hiển nhiên. Nếu bạn thấy chúng chạy tại chỗ, trực tiếp vào tường, khách hàng của bạn đang ngoại suy. Khi khách hàng của bạn nhận được dữ liệu mới, người chơi (trên máy khách của họ) có thể đã di chuyển một khoảng cách đáng kể và sẽ "băng cao su" hoặc dịch chuyển đến một vị trí mới ("độ giật" mà bạn đã đề cập?). Điều này xảy ra ngay cả trong các trò chơi lớn, thương hiệu.

Về mặt kỹ thuật, đây là sự cố với cơ sở hạ tầng mạng của người chơi, không phải trò chơi của bạn. Điểm mà nó đi từ điểm này sang điểm khác là chính đường bạn phải vẽ. Mã của bạn, trên 3 máy tính riêng biệt, ít nhiều sẽ ghi lại cùng một khoảng thời gian đã trôi qua. Nếu bạn không nhận được bản cập nhật, nó sẽ không ảnh hưởng đến tốc độ khung hình Cập nhật () của bạn; nếu có bất cứ điều gì, nó sẽ nhanh hơn vì có lẽ ít cập nhật hơn.

"Nếu bạn có mạng internet khủng khiếp, bạn không thể chơi trò chơi này một cách cạnh tranh."
Đó không phải là lỗi hay lỗi.

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.