Przeczytałem Valve + Gafferon i setki stron z Google, ale z jakiegokolwiek powodu nie mogę się oprzeć prognozom klientów.
Według mnie podstawowym problemem jest:
- Klient A wysyła dane wejściowe o
T0
- Serwer otrzymuje dane wejściowe o godzinie
T1
- Wszyscy klienci otrzymują zmianę o
T2
Na T2
Jednak użycie przewidywania klienta, klient A jest teraz w odpowiedniej pozycji do T4
.
W jaki sposób upewniasz się, że klient A, przewidując, że serwer zaakceptuje żądanie przeniesienia, nie wyprzedzi serwera? Oczywiście przez cały czas, gdy są do przodu, powoduje to powrót do miejsca, w którym serwer ich ostatnio widział. Po wszystkich poprawkach, które próbowałem, nadal jest to zauważalne po zatrzymaniu, ponieważ serwer zatrzymuje się za tobą
źródło
Nie zaimplementowałem tego (więc mogą pojawić się problemy, których nie widzę od razu), ale pomyślałem, że spróbuję pomóc.
Oto, co się wydarzyło:
Prawdopodobnie przydałoby się myśleć o czasie serwera. Jest (prawdopodobnie) bardzo podobny do działania interpolacji .
Każde polecenie jest wysyłane z czasem serwera. Ten czas serwera jest ustalany na początku meczu, sprawdzając tik serwera, kompensując czas pingowania. Na kliencie masz własną lokalną liczbę tików, a każde wysyłane polecenie jest konwertowane na tiki serwera (jest to prosta operacja odejmowania)
Ponadto klient zawsze renderuje „w przeszłości”. Zakładasz więc, że świat, który widzi klient, jest, powiedzmy, o 100 ms krótszy niż rzeczywisty czas serwera.
Przeformułujmy więc twój przykład z czasem serwera (oznaczonym przez S).
Klient wysyła dane wejściowe w czasie T0 z czasem serwera S0 (domyślam się, że tak naprawdę „reprezentacja czasu serwera przez klienta minus czas interpolacji”). Klient nie czeka na odpowiedź z serwera i natychmiast się przenosi.
Serwer otrzymuje dane wejściowe w T1. Serwer ustala wiarygodną pozycję klienta w czasie serwera S0 podaną przez klienta. Wysyła to do klienta.
Klient otrzymuje autorytatywną pozycję w T2 (nadal z wyznaczeniem czasu serwera S0). Klient śledzi przeszłe zdarzenia z przeszłości (prawdopodobnie tylko kolejkę wszystkich niepotwierdzonych prognoz).
Jeśli przewidywana pozycja / prędkość / cokolwiek, co serwer odsyła w S0, jest inne niż to, co klient zapisał w S0, klient jakoś sobie z tym poradzi. Albo przez przywrócenie odtwarzacza do poprzedniej pozycji, albo na powrót do poprzedniej informacji, albo może coś innego, o czym nie myślałem.
źródło
W rzeczywistości w github istnieje implementacja typu open source, która pokazuje, jak to się robi. Sprawdź Lance.gg
repozytorium github: https://github.com/lance-gg/lance
Kod prognozy klienta jest zaimplementowany w module o nazwie
src/syncStrategies/ExtrapolateStrategy.js
Oprócz ekstrapolacji istnieją dwa pojęcia, o których nie wspomniałem wyżej:
źródło
Klient A zawsze wyprzedza serwer - ale to nie ma znaczenia. Musisz tylko cofnąć klienta, jeśli serwer stwierdzi, że wystąpił problem z raportowaną pozycją, w którym to momencie klient ponownie uruchamia wszystkie zmiany, które wprowadził od czasu błędu z poprawionymi wartościami, aby doprowadzić go do stanu zgodnego z serwerem.
Aby to zrobić, klient musi zapamiętać niektóre z jego przeszłych stanów i poprzednich aktualizacji. Może to być tylko kilka prostych wartości, takich jak pozycja, prędkość, orientacja itp. Serwer okresowo wysyła potwierdzenie, że różne aktualizacje klienta były legalne, co oznacza, że można je teraz zapomnieć. Jeśli jednak serwer zgłasza, że aktualizacja była nieprawidłowa, stan klienta przywraca ten punkt i przyszłe zmiany są stosowane do tego zmodyfikowanego stanu.
Na dole artykułu Valve znajdują się dodatkowe linki, które warto przeczytać - jest to jeden z nich: https://developer.valvesoftware.com/wiki/Prediction
źródło
t=4
) otrzymuje informacje ot=2
, więc resetuje stan abyt=2
następnie Ponowne wykonanie aktualizacji przynieść przedmioty odt=2
dot=4
?