Autor Wątek: Jak zaprojektowac aplikacje serwerowe dla gry online.  (Przeczytany 13463 razy)

Offline zarius

  • Użytkownik

# Lipiec 30, 2006, 18:56:59
Nie bylem pewny czy wsadzic to do sieciowego czy do projektowania, ale baradziej chyba pasuje jednak tutaj.

Temat tez nie jest w 100% jasny ale ciezko mi bylo to sensownie uformowac. Otoz problem postaram sie zobrazowac na konkretnym przykladzie:

Wyobrazmy sobie gre z gatunku MMORPG (ahh ilez to razy juz bylo) tyle, ze z naciskiem na ekonomie nie exp. Chodzi o cos takiego.

Świat gry dzieli sie na kilka krolestw, kazde z nich rozni sie minimalnie od innego (gracz zamiasr wyboru klas, profesji i innych idoiotyzmow wybiera "kraj" w ktorym chce sie "urodzic", a z gry dalej wynika kim tak naprawde zostanie) i krolestwem trzeba zarzadzac.

Nie gralem we wszystkie mozliwe gry mmorpg ale motyw z krolem ponoc byl w Ultima online (tez nie gralem :/ ) no i krol ten mialby byc wybierany na jakis okres do rzadzenia krolestwem. On tez by zajmowal sie rozwojem technologicznym panstwa i relacjami z innymi krolestwami (wojny, sojusze handlowe etc)

Teraz przechodze do sedna sprawy - Jakie jest sensowne rozwiazanie problemu wielkich map i przetwarzaniem rzadzan klientow ?

Jesli online w "Świecie" mialo by byc mnostwo graczy w różnych krolestwach to sa 3 warianty:
- albo wielka mapa i na niej duzo malych krolestw ( srednio mi sie cos takiego podoba :/ )
- wielka mapa i kilka duzych krolestw ( jeszcze mniej mi sie to podoba :D )
- duze mapy jako pojedyncze krolestwa (podobnie bylo z kontynentami w WoW) ladowane przy przenoszeniu sie do innych "krolestw"

Ale teraz pytanie odnosnie serwera. Jak robi sie to w profesjonalnych produkcjach.

Do tej pory najczesciej widzialem podejscie Realmow czyli TA SAMA mapa ale inne ustawienia serwera i zupelnie inni ludzie, a czy moze da sie to zrobic w ten sposob:

Kazde krolestwo obslugiwane jest przez oddzielny gameserwer. Baza jest wspolna dla wszystkich krolestw, a gracze moga przenosic sie do innego krolestwa -> wtedy nowa mapa jest ladowana i obsluga postaci (klienta) jest przekierowywana na inny serwer gdzie tamten zajmuje sie przetwarzaniem rzadan.

Jak Wy byscie to rozwiazali i co myslicie o tym moim "rozwiazaniu" czy to jest w ogole sensowne/realne do tworzenia ?

Czekam na opinie ;p (nawet jak ta gra nie zostanie stworzona w 1% to i tak bardzo mnie interesuje jak takie rzeczy projektowac ;p)

Z gory dziekuje za odpowiedz,
Zarius

edit: czyzbym dostal od kogos po pupie za ten temat ;) (czytaj [-] ;p)
« Ostatnia zmiana: Lipiec 30, 2006, 19:15:27 wysłana przez zarius »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline sobol

  • Użytkownik

# Lipiec 30, 2006, 21:14:50
Nie jestem do końca pewien czy dobrze rozumiem o co pytasz, bo napisałeś to jak dla mnie troche chaotycznie, ale jeśli dobrze rozumiem to pytasz o bardzo wczesną fazę projektowania - czyli ogólnego wyglądu gry, a nie o dokładne rozwiązanie techniczne. No więc zakładając że rozumiem dobrze ja bym to widział tak: pamiętasz grę sims (sic! ;p) ? Tam wchodziło się do miasteczka i w nim wybierało się domek, czyli swój obszar gry. Można go było w każdym momencie zmienić - jednak nie bez konsekwencji (sprzedając dom). Takie rozwiązanie zastosowali z tego co pamiętam w NetStorm - były ringi na które się wchodziło i tam się grało. Czyli wracając do twojego pomysłu - Gra dzieli się na 2 tryby. W 1 trybie masz dużą mapę z królestwami zaznaczonymi schematycznie, nie możesz nic w nim robić jak tylko wybrać obszar do gry w trybie 2. Każda mapa którą wybierzesz może teraz działać jako niezależna aplikacja na serwerze, do której może się dołączyć x użytkowników (limit musiał by być oczywiście pokazywany w trybie 1 dla każdego królestwa). Czyli tryb 1 to coś jak menu które tylko uruchamia kolejne tryby gry. Zaletą takiego rozwiązania był by łatwy rozwój gry - chcesz dodać nowe królestwo, to robisz taką nową aplikacje i dodajesz jej uruchomienie do trybu 1, czyli ingerujesz tylko w ten 1 tryb - nie musisz wyłączać serwera etc. Nie jestem pewien czy mówię dość jasno o co mi chodzi, ani czy w ogóle odpowiadam na twoje pytanie (jeśli nie to napisz dokładniej o co Tobie chodzi ;p ).
Pozdrawiam

