I've used various systems in the past, auto-generated packets, hand coded seralziation fuctions, etc.. Eventually I settled upon a macro based scheme where you define the serazlation fucitons inline with the class/struct and it auto generates the read/write functional hooks. I also used marcos to support versioning since I've used this scheme for both networking and general save/load scheme, but not in this version. In the same vien, for packet registeration it's also auto-regsiterting but you do have to define some additional marcos in the implementation.
Looks something like this.
class netFileDownloadPacket : public netPacketBase { NET_PACKET_SIMPLE(netFileDownloadPacket,eNetFileDownloadPacket); public: netFileDownloadPacket(){} BIND_(1, SvcNet::NetBuffer, mData); BIND_(2, StringType, mPath); BIND_END_VIRTUAL(2,netFileDownloadPacket); }; BIND_OBJECT(netFileDownloadPacket); NET_PACKET_REGISTER(netFileDownloadPacket);
Some people don't like the marcos being in the class, header but it's very convient to keep the implementatino and serazlation in sync as they are one in the same.
Here's a snippet of the marcos
//serialization macros create interface functions //n = number of the param, will generate a read/write function for the given number//t = type of the member variable //m = member variable name itself#define BIND_(n,t,m) t m; void _W##n(SvcNet::NetBuffer& in) const {in.Write(m);} void _R##n(SvcNet::NetBuffer& out){out.Read(m);} //similar to BIND_, but defines a fixed sized array instead, param (s) is the size of the array#define BIND_A(n,t,m,s) t m; <span class="cpp-keyword">void</span> _W##n(SvcNet::NetBuffer& in) <span class="cpp-keyword">const</span> {in.WriteArray(m,s);} <span class="cpp-keyword">void</span> _R##n(SvcNet::NetBuffer& out){out.ReadArray(m,s);}<br><br><span class="cpp-comment">//similar to BIND_, but defines custom read/write functions (r,w)</span><br><span class="cpp-directive">#define</span> BIND_C(n,t,m,r,w) t m; <span class="cpp-keyword">void</span> _W##n(SvcNet::NetBuffer& in) <span class="cpp-keyword">const</span> {r(in,m);} <span class="cpp-keyword">void</span> _R##n(SvcNet::NetBuffer& out){w(out,m);} <br><br><br><br></pre></div><!–ENDSCRIPT–><br><br>this scheme does depend upon global templated functions hooks for read/write, that's what the BIND_OBJECT does as such<br><br><!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre><br><br><span class="cpp-comment">//defines global binding function, the object must implement the binding interface of Write/Read</span><br><span class="cpp-directive">#define</span> BIND_OBJECT(T) <span class="cpp-keyword">inline</span> <span class="cpp-keyword">void</span> Write (<span class="cpp-keyword">const</span> T&t, SvcNet::NetBuffer& buff){t.Write(buff);} <span class="cpp-keyword">inline</span> <span class="cpp-keyword">void</span> Read (T&t, SvcNet::NetBuffer& buff){t.Read(buff);}<br><br><span class="cpp-comment">//similar as BIND_END but makes the function virtual, allow for inheritance on the read/write</span><br><span class="cpp-directive">#define</span> BIND_END_VIRTUAL(n,p) <span class="cpp-keyword">virtual</span> <span class="cpp-keyword">void</span> Write (SvcNet::NetBuffer& buff)<span class="cpp-keyword">const</span>{BIND_WRITE(p,n);} <span class="cpp-keyword">virtual</span> <span class="cpp-keyword">void</span> Read (SvcNet::NetBuffer& buff){BIND_READ(p,n);}<br><br><br></pre></div><!–ENDSCRIPT–><br><br>Ultimately the hooks are called inside the NetBuffers read/write functions to complete seralzaition/deseralzitions. The last bit of the puzzle is the autogernation of the seralzaition functions with the proper number of calls to the auto generated read/write funcitons. You'll have to use a marco unrolling technique, it's a common template meta-programming techinque, used in libraries such as Boost, Luabind, etc..<br><br>It looks like this:<br><br><!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre><br><br><span class="cpp-directive">#define</span> BIND_WRITE1(type,n) type::_W1(buff);<br><span class="cpp-directive">#define</span> BIND_WRITE2(type,n) BIND_WRITE1(type,n-<span class="cpp-number">1</span>) type::_W2(buff); <br><span class="cpp-directive">#define</span> BIND_WRITE3(type,n) BIND_WRITE2(type,n-<span class="cpp-number">1</span>) type::_W3(buff); <br><span class="cpp-directive">#define</span> BIND_WRITE4(type,n) BIND_WRITE3(type,n-<span class="cpp-number">1</span>) type::_W4(buff); <br><span class="cpp-directive">#define</span> BIND_WRITE5(type,n) BIND_WRITE4(type,n-<span class="cpp-number">1</span>) type::_W5(buff); <br><span class="cpp-directive">#define</span> BIND_WRITE(type,n) BIND_WRITE##n(type,n-<span class="cpp-number">1</span>)<br><br><br><br></pre></div><!–ENDSCRIPT–><br><br>And there u go! <br><br>Enjoy!<br><br>-ddn