From c4227bca8e7a6be68180e4a41314ea3e82227fb7 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Tue, 12 Jan 2010 00:03:30 +0000 Subject: [PATCH] use growable packetbuf instead of ucharbuf git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@4762 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/client.cpp | 44 +++++---------- source/src/clientgame.cpp | 12 ++--- source/src/clients2c.cpp | 2 +- source/src/protocol.cpp | 35 ++++++++++-- source/src/protos.h | 10 ++++ source/src/server.cpp | 111 +++++++++++++------------------------- source/src/server.h | 2 +- source/src/tools.h | 100 +++++++++++++++++++++++++++++++--- 8 files changed, 191 insertions(+), 125 deletions(-) diff --git a/source/src/client.cpp b/source/src/client.cpp index abee6a4c..c4328d30 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -326,7 +326,6 @@ void sendpackettoserv(int chan, ENetPacket *packet) { if(curpeer) enet_peer_send(curpeer, chan, packet); else localclienttoserver(chan, packet); - if(!packet->referenceCount) enet_packet_destroy(packet); } void c2skeepalive() @@ -343,8 +342,7 @@ void c2sinfo(playerent *d) // send update to the server if(d->state==CS_ALIVE || d->state==CS_EDITING) { - ENetPacket *packet = enet_packet_create(NULL, 100, 0); - ucharbuf q(packet->data, packet->dataLength); + packetbuf q(100); int cn = d->clientnum, x = (int)(d->o.x*DMF), // quantize coordinates to 1/16th of a cube, between 1 and 3 bytes y = (int)(d->o.y*DMF), @@ -371,7 +369,7 @@ void c2sinfo(playerent *d) // send update to the server dz >= -8 && dz <= 7) { // compact POS packet bool noroll = !r, novel = !dx && !dy && !dz; - bitbuf b(&q); + bitbuf b(q); putint(q, SV_POSC); b.putbits(5, cn); b.putbits(2, usefactor - 7); @@ -412,18 +410,16 @@ void c2sinfo(playerent *d) // send update to the server putint(q, dz); putuint(q, f); } - enet_packet_resize(packet, q.length()); - sendpackettoserv(0, packet); + sendpackettoserv(0, q.finalize()); } if(sendmapidenttoserver || !c2sinit || messages.length() || totalmillis-lastping>250) { - ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, 0); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS); if(!c2sinit) // tell other clients who I am { - packet->flags = ENET_PACKET_FLAG_RELIABLE; + p.reliable(); c2sinit = true; putint(p, SV_INITC2S); sendstring(player1->name, p); @@ -433,7 +429,7 @@ void c2sinfo(playerent *d) // send update to the server if(sendmapidenttoserver) { // new map spawnallitems(); - packet->flags = ENET_PACKET_FLAG_RELIABLE; + p.reliable(); putint(p, SV_MAPIDENT); putint(p, maploaded); putint(p, hdr.maprevision); @@ -444,7 +440,7 @@ void c2sinfo(playerent *d) // send update to the server { int len = messages[i] | ((messages[i+1]&0x7F)<<8); if(p.remaining() < len) break; - if(messages[i+1]&0x80) packet->flags = ENET_PACKET_FLAG_RELIABLE; + if(messages[i+1]&0x80) p.reliable(); p.put(&messages[i+2], len); i += 2 + len; } @@ -455,12 +451,7 @@ void c2sinfo(playerent *d) // send update to the server putint(p, totalmillis); lastping = totalmillis; } - if(!p.length()) enet_packet_destroy(packet); - else - { - enet_packet_resize(packet, p.length()); - sendpackettoserv(1, packet); - } + if(p.length()) sendpackettoserv(1, p.finalize()); } if(clienthost) enet_host_flush(clienthost); @@ -469,8 +460,7 @@ void c2sinfo(playerent *d) // send update to the server void sendintro() { - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); putint(p, SV_CONNECT); putint(p, AC_VERSION); putint(p, (isbigendian() ? 0x80 : 0 )|(adler((unsigned char *)guns, sizeof(guns)) % 31 << 8)| @@ -495,8 +485,7 @@ void sendintro() clientpassword[0] = '\0'; connectrole = CR_DEFAULT; putint(p, player1->nextprimweap->type); - enet_packet_resize(packet, p.length()); - sendpackettoserv(1, packet); + sendpackettoserv(1, p.finalize()); } void gets2c() // get updates from the server @@ -591,8 +580,7 @@ void sendmap(char *mapname) uchar *cfgdata = readmcfggz(path(mapname), &cfgsize, &cfgsizegz); if(!cfgdata) { cfgsize = 0; cfgsizegz = 0; } - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS + mapsize + cfgsizegz, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS + mapsize + cfgsizegz, ENET_PACKET_FLAG_RELIABLE); putint(p, SV_SENDMAP); sendstring(mapname, p); @@ -605,7 +593,6 @@ void sendmap(char *mapname) conoutf(_("map %s is too large to send"), mapname); delete[] mapdata; if(cfgsize) delete[] cfgdata; - enet_packet_destroy(packet); return; } p.put(mapdata, mapsize); @@ -616,19 +603,16 @@ void sendmap(char *mapname) delete[] cfgdata; } - enet_packet_resize(packet, p.length()); - sendpackettoserv(2, packet); + sendpackettoserv(2, p.finalize()); conoutf(_("sending map %s to server..."), mapname); } void getmap() { conoutf(_("requesting map from server...")); - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(10, ENET_PACKET_FLAG_RELIABLE); putint(p, SV_RECVMAP); - enet_packet_resize(packet, p.length()); - sendpackettoserv(2, packet); + sendpackettoserv(2, p.finalize()); } void deleteservermap(char *mapname) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 87e7484a..e6ec057b 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -1022,8 +1022,7 @@ void callvote(int type, char *arg1, char *arg2) if(v) { calledvote = v; - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); putint(p, SV_CALLVOTE); putint(p, v->type); switch(v->type) @@ -1043,8 +1042,7 @@ void callvote(int type, char *arg1, char *arg2) putint(p, atoi(arg1)); break; } - enet_packet_resize(packet, p.length()); - sendpackettoserv(1, packet); + sendpackettoserv(1, p.finalize()); } else conoutf(_("\f3invalid vote")); } @@ -1068,12 +1066,10 @@ int vote(int v) { if(!curvote || v < 0 || v >= VOTE_NUM) return 0; if(curvote->localplayervoted) { conoutf(_("\f3you voted already")); return 0; } - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); putint(p, SV_VOTE); putint(p, v); - enet_packet_resize(packet, p.length()); - sendpackettoserv(1, packet); + sendpackettoserv(1, p.finalize()); // flowtron : 2008 11 06 : I don't think the following comments are still current if(!curvote) { /*printf(":: curvote vanished!\n");*/ return 0; } // flowtron - happens when I call "/stopdemo"! .. seems the map-load happens in-between curvote->stats[v]++; diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 0b188d10..b6e502c0 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -113,7 +113,7 @@ void parsepositions(ucharbuf &p) float yaw, pitch, roll; if(type == SV_POSC) { - bitbuf q(&p); + bitbuf q(p); cn = q.getbits(5); int usefactor = q.getbits(2) + 7; o.x = q.getbits(usefactor + 4) / DMF; diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 2ee6aff0..0faff1d0 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -11,13 +11,17 @@ void protocoldebug(bool enable) { protocoldbg = enable; } // all network traffic is in 32bit ints, which are then compressed using the following simple scheme (assumes that most values are small). -void putint(ucharbuf &p, int n) +template +static inline void putint_(T &p, int n) { DEBUGVAR(n); if(n<128 && n>-127) p.put(n); else if(n<0x8000 && n>=-0x8000) { p.put(0x80); p.put(n); p.put(n>>8); } else { p.put(0x81); p.put(n); p.put(n>>8); p.put(n>>16); p.put(n>>24); } } +void putint(ucharbuf &p, int n) { putint_(p, n); } +void putint(packetbuf &p, int n) { putint_(p, n); } +void putint(vector &p, int n) { putint_(p, n); } int getint(ucharbuf &p) { @@ -32,7 +36,8 @@ int getint(ucharbuf &p) } // much smaller encoding for unsigned integers up to 28 bits, but can handle signed -void putuint(ucharbuf &p, int n) +template +static inline void putuint_(T &p, int n) { DEBUGVAR(n); if(n < 0 || n >= (1<<21)) @@ -55,6 +60,9 @@ void putuint(ucharbuf &p, int n) p.put(n >> 14); } } +void putuint(ucharbuf &p, int n) { putuint_(p, n); } +void putuint(packetbuf &p, int n) { putuint_(p, n); } +void putuint(vector &p, int n) { putuint_(p, n); } int getuint(ucharbuf &p) { @@ -70,13 +78,34 @@ int getuint(ucharbuf &p) return n; } -void sendstring(const char *text, ucharbuf &p) +template +static inline void putfloat_(T &p, float f) +{ + lilswap(&f, 1); + p.put((uchar *)&f, sizeof(float)); +} +void putfloat(ucharbuf &p, float f) { putfloat_(p, f); } +void putfloat(packetbuf &p, float f) { putfloat_(p, f); } +void putfloat(vector &p, float f) { putfloat_(p, f); } + +float getfloat(ucharbuf &p) +{ + float f; + p.get((uchar *)&f, sizeof(float)); + return lilswap(f); +} + +template +static inline void sendstring_(const char *text, T &p) { const char *t = text; while(*t) putint(p, *t++); putint(p, 0); DEBUGVAR(text); } +void sendstring(const char *t, ucharbuf &p) { sendstring_(t, p); } +void sendstring(const char *t, packetbuf &p) { sendstring_(t, p); } +void sendstring(const char *t, vector &p) { sendstring_(t, p); } void getstring(char *text, ucharbuf &p, int len) { diff --git a/source/src/protos.h b/source/src/protos.h index d3f898d4..c07de981 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -703,10 +703,20 @@ extern void localdisconnect(); extern void localclienttoserver(int chan, ENetPacket *); extern void serverslice(uint timeout); extern void putint(ucharbuf &p, int n); +extern void putint(packetbuf &p, int n); +extern void putint(vector &p, int n); extern int getint(ucharbuf &p); extern void putuint(ucharbuf &p, int n); +extern void putuint(packetbuf &p, int n); +extern void putuint(vector &p, int n); extern int getuint(ucharbuf &p); +extern void putfloat(ucharbuf &p, float f); +extern void putfloat(packetbuf &p, float f); +extern void putfloat(vector &p, float f); +extern float getfloat(ucharbuf &p); extern void sendstring(const char *t, ucharbuf &p); +extern void sendstring(const char *t, packetbuf &p); +extern void sendstring(const char *t, vector &p); extern void getstring(char *t, ucharbuf &p, int len = MAXTRANS); extern void filtertext(char *dst, const char *src, int whitespace = 1, int len = sizeof(string)-1); extern void filterrichtext(char *dst, const char *src, int len = sizeof(string)-1); diff --git a/source/src/server.cpp b/source/src/server.cpp index 5a1d8e92..ff962299 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -498,11 +498,9 @@ void setupdemorecord() } demorecord->write(&hdr, sizeof(demoheader)); - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); - welcomepacket(p, -1, packet); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); + welcomepacket(p, -1); writedemo(1, p.buf, p.len); - enet_packet_destroy(packet); uchar buf[MAXTRANS]; loopv(clients) @@ -681,7 +679,7 @@ struct sflaginfo short x, y; // flag entity location } sflaginfos[2]; -void putflaginfo(ucharbuf &p, int flag) +void putflaginfo(packetbuf &p, int flag) { sflaginfo &f = sflaginfos[flag]; putint(p, SV_FLAGINFO); @@ -725,13 +723,10 @@ bool flagdistance(sflaginfo &f, int cn) void sendflaginfo(int flag = -1, int cn = -1) { - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); if(flag >= 0) putflaginfo(p, flag); else loopi(2) putflaginfo(p, i); - enet_packet_resize(packet, p.length()); - sendpacket(cn, 1, packet); - if(packet->referenceCount==0) enet_packet_destroy(packet); + sendpacket(cn, 1, p.finalize()); } void flagmessage(int flag, int message, int actor, int cn = -1) @@ -1224,12 +1219,11 @@ bool spamdetect(client *cl, char *text) // checks doubled lines and average typi void sendteamtext(char *text, int sender, int msgtype) { if(!valid_client(sender) || clients[sender]->team == TEAM_VOID) return; - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); putint(p, msgtype); putint(p, sender); sendstring(text, p); - enet_packet_resize(packet, p.length()); + ENetPacket *packet = p.finalize(); recordpacket(1, packet); int &st = clients[sender]->team; loopv(clients) if(i!=sender) @@ -1240,24 +1234,21 @@ void sendteamtext(char *text, int sender, int msgtype) (team_isspect(st) && team_isspect(rt))) // spectator to other spectators sendpacket(i, 1, packet); } - if(packet->referenceCount==0) enet_packet_destroy(packet); } void sendvoicecomteam(int sound, int sender) { if(!valid_client(sender) || clients[sender]->team == TEAM_VOID) return; - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); putint(p, SV_VOICECOMTEAM); putint(p, sender); putint(p, sound); - enet_packet_resize(packet, p.length()); + ENetPacket *packet = p.finalize(); loopv(clients) if(i!=sender) { if(clients[i]->team == clients[sender]->team || !m_teammode) sendpacket(i, 1, packet); } - if(packet->referenceCount==0) enet_packet_destroy(packet); } int spawntime(int type) @@ -2006,19 +1997,8 @@ void sendinits2c(client &c) sendf(c.clientnum, 1, "ri5", SV_INITS2C, c.clientnum, isdedicated ? SERVER_PROTOCOL_VERSION : PROTOCOL_VERSION, c.salt, scl.serverpassword[0] ? 1 : 0); } -void welcomepacket(ucharbuf &p, int n, ENetPacket *packet) +void welcomepacket(packetbuf &p, int n) { - #define CHECKSPACE(n) \ - { \ - int space = (n); \ - if(p.remaining() < space) \ - { \ - enet_packet_resize(packet, packet->dataLength + max(MAXTRANS, space - p.remaining())); \ - p.buf = packet->data; \ - p.maxlen = (int)packet->dataLength; \ - } \ - } - if(!smapname[0]) maprot.next(false); client *c = valid_client(n) ? clients[n] : NULL; @@ -2041,18 +2021,10 @@ void welcomepacket(ucharbuf &p, int n, ENetPacket *packet) if(numcl>0) { putint(p, SV_ITEMLIST); - loopv(sents) if(sents[i].spawned) - { - putint(p, i); - CHECKSPACE(256); - } + loopv(sents) if(sents[i].spawned) putint(p, i); putint(p, -1); } - if(m_flags) - { - CHECKSPACE(256); - loopi(2) putflaginfo(p, i); - } + if(m_flags) loopi(2) putflaginfo(p, i); } savedscore *sc = NULL; bool restored = false; @@ -2071,7 +2043,6 @@ void welcomepacket(ucharbuf &p, int n, ENetPacket *packet) restored = true; } - CHECKSPACE(256); putint(p, SV_FORCEDEATH); putint(p, n); sendf(-1, 1, "ri2x", SV_FORCEDEATH, n, n); @@ -2083,7 +2054,6 @@ void welcomepacket(ucharbuf &p, int n, ENetPacket *packet) { client &c = *clients[i]; if(c.type!=ST_TCPIP || (c.clientnum==n && !restored)) continue; - CHECKSPACE(256); putint(p, c.clientnum); putint(p, c.state.state); putint(p, c.state.lifesequence); @@ -2104,22 +2074,16 @@ void welcomepacket(ucharbuf &p, int n, ENetPacket *packet) const char *motd = scl.motd[0] ? scl.motd : infofiles.getmotd(c ? c->lang : ""); if(motd) { - CHECKSPACE(5+2*(int)strlen(motd)+1); putint(p, SV_TEXT); sendstring(motd, p); } - - #undef CHECKSPACE } void sendwelcome(client *cl, int chan) { - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); - welcomepacket(p, cl->clientnum, packet); - enet_packet_resize(packet, p.length()); - sendpacket(cl->clientnum, chan, packet); - if(!packet->referenceCount) enet_packet_destroy(packet); + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); + welcomepacket(p, cl->clientnum); + sendpacket(cl->clientnum, chan, p.finalize()); cl->haswelcome = true; } @@ -2285,26 +2249,23 @@ void process(ENetPacket *packet, int sender, int chan) if(packet->flags&ENET_PACKET_FLAG_RELIABLE) reliablemessages = true; #define QUEUE_MSG { if(cl->type==ST_TCPIP) while(curmsgmessages.add(p.buf[curmsg++]); } - #define QUEUE_BUF(size, body) { \ + #define QUEUE_BUF(body) { \ if(cl->type==ST_TCPIP) \ { \ curmsg = p.length(); \ - ucharbuf buf = cl->messages.reserve(size); \ { body; } \ - cl->messages.addbuf(buf); \ } \ } - #define QUEUE_INT(n) QUEUE_BUF(5, putint(buf, n)) - #define QUEUE_UINT(n) QUEUE_BUF(4, putuint(buf, n)) - #define QUEUE_STR(text) QUEUE_BUF(2*(int)strlen(text)+1, sendstring(text, buf)) + #define QUEUE_INT(n) QUEUE_BUF(putint(cl->messages, n)) + #define QUEUE_UINT(n) QUEUE_BUF(putuint(cl->messages, n)) + #define QUEUE_STR(text) QUEUE_BUF(sendstring(text, cl->messages)) #define MSG_PACKET(packet) \ - ENetPacket *packet = enet_packet_create(NULL, 16 + p.length() - curmsg, ENET_PACKET_FLAG_RELIABLE); \ - ucharbuf buf(packet->data, packet->dataLength); \ + packetbuf buf(16 + p.length() - curmsg, ENET_PACKET_FLAG_RELIABLE); \ putint(buf, SV_CLIENT); \ putint(buf, cl->clientnum); \ putuint(buf, p.length() - curmsg); \ buf.put(&p.buf[curmsg], p.length() - curmsg); \ - enet_packet_resize(packet, buf.length()); + ENetPacket *packet = buf.finalize(); int curmsg; while((curmsg = p.length()) < p.maxlen) @@ -2420,10 +2381,10 @@ void process(ENetPacket *packet, int sender, int chan) } } } - QUEUE_BUF(15, - putint(buf, SV_SETTEAM); - putint(buf, sender); - putint(buf, cl->team | (FTR_INFO << 4)) + QUEUE_BUF( + putint(cl->messages, SV_SETTEAM); + putint(cl->messages, sender); + putint(cl->messages, cl->team | (FTR_INFO << 4)) ); break; } @@ -2517,15 +2478,15 @@ void process(ENetPacket *packet, int sender, int chan) cl->state.lastspawn = -1; cl->state.state = CS_ALIVE; cl->state.gunselect = gunselect; - QUEUE_BUF(5*(5 + 2*NUMGUNS), + QUEUE_BUF( { - putint(buf, SV_SPAWN); - putint(buf, cl->state.lifesequence); - putint(buf, cl->state.health); - putint(buf, cl->state.armour); - putint(buf, cl->state.gunselect); - loopi(NUMGUNS) putint(buf, cl->state.ammo[i]); - loopi(NUMGUNS) putint(buf, cl->state.mag[i]); + putint(cl->messages, SV_SPAWN); + putint(cl->messages, cl->state.lifesequence); + putint(cl->messages, cl->state.health); + putint(cl->messages, cl->state.armour); + putint(cl->messages, cl->state.gunselect); + loopi(NUMGUNS) putint(cl->messages, cl->state.ammo[i]); + loopi(NUMGUNS) putint(cl->messages, cl->state.mag[i]); }); break; } @@ -2659,7 +2620,7 @@ void process(ENetPacket *packet, int sender, int chan) case SV_POSC: { - bitbuf q(&p); + bitbuf q(p); int cn = q.getbits(5); if(cn!=sender) { @@ -2880,7 +2841,6 @@ void process(ENetPacket *packet, int sender, int chan) vi->callmillis = servmillis; MSG_PACKET(msg); if(!scallvote(vi, msg)) delete vi; - if(!msg->referenceCount) enet_packet_destroy(msg); break; } @@ -2888,8 +2848,9 @@ void process(ENetPacket *packet, int sender, int chan) { int n = getint(p); MSG_PACKET(msg); + ++msg->referenceCount; // need to increase reference count in case a vote disconnects a player after packet is queued to prevent double-freeing by packetbuf svote(sender, n, msg); - if(valid_client(sender) && !msg->referenceCount) enet_packet_destroy(msg); // check sender existence first because he might have been disconnected due to a vote + --msg->referenceCount; break; } diff --git a/source/src/server.h b/source/src/server.h index 2b9b58ff..c2be5a4f 100644 --- a/source/src/server.h +++ b/source/src/server.h @@ -322,7 +322,7 @@ int calcscores(); void recordpacket(int chan, void *data, int len); void senddisconnectedscores(int cn); void process(ENetPacket *packet, int sender, int chan); -void welcomepacket(ucharbuf &p, int n, ENetPacket *packet); +void welcomepacket(packetbuf &p, int n); void sendwelcome(client *cl, int chan = 1); int numclients(); bool updateclientteam(int cln, int newteam, int ftr); diff --git a/source/src/tools.h b/source/src/tools.h index 062c4517..d588efd8 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -150,6 +150,8 @@ struct databuf int len, maxlen; uchar flags; + databuf() : buf(NULL), len(0), maxlen(0), flags(0) {} + template databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {} @@ -181,6 +183,15 @@ struct databuf len += min(maxlen-len, numvals); } + int get(T *vals, int numvals) + { + int read = min(maxlen-len, numvals); + if(read charbuf; typedef databuf ucharbuf; +struct packetbuf : ucharbuf +{ + ENetPacket *packet; + int growth; + + packetbuf(ENetPacket *packet) : ucharbuf(packet->data, packet->dataLength), packet(packet), growth(0) {} + packetbuf(int growth, int pflags = 0) : growth(growth) + { + packet = enet_packet_create(NULL, growth, pflags); + buf = (uchar *)packet->data; + maxlen = packet->dataLength; + } + ~packetbuf() { cleanup(); } + + void reliable() { packet->flags |= ENET_PACKET_FLAG_RELIABLE; } + + void resize(int n) + { + enet_packet_resize(packet, n); + buf = (uchar *)packet->data; + maxlen = packet->dataLength; + } + + void checkspace(int n) + { + if(len + n > maxlen && packet && growth > 0) resize(max(len + n, maxlen + growth)); + } + + ucharbuf subbuf(int sz) + { + checkspace(sz); + return ucharbuf::subbuf(sz); + } + + void put(const uchar &val) + { + checkspace(1); + ucharbuf::put(val); + } + + void put(const uchar *vals, int numvals) + { + checkspace(numvals); + ucharbuf::put(vals, numvals); + } + + bool overwrote() const { return false; } + + ENetPacket *finalize() + { + resize(len); + return packet; + } + + void cleanup() + { + if(growth > 0 && packet && !packet->referenceCount) { enet_packet_destroy(packet); packet = NULL; buf = NULL; len = maxlen = 0; } + } +}; + +template struct bitbuf { - ucharbuf *q; + T &q; int blen; - bitbuf(ucharbuf *oq) : q(oq), blen(0) {} + bitbuf(T &oq) : q(oq), blen(0) {} int getbits(int n) { int res = 0, p = 0; while(n > 0) { - if(!blen) q->get(); + if(!blen) q.get(); int r = 8 - blen; if(r > n) r = n; - res |= ((q->buf[q->len - 1] >> blen) & ((1 << r) - 1)) << p; + res |= ((q.buf[q.len - 1] >> blen) & ((1 << r) - 1)) << p; n -= r; p += r; blen = (blen + r) % 8; } @@ -222,10 +294,10 @@ struct bitbuf { while(n > 0) { - if(!blen) { q->put(0); if(q->overwrote()) return; } + if(!blen) { q.put(0); if(q.overwrote()) return; } int r = 8 - blen; if(r > n) r = n; - q->buf[q->len - 1] |= (v & ((1 << r) - 1)) << blen; + q.buf[q.len - 1] |= (v & ((1 << r) - 1)) << blen; n -= r; v >>= r; blen = (blen + r) % 8; } @@ -336,9 +408,23 @@ template struct vector return databuf(&buf[ulen], sz); } + void advance(int sz) + { + ulen += sz; + } + void addbuf(const databuf &p) { - ulen += p.length(); + advance(p.length()); + } + + void put(const T &v) { add(v); } + + void put(const T *v, int n) + { + databuf buf = reserve(n); + buf.put(v, n); + addbuf(buf); } void remove(int i, int n)