Offline zarius

  • Użytkownik

# Lipiec 30, 2006, 22:39:51
No wiec postaram sie jasniej.

Oczywiscie ze jest wczesna faza projektowania ale od strony technicznej ;p tu nie chodzi o gre (nie skupiac sie na tym krolestwach :D) tylko o budowe serwera ;p. Tlo gry jest tylko dla przykladu. Nie musi byc trybu pokazujacego krolestwa bo to jest po prostu mapa swiata z zaznaczonymi tymi krolestwami.

W World of Warcraft jest dla przykladu kontynent orkow i kontynent ludzi (akurat w to gralem ;p) Swiat jest duzy wiec podzielono go na 2 mapy ktore podczasz przenoszenia sa ladowane.

No wiec moje pytanie jest takie: Jesli ja podzielil bym swiat na np 5 duzych krolestw jako oddzielnych duzych map (nazwijmy A B C D E) to czy do przetwarzania tych zapytan klientow i wykonywania roznych obliczen (no to co serwery gier przewaznie robia ;) ) tworzy sie aplikacje serwerowa ktora dziala jako JEDNA na kilku kompach (np polaczonych ze soba, jak sie nie myle to kazda z nich to sa tak zwane klastry a pracuja jak jeden ;p) czy tez logiczniejsze jest zrobienie czegos takiego:

Aplikacja przyjmuja rzadanie od klienta z np kodem (ktore krolestwo np A) a ta odcina odpowiednie dane i przekazuje kompowi serwerwemu, ten komp przetwarza wszystkie zapytania ktore sa kierowane od ludzi z krolestwa A zwraca odpowiedz i zwraca tamtemu modulowi ktory przesyla odpowiedz klientowi.

W ten sposob dziala kilka instancji rdzenia gry ktore wspolpracuja ze soba ;p

uff... moze teraz bedzie wiadomo o co chodzi ;p

Po prostu pytam o jakis sensowny model serwerow gier online.

Offline blackstar

  • Użytkownik

# Lipiec 31, 2006, 00:02:43
Aplikacja przyjmuja rzadanie od klienta z np kodem (ktore krolestwo np A) a ta odcina odpowiednie dane i przekazuje kompowi serwerwemu, ten komp przetwarza wszystkie zapytania ktore sa kierowane od ludzi z krolestwa A zwraca odpowiedz i zwraca tamtemu modulowi ktory przesyla odpowiedz klientowi.

Mozna i tak, ale zamiast za kazdym razem wykonywac to przekierowanie chyba prosciej od razu wyslac klientowi pakiet mowiacy o tym, ze ma gadac z serwerem od adresie x.y.z.w. I zaoszczedzi sie przy okazji na lagu.

IMO o konkretach moznaby zaczac gadac dopiero jak ma sie ustalony model swiata, jakies zalozenia co do liczby uzytkownikow, wielkosci map itp.

Offline zarius

  • Użytkownik

# Lipiec 31, 2006, 03:16:27
Mozna i tak, ale zamiast za kazdym razem wykonywac to przekierowanie chyba prosciej od razu wyslac klientowi pakiet mowiacy o tym, ze ma gadac z serwerem od adresie x.y.z.w. I zaoszczedzi sie przy okazji na lagu.

IMO o konkretach moznaby zaczac gadac dopiero jak ma sie ustalony model swiata, jakies zalozenia co do liczby uzytkownikow, wielkosci map itp.

