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

[SFML 2.0 - Network] Wysyłanie informacje o mapie.

Ostatnio zmodyfikowano 2013-08-28 13:38
Autor Wiadomość
RazzorFlame
Temat założony przez niniejszego użytkownika
[SFML 2.0 - Network] Wysyłanie informacje o mapie.
» 2013-08-27 12:16:34
Dobra, nie wiem czy ja jakiś ułomny jestem czy co ale już od 4 dni szukam błędu i nadal nie moge znaleźć... Klasa mapy (server):

Server

C/C++
class GameMap
{
   
public:
    short m_SizeX, m_SizeY;
   
    GameMap( const GameMap & );
    GameMap( int, int );
    GameMap();
    ~GameMap();
   
    short * m_MapInfo_First;
    short * m_MapInfo_Second;
   
    void loadFromTiles( short[] );
    void loadFromFile( string );
    void saveToFile( string );
   
    void resizeMap( int, int );
   
    short * getElement( Vector2D, char );
   
};
Definicja klasy mapy:
C/C++
GameMap::GameMap( const GameMap & tmp )
{
    m_SizeX = tmp.m_SizeX;
    m_SizeY = tmp.m_SizeY;
    resizeMap( m_SizeX, m_SizeY );
}
GameMap::GameMap()
{
    m_SizeX = 0;
    m_SizeY = 0;
    m_MapInfo_First = NULL;
    m_MapInfo_Second = NULL;
}
GameMap::GameMap( int sizeX, int sizeY )
{
    m_SizeX = sizeX;
    m_SizeY = sizeY;
    resizeMap( m_SizeX, m_SizeY );
}
GameMap::~GameMap()
{
    delete m_MapInfo_First;
    delete m_MapInfo_Second;
}
void GameMap::resizeMap( int x, int y )
{
    delete m_MapInfo_First;
    delete m_MapInfo_Second;
    m_MapInfo_First = new short[ x * y ];
    m_MapInfo_Second = new short[ x * y ];
    m_SizeX = x;
    m_SizeY = y;
   
    for( int i = 0; i < x * y; i++ )
    {
        m_MapInfo_First[ i ] = 0;
        m_MapInfo_Second[ i ] = 0;
    }
}
short * GameMap::getElement( Vector2D v, char id )
{
    if( v.X > m_SizeX || v.X < 0 || v.Y < 0 || v.Y > m_SizeY )
    {
        cout << "v.X = " << v.X << "/v.Y = " << v.Y << endl;
        return NULL;
    }
    if( id == 1 ) return & m_MapInfo_First[( int ) m_SizeX *( int ) v.Y +( int ) v.X ];
    else if( id == 2 ) return & m_MapInfo_Second[( int ) m_SizeX *( int ) v.Y +( int ) v.X ];
   
    return NULL;
}
Reszte funkcji (loadFromFile, loadFromTiles i saveToFile jest zdefiniowanych ale ich nie używam i działają poprawnie).
Tak tworze mape (losuje ją na razie a potem kiedy będzie działało dodam edytor map):
C/C++
void Server::loadServer()
{
   
    m_Map.resizeMap( 50, 50 );
    for( int i = 0; i < 50 * 50; i++ )
    {
        m_Map.m_MapInfo_First[ i ] = 2;
    }
    *( m_Map.getElement( Vector2D( 0, 0 ), 1 ) ) = 3;
   
    for( int i = 0; i < 50 * 50; i++ )
    {
        cout << m_Map.m_MapInfo_First[ i ] << " ";
        if( i % 50 == 0 && i != 0 ) cout << endl;
       
    }
    //tu reszta kodu ale z ladowaniem postaci
}
Pewnie sie też zdziwiliście dlaczego resizeMap usuwa mape i dodaje nową... takie coś mi wystarczy na razie, potem dodam kopiowanie :)
A oto jak wysyłam (z servera do clienta) mape:
C/C++
void Server::sendMapInfo( unsigned short id )
{
    sf::Packet pack;
   
    int pos_x = m_Players[ id ]->getData()->getPosition()->X;
    int pos_y = m_Players[ id ]->getData()->getPosition()->Y;
    if( pos_x != m_Players[ id ]->getData()->getPosition()->X || pos_y != m_Players[ id ]->getData()->getPosition()->Y ) return;
    //cout<<"Player ("<<*(m_Players[id]->getData()->getName())<<") position is "<<pos_x<<"/"<<pos_y<<endl;
   
    pack << std::string( "MAP" );
   
    for( int y = pos_y - 7; y < pos_y + 7; y++ )
    {
        for( int x = pos_x - 10; x < pos_x + 10; x++ )
        {
            if( m_Map.getElement( Vector2D( x, y ), 1 ) != NULL )
            {
                short el = *( m_Map.getElement( Vector2D( x, y ), 1 ) ) + 1;
                pack << el;
                //cout<<el<<" ";
            }
            else
            {
                pack << 1;
                cout << "Can't read!" << endl;
            }
        }
        cout << endl;
    }
   
    m_Players[ id ]->getConnection()->sendPacket( pack );
}

