Piszę program sieciowy który ma symulować ruch obiektów fizycznych (sandbox w którym można ustawiać obiekty a potem uruchomić symulację i śledzić trajektorie ich ruchu oraz siły jakie na nie działają). Do jednej symulacji przez sieć może być podłączonych kilku klientów. Już opisuję co jest nie tak, ale najpierw powiem jak wszystko działa.
Server:
- Ogarnia podłączenia się klientów
- 100 razy na sekundę wykonuje jeden step symulacji (co 10ms).
- Kiedy server dostanie command od klienta (np rusz tą piłkę w bok) to:
- bierze lock do symulacji żeby wykonać command (np ruszyć tą piłkę) oraz zeby sprawdzić poprawność danych, na chwile stopuję symulację ale na pewno nie na 10ms (bo ile może trwać przypisanie czegoś? :D)
- czeka na następny step symulacji (jeżeli pakiet przyszedł zaraz przed to czeka 1ms, jeżeli w połowie to 5ms, etc) (jest to zrobione tak że wątek nasłuchujący robi
.wait();
a symulacja robi.notify();
kiedy jest wykonywana). - znowu zabiera lock do symulacji, robi kopię świata
- odsyła info o pozycjach do klienta.
Klient:
- Przeprowadza swoją symulację u siebie
- Kiedy coś jest zmieniane wysyła command do servera
- Kiedy pakiet wraca symulacja jest updatowana tak żeby zgadzała się z serverem.
Nie jest to idealne wyjście ponieważ tworzy to ten sztuczny lag 10ms (myślałem że mogę to zignorować), początkowy plan jednak był taki że pakiet od razu wraca do klienta (trzeba jednak czekać na ten jeden step symulacji because of spójność danych i czasu (symulacja jest fixed timestep)).
Normalne zachowanie jest wtedy gdy
- Klient wyślę komand 1
- Server odeślę odpowiedź na komand 1
Nieoczekiwane zachowanie pojawia się gdy
- Klient wyślę komand 1
- Klient wyślę komand 2
- Server odeślę odpowiedź na komand 1
- Server odeślę odpowiedź na komand 2
Wtedy pojawia się taki "przeskok do tyłu", nie wiem jak to opisać więc sugeruję wyobrazić sobie zegarek w tej symulacji, zachowuje się on wtedy tak:
0:00
, 0:01
, 0:02
, 0:00
, 0:01
, 0:02
, 0:06
, 0:07
, 0:08
Progres symulacji u klienta wygląda wtedy tak:
Według mnie powodowane jest to tym że pakiet leci w jedną stronę np 30ms, 10ms czekania na step i wraca kolejne 30ms. Czyli stary pakiet jest te 70ms starszy (chyba?).
Moim rozwiązanie byłoby takie że:
- Klient nie pozwoliłby użytkownikowi wysłać nowego pakietu zanim odpowiedź na stary nie dotrze (co jak pakiet zginie w sieci?)
- Klient ignorowałby odpowiedź na stary pakiet, jeżeli nowy został wysłany.
Czy ktoś się wypowie o tym sposobie? Nie wiem czy ktoś z niego korzysta, napisałem to sam i chyba jest warte tyle co nic? :c