Nie moge robic zalozen bo tego nie jest w stanie powiedziec nikt. Obserwujac rozne gry online mozna niby cos wniskowac ale gra grze nie rowna i np w taki WoW gra juz ok 6mln ludzi (officiale) a w Tibie na 72 realmach srednio ok 40 tys graczy.

Zakldac to niewiele moge ;p co do projektu to wstepna wizja jest, narazie chce z reszta ustalic kazdy aspekt zeby miec ogolny zarys bo sam nie bede o wszystkim decydowal (nie wypada ;p) ale wszelkie szczegoly i dokladny projekt powstanie duzo pozniej ;p Ale chce sie o takim czyms dowiedziec juz teraz i uwzglednic to juz na tym etapie ;)

OT: Czy wie ktos ile jeden Realm w WoW jest w stanie pomiescic ludzi online ? Bo jak to jest mozliwe usatysfakcjonowac 6mln graczy przy 7 realmach... nawet gdyby bylo 150 tys online (w co niewieze) to co z pozostalymi graczami ?

OT2: Wlasciwie jak to jest z tymi wielkosciami map... Czy istnieje jakas wirtualna miara ? Siatki sa przewaznie budowane z quadow (czyli 2 trojkaty tworzace prostokat/kwadrat jak dobrze pamietam) czy jest jakos "ustandaryzowane" jak wielki jest taki quad ;p Bo jak inaczej mozna sie odnosic do wielkosci nizeli uzywajac przymiotnikow, duza wielka etc ;p, a moze da sie to jakos sensownie przeliczyc ile cos ma wirtualnych km. Wiem ze to moze idiotyczne ale czy sa jakies informacje/arty na temat wlasnie wielkosci swiatow, jakies przyklady ;p

Chociazby interesuje mnie to jak wielka jest postac w porownaniu z cala mapa ;) Wiadomo ze chcialo by sie zrobic swiat jak najwiekszy ale w tym momencie nawet nie jestem w stanie sobie wyobrazic jaki "wymiar" jest odpowiedni.

Pozdrawiam
OT2:

Offline dx0ne

  • Użytkownik
    • Pierdoły od dx0ne'a

# Lipiec 31, 2006, 06:00:15
Mi się gdzieś obiło o uszy jakoby std 2 jednotki opengl to 1 metr. Ale to przecież jest umowne. Ktoś sobie zrobi postać człowieka (dajmy te circa 2m) na 10 jednostek i tyle. Podsumowując sądzę że skale ustalasz sobie raczej sam.
Tyle że: zakładasz że ludek ma 2m, więc jak powiesz ze mapa to 1000km2 to daje obraz że jest duża :)

Offline skiter

  • Użytkownik

# Lipiec 31, 2006, 08:44:31
Ja bym to zrobil tak:
- 1 krolestwo = 1 mapa, czyli ... mapa ma wielkosc powiedzmy 1000x1000 pól, zakladajac ze zrobisz to calkiem wydajnie, a powiem ze sie DA!, zrobic to na wskaznikach, tak jak ja mam to zrobione ( kchem ... ), to jak masz 5 takich lokacji to jest ok 97MB, samych wskaznikow ; ), liczona jakos "calosc".

Podstawie kod mapy ( wielkosc 5000x500 - wersja edytora ? ; p ) :

File: map.h
#ifndef MAP_H
#define MAP_H
#include <fstream.h>
#include <vector>

class Map
{
   public:
               Map();
               ~Map();
      void     Save( char *Map_File_out );
      void     Load( char *Map_File_in );

      void     Put( int Put_X, int Put_Y , int Put_ID );

      void     PutItem( int Put_X, int Put_Y , int Put_ID );
      void     DelItem( int Del_X, int Del_Y );

      void     Del( int Del_X, int Del_Y );
      void     Get( int Get_X, int Get_Y );
   private:
      struct Title
         {
            short int         Position_X;
            short int         Position_Y;
            int               Title_ID;
            std::vector<int>  Items;
         };

      fstream  Map_File;
      Title    ***Map_2D;
};

#endif // MAP_H

File: Map.cpp
#include "map.h"
#include <fstream.h>
#include <vector>

#define SIZE_ 5000

Map::Map()
{
   Map_2D = new Title ** [SIZE_];
   for( unsigned int i=0 ; i<SIZE_ ; i++ )
      {
         Map_2D[i] = new Title * [SIZE_];
         for( unsigned int j=0 ; j<SIZE_ ; j++ )
            {
               Map_2D[i][j] = NULL;
            }
      }
}

