Autor Wątek: petla wysylajaca informacje o graczach  (Przeczytany 6509 razy)

Offline Psiryj

  • Użytkownik

# Maj 27, 2014, 20:02:34
siemka, pisze sobie gre mmorpg i natrafilem na problem z wysylaniem informacji o graczach do pozostalych klientow, otoz, gdy polaczy sie 2 graczy wszystko jest oki, ale gorka sie zaczyna gdy wejdzie trzecia lub wiecej osob, mianowicie przy 3 dolaczonym graczu otrzymuje on pakiety o graczach na mapie kilka razy, to samo gdy wejdzie 4 lub wiecej, lecz liczba kopii pakietow rosnie, mysle ze nie ma sensu wrzucac calego kodu, wiec pozwolcie ze umieszcze metode odpowiadajaca za wysylanie owych informacji
void Server::SendMapInfo()
{
    for( std::list < Client *>::iterator it = clients.begin(); it != clients.end(); ++it )
    {
        Client & client = ** it;
        if( inGameClients.size() > 1 )
        {
            for( std::list < Client *>::iterator itt = inGameClients.begin(); itt != inGameClients.end(); ++itt )
            {
                Client & temp = ** itt;
                if( temp.ClientID != client.ClientID && client.inGame == true && temp.inGame == true )
                {
                    if( client.Char.X / maps[ client.Char.MapID ]->tilesize - 8 <= temp.Char.X / maps[ client.Char.MapID ]->tilesize
                    && client.Char.X / maps[ client.Char.MapID ]->tilesize + 8 >= temp.Char.X / maps[ client.Char.MapID ]->tilesize
                    && client.Char.Y / maps[ client.Char.MapID ]->tilesize - 8 <= temp.Char.Y / maps[ client.Char.MapID ]->tilesize
                    && client.Char.Y / maps[ client.Char.MapID ]->tilesize + 8 >= temp.Char.Y / maps[ client.Char.MapID ]->tilesize
                    )
                    {
                        client.family = Packet::PACKET_WORLD;
                        client.action = Packet::PACKET_REQUEST;
                        client.send << client.family << client.action << temp.Char.Name << temp.ClientID << temp.Char.X << temp.Char.Y;
                        client.Send();
                        std::string str;
                        str = std::to_string( temp.ClientID );
                        str += " ";
                        str += temp.Char.Name;
                        str += " ";
                        str += std::to_string( temp.Char.X );
                        str += " ";
                        str += std::to_string( temp.Char.Y );
                        client.SMsg( str.c_str() );
                    }
                }
            }
        }
    }
}

Offline Mr. Spam

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

Offline .:NOXY:.

  • Użytkownik
    • Profil

# Maj 28, 2014, 10:42:31
Umm w takim razie jakie jest pytanie ? :D

Offline Psiryj

  • Użytkownik

# Maj 28, 2014, 16:36:32
oj sory, zapomnialem, :v, co jest takiego w tym kodzie ze dostaje powtarzajace sie pakiety przy wiecej niz 2 graczach?

Offline Malkavian Ass...

  • Użytkownik

  • +1
# Maj 28, 2014, 17:00:16
Nie wiem, czym różnią się clients i inGameClients, ale Twoja pętla wykonuje kwadratową ilość iteracji.

Offline Psiryj

  • Użytkownik

# Maj 28, 2014, 17:08:39
nie roznia sie niczym po za tym ze przechowuje wskazniki na obiekty, ktore sa w zalogowane do swiata gry, tak wiem ze wykonuje sie do kwadratu, stad te bledy i nie mam pomyslu jak to naprawic :v

Offline Malkavian Ass...

  • Użytkownik

# Maj 28, 2014, 17:27:35
Wywal jedną z pętli, zewnętrzną lub wewnętrzną.

Offline lethern

  • Użytkownik

# Maj 28, 2014, 17:34:11
brzmi zbyt prosto


nie mogłem się powstrzymać :D

@Topic - może napisz +- opis tego co chcesz uzyskać, albo w pseudokodzie, bo póki co to mamy z fusów wróżyć
« Ostatnia zmiana: Maj 28, 2014, 17:36:38 wysłana przez lethern »

Offline Psiryj

  • Użytkownik

# Maj 28, 2014, 17:48:35
Wywal jedną z pętli, zewnętrzną lub wewnętrzną.
swietne rozwiazanie, tym bardziej ze nie bede mial iteratora dla jednego ze wskaznikow, mam wysylac pakiety do samego siebie? xd

Offline Malkavian Ass...

  • Użytkownik

# Maj 28, 2014, 18:14:11
No ja nie rozumiem, po co iterować klient x klient razy.

Offline Psiryj

  • Użytkownik

# Maj 28, 2014, 18:29:01
if( temp.ClientID != client.ClientID && client.inGame == true && temp.inGame == true )
ten if chyba wystarczajaco duzo tlumaczy nie sadzisz? ;)

Offline Psiryj

  • Użytkownik

