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.cppwhile( 1 ) { if( ev.type == ALLEGRO_EVENT_TIMER ) { player->update( key ); _beginthread( player_updatePos, 0, player ); }
Client - player.cpp void CPlayer::update( CKeyboard key ) { ++timeToSend; if( timeToSend >= 1 ) { timeToSend = 0; 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 ); } }
void __cdecl player_updatePos( void * arg ) { 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 ) { v_otherPlayers.push_back( COtherPlayer( nickInnego ) ); } } else player->oldPos = player->pos; } } _endthread(); }
Client - funkcja na wysyłanie pozycji: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)while( 1 ) { serviceResult = enet_host_service( server, & event, 1 ); 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! |
|
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? char mess[ event.packet->dataLength ];
Tak się nie tworzy tablic. |
|
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. |
|
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. |
|
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. |
|
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. |
|
Monika90 |
» 2013-11-07 11:51:41 while( 1 ) { if( ev.type == ALLEGRO_EVENT_TIMER ) { _beginthread( player_updatePos, 0, player ); }
Czy to oznacza, że tworzysz wątki w tempie 60 na sekundę? |
|
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ł. |
|
« 1 » 2 |