Map::~Map()
{
   for( int i=0 ; i<SIZE_ ; i++ )
      {
         delete[] Map_2D[i];
      }
   delete[] Map_2D;
}

void Map::Load(  char *Map_File_in )
{
   Map_File.open( Map_File_in, std::ios::in | std::ios::binary );

   Title Read;

   while( Map_File.read( (char*)&Read, sizeof( Read ) ) )
      {
         printf( "\t-----------------\n" );
         printf( "\tPos_X: %d\n", Read.Position_X );
         printf( "\tPos_Y: %d\n", Read.Position_Y );
         printf( "\tID:    %d\n", Read.Title_ID );
         if( Read.Items.size() != 0 )
            {
               for( int i=0; i<Read.Items.size() ; i++ )
                  {
                     if( i != 0 )
                        {
                           printf( "\tItem's: %d\n", Read.Items.at(i) );
                        }
                  }
            }
         Put( Read.Position_X, Read.Position_Y, Read.Title_ID );
         Map_2D[Read.Position_X][Read.Position_Y]->Items = Read.Items;
      }

   Map_File.close();
}

void Map::Save( char *Map_File_out )
{
   Map_File.open( Map_File_out, std::ios::out | std::ios::binary );

   Title Write;

   for( int i=0; i<SIZE_ ; i++ )
      {
         for( int j=0; j<SIZE_ ; j++ )
            {
               if( Map_2D[i][j] != NULL | Map_2D[i][j] != 0 )
                  {
                     Write.Position_X  = Map_2D[i][j]->Position_X;
                     Write.Position_Y  = Map_2D[i][j]->Position_Y;
                     Write.Title_ID    = Map_2D[i][j]->Title_ID;
                     Write.Items       = Map_2D[i][j]->Items;

                     printf( "\t-----------------\n" );
                     printf( "\tPos X: %d\n", Write.Position_X );
                     printf( "\tPos Y: %d\n", Write.Position_Y );
                     printf( "\tID:    %d\n", Write.Title_ID );
                     for( int i=0; i<Write.Items.size() ; i++ )
                        {
                           if( i != 0 )
                              {
                                 printf( "\tItem's: %d\n", Write.Items.at(i) );
                              }
                        }

                     Map_File.write( (char*)&Write, sizeof( Write ) );
                  }
            }
      }

   Map_File.close();
}

void Map::Put( int Put_X, int Put_Y, int Put_ID )
{
   Map_2D[Put_X][Put_Y] = new Title();
   Map_2D[Put_X][Put_Y]->Position_X   = Put_X;
   Map_2D[Put_X][Put_Y]->Position_Y   = Put_Y;
   Map_2D[Put_X][Put_Y]->Title_ID     = Put_ID;
   Map_2D[Put_X][Put_Y]->Items.push_back( 0 );
}

void Map::PutItem( int Put_X, int Put_Y, int Put_ID )
{
   Map_2D[Put_X][Put_Y]->Items.push_back( Put_ID );
}

void Map::DelItem( int Del_X, int Del_Y )
{
   Map_2D[Del_X][Del_Y]->Items.pop_back();
}

void Map::Del( int Del_X, int Del_Y )
{
   Map_2D[Del_X][Del_Y] = NULL;
}

void Map::Get( int Get_X, int Get_Y )
{
   printf( "\t-----------------\n" );
   printf( "\tPos X: %d\n", Map_2D[Get_X][Get_Y]->Position_X );
   printf( "\tPos Y: %d\n", Map_2D[Get_X][Get_Y]->Position_Y );
   printf( "\tID:    %d\n", Map_2D[Get_X][Get_Y]->Title_ID );
   for( int i=0; i<Map_2D[Get_X][Get_Y]->Items.size() ; i++ )
      {
         if( i != 0 )
            {
               printf( "\tItem's: %d\n", Map_2D[Get_X][Get_Y]->Items.at(i) );
            }
      }
}

File: main.cpp
#include <iostream>
#include <fstream.h>
#include <conio.h>
#include <stdio.h>
#include <vector>

#include "map.h"

using namespace std;

