# Notatki do pracy inżynierskiej [TOC] ## Kod ### Główny kod https://gitlab-stud.elka.pw.edu.pl/dkolaska/first-agent-shooter ### Proste sceny testowe (demka) https://gitlab-stud.elka.pw.edu.pl/dkolaska/first-agent-shooter-demos ## Repozytorium z zasobami https://github.com/rumaniel/Awesome-Game-Networking ## Cel pracy Celem pracy jest porównanie różnych rozwiązań sieciowych dla gier typu FPS pod względem grywalności (płynność rozgrywki po stronie klienta, spójność gry, odporność na oszustwa, odporność na słabe połączenie). Rozwiązania chciałbym implementować w sposób iteracyjny, za każdym razem pokazując dobre i słabe strony rozwiązania. <br> Dodatkowo zbadam także miary takie jak obciążenie sieci i procesora. <br> W miarę możliwości postaram się zaprojektować rozwiązania w postaci modułów, które mógłbym podmienić w czasie działania aplikacji. Może się jednak to okazać zbyt dużym wyzwaniem. W takim przypadku powstanie kilka wariantów aplikacji. <br> Jeśli starczy czasu chciałbym także zająć się aspektem wizualnym, inteligencją przeciwników oraz logiką samej gry. Na ten moment jednak ciężko ocenić czy jakiekolwiek prace w zostaną w tę stronę wykonane. ## Narzędzia i biblioteki ### Symulacja ruchu sieciowego https://jagt.github.io/clumsy/ ## Biblioteki sieciowe w Unity ### Forge https://github.com/BeardedManStudios/ForgeNetworkingRemastered ### MLAPI (obecnie używane) https://docs-multiplayer.unity3d.com/docs/getting-started/about-mlapi ### Mirror Podobno bardzo fajne, ale trzeba płacić za pro toolsy, w tym profiler (5$ per month) https://mirror-networking.com/ # Postęp prac Na ten moment przyjmuję następujący schemat wersonowania * 0.0.X - ostatnia cyfra oznacza kolejne iteracje danej implementacji kodu sieciowego * 0.X.X - przy pomocy drugiej cyfry będę rozróżniał kolejne implementacje 0.0.X - najprostsza implementacja. W momencie strzału klient sam sprawdza czy trafił przeciwnika i wysyła informację o tym do serwera. Serwer następnie rozsyła ją do innych klientów. Serwer jest nieautorytatywny. ## Wersja 0.0 - serwer nieautorytatywny ### Wersja 0.0.1 (09.04.2021r.) Udało się stworzyć proste demo synchronizujące przez się rotacje i pozycje graczy. Do implementacji warstwy sieciowej wybrałem https://github.com/BeardedManStudios/ForgeNetworkingRemastered Model oraz animacja postaci pochodzą z darmowej próbki ze sklepu Unity. https://assetstore.unity.com/packages/3d/props/weapons/low-poly-fps-pack-free-sample-144839 Kod i ogólna organizacja próbki były na bardzo słabym poziomie toteż sporo czasu poświęciłem na refaktoryzację kodu oraz na zrozumienie zawiłych zależności pomiędzy komponentami. <br> Jeden z błędów był szczególnie uciążliwy do wytropienia. Błąd przejawiał się tym, że ręce przeciwników były zawsze przesunięte. ![](https://i.imgur.com/Nynfxpm.png) Dosyć szybko zauważyłem, że autor użył w swoim rozwiązaniu dwóch kamer. Jednej dla rąk i broni, a drugiej dla reszty obiektów. Nie mając jednak dostatecznego doświadczenia z Unity problemu szukałem w kodzie. Ostatecznie znalazłem rozwiązanie. Kamera wyświetlająca broń korzysta z *CullingMask*. Należało zatem zmienić warstwę obiektów na *Default* jeśli nie jesteśmy właścicielem obiektu. ```csharp= protected override void NetworkStart() { base.NetworkStart(); if (!networkObject.IsOwner) { // Set Default layer so GunCamera won't distort it Utils.SetLayerInChildren(transform, LayerMask.NameToLayer("Default")); DisableHostOnlyComponents(); } } ``` Ostateczny rezultat. ![](https://i.imgur.com/sUV5RMZ.png) ### Wersja 0.0.2 (21.04.2021r.) W tej wersji chciałem zaimplementować synchronizację animacji. Pojawiło się jednak pytanie jak to zrobić? * synchronizować stan animacji? : Wymagałoby to synchronizacji kilku/kilkunastu zmiennych boolowskich (biblioteka Forge nie wspiera synchronizacji tablic/wektorów n-wymiarowych) * wysyłać polecenia, np. Run(), Jump(), ale co jeśli jakiś pakiet zostanie utracony? Czy biblioteka dowie się o tym i go ponowi? Z tego co wyczytałem to Forge używa mieszanki TCP i UDP/RUDP, ale nie wiem w jaki sposób. Okazuję się, że Unity dostarcza klasę Network Animator, jako cześć wycofanego UNET oraz nowo rozwijanego MLAPI: https://docs-multiplayer.unity3d.com/docs/getting-started/about-mlapi W międzyczasie zdałem sobie sprawę, że biblioteka Forge może nie być tak cudowna jak mi się na początku wydawało. * Na repozytorium brakuje źródeł (niektórych, uniemożliwa to zbudowanie, np. aplikacji serwera), a linki do binarek nie działają * Ostatnie istotne zmiany były 2 lata temu. * Równolegle rozwijana jest 3 wersja zwana Alloy. Problem w tym, że wydaje się nie być gotowa. * Develop jest 4 commity za masterem... Z tych powodów zastanawiam się nad migracją do MLAPI * Dokumentacja wydaje się lepsza. Ma API reference, czego brakuje w Forge * Jest to oficjalne rozwiązanie Unity * Jest wciąż rozwijane Ale * Start i doprowadzenie aplikacji do stanu w jakim jest teraz może zająć więcej. MLAPI nie dostarcza gotowych modułów oraz wydaje się być bardziej niskopoziomowe ### Wersja 0.0.2 (29.04.2021) W tym tygodniu spróbowałem przepisać demo przy użyciu MLAPI. Okazało się to całkiem proste. Po przerobieniu dwóch krótkich tutoriali byłem w stanie to zrobić. Jestem pozytywnie zaskoczony biblioteką. Używa się się jej równie prosto co Forge'a. Ostatecznie udało się odtworzyć demo napisane w Forge, dodatkowo synchronizując. Okazało się to nawet prostsze po tym jak odkryłem dwie klasy: * NetworkTransform * NetworkAnimator Aby ta część była kompletna chciałbym jeszcze synchronizować efekty takie jak błysk i iskry z lufy. Będziemy wtedy w stanie zobaczyć czy przeciwnik do nas strzela. Zanim zaimplementuję tą funkcjonalność, chciałbym dokonać kolejnej refaktoryzacji kodu. Tym razem skupiłbym się na podzieleniu logiki na jak najmniejsze, niezależne moduły. Rezultat ![](https://i.imgur.com/89fJGXS.png) ### Wersja 0.0.3 (15.05.2021) W tej iteracji chciałem skupić się na zbadaniu możliowości badania parametrów komunikacji sieciowej. Poszukiwania zacząłem od dokumentacji MLAPI. Natrafiłem tam na sekcę profiling. https://docs-multiplayer.unity3d.com/docs/mlapi-api/MLAPI.Profiling.NetworkProfiler/index.html . Sugeruje ona, że biblioteka oferuje tego typu rozwiązanie. Nie mogłem jednak znaleźć informacji o tym jak je uruchomić. W międzyczasie odkryłem profiler wbudowany w Unity ![](https://i.imgur.com/cK8N4wV.png) Początkowo miałem pewne problemy z podpięciem profilera pod aplikację uruchomioną z pliku .exe (nie z edytora). Dostawałem błąd `[65261] The message header is corrupted and for security reasons connection will be terminated.` Pomogło zaznaczenie opcji Development Build i Autoconnect Profiler w oknie Build Settings. Po uruchomieniu profilera natrafiłem na kolejny problem. Jak widać profiler działa. ![](https://i.imgur.com/tqpsWaa.png) Jednak sekcja monitorująca sieć nie rejestruje żadnego ruchu. ![](https://i.imgur.com/ROnemsc.png) W dokumentacji https://docs.unity3d.com/Manual/Profiler.html możemy natrafić na tabelkę mówiąca, że funkcja ta jest przestarzała. ![](https://i.imgur.com/od9onj9.png) W dokumentacji MLAPI natomiast widnieje informacji, że od wersji Unity 2020.2 dodano integrację z profilerem Unity. Wcześniej korzystano z profilera dostarczanego przez MLAPI. Analiza kodu MLAPI to potwierdza <br> https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/blob/3e3aef6aa02c2a25359898319e5bd49d3518b57b/com.unity.multiplayer.mlapi/Editor/MLAPIProfiler.cs <br> ![](https://i.imgur.com/vs9PqPt.png) <br> Wygląd starego profilera <br> https://docs-multiplayer.unity3d.com/docs/advanced-topics/networkprofiler-window/index.html ![](https://i.imgur.com/I0xu3BD.png) Na obecną chwilą udało mi się znaleźć opcje profiler wbudowanego w Unity umożliwiające monitorowanie niektórych parametrów. Jednak wciąż nie jestem w stanie uzyskać takiej ilości informacji jak na zrzucie powyżej. ![](https://i.imgur.com/ph27xD9.png) ### Wersja 0.0.3 (27.05.2021r.) Przeciwnicy mogą zadawać sobie obrażenie. Tak w zasadzie to zaimplementowałem to już tydzień temu, ale nie miałem czasu tego opisać. ![](https://i.imgur.com/kYvAbZw.jpg) W tym momencie działa to tak. Kiedy strzelamy z broni w stronę przeciwnika leci obiekt pocisku. Pocisk przy wystrzale dostaje od właściciela callback. Callback jest konieczny, ponieważ RPC może być wywołane tylko przez ownera obiektu. W momencie kolizji pocisk pobiera network object ID przeciwnika w którego trafił i wywołuje callback. Callback natomiast wywołuje ServerRPC, które trafia do serwera. Serwer w obsłudze RPC wywołuje ClientRPC. Jest użyty dodatkowy parametr określający do kogo ma być wysłane. Klient po otrzymaniu RPC znajduje w swojej sesji przeciwnika o określonym ID i zadaje mu obrażenia. <br> Mamy do czynienia z nieautorytatywną obsługą logiki gry. ### Wersja 0.0.3 (12.06.2021r.) Tym razem postanowiłem przyjrzeć się narzędziu do symulacji zaburzeń ruchu sieciowego clumsy. https://jagt.github.io/clumsy/ Przy użyciu narzędzia byłem w stanie sprawić, że ruch przeciwnika był mocno opóźniony, przerywany itd. Testy przeprowadzałem uruchamiając wszystkie instancje aplikacji na jednej maszynie (bez wirtualizacji). W ramach testów chciałbym jednak zbadać także sytuację, w której tylko jeden z klientów ma problem z łączem. Skierowałem zatem swoją uwagę w stronę wirtualizacji. Początkowo obawiałem się, że wirtualizacja maszyn Windowsowych będzie problematyczna z racji na licencję. Znalazłem jednak w sieci obraz maszyny deweloperskiej https://developer.microsoft.com/pl-pl/windows/downloads/virtual-machines/ Po uruchomieniu maszyn wirtualnych okazało się jednak, że dla środowiska uruchomienioweog VirtualBox wydajność (renderowania grafiki 3D) jest bardzo słaba. Zamierzam zatem sprawdzić jak radzą sobie konkurencyjne rozwiązania, a jeśli i one nie będę wystarczające to najprawdopodobniej będę przeprowadzał takie testy na własnych dwóch laptopach lub na maszynach w laboratorium. Uważam także, że bardzo przydatne byłoby napisanie automatycznych scenariuszy testowych. ### Wersja 0.0.4 (11.10.2021) Wciąż nie zacząłem pisać kodu serwera autorytatywnego. W tym tygodniu natomiast pracowałem nad modyfikacją kodu tak, aby wyciągnąć input do klasy (nie używać wbudowanej, statycznej Input). Będzie to potrzebne, ponieważ w przypadku serwera autorytatywnego musimy przesyłać input przez sieć. Przykład prostego serwera autorytatywnego http://darrellbircsak.com/2020/09/27/simple-mlapi-authoritative-server/ Zanim zacznę pisać serwer chciałbym najpierw sprawdzić jaka jest różnica pomiędzy napisaniem customowego serilizatora, a skorzystaniem z wbudowanej w MLAPI NetworkVariable. ### Wersja 0.1.0 (18.10.2021) Okazuje się, że w MLAPI jedną z metod (sugerowaną w ramach jednego z zamieszczonych przykładów) jest przekazywanie komend poprzez RPC. Bazując na https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize/tree/main/Basic/2DSpaceShooter Zaimplementowałem naiwną wersję serwera autorytatywnego. Na pierwszy rzut oka widać, że jest to słabe rozwiązanie i że potrzebna jest predykcja po stronie klienta. W tym czasie napisałem także proste skryptu pozwalające uruchomić mi aplikację z wiersza poleceń ułatwiając w ten sposób prototypowanie. ### Wersja 0.2.0 (21.10.2021) Na dicordzie poświęconym MLAPI zobaczyłem, że wypuścili nową wersję 1.0.0. Nowa wersja zmienia nazwę biblioteki na Netcode for Gameobjects. Pod pewnymi względami łamie kompatybilność z API. Jednak patrząc na to co wprowadza stwierdziłem, że warto będzie dokonać upgrade'u. <br> https://docs-multiplayer.unity3d.com/docs/migration/upgrade-guide Zmiany, które nie są jasne po przeczytaniu release notes'ów. * NetworkVariable nie pozwalają teraz na zapis po stronie klienta Możemy dla nich określic tylko prawa do zapisu. Twórcy zapewne chcieli narzucić komunikację Client -> Server za pomocą RPC. ## Różne pomysły (może być przestarzałe) 2. Proste AI na potrzeby dalszych eksperymentów. 4. Udoskonalenie modelu postaci oraz animacji chodu 5. Bardziej rozbudowane AI. 6. Opracowanie i implementacja logiki samej gry. 7. Udoskonalenie menu startowego oraz dodanie prostego menu ustawień # Archiwum ### FPS networking #### Dyskusja na temat kodu sieciowego w grach https://www.reddit.com/r/truegaming/comments/2ruqba/advances_in_fps_netcode/ #### Opis netcode w silniku Source (może być bardzo przydatne) https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking #### Deep dive into networking for Unity's FPS Sample game - Unite LA https://www.youtube.com/watch?v=k6JTaFE7SYI https://github.com/Unity-Technologies/FPSSample Główne punkty: * używamy UDP, ale numerujemy pakiety * klient przesyła input (commands), serwer zwraca snapshoty gamestate'u * snapshoty przesyłamy jako delty, gdzie delta = real_state - predicted_state * aby otrzymać real_state klient musi najpierw wyliczyć predicted_state * rollback (w filmie nie ma szczegółów co do implementacji) * aby przeciwdziałać input lagowi klient wykonuje interpolację ruchu * pomiar RTT ### Raczej już nie będzie potrzebne ### GGPO i jego porty #### Unreal Engine https://github.com/BwdYeti/GGPOUE4 #### Unity https://github.com/HouraiTeahouse/Backroll #### Potencjalne problemy z GGPO Z tego co rozumiem to GGPO jest napisane głównie z myślą o grach peer-to-peer, np. bijatykach (Mortal Kombat, Tekken, ...) https://forums.unrealengine.com/development-discussion/c-gameplay-programming/1789730-it-s-been-almost-a-year-since-ggpo-went-open-source-how-come-no-information-about-integration ![](https://i.imgur.com/ChUIFnz.png) #### Dyskusja na temat używania GGPO w grach innych niż bijatyki Ciężko wyciągnąć jakieś wnioski z tej dyskusji. https://www.reddit.com/r/Fighters/comments/1kurbv/ggpo_netcode_could_it_work_with_other_game_genres/S ### Różne linki https://www.reddit.com/r/Fighters/comments/jfzym8/is_there_a_resource_to_learning_how_to_create/ https://gist.github.com/rcmagic/f8d76bca32b5609e85ab156db38387e9 https://www.ggpo.net/ https://github.com/pond3r/ggpo https://www.reddit.com/r/unrealengine/comments/60z2ta/question_does_anyone_know_how_i_can_get_ggpo/ 3.03 https://www.codersblock.org/blog/multiplayer-fps-part-1 # Notatki do tekstu pracy inżynierskiej ## Lista tematów które można poruszyć * przedstawić obecnie dostępne biblioteki sieciowe, ich wady zalety * peer-to-peer a client-server https://pvigier.github.io/2019/09/08/beginner-guide-game-networking.html * wspomnieć o tym, że w grach najczęściej nie ma sensu wysyłać pozycji myszy do serwera, ponieważ najczęściej nie mamy ograniczeń co do szybkości ruchu myszką. https://gamedev.stackexchange.com/questions/118981/sending-a-players-mouse-movement-to-the-server-in-an-fps * jak synchronizować animacje? lokalnie (można wtedy oszukiwac i wysyłać animację stania kiedy się biega, czy to bardzo szkodliwe), przez serwer (mniej wydajnie, więcej informacji leci przez sieć) * opowiedzieć o serializacji, ale jednocześnie zaznaczyć, że MLAPI jest biblioteką wysokiego poziomu i że z tego względu nie musiałem zgłębiać się w te tematy # Bibliografia ## FPSSample https://assetstore.unity.com/packages/3d/props/weapons/low-poly-fps-pack-free-sample-144839 ## Glowing shader https://www.youtube.com/watch?v=Ar9eIn4z6XE ## Shader Graph Żeby działał preview trzeba dodać Universal Rendering Pipeline https://medium.com/nerd-for-tech/how-to-upgrade-your-project-to-urp-in-unity-2021-2-ef10404935a7 ## URP i Camera Stacking https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.2/manual/camera-stacking.html ## Spectator Camera https://www.youtube.com/watch?v=3MEvyGjAIxc&t=307s ## Banana Man https://assetstore.unity.com/packages/3d/characters/humanoids/banana-man-196830#description ## Animacja https://www.youtube.com/watch?v=hs2goLjUz4U https://www.youtube.com/watch?v=acMK93A-FSY ## Dissolve shader https://unitylist.com/p/cn1/Unity-Shader-graph-sandbox ## Lobby https://www.youtube.com/watch?v=sBR0oJJjx6Q&t=30s Dapper Dino Tutorials https://docs-multiplayer.unity3d.com/docs/learn/dapper/dapper-objectspawning/index.html ## Event System https://www.youtube.com/watch?v=gx0Lt4tCDE0 ## Settings Menu https://www.youtube.com/watch?v=YOaYQrN1oYQ ## Menu Music https://assetstore.unity.com/packages/audio/music/electronic/free-soundtrack-chill-synthwave-194432#content ## Przechowywanie statystyk https://gamedev.stackexchange.com/questions/110958/what-is-the-proper-way-to-handle-data-between-scenes ## Drobne rzeczy o których można napisać * Dyrektywy #define DEVELOPMENT BUILD * Build Settings * Cinemachine * Shader graph set up * Unity Character Controller * MyUtils * skrypty do startu ![](https://i.imgur.com/huOaREs.png) * https://www.youtube.com/watch?v=hMnetI4-dNY https://www.youtube.com/watch?v=LNidsMesxSE&t=4s * ProBuilder (instalacja pakietu, to że Meshe muszę byc te z ProBuildera) * Light baking (muszą być static) (brak realtime area lights w Unity) (realtime lightmap swapping) * Architektura portali * instalacja netcode extensions (najpierw zainstalować utp potem z gita) ## TODOSY ### Przerobić na raycasty i zmienić model,animacje broni https://www.youtube.com/watch?v=THnivyG0Mvo