Jak zsynchronizować zegary przez sieć do tworzenia gier?

10

Piszę grę, która ma wiele aspektów czasu. Korzystam z czasu, aby pomóc oszacować pozycje graczy, gdy sieć nie zatrzymuje się i pakiety nie przechodzą (i czas między otrzymaniem pakietu a jego brakiem). Jest to gra typu pacman, w tym sensie, że gracz wybiera kierunek i nie może przestać się poruszać, więc system ma sens (a przynajmniej tak mi się wydaje).

Mam więc dwa pytania: 1) Jak zsynchronizować zegary gier na początku, ponieważ w sieci występuje opóźnienie. 2) Czy jest w porządku NIE synchronizować ich i po prostu założyć, że są takie same (mój kod jest niezależny od strefy czasowej). To nie jest super konkurencyjna gra, w której ludzie zmieniają swoje zegary, aby oszukiwać, ale nadal.

Gra jest programowana w Javie i Pythonie (równoległe tworzenie jako projekt)

sinθ
źródło
7
look up ntp
ratchet freak
5
Jestem pewien, że to pytanie jest już zawarte na stronie gamedev.stackexchange.com, a przynajmniej tam należy.
congusbongus
1
@CongXu: Nie jestem tego taki pewien. Chociaż jest to zwykle wykonywane w przypadku gier, nie jest ono ściśle związane z tworzeniem gier. Wiele innych systemów rozproszonych wymaga zsynchronizowanego zegara.
Jan Hudec
2
Czy próbowałeś już użyć opcji TIMESTAMP IPv4? Więcej informacji znajduje się na linux.die.net/man/7/socket stamtąd do linux.die.net/man/3/cmsg, a następnie mały przykładowy program na pdbuchan.com/rawsock/rawsock.html ostatni przed Sekcja IPv6.
ott--
2
Gry (aplikacje) nie powinny dotykać zegara systemowego.
Przywróć Monikę - M. Schröder

Odpowiedzi:

9

Myślę, że to na pewno nie OK synchornize zegara w systemie . Użytkownik nie oczekuje, że dotkniesz ustawień systemu, a wiele systemów nawet na to nie pozwala.

Wystarczy mieć korelację, aby przekonwertować znacznik czasu z zegara jednej strony na zegar drugiej strony. Z drugiej strony potrzebujesz, aby ta korelacja była dość precyzyjna, powiedzmy co najmniej do setnej sekundy, jeśli chcesz użyć jej do przewidywania pozycji graczy. Zegar systemowy nigdy nie będzie tak dobrze skorelowany między losowymi maszynami. Dlatego powinieneś sam ustalić korelację, używając pewnej odmiany motywu NTP , prawdopodobnie osadzonej w innych wiadomościach w celu zachowania przepustowości sieci.

Podstawową ideą może być to, że z każdym wysłanym pakietem wysyłany jest znacznik czasu oraz numer sekwencji i znacznik czasu, gdy otrzymałeś ostatni pakiet z drugiej strony. Na tej podstawie obliczasz objazd: Na przykład, jeśli pakiet Q mówi, że został wysłany o wartości 1000, a pakiet P został odebrany o wartości 500, niż biorąc pod uwagę, że wysłałeś pakiet P o wartości 0 i otrzymujesz Q o wartości 800, podróż w obie strony wynosi (800 - 0 ) - (1000 - 500) = 300. Nie ma sposobu na poznanie asymetrii, więc po prostu zakładasz, że pakiet zabiera połowę (150) tyknięć w dowolnym kierunku. I ten zdalny znacznik czasu wyprzedza lokalny o 1000 - (800 - 150) = 350 tyknięć. Podróż w obie strony będzie się różnić. Jeśli przyjmiesz, że zegar jest dość precyzyjny, powinieneś użyć długoterminowej średniej korelacji.

Zauważ, że nie chcesz również używać zegara systemowego dla zegara. Mogą zostać zsynchronizowane w połowie drogi, co zepchnie cię z toru. Powinieneś używać clock(CLOCK_MONOTONIC)na Unixie lub GetTickCountWindowsie (nie jestem pewien, jak te interfejsy API są teraz opakowane w Javie lub Pythonie).