int main()
{
   printf( "Nowa mapa\n" );
   Map *NewMap;
   NewMap = new Map();
   printf( "Nowe Pole\n" );

   getch();
   for( int i=0 ; i<100 ; i++ )
      {
         NewMap->Put( i, i, 10 );
         NewMap->PutItem( i, i, 40 );
      }
   getch();

   printf( "Zapisywanie mapy\n" );
   NewMap->Save( "Test.dat" );
   delete NewMap;

   Map *NewMap1;
   NewMap1 = new Map();
   printf( "Wczytywanie mapy\n" );
   NewMap1->Load( "Test.dat" );
   printf( "Pobieranie pola\n" );
   NewMap1->Get( 10, 10 );
   printf( "Usowanie pola\n" );
   NewMap1->Del( 10, 10 );
   printf( "Pobieranie pola\n" );
   NewMap1->Get( 20, 20 );

   printf( "Usowanie Itema\n" );
   getch();
   NewMap1->DelItem( 20, 20 );
   getch();

   printf( "Zapisywanie mapy\n" );
   NewMap1->Save( "Test.dat" );
   printf( "Usowanie objektu z pamieci\n" );
   delete NewMap1;

   getch();

   return 0;
}
Jak widac ... rozpiska mapy 2D, jest calkiem szybka ; p

Czyli wychodzimy dalej, to jest 5 "królestw" po 1000x1000 kazde, w/g mnie powino starczyc ; ), dla kazdego ; p

Jezeli chodzi o sam "silnik" serwera, to pytanie jest takie: Windows czy Linux ?
Czy jedno czy inne:

http://forum.warsztat.gd/index.php/topic,1254.0.html

Mozna tez pod linuxem uzywac "Poll", lub "select", jak ktos lubi na "ostro!", bez mydla to uzywa "fork'a" ; ), ja generalnie uzywam "wątków" jakos sie tak przyzwyczajilem, i tak sobie klepie ; p

Protokol tez sie w miare szybko pisze, jezeli wie sie co "trzeba" napisac ...
« Ostatnia zmiana: Lipiec 31, 2006, 08:48:07 wysłana przez skiter »

Offline blackstar

  • Użytkownik

# Lipiec 31, 2006, 12:35:01
Stanowczo odradzam koncepcje w stylu 1 watek (a tym bardziej proces) na jednego klienta! Przy kilkudziesieciu/kilkunastu(?) tysiacach klientow zabija cie zmiany kontekstow (context switches - jak to sie mowi po polsku? :P) i to, ze calcy czas bedziesz mial "zimny" cache. Zdecydowanie lepiej pojsc w strone funkcji select()/poll(). Jesli mamy wiecej niz jeden CPU (a nawet jesli nie mamy) to do przetwarzania "ciezszych" operacji mozna uzyc jakiegos thread poola (http://en.wikipedia.org/wiki/Thread_pool_pattern).

Do reprezentacji mapy zamiast tablicy MxN zastosowalbym jakies drzewo czworkowe.

Prawda jest taka, ze jesli wczesniej nie pisales czegos takiego, to za pierwszym razem ci nie wyjdzie. Nawet jesli pisales to tez sugeruje najpierw skodowac jakis prototyp. Zobaczyc z czym sa problemy, sprofilowac (!!), byc moze poszukac jakis lepszych struktur danych i dopiero potem zabrac sie za wlasciwa wersje.

Oprocz Windowsa i Linuxa jest tez FreeBSD i Solaris/NexentaOS.

Bardzo pomocne moze byc narzedzie zwane valgrind/callgrind.

IMO Blizzard nie hostuje calej krainy na jednej maszynie. Raczej jakis klaser, byc moze z podzialem rol. Ale to tylko dywagacje :)

[w tym momencie poszedlem robic kanapki i wymyslilem, ze:]
Jesli oprzesz interakcje miedzy jednostkami gry na przekazywaniu komunikatow to mozesz w dosc latwy sposob rozlozyc obciazenie na kilka serwerow. Przy wysylaniu komunikatu patrzysz czy jednostka, dla ktorej jest on przeznaczony, jest obslugiwana przez dany serwer i jesli nie, to wysylasz go do odpowiedniego serwera na LANie. Przydaloby sie pomyslec nad jakims sposobem przyporzadkowywania jednostek/graczy do poszczegolnych serwerow tak, zeby zminimalizowac ilosc komunikatow przesylanych pomiedzy serwerami.

Offline skiter

  • Użytkownik

# Lipiec 31, 2006, 12:58:30
Zgodze sie do pewnych rzeczy, mianowicie:

