Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++, eNet] Wysyłanie stanu gracza klient <-> server

Ostatnio zmodyfikowano 2013-11-10 12:20
Autor Wiadomość
Rughailon
Temat założony przez niniejszego użytkownika
[C++, eNet] Wysyłanie stanu gracza klient <-> server
» 2013-11-06 21:13:25
Witam. Piszę grę MMORPG i mam pewien problem. Spędziłem dużo czasu szukając odpowiedzi, ale niestety nic nie znalazłem.

Jeśli jest tylko jeden gracz w grze, to wszystko jest w porządku. Ale jeśli jest więcej graczy, poruszają się oni jeden po drugim, w kolejności w której pierwszy gracz się poruszył. Każdy klient wysyła pozycję gracza w normalnej funkcji, a otrzymuje ją w funkcji w innym wątku. Jeśli staram się stworzyć drugi wątek na serwerze (tylko w celu uzyskania pozycji), klient ma około 10 fps (normalnie ma 60).

Od razu ostrzegam, że kod może nie być najładniejszy. Wszystko się zmieni, kiedy uporamy się z tym problemem. :)
Client - main.cpp
C/C++
while( 1 ) {
    //...
    if( ev.type == ALLEGRO_EVENT_TIMER ) { // 60 fps
        //...
        /*** LOGIC ***/
        player->update( key );
       
        _beginthread( player_updatePos, 0, player );
       
    }
Client - player.cpp
C/C++
// - send pos
void CPlayer::update( CKeyboard key ) {
    ++timeToSend;
   
    if( timeToSend >= 1 /* && (oldPos.x != pos.x || oldPos.y != pos.y)*/ ) { //  [ 20 = 1/3 sec with 60 FPS ]
        timeToSend = 0;
       
        // send position
        char wiad[ 45 ] = "";
       
        char buf[ 10 ];
        itoa( pos.x, buf, 10 );
        char buf2[ 10 ];
        itoa( pos.y, buf2, 10 );
       
        char buf4[ 20 ];
        itoa( nick.size(), buf4, 10 );
       
        char * buf3 = new char[ nick.size() ];
        for( int i = 0; i < nick.size(); ++i )
             buf3[ i ] = nick[ i ];
       
        sprintf( wiad, "POS%s%s=%sx%s", buf4, buf3, buf, buf2 );
       
        sendToServerUnseq( wiad, 1 );
    }
}
// - otrzymanie pozycji:
void __cdecl player_updatePos( void * arg ) {
    //void player_updatePos(CPlayer* player) {
   
    CPlayer * player = static_cast < CPlayer *>( arg );
   
    if( event.type == ENET_EVENT_TYPE_RECEIVE ) {
       
        if( receive( event.packet->data, "POS" ) ) {
            string mes = getPacket( event.packet->data );
           
            //...
            if( nickInnego != player->nick )
            {
                bool finded = false;
                for( int i = 0; i < v_otherPlayers.size(); ++i ) {
                    if( v_otherPlayers[ i ].nick == nickInnego ) {
                        v_otherPlayers[ i ].pos.x = atoi( posX.c_str() );
                        v_otherPlayers[ i ].pos.y = atoi( posY.c_str() );
                        v_otherPlayers[ i ].timeFromLastReceive = 0;
                        finded = true;
                        break;
                    }
                }
                if( !finded ) { // new player
                    v_otherPlayers.push_back( COtherPlayer( nickInnego ) );
                }
            }
            else
                 player->oldPos = player->pos;
           
        }
    }
   
    _endthread();
}
Client - funkcja na wysyłanie pozycji:
C/C++
void sendToServerUnseq( char * message, int channelID ) {
    ENetPacket * p = enet_packet_create(( char * ) message, strlen( message ) + 1, ENET_PACKET_FLAG_UNSEQUENCED );
    enet_peer_send( peer, channelID, p );
   
    enet_host_flush( client );
   
    serviceResult = enet_host_service( client, & event, 100 );
}

Server - main.cpp (wysyła tylko to, co dostał od klienta)
C/C++
while( 1 )
{
    serviceResult = enet_host_service( server, & event, 1 ); //1000 = 1 sec
   
   
case ENET_EVENT_TYPE_RECEIVE:
    {
        if( receive( event.packet->data, "POS" ) ) {
            char mess[ event.packet->dataLength ];
           
            for( int i = 0; i < event.packet->dataLength; ++i )
                 mess[ i ] = event.packet->data[ i ];
           
            ENetPacket * p = enet_packet_create( mess, strlen( mess ) + 1, ENET_PACKET_FLAG_UNSEQUENCED );
           
            enet_host_broadcast( server, 1, p );
            enet_host_flush( server );
        }
    }
}

Co jest nie tak? Z góry dzięki za pomoc!
P-95508
pekfos
» 2013-11-06 21:31:39
Ale jeśli jest więcej graczy, poruszają się oni jeden po drugim, w kolejności w której pierwszy gracz się poruszył.
Czyli co?

C/C++
char mess[ event.packet->dataLength ];
Tak się nie tworzy tablic.
P-95511
Rughailon
Temat założony przez niniejszego użytkownika
» 2013-11-06 21:36:34
Chodzi o to, że gdy kilka postaci się porusza, to następuje kolejka pakietów. I pakiet drugiego gracza jest odbierany tylko po skończeniu pracy nad pakietem pierwszego. Czyli w danym momencie serwer obsługuje tylko jednego gracza.
P-95512
RazzorFlame
» 2013-11-06 22:05:38
I co ci się w tym nie podoba? Zazwyczaj właśnie tak działa serwer...

Edit:
Ogólnie z tego kodu widać że masz niezbyt dobre podejście. Użyj klas. Ja kiedy pisałem coś w tym stylu w SFML (sockety przy użyciu modułu Network) to tworzyłem najpierw klasy potem robiłem tak:
Serwer tworzył liste wskaźników na obiekty klasy gracza.
Następnie tworzyłem dynamicznie jeden taki obiekt (a raczej obiekt klasy połączenia a nie gracza) i jeśli takowy obiekt chciał się połączyć to dodawałem to połączenie do kolejki niezalogowanych połączeń i jeśli któryś z tych połączeń wysłał login i hasło do serwera i były to poprawne dane to usuwałem ten wskaźnik z kolejki niezalogowanych i dodawałem wskaźnik na dynamicznie stworzony obiekt gracza z pobranymi odpowiednimi danymi z bazy danych (a dokładnie danymi o graczu z podanym przez clienta loginem i hasłem).
A teraz kluczowa część: Po kolei sprawdzałem czy jakiś z graczy nie przysłał komendy. Jeśli tak, to sprawdzałem czy gracz może je zrealizować i jeśli i to było możliwe to dodawałem akcje do kolejki kolejno (stopniowo) wykonywanych zadań. Nie znaczy to że jeśli gracz przysłał komende "idz w lewo" to pętlą powoli zmniejszałem jego pozycje X o jakiś mnożnik bo serwer obsługiwałby tylko 1 gracza jednocześnie tak jak to jest w twoim przypadku.
P-95513
braders
» 2013-11-06 23:14:46
Zazwyczaj właśnie tak działa serwer

Nie jestem jakimś specjalistą ale wydaje mi się ze serwer działa na wielu wątkach.
P-95519
DejaVu
» 2013-11-07 08:57:26
Wypisuj więc w logu serwera informacje kiedy np. przychodzi pakiet i dodaj tam Sleepa (np. 50ms), aby przetestować czy problem dotyczy serwera czy też sposobu odbierania pakietów przez klienta.
P-95524
Monika90
» 2013-11-07 11:51:41
C/C++
while( 1 ) {
    if( ev.type == ALLEGRO_EVENT_TIMER ) { // 60 fps
        _beginthread( player_updatePos, 0, player );
    }
Czy to oznacza, że tworzysz wątki w tempie 60 na sekundę?
P-95529
Rughailon
Temat założony przez niniejszego użytkownika
» 2013-11-09 19:40:25
To tak. Dziękuję wszystkim za rady. :)

Poprawiłem tworzenie tablic, zmniejszyłem szybkość wykonywania wątku do 6 razy na sekundę(niedopatrzenie z mojej strony. ), dodałem też klasę gracza z vectorem, w którym pozycje graczy są rozsyłane pomiędzy resztą obiektów z vectora. I powiem, że jest ciut lepiej, ale nadal nie ma zadowalającego wyniku. Chcę, żeby kilku graczy mogło poruszać się real-time.

Gdyby było koniecznie już teraz, to mogę przebudować cały ten system, jak RazzorFlame napisał.
P-95820
« 1 » 2
  Strona 1 z 2 Następna strona