Client


Tak odbieram ten pakiet z mapą (i co ciekawe przychodzi chyba bez szwanku):
C/C++
else if( packetType == "MAP" )
{
    cout << "MAP" << endl;
    m_Map.resizeMap( 21, 15 );
    pack >> m_Map;
}
A tak wypakowuje oraz wyświetlam to (mape):
C/C++
void GameMap::draw( sf::RenderWindow * win, sf::Sprite * spr )
{
    //cout<<"..."<<endl;
    if( m_SizeX > 0 && m_SizeY > 0 )
    {
        Rect2D dre;
        dre.W = 40;
        dre.H = 40;
        //cout <<m_SizeX<< "/" << m_SizeY<<endl;
       
        for( int x = 0; x < m_SizeX; x++ )
        {
            for( int y = 0; y < m_SizeY; y++ )
            {
                dre.X =( *( getElement( Vector2D( x, y ), 1 ) ) ) * 40;
                dre.Y = 0;
                spr->setTextureRect( dre.convertToI( true ) );
                spr->setPosition( 20 + x * 40, y * 40 );
                win->draw( * spr );
            }
        }
    }
   
}
sf::Packet & operator >>( sf::Packet & packet, GameMap & gm )
{
   
    for( int i = 0; i < 21 * 15; i++ )
    {
        short element;
        packet >> element;
        gm.m_MapInfo_First[ i ] = element - 1;
    }
    return packet;
}
Warto też wspomnieć że klasa mapy wygląda identycznie w serwerze i cliencie ale do clienta dodane są jeszcze 2 funkcje (czyli wyświetlanie i wypakowywanie)...
Edit: Kurcze zapomniałem opisać błędu:
Mapa przychodzi niemiłosiernie zdeformowana, już nie mówiąc o wyświetlaniu...
P-91010
DejaVu
» 2013-08-28 09:35:07
Sprawdź czy dane wysłane = dane odebrane, a potem pewnie stwierdzisz, że algorytm nanoszenia otrzymanych danych na mapę jest zły :) Jeżeli dane odebrane != dane wysyłane to również będziesz wiedział gdzie coś poprawiać.
P-91101
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2013-08-28 10:06:04
Sprawdziłem, dane które wysyłam na serwerze są prawidłowe i wyglądają tak:

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
Gdzie 1 = puste pole (wychodzi poza mape), 2 = trawa, 3 = woda... Taką mape ustawiam teraz na początku (już nie losuje żeby widzieć czy dane przyszły dobre).
Zaś w cliencie takie dane dostaje:

-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0,
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0,
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0,
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0,
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0,
-1, 0, -1, 0, -1, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, -1,
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0,
-1, 0, -1, 0, -1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, -1,
Na prawde nie wiem skąd są tu te -1 jeżeli nie wysyłam z serwera żadnego 0 (bo na razie "koduje" mape tak że dodaje do niej 1 w serwerze a odejmuje 1 w cliencie (tak wiem, to sie nie ma prawa nazywać kodowaniem ;))... A oto aktualny kod wysyłania (serwer):
C/C++
sf::Packet pack;
pack << std::string( "MAP" );