select ,spoll, poll pod linux ... bsd ma jeszcze inne "ciekawe" rozwiazania.

Kolega wyrzeja faktycznie zwrocil uwage na "contex" czyli przelaczanie, bo jądro systemu, musi trzymac, numery ( PID'y ), procesow, i zaleznie od wykonywanych ... przelaczac, co gdzie dalej idzie.

Teraz tak sobie siedze, i psuje wlasnie nowego kernelka 2.6.15 ( mozenie nowy ; p, ale dziala ; ) ), i jak widze kod, tak po malych ogledzinach to wyglada to troszke ... lepjej niz w 2.4.x, gdzie tam byl faktycznie problem, z tym "przelaczaniem", teraz pozostaje opcja taka, ze jezeli bedzie, masa "atakow" malych pakietow, select i poll moga sie "przydusic", bo beda za male i za "szybkie", i moze nie wygladac to wesolo, ja z swojej strony tak jak kolega napisal, zrobic prosty szkielet, na jednym i 2 rozwiazniu, pokombinowac troszke i "zabic" go na testach, sprawdzajac ktore rozwiaznie bedzie bardziej "wydajne", ja pisze swoj serwer wlasnie pod 2.6, na Pthread, i calkiem ladnie sie reprezentuje, na nostrada 256 ( upload ), wyszlem na czyst z 1200 "graczy", problem tylko byl taki ze mi "serwer" wyciekal, i skonczylo sie na 30 min "zabawy" ; ).

Kazde rozwiaznie ma swoje plusy i minusy, wątki maja to ze je sie "łatwo" pisze, ale gorzej "pilnuje" ( Mutexy etc ... ), select sie latwo pisze a jeszcze gorzej "pilnuje" niz wątki ... bo jak sie rozrosna deskryptory to uf ... kolejka murowana ; ), mzoe nie beda to "sekundowe" opuznienia, wytrzyma wiecej graczy, teraz pytanie czy warta skorka za wyprawke, to trzeba jednak sprawdzic samemu ...

Offline zarius

  • Użytkownik

# Lipiec 31, 2006, 15:49:31
Dzieki za odpowiedz.

Jesli chodzi o platforme to narazie bedzie to raczej Windows z powodu jezyka (C#), niby jest go-mono ale nie zaimplementowalo chyba jeszcze wszystkich mozliwosci CLR'a.

Co do tej wielowatkowosci. Jesli nie uzywac nowego watku dla kazdego polaczenia z serwerem to jak mozna inaczej obslugiwac te setki polaczen ?

Linuxem narazie sie po prostu nie zajmuje bo nawet nie korzystalem z teg OS'a (no Knoppixem Live sie pobawilem troche ale to prawie jak nie linux ;p), nie wspominajac juz o kodowaniu.

Co do samych map to w C# nie wypada uzywac tych wskaznikow xD, pozniej przejrze ten kod narazie mam jeszcze kilka innych spraw do zrobienia :/

Cytuj
Jesli oprzesz interakcje miedzy jednostkami gry na przekazywaniu komunikatow to mozesz w dosc latwy sposob rozlozyc obciazenie na kilka serwerow. Przy wysylaniu komunikatu patrzysz czy jednostka, dla ktorej jest on przeznaczony, jest obslugiwana przez dany serwer i jesli nie, to wysylasz go do odpowiedniego serwera na LANie. Przydaloby sie pomyslec nad jakims sposobem przyporzadkowywania jednostek/graczy do poszczegolnych serwerow tak, zeby zminimalizowac ilosc komunikatow przesylanych pomiedzy serwerami.

Nie do konca zrozumialem, czyli chodzi po prostu o to zeby rozbic serwer zajmujacy sie logika gry na kilka jednostek zajmujacych sie pewnymi zadaniami i zlecac wykonanie roznych dzialan tym jednostkom poprzez wysylanie komunikatow ?

Nie wiem czy to akurat dobre rozwiazanie ale mozna by zrobic taki pomost. Zaraz w paincie narysuje o co mi chodzi ;p

[po chwili...]
Zrobilem taki schemat tylko nie wiem czy o to dokladnie chodzilo.

Kazdy system jakis wiekszy (np zarzadzajacy walka, sterowaniem NPC, chatem etc) to jedna jednostka obliczeniowa. Gracz widzi tylko jeden punkt (bramke) i to ów punkt decyduje o dalszym przekazywainu danych. Czy taki sposob jest logiczny ?

Pozdrawiam ;p


Offline skiter

  • Użytkownik

# Lipiec 31, 2006, 16:38:32
No to faktycznie, ... bedzie pare malych "ale", jak rownierz wyjasnie wiecje spraw, co pokazuje sam jezyk i paltforma, co zawerza "widok".

Doa samego jezyka nic nie mam poza firmą ; p, tam jest jakis "smietnik" co czysci za programiste, jakeis dziwne ulatwienia, generalnie w tej kwesti nie pomoge ; )