# Maj 28, 2014, 21:11:51
@up, zamienilem sobie liste na wektory bym mial wiecej mozliwosci, jednak nadal nic nie moge wymyslec, jakies pomysly?
void Server::SendMapInfo()
{
    for( int i=0;i<inGame;++i )
    {
        if(inGame>1)
        {
            for( int j=0;j<inGame;++j)
            {
                if(inGameClients[j]->ClientID!=inGameClients[i]->ClientID&&inGameClients[i]->inGame==true&&inGameClients[j]->inGame==true)
                {
                    if(inGameClients[i]->Char.X/maps[inGameClients[i]->Char.MapID]->tilesize-8<=inGameClients[j]->Char.X/maps[inGameClients[i]->Char.MapID]->tilesize
                        && inGameClients[i]->Char.X/maps[inGameClients[i]->Char.MapID]->tilesize+8 >= inGameClients[j]->Char.X/maps[inGameClients[i]->Char.MapID]->tilesize
                        && inGameClients[i]->Char.Y/maps[inGameClients[i]->Char.MapID]->tilesize-8 <= inGameClients[j]->Char.Y/maps[inGameClients[i]->Char.MapID]->tilesize
                        && inGameClients[i]->Char.Y/maps[inGameClients[i]->Char.MapID]->tilesize+8 >= inGameClients[j]->Char.Y/maps[inGameClients[i]->Char.MapID]->tilesize
                    )
                    {
                        inGameClients[i]->family=Packet::PACKET_WORLD;
                        inGameClients[i]->action=Packet::PACKET_REQUEST;
                        inGameClients[i]->send<<inGameClients[i]->family<<inGameClients[i]->action<<inGameClients[j]->Char.Name<<inGameClients[j]->ClientID<<inGameClients[j]->Char.X<<inGameClients[j]->Char.Y;
                        inGameClients[i]->Send();
                        std::string str;
                        str=std::to_string(inGameClients[j]->ClientID);
                        str+=" ";
                        str+=inGameClients[j]->Char.Name;
                        str+=" ";
                        str+=std::to_string(inGameClients[j]->Char.X);
                        str+= " ";
                        str+=std::to_string(inGameClients[j]->Char.Y);
                        str+="I "+std::to_string(i);
                        str+=" J "+std::to_string(j);
                        inGameClients[i]->SMsg(str.c_str());
                    }
                }
            }
        }
    }
}

Offline remz

  • Użytkownik

# Maj 28, 2014, 21:22:06
Skoro to gra MMORPG, to raczej nie każdy klient wysyła informacje do każdego klienta (o co w ogóle chodzi?), tylko serwer wysyła informacje o mapie do każdego klienta. Po co więc dwie pętle?

PS: Wysyłając w ten sposób informacje MMO nie napiszesz, świat powinien być podzielony na mniejsze części i tylko informacje potrzebne dla danego klienta powinny być do niego przesyłane. - powiedzmy, że nie zauważyłem jednego if-a.
« Ostatnia zmiana: Maj 28, 2014, 21:49:23 wysłana przez remz »

Offline Psiryj

  • Użytkownik

# Maj 28, 2014, 21:27:42
ale to jest po stronie serwera, musze skads pobierac przeciez dane o graczach, trzymam je w kontenerach, wyglada to tak:
class Server
{
    public:
        void init( int Port );
        void SendMapInfo();
        void select();
        void update();
        void ping();
        void LoadMaps();
        CDataFile Acc;
    private:
        sf::TcpListener Listener;
        sf::SocketSelector Selector;
        std::vector<Client*> clients;
        std::vector<Client*> inGameClients;
        std::vector<Map*> maps;
        int inGame;
};
 vector clients trzyma obiekty polaczone z serwerem, lecz nie sa zalogowani na zadna postac, vector inGameClients zas juz ma postaci zalogowane do swiata gry, stad dwie petle, pierwsza petla wybiera do ktorego klienta serwer ma wyslac informacje, druga petla to wysylanie owych informacji, jednak przy 3 i powyzej klientach petla wykonuje zbyt duzo ruchow i nie wiem jak to zmienic, gdybym wiedzial nie zakladalbym tego tematu przecie : D

Offline remz

  • Użytkownik

# Maj 28, 2014, 21:44:22
Gracz1 wysyła pakiet do Gracza2 (pakiet)
Gracz1 wysyła pakiet do Gracza3 (pakiet)

Gracz2 wysyła pakiet do Gracza1 (pakiet)
Gracz2 wysyła pakiet do Gracza3 (pakiet)

Gracz3 wysyła pakiet do Gracza1 (pakiet)
Gracz3 wysyła pakiet do Gracza2 (pakiet)

Tak działa ta pętla, więc to chyba nic dziwnego, że każdy gracz dostaje pakiet x2? :p Jak to zmienić? Nie wysyłać pakietów o stanie świata 'każdy do każdego', bo nie ma takiej potrzeby?
« Ostatnia zmiana: Maj 28, 2014, 21:46:54 wysłana przez remz »

Offline Xion

  • Redaktor
    • xion.log

  • +1
# Maj 28, 2014, 21:51:38
Cytuj
Nie wiem, czym różnią się clients i inGameClients, ale Twoja pętla wykonuje kwadratową ilość iteracji.
Thank you, Captain Obvious.
Cytuj
Wywal jedną z pętli, zewnętrzną lub wewnętrzną.
LOLWUT?

@op: Jakkolwiek koszmarnym pomysłem jest informowanie każdego klienta osobnym pakietem o stanie każdego innego klienta (bo o wiele lepiej jest zebrać cały stan gry -- czy raczej okolicy gracza -- w jedną paczkę), podany kawałek kodu zasadniczo ma sens.
Problem leży gdzie indziej, na przykład w tym kiedy tę funkcję wywołujesz. Nie jest przypadkiem tak, że każda akcja jednego klienta powoduje wysłanie tego update'a do wszystkich? Wtedy rzeczywiście większa liczba klientów skutkowałaby większą liczbą pakietów.