Jak obsługiwać dużą liczbę przetworników w grze MMO

26

Jak radzą sobie z nimi gry takie jak Minecraft, a właściwie każda gra MMO z przetwornikami?

Powiedzmy, że teren odradza 3 krople „brudu” za każdym razem, gdy kopiesz wspomniany teren. Powiedzmy, że każdy element ma animację obrotu obliczoną dla każdej klatki. Jeśli liczba odbiorników na świecie będzie bardzo wysoka, byłby to bezużyteczny, ogromny narzut w obliczeniach ramek dla klienta na danym serwerze, ponieważ jest prawdopodobne, że wiele z tych przedmiotów znajduje się o wiele lat świetlnych od Ciebie.

Pomyślałem więc, że musisz „robić rzeczy” tylko przy przetwornikach zbliżonych do lokalnego odtwarzacza, ale nadal oznacza to, że każda klatka muszę sprawdzać, czy jakikolwiek inny przedmiot jest wystarczająco blisko, aby zaczął się animować.

Moje aktualne pytanie brzmi: w jaki sposób inne MMO rozwiązały ten problem?

Alakanu
źródło
9
Ponadto, w kontekście Minecraft, po tym, jak pewna liczba elementów jest wystarczająco blisko siebie (3+ tego samego elementu w tym samym obszarze bloków), serwer zastępuje 3 wystąpienia zgrupowanym wystąpieniem zawierającym typ bloku ( minecraft:dirt) i liczba (30), więc gdy gracz jest wystarczająco blisko, aby go podnieść, wystarczy dodać jak najwięcej z ekwipunku gracza. Jeśli gracz ma tylko miejsce na 6 przedmiotów, a stos 30 leży na ziemi, gracz podniesie 6, a stos na ziemi zmniejszy się do 24.
Zymus
6
@Zymus Warto zauważyć, że faktycznie zmniejszyła się wydajność kleszcza dla umiarkowanej liczby upuszczonych przedmiotów, ponieważ wszystkie one stale szukają pobliskich.
user253751,

Odpowiedzi:

48

Po prostu ładując tylko te części świata, które znajdują się blisko gracza. Wszystko inne jest zawieszone na dysku twardym. Kiedy w odległości około dwóch kilometrów leży niewielki obiekt, gracz nie może go zobaczyć i nie może z nim współdziałać. Nie ma więc powodu, aby go aktualizować lub wysyłać do GPU w celu renderowania. Im mniejszy obiekt i jego zakres interakcji, tym niższy zasięg wokół odtwarzacza, w którym należy go załadować.

Odnalezienie tego, co jest blisko gracza: sprowadza się to głównie do przechowywania świata w strukturze danych zoptymalizowanej pod kątem wyszukiwania przestrzennego. Dobrymi kandydatami do nich są hasze przestrzenne i wielowymiarowe drzewa .

Philipp
źródło
Dzięki za szybką odpowiedź. Myślałem o użyciu Unity, ponieważ domyślam się, że używa jakiegoś podziału przestrzennego w celu sprawdzenia zderzaczy wyzwalaczy, więc stworzyłem jeden duży zderzak wokół mojej postaci, a każdy element w nim byłby „animowany”. Czy to sposób na wdrożenie Twojej odpowiedzi? Popraw mnie, jeśli się mylę, na zdrowie!
Alakanu,
2
@Alakanu Można go użyć, jeśli chcesz, aby obiekty były widoczne z dużej odległości, ale wykonuj określone zachowania wymagające intensywnych obliczeń, gdy jesteś blisko gracza (a samo obracanie czegoś wokół jego osi y nie powinno być bardzo drogie). Ale prawdziwym wyzwaniem podczas implementacji gry z otwartym światem w Unity jest inteligentne tworzenie instancji i niszczenie obiektów gry, podczas gdy gracz porusza się po świecie (lub nawet lepiej: użyj puli obiektów zamiast instancji i niszczenia).
Filip
Tak, w tej sytuacji pula obiektów jest obowiązkowa :) Ok, dziękuję bardzo!
Alakanu,
3
@Alakanu Możesz sprawdzić koncepcję „Loaded Chunks” Minecrafta, aby uzyskać więcej informacji o tym, jak ta odpowiedź dotyczy tej gry.
T. Sar - Przywróć Monikę
1
Dotyczy to nie tylko przetworników. KAŻDY obiekt, który jest zbyt daleko od gracza, może być traktowany w ten sposób. Czasami nawet obiekty, które są blisko gracza. Wyobraź sobie dom z pełnym wnętrzem, ale nie musisz renderować, dopóki nie wejdziesz do domu.
Zibelas,
22