Pod systemem Windows, wygodniej i szybciej bedzie uzywanie: 1 wątek = 1 gracz, pod systemem Linux jest wiecej mozliwosci i zawsze "dylemat" ( ma to swoje plusy ; )  ).

Wiec jak rozpisac serwer?

socket ...
adres ...
konfiguracja gniazdek etc ...

if ( nowe poalczenie )
create_Thread ... utworz watek i tam czytaj dane usera i je odpowiednio, interpretuj
Podejrzewam, na oko ze bedzie male "kuku" z ty mejzykiem, co prawda nie znam!, nie jestem specem od C#, ale tylko "wydaje mnie sie", ze to bedzie dluga droga ... ; )

Co do tych serwerow, to nie wiem co kolega chcial przekazac, cos na "klastry" ale takowe sie robi pod systemem Linux, tam tez sa odpowiednie "biblioteki systemowe" ktore wspomagaja takie zadania, pod systemem windows ... moze sie da, ale ja bym tego tam nie testowal ; p

Offline blackstar

  • Użytkownik

# Lipiec 31, 2006, 16:44:06
Co do tej wielowatkowosci. Jesli nie uzywac nowego watku dla kazdego polaczenia z serwerem to jak mozna inaczej obslugiwac te setki polaczen ?
Patrzysz czy sa jakies dane na ktoryms z gniazdek i jesli tak, to je przetwarzasz. Jak przelecisz wszystkie gniazdka to zasypiasz i czekasz az znowu jakies dane sie pojawia. Do tego sluza wlasnie funkcje select() i poll() lub ich odpowiedniki.

Cytuj
Jesli oprzesz interakcje miedzy jednostkami gry na przekazywaniu komunikatow to mozesz w dosc latwy sposob rozlozyc obciazenie na kilka serwerow. Przy wysylaniu komunikatu patrzysz czy jednostka, dla ktorej jest on przeznaczony, jest obslugiwana przez dany serwer i jesli nie, to wysylasz go do odpowiedniego serwera na LANie. Przydaloby sie pomyslec nad jakims sposobem przyporzadkowywania jednostek/graczy do poszczegolnych serwerow tak, zeby zminimalizowac ilosc komunikatow przesylanych pomiedzy serwerami.

Nie do konca zrozumialem, czyli chodzi po prostu o to zeby rozbic serwer zajmujacy sie logika gry na kilka jednostek zajmujacych sie pewnymi zadaniami i zlecac wykonanie roznych dzialan tym jednostkom poprzez wysylanie komunikatow ?

Nie wiem czy to akurat dobre rozwiazanie ale mozna by zrobic taki pomost. Zaraz w paincie narysuje o co mi chodzi ;p
Chodzi mi o cos takiego. Zalozmy, ze gracz w kogos strzelil. Szukamy kolizjii, dostajemy ID trafionego obiektu i:
messageDispatcher.sendMessage(targetID, myID, MSG_HIT, 10); // zadaj 10 obrazen

Teraz messageDispatcher (obiekt przekazujacy komunikaty miedzy jednostkami w grze) szuka jednostki o id targetID i jesli jest ona obslugiwana przez lokalny serwer to wywoluje na niej odp metode (dajmy na to onHit()). Ta metoda odejmuje pkt zycia, itp i np wywoluje messageDispatcher.sendMessage(senderID /* odsylamy do tego, ktory nas uderzyl */, myID, MSG_CHAT, "Idioto, jestem w twojej druzynie!").

Jesli w dowolnym momencie messageDispatcher stwierdzi, ze adresat komunikatu jest obslugiwany przez inny serwer to wysyla mu np po UDP ten komunikat i jego parametry. Jednoczesnie kazdy serwer nasluchuje na pewnym porcie komunikatow od innych serwerow i wywoluje odpowiednie metody na obiektach bedacych adresatami tych komunikatow. Takie troche Remote Procedure Call.

