sf::Network, Protobuf, or Another?
Nice work on the restart branch, it's starting to look pretty shiny :). SFML is pretty nice, that's what we used in Highrise Developer.
I've been looking at networking options and playing around a bit with the various options. I think that we probably don't want to homebrew this if we can avoid it, or at least we should take advantage of existing code as much as possible. Thus, the two options I've been looking at are using the sf::Network library (building our own packet structure), and the possibility of using google's protobuf library and defining what the packets look like (having protobuf generate the structs for us).
The biggest issue here is that C++ does not have any sort of reflection, so we can't write the network library in such a way that it figures everything out just given, say, a packet type and some data object. At least, we can't do that on the C++ end. If we could, I might try and write a library that talks to gob. This means that we are going to have to tell C++ how we want our data encoded, either by writing an overload for << on it (SFML), or by writing an external data definition file (protobuf).
Another option is just to send raw memory (with SFML for the basic network functionality), which would work for simple stuff like a struct of int32's, but would likely fail catastrophically for strings (since it would copy the pointer as an int, not copy the whole string). We would have to somehow write code to deal with this. Not sure if this is possible/easy with C++. This is the nicest in that it doesn't require any boilerplate code for new packets, but is a bit more dangerous in that adding a field on the client necessitates adding it on the server as well. We can minimize user issues with this by incrementing the version sent in the handshake for both client and server with each release, but it's still a potential issue when developing. Not a huge issue, however, as it should be reasonably easy to spot when you get totally bogus values, and the corruption would be limited to that packet (each packet has a length sent at the start, so even if the server/client doesn't know what to do with the data in that packet, it can still read the next one).
That was a bit of a brain dump, let me know if things don't make sense. I just kind of typed things as they came to mind :).
So far I've only really played with the sf::Network library, but it doesn't seem difficult at all to parse on the go end. My primary concern with both solutions at the moment is the boilerplate.
The following hack works, but requires that you use fixed-size char arrays for strings:
struct PTest {
sf::Int32 Field1;
char Field3[10];
};
[...]
PTest ptest;
ptest.Field1 = 3;
strcpy(ptest.Field3, "Thing 2!");
sf::Packet structTest;
structTest.Append(&ptest, sizeof(ptest));
client.Send(structTest);
Not very elegant... Not that nice to parse either, since the string doesn't have any length prefix, so you have to hit \0 before you know that you've hit the end.