Masz dwie bardzo różne rzeczy do zarządzania:

  1. Serwer musi zarządzać całym światem w autorytatywny sposób. W tym celu konieczna jest komunikacja z N klientami (gdzie N jest „masywny”).

  2. Klient mógł w zasadzie wiedzieć o całym świecie, ale nie musi . Dla klienta wystarczy wiedzieć o tym, co znajduje się w pobliżu gracza. Zakładając na przykład dość zgrubne podziałanie podobne do siatki, musiałby znać tylko komórkę gracza i 26 komórek wokół odtwarzacza (lub 8 komórek, jeśli masz siatkę 2D). Lepsza jest nieco drobniejsza siatka, ale masz pomysł.

Teraz dużo przetworników, co to jest „dużo”? Kopiesz może 5 rzeczy na sekundę, to może dwa tuziny liczb, które muszą zostać zaktualizowane na serwerze, a serwer może być zmuszony przekazać je innemu graczowi, którego obszar zainteresowania pokrywa się z twoją komórką. W przypadku komputera jest to dość absurdalna ilość danych i nieistotna ilość obliczeń. Może stać się wyzwaniem, gdy w tej samej komórce znajdują się setki / tysiące graczy (wtedy twoje parowanie jest zbyt szorstkie).

Serwer nie musi wiedzieć ani przejmować się obrotami przetworników ani takimi szczegółami. Dlaczego miałoby to

Klient tak naprawdę nie przejmuje się tym, ponieważ jest to po prostu oko, które klient może nadrobić w locie.

Z punktu widzenia serwera niezbędna jest wiedza, że ​​kopałeś (30, 40, 50) w węźle, w którym się znajdujesz, i decyduje, że spawnuje to np. Trzy obiekty typu 5 lub jeden obiekt typu 7 z liczba 3. To wszystko, na czym mi zależy i to wszystko, co ci mówi. Będzie również zawierać tę informację w danych wysyłanych do kogoś, kto później przesunie swój obszar zainteresowania nad komórką siatki (zakładając, że do tego czasu nadal tam jest).

Klient zostaje poinformowany o pojawieniu się tam trzech obiektów, bla bla. Teraz, niezależnie od tego, czy klient wyświetla mapę ASCII-art, na której jest teraz „D”, czy pokazuje wirującą kupę brudu, wszystko jest takie samo. Niezależnie od tego, czy stosy mają różne obroty, czy tylko te znajdujące się w pobliżu gracza obracają się tak samo. To tylko rzeczy wyświetlane na monitorze, nie mają wpływu na nikogo innego.

Tak więc w konkretnym przypadku, w którym chcesz obracać tylko stosy brudu w pobliżu, możesz po prostu sprawdzić zasięg wszystkich znanych ci obiektów. Ponieważ zestaw danych nie jest duży, nawet brutalna siła na wszystko będzie działać.

Możesz (i powinieneś) w zależności od rozmiaru partycjonowania, trywialnie przyciąć komórki siatki, które są zbyt daleko.

Możesz oczywiście dalej dzielić komórkę na partycje i używać czegoś super inteligentnego. Jeśli chcesz, użyj drzewa kd, ale nie spodziewaj się wielkich zysków. Możesz przycinać rzeczy na Manhattanie lub sortować swoje rzeczy na małej siatce ... ale dlaczego?

Kontrola odległości (naprawdę do kwadratu odległość, ale jest taka sama dla ciebie) to tylko dwa mnożenia i dodatek (zoptymalizowany do MUL, MADD, więc tak naprawdę tylko dwie operacje), po którym następuje ruch rozgałęzienia lub warunkowy. Jest to prawie tak szybkie, jak każda inna operacja, która nie przycina jednocześnie całych komórek siatki. W rzeczywistości jest to coś, co można nawet zrobić na GPU ...

Widząc, jak będziesz mieć kilkaset lub co najwyżej kilka tysięcy kontroli odległości względem tej samej pozycji (odległość kwadratowa działa dobrze), naprawdę nie masz problemów z wykonaniem tych obliczeń, tym bardziej, że jest to raczej pamięć podręczna - przyjazna iteracja nad ciągłą pamięcią, a przy ruchach warunkowych jest tanio brudna. Coś jak (pseudokod) rot = r[i] + 1; r[i] = ((dx*dx+dy*dy) < DIST_SQ) ? rot : r[i];. To jedna iteracja na tablicy kilkuset wartości na ramkę. Komputer nie mógł się tym mniej przejmować, to ciągłe ładunki i sklepy, prosta ALU, żadnych oddziałów i tylko kilka tysięcy iteracji.

To (wiele do jednego) nie jest tą samą klasą problemu (wiele do wielu) jak na serwerze. Naprawdę klient nie jest problemem.