for( int y = pos_y - 7; y < pos_y + 7; y++ )
{
    for( int x = pos_x - 10; x < pos_x + 10; x++ )
    {
        if( m_Map.getElement( Vector2D( x, y ), 1 ) != NULL )
        {
            short el = *( m_Map.getElement( Vector2D( x, y ), 1 ) ) + 1;
            pack << el;
            cout << el << ", ";
        }
        else
        {
            pack << 1;
            cout << "1, ";
        }
    }
    cout << endl;
}
m_Map.getElement zwraca wskaźnik na element mapy o podanym Vector2D (zwraca NULL jeśli Vector2D wychodzi poza mape).
Tak wygląda odbieranie w cliencie:
C/C++
else if( packetType == "MAP" )
{
    cout << "MAP" << endl;
    m_Map.resizeMap( 21, 15 );
    pack >> m_Map;
}
I operator do wczytywania klasy GameMap:
C/C++
sf::Packet & operator >>( sf::Packet & packet, GameMap & gm )
{
   
    for( int i = 0; i < 21 * 15; i++ )
    {
        short element;
        if( !( packet >> element ) )
        {
            cout << "Failed to read \"short\" (" << sizeof( short ) << " bytes) from packet!" << endl;
        }
        if( i % 21 == 0 && i != 0 ) cout << endl;
       
        cout << element - 1 << ", ";
       
        gm.m_MapInfo_First[ i ] =( element > 0 ? element - 1: 0 );
    }
    return packet;
}
Dziwne też jest to że wypakowywanie "shortów" z packet'u się powodzi bo nie widze wiadomości która ma być wyświetlana kiedy nie powiedzie sie.
To jest jakieś nawiedzone chyba :). Tak więc dane przychodzą zdeformowane...


EDIT!!

Log konsoli serwera (a raczej dane o mapie) są już po dodaniu, czyli w rzeczywistości każdy element powinien być o 1 mniejszy... Zaś dane w cliencie są już po odjęciu 1.
P-91103
DejaVu
» 2013-08-28 10:38:55
Nie koduj i nie dekoduj na razie żadnych informacji. Twoim celem jest wysłać wiadomość X i odebrać ją w tej samej postaci. Kodowanie/szyfrowanie możesz dorobić sobie później.

/edit:
Zmniejsz również wysyłaną i odbieraną mapę do rozmiaru np. 3x5 to łatwiej będzie Ci analizować dane. Dodatkowo wysyłaj mapę w postaci: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 i zobacz co zostanie wówczas odebrane.

http://www.sfml-dev.org​/documentation/2.0​/classsf_1_1Packet.php

Z dokumentacji wynika, że wysyłanie i odbieranie danych raczej do trudnych zadań nie należy.
P-91105
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2013-08-28 11:03:40
Z dokumentacji wynika, że wysyłanie i odbieranie danych raczej do trudnych zadań nie należy.
Przecież wiem... Ale nie rozumiem o co chodzi ci z tym "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15". Mam sprawdzić co będzie jak to wyśle? Miałem też pomysł żeby nie wysyłać każdego shorta oddzielnie (bo może sf::Packet ma jakieś ograniczenie co do ilości zmiennych???) i zapisać całą mape w stringu po czym go wysłać ale to by nie miało sensu bo przecież string to opakowana tablica char'ów :/
P-91107
akwes
» 2013-08-28 11:16:03

Ale nie rozumiem o co chodzi ci z tym "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15".

@up, wyślij i odbierz to samo i nic więcej z tym nie rób. Jednym wyślij taki ciąg, i niech drugi program go wyświetli. I dopiero potem kombinuj jak będziesz pewien, że to przesyłanie przechodzi poprawnie. Potem dokładaj kolejno następne warstwy złożoności i na każdej warstwie kontroluj czy odbierasz to co wysłałeś. W pewnym momencie będą inne dane i będziesz wiedział w której warstwie leży błąd.
P-91109
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2013-08-28 11:27:19
Ale ja jestem pewien że przychodzi dobrze rozumiesz? Nie tylko mape wysyłam ale też pozycje innych zalogowanych graczy i komendy od clienta (np. przemieszczanie)
P-91110
akwes
» 2013-08-28 11:36:40
@RazzorFlame, to teraz przeczytaj resztę mojego postu a nie tylko pierwsze zdanie.
P-91111
« 1 » 2
  Strona 1 z 2 Następna strona