cocosushi
cocosushi

Reputation: 144

SFML Networking | Sending objects containing other objects over sf::Packets cause null data

I am trying to send map data to a client, which takes the form of multiple vectors containing coordinates of the map's tiles. The whole map structure can be reduced to something like this (not actual code, but I reproduced the problem using this too) :

struct Tile {
    sf::Vector3<int> coords;
};

struct Map {
    Tile tiles[4];
};

Then, I use these operators to add this type of objects to a sf::Packet :

sf::Packet& operator<<(sf::Packet& packet, sf::Vector3<int> vec) {
    return packet << vec.x << vec.y << vec.z;
}

sf::Packet& operator>>(sf::Packet& packet, sf::Vector3<int> vec) {
    return packet >> vec.x >> vec.y >> vec.z;
}

sf::Packet& operator<<(sf::Packet& packet, Tile test) {
    return packet << test.coords;
}

sf::Packet& operator>>(sf::Packet& packet, Tile test) {
    return packet >> test.coords;
}

sf::Packet& operator<<(sf::Packet& packet, Map test) {
    for(int i = 0; i < 4; i++) {
        packet << test.tiles[i];
    }
    return packet;
}

sf::Packet& operator>>(sf::Packet& packet, Map test) {
    for(int i = 0; i < 4; i++) {
        packet >> test.tiles[i];
    }
    return packet;
}

Up to here, there shouldn't be any problem : the map must be deserialized to 4 tiles, which must be deserialised to a sf::Vector3<int> itself.

Then comes the sending :

Tile test;
test.coords.x = 42;
test.coords.y = 34;
test.coords.z = 43;

Map test3;
test3.tiles[0] = test;

sf::Packet packet;
packet << test3;

sock.send(packet);

This code works very well (I checked the content of the packet with GDB, data is indeed the same). The reception code works well too server-side :

sf::Packet packet;
sock.receive(packet);
Map test;
cout << "packet received" << endl;

Checking the content of the packet (still with GDB) gives the same thing as when it was sent. The contents of test are random (which is normal, because it hasn't been initialised yet).

The real problem happens when deserializing the actual packet data to the test variable :

if(packet >> test) {
    cout << test.tiles[0].coords.x;
} else {
    cout << "fail" << endl;
}

The result printed is 0. The deserialisation did well (no "fail" appearing in the console), but data is incorrect. Inspecting test's contents with GDB reveals every element its arrays are 0s. Here's GDB's output :

(gdb) print test
$1 = {tiles = {{coords = {x = 0, y = 0, z = 0}}, {coords = {x = 0, y = 0, z = 0}}, {coords = {x = 0, y = 0, z = 0}}, {coords = {
        x = 0, y = 0, z = 0}}}}

What could be the cause of this ? I am very sure I'm doing something wrong here, but I really can't get why.

Thanks in advance for any help :)

Upvotes: 1

Views: 346

Answers (1)

cocosushi
cocosushi

Reputation: 144

Ok, I finally managed to understand why this did not work. The answer, was, of course, extremely stupid, and typical of a silly C++ beginner :D.

Using the operator functions without passing the objects by reference was not having a single chance to work (as the variable's content would stay in the operator function and not be changed).

So, changing this :

sf::Packet& operator>>(sf::Packet& packet, Map test) {
    for(int i = 0; i < 4; i++) {
        packet >> test.tiles[i];
    }
    return packet;
}

to this :

sf::Packet& operator>>(sf::Packet& packet, Map& test) {
    for(int i = 0; i < 4; i++) {
        packet >> test.tiles[i];
    }
    return packet;
}

worked much better :)

Upvotes: 1

Related Questions