Damon
źródło
Przepraszam, pomyślałem, że było jasne, że mówiłem o kliencie, kiedy zacząłem mówić o framerate.
Alakanu,
1
Ale klient nigdy nie stanowi problemu. Klient jest bardzo mało masywny i bardzo lokalny, musi wiedzieć znacznie mniej niż serwer. Idealnie, klient zna węzeł podziału przestrzennego (cokolwiek to jest, powiedzmy, grid), w którym znajduje się gracz, i te bezpośrednio otaczające, i to wszystko. Aktualizacje są więc bardzo skromne, chyba że tysiąc graczy stanie obok siebie. Zwykle potrzebne są tylko delty dla jednego lub dwóch obiektów oraz zawartość nowego węzła siatki po przejściu w jednym kierunku na ponad połowę szerokości węzła. Wszystko inne: nie twój problem.
Damon
1
Chodzi o to, że zbyt mądry może być głupim pomysłem. Twój świat jest już koniecznie podzielony przestrzennie, z możliwą do zarządzania liczbą obiektów w każdym węźle. Nowoczesne procesory (a jeszcze bardziej GPU) są dobre w sekwencyjnym przetwarzaniu dużych ilości danych SoA. Nie lubią niespójnych rozgałęzień i jeszcze mniej lubią niespójny dostęp do pamięci - co jednak dokładnie robi „tylko proces w pobliżu”. W przypadku liczb zarządzalnych (około stu, kilku tysięcy) „przetwarzanie wszystkich” w jednej komórce jest całkowicie wystarczające i prawdopodobnie najlepsza rzecz, jaką możesz zrobić.
Damon,
1
@Alakanu Dla mnie wygląda to na szczegółową i kompletną odpowiedź na twoje pytanie. Jeśli uważasz, że to nie jest odpowiedź, albo źle ją zrozumiałeś, albo twoje pytanie jest tak niejasne, że zostało źle zrozumiane przez Damona, mnie i wszystkich ludzi, którzy głosowali tę odpowiedź.
David Richerby,
2
@Alakanu Naprawdę spędzasz dużo czasu na narzekaniu na ludzi, którzy próbują ci pomóc. Powodzenia z tym.
David Richerby,
2

@ T.Sar pisze w komentarzu, że powinieneś przyjrzeć się koncepcji „załadowanej porcji” Minecrafta, aby uzyskać więcej informacji. Jeśli tak, pamiętaj, że jest to dość skomplikowane w Minecraft, ponieważ ludzie budują maszyny w grze.

Oto bardzo uproszczona wersja:

Świat jest podzielony na kwadratowe regiony (fragmenty). W Minecraft istnieje również podział wysokości, ale większość MMO tego nie potrzebuje.

Klient gry dba tylko o regiony blisko gracza. Jest to o wiele prostsze niż narysowanie koła wokół gracza, ale wystarczająco dobre.

W Minecraft regiony to 16 x 16 bloków, a klient wie o 9 x 9 regionów, 4 regiony w każdym kierunku. (4 regiony na wschód + region gracz znajduje się w + 4 regionach na zachód = łącznie 9 regionów. Ta sama północ / południe)

W tych liczbach nie ma nic magicznego, używaj tego, co ma sens w grze.

Klient animuje tylko rzeczy w tym obszarze. Serwer oblicza rzeczy takie jak wędrujące potwory tylko w regionach zbliżonych do niektórych graczy.

Kiedy gracz chodzi po regionie, nic szczególnego się nie dzieje, kiedy przekracza granicę regionu, „krawędź animacji” zostaje przesunięta o jeden region. Następnie klient musi zapytać serwer o regiony, które teraz widzi.

Nie ma nic złego w posiadaniu kilku zagnieżdżonych limitów animacji. Np. Animowany przedmiot spada na obszar 3x3, wędrując potwory na obszarze 5x5 i po prostu pokazuje krajobraz w obszarze 9x9.

Serwer przechowuje „zamrożoną wersję” regionów, których żaden gracz nie widzi. Jeśli zajmuje to dużo pamięci, możesz po pewnym czasie je rozładować. Kiedy gracz przyjedzie, region zostanie ponownie załadowany bez upuszczenia przedmiotu. Następnym razem musisz być szybszy, Gracz 1.

Stig Hemmer
źródło
Odległość rysowania jest regulowana, ale w tym przypadku 8 fragmentów ma wymiary 9 x 9 i jest decyzją po stronie klienta, może jednak poinformować serwer o przyspieszeniu (aby serwer nie wysyłał danych, których klient nie będzie renderował). Poza tym ... czy Doom i Quake nie rozwiązali tego problemu z renderowaniem tylko tego, co ma sens?
SparK
O odradzaniu upuszczonych przedmiotów ... w Minecrafcie przedmiot „starzeje się” tylko wtedy, gdy w pobliżu jest gracz. Możesz więc „zapisać” upuszczony przedmiot w rozładowanej części i zdobyć go później.
SparK