Uwaga: Opcja SO_TIMESTAMPgniazda (patrz gniazdo (7) wspomniane przez ott - w komentarzu do pytania) byłaby przydatna do oddzielenia efektu opóźnienia pętli zdarzeń, która odbiera pakiety. To, czy warto wysiłek, zależy od tego, jak dobrej precyzji potrzebujesz.

Jan Hudec
źródło
1

Skąd wiesz, który zegar gracza jest prawidłowy? Nie, więc użyj zegara referencyjnego .

NTP jest tutaj przesadą - potrzebujesz tylko ~ 1 sekundy dokładności - więc użyj rdate lub wybierz coś z jednego z wielu algorytmów synchronizacji zegara.

Po wybraniu metody spraw, aby maszyna każdego gracza wybrała czas dla tej metody (bez zmiany zegara systemowego). Niezależnie od tego, jaka jest różnica między referencyjnym czasem UTC a zegarem systemowym graczy w czasie UTC, ich efektywne przesunięcie. Za każdym razem, gdy wykonujesz obliczenia związane z czasem, np. Ekstrapolując ruchy bota lub pociski ray-trace, bierzesz pod uwagę to przesunięcie po uzyskaniu czasu systemowego. Korzystanie z UTC wyeliminuje czynniki strefy czasowej.

JBRWilkinson
źródło
1

Po drugie stwierdzam, że nie powinieneś używać NTP ani zbliżać się do zegara systemowego. Jeśli faktycznie przeanalizujesz ten wymóg, zauważysz, że masz następujące potrzeby:

  • Ile czasu upłynęło od poprzedniej klatki, abyś mógł przejść do rzeczy zależnych od czasu. Może się to różnić na kliencie i serwerze, jeśli oba zaznaczają różne szybkości (np. Czasami można zobaczyć serwery działające ze stałą częstotliwością 20 Hz (lub cokolwiek innego), ale klienci, którzy mogą działać tak szybko, jak chcą).
  • Ile czasu upłynęło od rozpoczęcia bieżącej mapy. Jest to licznik czasu liczony od zera (po uruchomieniu należy go ustawić na 0 zarówno na kliencie, jak i na serwerze), a czas serwera jest uważany za „główny”, więc serwer wysyła aktualny widok tego czasu do klienta dla każdej ramki który działa na serwerze. Można to uzyskać, pobierając bieżący czas serwera i odejmując czas, w którym serwer się uruchomił, lub kumulując czasy na ramkę powyżej. Powyższy czas na ramkę po stronie klienta można również wykorzystać do wygenerowania punktów interpolacji między dowolnymi dwiema kolejnymi ramkami serwera.
  • Referencyjny „czas bazowy”, od którego upływa cały pozostały czas; może to być (ale nie musi być absolutnie konieczne dla wszystkich typów gier) zarówno na kliencie, jak i na serwerze i jest inicjowane na początku gry (lub bieżącej mapy), ale nigdy nie ulega zmianie po (chyba że nowa gra - lub nowa mapa - uruchomiono).

Jest to uproszczony zarys - nie próbuję zajmować się takimi kwestiami, jak opóźnienie / upuszczone pakiety itp. - ale jest to podstawowa struktura, na której powinna opierać się cała sprawa.

Nic nie musi zbliżać się do zegara systemowego ani zajmować się takimi sprawami, jak różne strefy czasowe, chociaż ostatnia pozycja może w razie potrzeby użyć strefy czasowej. Ważne jest to, że rzeczywiste czasy, które upłynęły, są mierzone za pomocą timera o wysokiej rozdzielczości opartego na zerach, więc są one całkowicie niezależne od różnic stref czasowych. Chcesz znaleźć aktualny czas na serwerze? Wystarczy dodać czas, który upłynął, do bazowego czasu odniesienia i już go masz. Podobnie dla klienta.

Maximus Minimus
źródło