Zobacz, ze w tym przypadku nie trzeba zadnych osobnych serwerow dla chata czy aukcji; wszystko to mozna zbudowac definiujac odpowiednie komunikaty i funkcje je obslugujace (MSG_CHAT, MSG_BID, itp).

Dodatkowo, nic nie stoi na przeszkodzie, zeby uzyc tego samego protokolu (i kodu!) do komunikacji z klientem. Wypadaloby tylko po stronie serwera filtrowac komunikaty przychodzace od klientow, zeby np ktos nieuprawniony nie wyslal MSG_KICK/MSG_BAN.. :P

Klient, w odpowiedzi na wciskane klawisze, wysyla komunikaty MSG_MOVEUP/MSG_MOVELEFT/MSG_FIRE, etc.. i przyjmuje MSG_CHAT, MSG_LOGOUT, ... implementujac odpowiednio metody onChat(), onLogout() np w klasie Player.

I wlasnie taka architektura pozwala uniknac serwera-pomostu, ktory przekazuje pakiety odpowiedno do serwera chata, aukcji i czegostam :)

Offline skiter

  • Użytkownik

# Lipiec 31, 2006, 17:08:21
Patrzysz czy sa jakies dane na ktoryms z gniazdek i jesli tak, to je przetwarzasz. Jak przelecisz wszystkie gniazdka to zasypiasz i czekasz az znowu jakies dane sie pojawia. Do tego sluza wlasnie funkcje select() i poll() lub ich odpowiedniki.
Pod linuxem moze i t odziala fajnie i wydajnie, pod windowsem mam pewne obawy, aczkolwiek ... nie poparte zadnym dowodem poza tym ze to "windows" tutaj wszystko jest mozliwe ; )

-- Czas nma doczytanie innego posta --
http://groups.google.pl/group/pl.comp.lang.c/browse_thread/thread/c26fb641cfba940c/9c35d47d81f48d6d?lnk=st&q=&rnum=3&hl=pl#9c35d47d81f48d6d

E ... to ja dalej jestem za watkami ; p, i mam "serwer" na 2 systemy bez walenia sie w "systemowe ograniczenia"

Offline zarius

  • Użytkownik

# Lipiec 31, 2006, 17:10:45
Patrzysz czy sa jakies dane na ktoryms z gniazdek i jesli tak, to je przetwarzasz. Jak przelecisz wszystkie gniazdka to zasypiasz i czekasz az znowu jakies dane sie pojawia. Do tego sluza wlasnie funkcje select() i poll() lub ich odpowiedniki.
Czyli jeden watek dla wszystkich polaczen ? ;p Poczytam pozniej o tym select i pool bo szczerze do tej pory watkow uzywalem raczej w prostszy sposob. Zadnym mutex'ow etc nie uzywalem bo nawet nie wiem jak ich uzywac ;) Takze bede musial zawidac na MSDN

I wlasnie taka architektura pozwala uniknac serwera-pomostu, ktory przekazuje pakiety odpowiedno do serwera chata, aukcji i czegostam :)
Czyli rozumiem ze to rozwiazanie zaprezentowane wyszej to jednym slowem kaszanka ;p ?

No bo jak sie przygladam temu rozwiazaniu do np takie wywolanie sendMessage oprocz odbiorcy i adresata oraz typu wiadomosci ma jeszcze parametr a ten parametr lub nawet ich ilosc w zaleznosci od typu by sie roznila. Srednio mi sie to podoba ;p Ale wlasciwie pomysl z Eventami i wiadomosciami (w C# jest wlasciwie wbudowany system do zdarzen wiec nie musial bym specjalnie pisac czegos swojego tylko przypomniec sobie jak to cholersto wdziala dokladnie ;p) moze nie byc zly...

Offline skiter

  • Użytkownik

# Lipiec 31, 2006, 17:17:30
Czyli jeden watek dla wszystkich polaczen ? ;p Poczytam pozniej o tym select i pool bo szczerze do tej pory watkow uzywalem raczej w prostszy sposob. Zadnym mutex'ow etc nie uzywalem bo nawet nie wiem jak ich uzywac ;) Takze bede musial zawidac na MSDN
Poll'a nie ma w Windows!, jest tylko select(), z tego co wyczytalem to bedzie dluga bajak z tym, wiec odrazu zacznij czytac o _beginthread().