]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
Initial commit of protocol redesign
authorCloudwalk <cloudwalk009@gmail.com>
Tue, 22 Sep 2020 02:34:48 +0000 (22:34 -0400)
committerCloudwalk <cloudwalk009@gmail.com>
Tue, 22 Sep 2020 02:34:48 +0000 (22:34 -0400)
The Quake protocol family is now implemented on a per-struct basis
using the new protocol_t struct. It's a container for protocol info such
as name, number, and soon max edicts, max models, max frames, max
sounds, etc. For now, it also contains function pointers to MSG_
functions.

The MSG_ functions (specifically the Read and WriteCoord, Angle, Vector
functions have been made generic, and these function pointers point to
them instead of using protocol-based branching.

The protocol net messages themselves are now a jump table, not unlike
the QC builtins interface. This will make things cleaner and scalable
for implementing Quake protocols that might be dramatically different
from NQ and QW.

44 files changed:
cl_cmd.c
cl_demo.c
cl_ents.c
cl_ents5.c
cl_ents_nq.c
cl_ents_qw.c
cl_input.c
cl_main.c
cl_parse.c
cl_parse.h [new file with mode: 0644]
cl_particles.c
cl_protocol_basenq.h [new file with mode: 0644]
cl_protocol_baseqw.h [new file with mode: 0644]
cl_protocol_dpp7.c [new file with mode: 0644]
cl_protocol_ext.h [new file with mode: 0644]
cl_protocol_nq.c [new file with mode: 0644]
cl_protocol_qw.c [new file with mode: 0644]
cl_screen.c
client.h
clvm_cmds.c
com_msg.c
common.h
csprogs.c
gl_rmain.c
makefile.inc
mvm_cmds.c
netconn.c
netconn.h
protocol.c
protocol.h
sbar.c
server.h
snd_main.c
sv_ccmds.c
sv_ents.c
sv_ents5.c
sv_ents_nq.c
sv_main.c
sv_protocol.c [new file with mode: 0644]
sv_protocol_base.h [new file with mode: 0644]
sv_user.c
sv_user.h [new file with mode: 0644]
svvm_cmds.c
view.c

index 569ba83472f409e353e4afbf29c22a62373c774a..c7918be14039a30067e5c861ced6fb5d94549a58 100644 (file)
--- a/cl_cmd.c
+++ b/cl_cmd.c
@@ -64,8 +64,8 @@ void CL_ForwardToServer (const char *s)
        // LadyHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
        // attention, it has been eradicated from here, its only (former) use in
        // all of darkplaces.
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
-               MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+       if (cls.protocol == &protocol_quakeworld)
+               MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
        else
                MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
        if ((!strncmp(s, "say ", 4) || !strncmp(s, "say_team ", 9)) && cl_locs_enable.integer)
index 7c7874329c5bc0996dc964e0544f6232e8e42eb3..337feeb5b1358bb11f63c0a8945a7282e5b9a8f8 100644 (file)
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -443,7 +443,7 @@ void CL_PlayDemo_f(cmd_state_t *cmd)
        // update networking ports (this is mainly just needed at startup)
        NetConn_UpdateSockets();
 
-       cls.protocol = PROTOCOL_QUAKE;
+       cls.protocol = &protocol_netquake;
 
        Con_Printf("Playing demo %s.\n", name);
        cls.demofile = f;
index b5e93f61852bfa8aff7c22053e104a4c39a81985..11fd2a597d13f48a521c2a84e0bc8438da6f46a3 100644 (file)
--- a/cl_ents.c
+++ b/cl_ents.c
@@ -20,7 +20,7 @@ int EntityState_ReadExtendBits(void)
 
 void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
 {
-       if (cls.protocol == PROTOCOL_DARKPLACES2)
+       if (cls.protocol == &protocol_dpp2)
        {
                if (bits & E_ORIGIN1)
                        e->origin[0] = MSG_ReadCoord16i(&cl_message);
@@ -52,7 +52,7 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
                                e->origin[2] = MSG_ReadCoord32f(&cl_message);
                }
        }
-       if ((cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6) && !(e->flags & RENDER_LOWPRECISION))
+       if ((cls.protocol == &protocol_dpp5 || cls.protocol == &protocol_dpp6) && !(e->flags & RENDER_LOWPRECISION))
        {
                if (bits & E_ANGLE1)
                        e->angles[0] = MSG_ReadAngle16i(&cl_message);
@@ -94,7 +94,7 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
                e->glowsize = MSG_ReadByte(&cl_message);
        if (bits & E_GLOWCOLOR)
                e->glowcolor = MSG_ReadByte(&cl_message);
-       if (cls.protocol == PROTOCOL_DARKPLACES2)
+       if (cls.protocol == &protocol_dpp2)
                if (bits & E_FLAGS)
                        e->flags = MSG_ReadByte(&cl_message);
        if (bits & E_TAGATTACHMENT)
index d245e8a2f2281e76bca00f9a427eb0c993bc356a..08b0409c96653c789ed71c762aa1842e6296ef3b 100644 (file)
@@ -294,7 +294,7 @@ void EntityFrame5_CL_ReadFrame(void)
        // read the number of this frame to echo back in next input packet
        framenum = MSG_ReadLong(&cl_message);
        CL_NewFrameReceived(framenum);
-       if (cls.protocol != PROTOCOL_QUAKE && cls.protocol != PROTOCOL_QUAKEDP && cls.protocol != PROTOCOL_NEHAHRAMOVIE && cls.protocol != PROTOCOL_DARKPLACES1 && cls.protocol != PROTOCOL_DARKPLACES2 && cls.protocol != PROTOCOL_DARKPLACES3 && cls.protocol != PROTOCOL_DARKPLACES4 && cls.protocol != PROTOCOL_DARKPLACES5 && cls.protocol != PROTOCOL_DARKPLACES6)
+       if (cls.protocol != &protocol_netquake && cls.protocol != &protocol_quakedp && cls.protocol != &protocol_nehahramovie && cls.protocol != &protocol_dpp1 && cls.protocol != &protocol_dpp2 && cls.protocol != &protocol_dpp3 && cls.protocol != &protocol_dpp4 && cls.protocol != &protocol_dpp5 && cls.protocol != &protocol_dpp6)
                cls.servermovesequence = MSG_ReadLong(&cl_message);
        // read entity numbers until we find a 0x8000
        // (which would be remove world entity, but is actually a terminator)
index 0edd34e3cbc92a4ee0c13c9b509dd91676ea5330..3d1b175283243b4315e7385fa6fd57c55a19edfd 100644 (file)
@@ -9,7 +9,7 @@ void EntityFrameQuake_ReadEntity(int bits)
 
        if (bits & U_MOREBITS)
                bits |= (MSG_ReadByte(&cl_message)<<8);
-       if ((bits & U_EXTEND1) && cls.protocol != PROTOCOL_NEHAHRAMOVIE)
+       if ((bits & U_EXTEND1) && cls.protocol != &protocol_nehahramovie)
        {
                bits |= MSG_ReadByte(&cl_message) << 16;
                if (bits & U_EXTEND2)
@@ -54,7 +54,7 @@ void EntityFrameQuake_ReadEntity(int bits)
        s.flags = 0;
        if (bits & U_MODEL)
        {
-               if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3)
+               if (cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3)
                                                        s.modelindex = (unsigned short) MSG_ReadShort(&cl_message);
                else
                                                        s.modelindex = (s.modelindex & 0xFF00) | MSG_ReadByte(&cl_message);
@@ -63,12 +63,12 @@ void EntityFrameQuake_ReadEntity(int bits)
        if (bits & U_COLORMAP)  s.colormap = MSG_ReadByte(&cl_message);
        if (bits & U_SKIN)              s.skin = MSG_ReadByte(&cl_message);
        if (bits & U_EFFECTS)   s.effects = (s.effects & 0xFF00) | MSG_ReadByte(&cl_message);
-       if (bits & U_ORIGIN1)   s.origin[0] = MSG_ReadCoord(&cl_message, cls.protocol);
-       if (bits & U_ANGLE1)    s.angles[0] = MSG_ReadAngle(&cl_message, cls.protocol);
-       if (bits & U_ORIGIN2)   s.origin[1] = MSG_ReadCoord(&cl_message, cls.protocol);
-       if (bits & U_ANGLE2)    s.angles[1] = MSG_ReadAngle(&cl_message, cls.protocol);
-       if (bits & U_ORIGIN3)   s.origin[2] = MSG_ReadCoord(&cl_message, cls.protocol);
-       if (bits & U_ANGLE3)    s.angles[2] = MSG_ReadAngle(&cl_message, cls.protocol);
+       if (bits & U_ORIGIN1)   s.origin[0] = cls.protocol->ReadCoord(&cl_message);
+       if (bits & U_ANGLE1)    s.angles[0] = cls.protocol->ReadAngle(&cl_message);
+       if (bits & U_ORIGIN2)   s.origin[1] = cls.protocol->ReadCoord(&cl_message);
+       if (bits & U_ANGLE2)    s.angles[1] = cls.protocol->ReadAngle(&cl_message);
+       if (bits & U_ORIGIN3)   s.origin[2] = cls.protocol->ReadCoord(&cl_message);
+       if (bits & U_ANGLE3)    s.angles[2] = cls.protocol->ReadAngle(&cl_message);
        if (bits & U_STEP)              s.flags |= RENDER_STEP;
        if (bits & U_ALPHA)             s.alpha = MSG_ReadByte(&cl_message);
        if (bits & U_SCALE)             s.scale = MSG_ReadByte(&cl_message);
@@ -83,7 +83,7 @@ void EntityFrameQuake_ReadEntity(int bits)
        if (bits & U_EXTERIORMODEL)     s.flags |= RENDER_EXTERIORMODEL;
 
        // LadyHavoc: to allow playback of the Nehahra movie
-       if (cls.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
+       if (cls.protocol == &protocol_nehahramovie && (bits & U_EXTEND1))
        {
                // LadyHavoc: evil format
                int i = (int)MSG_ReadFloat(&cl_message);
index dcbe749088fa9804744480dfbea45a4ab66030fb..553870f4baa5b80e95ec86f191aa9be7d3120207 100644 (file)
@@ -67,7 +67,7 @@ void EntityStateQW_ReadPlayerUpdate(void)
        s->number = enumber;
        s->colormap = enumber;
        playerflags = MSG_ReadShort(&cl_message);
-       MSG_ReadVector(&cl_message, s->origin, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, s->origin);
        s->frame = MSG_ReadByte(&cl_message);
 
        VectorClear(viewangles);
index ebde4ed76d674483157846c6a92fa3da48c95517..8c8120180ff9b6784bd2f6b121aab2a974df320b 100644 (file)
@@ -1059,7 +1059,7 @@ static void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
        if (s->waterjumptime <= 0)
        {
                // water friction
-               f = 1 - s->cmd.frametime * cl.movevars_waterfriction * (cls.protocol == PROTOCOL_QUAKEWORLD ? s->waterlevel : 1);
+               f = 1 - s->cmd.frametime * cl.movevars_waterfriction * (cls.protocol == &protocol_quakeworld ? s->waterlevel : 1);
                f = bound(0, f, 1);
                VectorScale(s->velocity, f, s->velocity);
 
@@ -1359,7 +1359,7 @@ static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
                                // this mimics it for compatibility
                                VectorSet(neworigin2, s->origin[0] + s->velocity[0]*(16/f), s->origin[1] + s->velocity[1]*(16/f), s->origin[2] + s->mins[2]);
                                VectorSet(neworigin3, neworigin2[0], neworigin2[1], neworigin2[2] - 34);
-                               if (cls.protocol == PROTOCOL_QUAKEWORLD)
+                               if (cls.protocol == &protocol_quakeworld)
                                        trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, 0, 0, collision_extendmovelength.value, true, true, NULL, true);
                                else
                                        trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, 0, 0, collision_extendmovelength.value, true, true, NULL, true, false);
@@ -1385,7 +1385,7 @@ static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
                        else
                                s->velocity[2] -= gravity;
                }
-               if (cls.protocol == PROTOCOL_QUAKEWORLD)
+               if (cls.protocol == &protocol_quakeworld)
                        s->velocity[2] = 0;
                if (VectorLength2(s->velocity))
                        CL_ClientMovement_Move(s);
@@ -1473,7 +1473,7 @@ static void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s)
 extern cvar_t host_timescale;
 void CL_UpdateMoveVars(void)
 {
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
        {
                cl.moveflags = 0;
        }
@@ -1820,7 +1820,7 @@ void CL_SendMove(void)
                cl.cmd.msec = 100;
        cl.cmd.frametime = cl.cmd.msec * (1.0 / 1000.0);
 
-       switch(cls.protocol)
+       switch(cls.protocol->num)
        {
        case PROTOCOL_QUAKEWORLD:
                // quakeworld uses a different cvar with opposite meaning, for compatibility
@@ -1842,11 +1842,10 @@ void CL_SendMove(void)
 
        cl.cmd.jump = (cl.cmd.buttons & 2) != 0;
        cl.cmd.crouch = 0;
-       switch (cls.protocol)
+       switch (cls.protocol->num)
        {
        case PROTOCOL_QUAKEWORLD:
        case PROTOCOL_QUAKE:
-       case PROTOCOL_QUAKEDP:
        case PROTOCOL_NEHAHRAMOVIE:
        case PROTOCOL_NEHAHRABJP:
        case PROTOCOL_NEHAHRABJP2:
@@ -1886,7 +1885,7 @@ void CL_SendMove(void)
        }
 
        // do not send 0ms packets because they mess up physics
-       if(cl.cmd.msec == 0 && cl.time > cl.oldtime && (cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon == SIGNONS))
+       if(cl.cmd.msec == 0 && cl.time > cl.oldtime && (cls.protocol == &protocol_quakeworld || cls.signon == SIGNONS))
                return;
        // always send if buttons changed or an impulse is pending
        // even if it violates the rate limit!
@@ -1928,12 +1927,12 @@ void CL_SendMove(void)
        // set prydon cursor info
        CL_UpdatePrydonCursor();
 
-       if (cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon == SIGNONS)
+       if (cls.protocol == &protocol_quakeworld || cls.signon == SIGNONS)
        {
-               switch (cls.protocol)
+               switch (cls.protocol->num)
                {
                case PROTOCOL_QUAKEWORLD:
-                       MSG_WriteByte(&buf, qw_clc_move);
+                       MSG_WriteByte(&buf, clc_move);
                        // save the position for a checksum byte
                        checksumindex = buf.cursize;
                        MSG_WriteByte(&buf, 0);
@@ -1956,14 +1955,13 @@ void CL_SendMove(void)
                        if (cl.qw_validsequence && !cl_nodelta.integer && cls.state == ca_connected && !cls.demorecording)
                        {
                                cl.qw_deltasequence[cls.netcon->outgoing_unreliable_sequence & QW_UPDATE_MASK] = cl.qw_validsequence;
-                               MSG_WriteByte(&buf, qw_clc_delta);
+                               MSG_WriteByte(&buf, clc_delta);
                                MSG_WriteByte(&buf, cl.qw_validsequence & 255);
                        }
                        else
                                cl.qw_deltasequence[cls.netcon->outgoing_unreliable_sequence & QW_UPDATE_MASK] = -1;
                        break;
                case PROTOCOL_QUAKE:
-               case PROTOCOL_QUAKEDP:
                case PROTOCOL_NEHAHRAMOVIE:
                case PROTOCOL_NEHAHRABJP:
                case PROTOCOL_NEHAHRABJP2:
@@ -2042,7 +2040,7 @@ void CL_SendMove(void)
                                        continue;
                                // 5/9 bytes
                                MSG_WriteByte (&buf, clc_move);
-                               if (cls.protocol != PROTOCOL_DARKPLACES6)
+                               if (cls.protocol != &protocol_dpp6)
                                        MSG_WriteLong (&buf, cmd->predicted ? cmd->sequence : 0);
                                MSG_WriteFloat (&buf, cmd->time); // last server packet time
                                // 6 bytes
@@ -2073,7 +2071,7 @@ void CL_SendMove(void)
                }
        }
 
-       if (cls.protocol != PROTOCOL_QUAKEWORLD && buf.cursize)
+       if (cls.protocol != &protocol_quakeworld && buf.cursize)
        {
                // ack entity frame numbers received since the last input was sent
                // (redundent to improve handling of client->server packet loss)
index de1d5319b6af3bf207f127d18386c06e066949a8..ae4c7f996b6c7303f3a334881b3e05af0535761a 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -248,9 +248,9 @@ void CL_SetInfo(const char *key, const char *value, qbool send, qbool allowstark
        InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), key, value);
        if (cls.state == ca_connected && cls.netcon)
        {
-               if (cls.protocol == PROTOCOL_QUAKEWORLD)
+               if (cls.protocol == &protocol_quakeworld)
                {
-                       MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+                       MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                        MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "setinfo \"%s\" \"%s\"", key, value));
                }
                else if (!strcasecmp(key, "name"))
@@ -394,10 +394,10 @@ void CL_Disconnect(void)
                memset(&buf, 0, sizeof(buf));
                buf.data = bufdata;
                buf.maxsize = sizeof(bufdata);
-               if (cls.protocol == PROTOCOL_QUAKEWORLD)
+               if (cls.protocol == &protocol_quakeworld)
                {
                        Con_DPrint("Sending drop command\n");
-                       MSG_WriteByte(&buf, qw_clc_stringcmd);
+                       MSG_WriteByte(&buf, clc_stringcmd);
                        MSG_WriteString(&buf, "drop");
                }
                else
@@ -446,7 +446,7 @@ void CL_Reconnect_f(cmd_state_t *cmd)
                return;
        }
        // if connected, do something based on protocol
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
        {
                // quakeworld can just re-login
                if (cls.qw_downloadmemory)  // don't change when downloading
@@ -457,7 +457,7 @@ void CL_Reconnect_f(cmd_state_t *cmd)
                if (cls.state == ca_connected)
                {
                        Con_Printf("Server is changing level...\n");
-                       MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
+                       MSG_WriteChar(&cls.netcon->message, clc_stringcmd);
                        MSG_WriteString(&cls.netcon->message, "new");
                }
        }
@@ -1268,7 +1268,7 @@ static void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qbool interp
        if (!(e->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST))
         && (e->render.alpha >= 1)
         && !(e->render.flags & RENDER_VIEWMODEL)
-        && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer)))
+        && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != &protocol_nehahramovie && !cl_noplayershadow.integer)))
                e->render.flags |= RENDER_SHADOW;
        if (e->render.flags & RENDER_VIEWMODEL)
                e->render.flags |= RENDER_NOSELFSHADOW;
index 70467a997aa5bef1965c5aa627b05bd35fdf3ea4..c797d0f1fe462c980c9244b3f2612a263d452e28 100644 (file)
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // cl_parse.c  -- parse a message received from the server
 
 #include "quakedef.h"
+#include "cl_parse.h"
 #include "cdaudio.h"
 #include "cl_collision.h"
 #include "csprogs.h"
@@ -30,138 +31,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #endif
 #include "cl_video.h"
 
-const char *svc_strings[128] =
-{
-       "svc_bad",
-       "svc_nop",
-       "svc_disconnect",
-       "svc_updatestat",
-       "svc_version",          // [int] server version
-       "svc_setview",          // [short] entity number
-       "svc_sound",                    // <see code>
-       "svc_time",                     // [float] server time
-       "svc_print",                    // [string] null terminated string
-       "svc_stufftext",                // [string] stuffed into client's console buffer
-                                               // the string should be \n terminated
-       "svc_setangle",         // [vec3] set the view angle to this absolute value
-
-       "svc_serverinfo",               // [int] version
-                                               // [string] signon string
-                                               // [string]..[0]model cache [string]...[0]sounds cache
-                                               // [string]..[0]item cache
-       "svc_lightstyle",               // [byte] [string]
-       "svc_updatename",               // [byte] [string]
-       "svc_updatefrags",      // [byte] [short]
-       "svc_clientdata",               // <shortbits + data>
-       "svc_stopsound",                // <see code>
-       "svc_updatecolors",     // [byte] [byte]
-       "svc_particle",         // [vec3] <variable>
-       "svc_damage",                   // [byte] impact [byte] blood [vec3] from
-
-       "svc_spawnstatic",
-       "OBSOLETE svc_spawnbinary",
-       "svc_spawnbaseline",
-
-       "svc_temp_entity",              // <variable>
-       "svc_setpause",
-       "svc_signonnum",
-       "svc_centerprint",
-       "svc_killedmonster",
-       "svc_foundsecret",
-       "svc_spawnstaticsound",
-       "svc_intermission",
-       "svc_finale",                   // [string] music [string] text
-       "svc_cdtrack",                  // [byte] track [byte] looptrack
-       "svc_sellscreen",
-       "svc_cutscene",
-       "svc_showlmp",  // [string] iconlabel [string] lmpfile [short] x [short] y
-       "svc_hidelmp",  // [string] iconlabel
-       "svc_skybox", // [string] skyname
-       "", // 38
-       "", // 39
-       "", // 40
-       "", // 41
-       "", // 42
-       "", // 43
-       "", // 44
-       "", // 45
-       "", // 46
-       "", // 47
-       "", // 48
-       "", // 49
-       "svc_downloaddata", //                          50              // [int] start [short] size [variable length] data
-       "svc_updatestatubyte", //                       51              // [byte] stat [byte] value
-       "svc_effect", //                        52              // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
-       "svc_effect2", //                       53              // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
-       "svc_sound2", //                        54              // short soundindex instead of byte
-       "svc_spawnbaseline2", //        55              // short modelindex instead of byte
-       "svc_spawnstatic2", //          56              // short modelindex instead of byte
-       "svc_entities", //                      57              // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata
-       "svc_csqcentities", //          58              // [short] entnum [variable length] entitydata ... [short] 0x0000
-       "svc_spawnstaticsound2", //     59              // [coord3] [short] samp [byte] vol [byte] aten
-       "svc_trailparticles", //        60              // [short] entnum [short] effectnum [vector] start [vector] end
-       "svc_pointparticles", //        61              // [short] effectnum [vector] start [vector] velocity [short] count
-       "svc_pointparticles1", //       62              // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1
-};
-
-const char *qw_svc_strings[128] =
-{
-       "qw_svc_bad",                                   // 0
-       "qw_svc_nop",                                   // 1
-       "qw_svc_disconnect",                    // 2
-       "qw_svc_updatestat",                    // 3    // [byte] [byte]
-       "",                                                             // 4
-       "qw_svc_setview",                               // 5    // [short] entity number
-       "qw_svc_sound",                                 // 6    // <see code>
-       "",                                                             // 7
-       "qw_svc_print",                                 // 8    // [byte] id [string] null terminated string
-       "qw_svc_stufftext",                             // 9    // [string] stuffed into client's console buffer
-       "qw_svc_setangle",                              // 10   // [angle3] set the view angle to this absolute value
-       "qw_svc_serverdata",                    // 11   // [long] protocol ...
-       "qw_svc_lightstyle",                    // 12   // [byte] [string]
-       "",                                                             // 13
-       "qw_svc_updatefrags",                   // 14   // [byte] [short]
-       "",                                                             // 15
-       "qw_svc_stopsound",                             // 16   // <see code>
-       "",                                                             // 17
-       "",                                                             // 18
-       "qw_svc_damage",                                // 19
-       "qw_svc_spawnstatic",                   // 20
-       "",                                                             // 21
-       "qw_svc_spawnbaseline",                 // 22
-       "qw_svc_temp_entity",                   // 23   // variable
-       "qw_svc_setpause",                              // 24   // [byte] on / off
-       "",                                                             // 25
-       "qw_svc_centerprint",                   // 26   // [string] to put in center of the screen
-       "qw_svc_killedmonster",                 // 27
-       "qw_svc_foundsecret",                   // 28
-       "qw_svc_spawnstaticsound",              // 29   // [coord3] [byte] samp [byte] vol [byte] aten
-       "qw_svc_intermission",                  // 30           // [vec3_t] origin [vec3_t] angle
-       "qw_svc_finale",                                // 31           // [string] text
-       "qw_svc_cdtrack",                               // 32           // [byte] track
-       "qw_svc_sellscreen",                    // 33
-       "qw_svc_smallkick",                             // 34           // set client punchangle to 2
-       "qw_svc_bigkick",                               // 35           // set client punchangle to 4
-       "qw_svc_updateping",                    // 36           // [byte] [short]
-       "qw_svc_updateentertime",               // 37           // [byte] [float]
-       "qw_svc_updatestatlong",                // 38           // [byte] [long]
-       "qw_svc_muzzleflash",                   // 39           // [short] entity
-       "qw_svc_updateuserinfo",                // 40           // [byte] slot [long] uid
-       "qw_svc_download",                              // 41           // [short] size [size bytes]
-       "qw_svc_playerinfo",                    // 42           // variable
-       "qw_svc_nails",                                 // 43           // [byte] num [48 bits] xyzpy 12 12 12 4 8
-       "qw_svc_chokecount",                    // 44           // [byte] packets choked
-       "qw_svc_modellist",                             // 45           // [strings]
-       "qw_svc_soundlist",                             // 46           // [strings]
-       "qw_svc_packetentities",                // 47           // [...]
-       "qw_svc_deltapacketentities",   // 48           // [...]
-       "qw_svc_maxspeed",                              // 49           // maxspeed change, for prediction
-       "qw_svc_entgravity",                    // 50           // gravity change, for prediction
-       "qw_svc_setinfo",                               // 51           // setinfo on a client
-       "qw_svc_serverinfo",                    // 52           // serverinfo
-       "qw_svc_updatepl",                              // 53           // [byte] [byte]
-};
-
 //=============================================================================
 
 cvar_t cl_worldmessage = {CF_CLIENT | CF_READONLY, "cl_worldmessage", "", "title of current level"};
@@ -201,7 +70,7 @@ static void QW_CL_StopUpload_f(cmd_state_t *cmd);
 CL_ParseStartSoundPacket
 ==================
 */
-static void CL_ParseStartSoundPacket(int largesoundindex)
+void CL_ParseStartSoundPacket(int largesoundindex)
 {
        vec3_t  pos;
        int     channel, ent;
@@ -212,7 +81,7 @@ static void CL_ParseStartSoundPacket(int largesoundindex)
        float   speed;
        int             fflags = CHANNELFLAG_NONE;
 
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
        {
                channel = MSG_ReadShort(&cl_message);
 
@@ -264,13 +133,13 @@ static void CL_ParseStartSoundPacket(int largesoundindex)
                        channel &= 7;
                }
 
-               if (largesoundindex || (field_mask & SND_LARGESOUND) || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3)
+               if (largesoundindex || (field_mask & SND_LARGESOUND) || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3)
                        sound_num = (unsigned short) MSG_ReadShort(&cl_message);
                else
                        sound_num = MSG_ReadByte(&cl_message);
        }
 
-       MSG_ReadVector(&cl_message, pos, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, pos);
 
        if (sound_num < 0 || sound_num >= MAX_SOUNDS)
        {
@@ -338,7 +207,7 @@ void CL_KeepaliveMessage (qbool readmessages)
        }
 
        // no need if server is local and definitely not if this is a demo
-       if (sv.active || !cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon >= SIGNONS)
+       if (sv.active || !cls.netcon || cls.protocol == &protocol_quakeworld || cls.signon >= SIGNONS)
        {
                recursive = thisrecursive;
                return;
@@ -564,7 +433,7 @@ static qbool QW_CL_CheckOrDownloadFile(const char *filename)
                cls.qw_downloadmemorymaxsize = 1024*1024; // start out with a 1MB buffer
        }
 
-       MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+       MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
        MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "download %s", filename));
 
        cls.qw_downloadnumber++;
@@ -616,7 +485,7 @@ static void QW_CL_RequestNextDownload(void)
                {
                        cls.signon = SIGNONS-1;
                        // we'll go to SIGNONS when the first entity update is received
-                       MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+                       MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                        MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "begin %i", cl.qw_servercount));
                }
                break;
@@ -686,7 +555,7 @@ static void QW_CL_RequestNextDownload(void)
                CL_SetInfo("emodel", va(vabuf, sizeof(vabuf), "%i", FS_CRCFile("progs/eyes.mdl", NULL)), true, true, true, true);
 
                // done checking sounds and models, send a prespawn command now
-               MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+               MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "prespawn %i 0 %i", cl.qw_servercount, cl.model_precache[1]->brush.qw_md4sum2));
 
                if (cls.qw_downloadmemory)
@@ -737,7 +606,7 @@ static void QW_CL_RequestNextDownload(void)
                Mem_CheckSentinelsGlobal();
 
                // done with sound downloads, next we check models
-               MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+               MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, 0));
                break;
        case dl_none:
@@ -746,7 +615,7 @@ static void QW_CL_RequestNextDownload(void)
        }
 }
 
-static void QW_CL_ParseDownload(void)
+void QW_CL_ParseDownload(void)
 {
        int size = (signed short)MSG_ReadShort(&cl_message);
        int percent = MSG_ReadByte(&cl_message);
@@ -796,7 +665,7 @@ static void QW_CL_ParseDownload(void)
        if (percent != 100)
        {
                // request next fragment
-               MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+               MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                MSG_WriteString(&cls.netcon->message, "nextdl");
        }
        else
@@ -813,7 +682,7 @@ static void QW_CL_ParseDownload(void)
        }
 }
 
-static void QW_CL_ParseModelList(void)
+void QW_CL_ParseModelList(void)
 {
        int n;
        int nummodels = MSG_ReadByte(&cl_message);
@@ -837,7 +706,7 @@ static void QW_CL_ParseModelList(void)
        n = MSG_ReadByte(&cl_message);
        if (n)
        {
-               MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+               MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, n));
                return;
        }
@@ -848,7 +717,7 @@ static void QW_CL_ParseModelList(void)
        QW_CL_RequestNextDownload();
 }
 
-static void QW_CL_ParseSoundList(void)
+void QW_CL_ParseSoundList(void)
 {
        int n;
        int numsounds = MSG_ReadByte(&cl_message);
@@ -873,7 +742,7 @@ static void QW_CL_ParseSoundList(void)
 
        if (n)
        {
-               MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+               MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, n));
                return;
        }
@@ -915,7 +784,7 @@ void QW_CL_NextUpload_f(cmd_state_t *cmd)
        size = min(1, cls.qw_uploadsize);
        percent = (cls.qw_uploadpos+r)*100/size;
 
-       MSG_WriteByte(&cls.netcon->message, qw_clc_upload);
+       MSG_WriteByte(&cls.netcon->message, clc_upload);
        MSG_WriteShort(&cls.netcon->message, r);
        MSG_WriteByte(&cls.netcon->message, percent);
        SZ_Write(&cls.netcon->message, cls.qw_uploaddata + cls.qw_uploadpos, r);
@@ -984,7 +853,7 @@ static void QW_CL_ProcessUserInfo(int slot)
        // TODO: skin cache
 }
 
-static void QW_CL_UpdateUserInfo(void)
+void QW_CL_UpdateUserInfo(void)
 {
        int slot;
        slot = MSG_ReadByte(&cl_message);
@@ -1001,7 +870,7 @@ static void QW_CL_UpdateUserInfo(void)
        QW_CL_ProcessUserInfo(slot);
 }
 
-static void QW_CL_SetInfo(void)
+void QW_CL_SetInfo(void)
 {
        int slot;
        char key[2048];
@@ -1019,7 +888,7 @@ static void QW_CL_SetInfo(void)
        QW_CL_ProcessUserInfo(slot);
 }
 
-static void QW_CL_ServerInfo(void)
+void QW_CL_ServerInfo(void)
 {
        char key[2048];
        char value[2048];
@@ -1032,7 +901,7 @@ static void QW_CL_ServerInfo(void)
        cl.qw_teamplay = atoi(temp);
 }
 
-static void QW_CL_ParseNails(void)
+void QW_CL_ParseNails(void)
 {
        int i, j;
        int numnails = MSG_ReadByte(&cl_message);
@@ -1054,7 +923,7 @@ static void QW_CL_ParseNails(void)
        }
 }
 
-static void CL_UpdateItemsAndWeapon(void)
+void CL_UpdateItemsAndWeapon(void)
 {
        int j;
        // check for important changes
@@ -1081,7 +950,7 @@ static void CL_BeginDownloads(qbool aborteddownload)
 {
        char vabuf[1024];
        // quakeworld works differently
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
                return;
 
        // this would be a good place to do curl downloads
@@ -1467,7 +1336,7 @@ static void CL_StopDownload(int size, int crc)
        cls.qw_downloadpercent = 0;
 }
 
-static void CL_ParseDownload(void)
+void CL_ParseDownload(void)
 {
        int i, start, size;
        static unsigned char data[NET_MAXMESSAGE];
@@ -1602,7 +1471,7 @@ CL_SignonReply
 An svc_signonnum has been received, perform a client side setup
 =====================
 */
-static void CL_SignonReply (void)
+void CL_SignonReply (void)
 {
        Con_DPrintf("CL_SignonReply: %i\n", cls.signon);
 
@@ -1668,11 +1537,11 @@ static void CL_SignonReply (void)
 CL_ParseServerInfo
 ==================
 */
-static void CL_ParseServerInfo (void)
+void CL_ParseServerInfo (void)
 {
        char *str;
        int i;
-       protocolversion_t protocol;
+       protocol_t *protocol;
        int nummodels, numsounds;
        char vabuf[1024];
 
@@ -1704,21 +1573,21 @@ static void CL_ParseServerInfo (void)
 
 // parse protocol version number
        i = MSG_ReadLong(&cl_message);
-       protocol = Protocol_EnumForNumber(i);
-       if (protocol == PROTOCOL_UNKNOWN)
+       protocol = Protocol_ForNumber(i);
+       if (!protocol)
        {
                Host_Error("CL_ParseServerInfo: Server is unrecognized protocol number (%i)", i);
                return;
        }
        // hack for unmarked Nehahra movie demos which had a custom protocol
-       if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && gamemode == GAME_NEHAHRA)
-               protocol = PROTOCOL_NEHAHRAMOVIE;
+       if (protocol == &protocol_quakedp && cls.demoplayback && gamemode == GAME_NEHAHRA)
+               protocol = &protocol_nehahramovie;
        cls.protocol = protocol;
-       Con_Printf("Server protocol is %s\n", Protocol_NameForEnum(cls.protocol));
+       Con_Printf("Server protocol is %s\n", protocol->name);
 
        cl.num_entities = 1;
 
-       if (protocol == PROTOCOL_QUAKEWORLD)
+       if (protocol == &protocol_quakeworld)
        {
                char gamedir[1][MAX_QPATH];
 
@@ -1776,7 +1645,7 @@ static void CL_ParseServerInfo (void)
 
                if (cls.netcon)
                {
-                       MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+                       MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                        MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, 0));
                }
 
@@ -1816,7 +1685,7 @@ static void CL_ParseServerInfo (void)
                cl.gametype = MSG_ReadByte(&cl_message);
                // the original id singleplayer demos are bugged and contain
                // GAME_DEATHMATCH even for singleplayer
-               if (cl.maxclients == 1 && cls.protocol == PROTOCOL_QUAKE)
+               if (cl.maxclients == 1 && cls.protocol == &protocol_netquake)
                        cl.gametype = GAME_COOP;
 
        // parse signon message
@@ -1824,7 +1693,7 @@ static void CL_ParseServerInfo (void)
                strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage));
 
        // seperate the printfs so the server message can have a color
-               if (cls.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
+               if (cls.protocol != &protocol_nehahramovie) // no messages when playing the Nehahra movie
                        Con_Printf("\n<===================================>\n\n\2%s\n", str);
 
                // check memory integrity
@@ -1912,7 +1781,7 @@ static void CL_ParseServerInfo (void)
                Mem_CheckSentinelsGlobal();
 
        // if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already
-               if (cl_autodemo.integer && cls.netcon && cls.protocol != PROTOCOL_QUAKEWORLD)
+               if (cl_autodemo.integer && cls.netcon && cls.protocol != &protocol_quakeworld)
                {
                        char demofile[MAX_OSPATH];
 
@@ -2093,7 +1962,7 @@ void CL_MoveLerpEntityStates(entity_t *ent)
 CL_ParseBaseline
 ==================
 */
-static void CL_ParseBaseline (entity_t *ent, int large)
+void CL_ParseBaseline (entity_t *ent, int large)
 {
        int i;
 
@@ -2105,7 +1974,7 @@ static void CL_ParseBaseline (entity_t *ent, int large)
                ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort(&cl_message);
                ent->state_baseline.frame = (unsigned short) MSG_ReadShort(&cl_message);
        }
-       else if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3)
+       else if (cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3)
        {
                ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort(&cl_message);
                ent->state_baseline.frame = MSG_ReadByte(&cl_message);
@@ -2119,8 +1988,8 @@ static void CL_ParseBaseline (entity_t *ent, int large)
        ent->state_baseline.skin = MSG_ReadByte(&cl_message);
        for (i = 0;i < 3;i++)
        {
-               ent->state_baseline.origin[i] = MSG_ReadCoord(&cl_message, cls.protocol);
-               ent->state_baseline.angles[i] = MSG_ReadAngle(&cl_message, cls.protocol);
+               ent->state_baseline.origin[i] = cls.protocol->ReadCoord(&cl_message);
+               ent->state_baseline.angles[i] = cls.protocol->ReadAngle(&cl_message);
        }
        ent->state_previous = ent->state_current = ent->state_baseline;
 }
@@ -2133,7 +2002,7 @@ CL_ParseClientdata
 Server information pertaining to this client only
 ==================
 */
-static void CL_ParseClientdata (void)
+void CL_ParseClientdata (void)
 {
        int i, bits;
 
@@ -2142,7 +2011,7 @@ static void CL_ParseClientdata (void)
        VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
        cl.mviewzoom[1] = cl.mviewzoom[0];
 
-       if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
+       if (cls.protocol == &protocol_netquake || cls.protocol == &protocol_quakedp || cls.protocol == &protocol_nehahramovie || cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3 || cls.protocol == &protocol_dpp1 || cls.protocol == &protocol_dpp2 || cls.protocol == &protocol_dpp3 || cls.protocol == &protocol_dpp4 || cls.protocol == &protocol_dpp5)
        {
                cl.stats[STAT_VIEWHEIGHT] = DEFAULT_VIEWHEIGHT;
                cl.stats[STAT_ITEMS] = 0;
@@ -2176,21 +2045,21 @@ static void CL_ParseClientdata (void)
        {
                if (bits & (SU_PUNCH1<<i) )
                {
-                       if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3)
+                       if (cls.protocol == &protocol_netquake || cls.protocol == &protocol_quakedp || cls.protocol == &protocol_nehahramovie || cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3)
                                cl.mpunchangle[0][i] = MSG_ReadChar(&cl_message);
                        else
                                cl.mpunchangle[0][i] = MSG_ReadAngle16i(&cl_message);
                }
                if (bits & (SU_PUNCHVEC1<<i))
                {
-                       if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
+                       if (cls.protocol == &protocol_dpp1 || cls.protocol == &protocol_dpp2 || cls.protocol == &protocol_dpp3 || cls.protocol == &protocol_dpp4)
                                cl.mpunchvector[0][i] = MSG_ReadCoord16i(&cl_message);
                        else
                                cl.mpunchvector[0][i] = MSG_ReadCoord32f(&cl_message);
                }
                if (bits & (SU_VELOCITY1<<i) )
                {
-                       if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
+                       if (cls.protocol == &protocol_netquake || cls.protocol == &protocol_quakedp || cls.protocol == &protocol_nehahramovie || cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3 || cls.protocol == &protocol_dpp1 || cls.protocol == &protocol_dpp2 || cls.protocol == &protocol_dpp3 || cls.protocol == &protocol_dpp4)
                                cl.mvelocity[0][i] = MSG_ReadChar(&cl_message)*16;
                        else
                                cl.mvelocity[0][i] = MSG_ReadCoord32f(&cl_message);
@@ -2198,13 +2067,13 @@ static void CL_ParseClientdata (void)
        }
 
        // LadyHavoc: hipnotic demos don't have this bit set but should
-       if (bits & SU_ITEMS || cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
+       if (bits & SU_ITEMS || cls.protocol == &protocol_netquake || cls.protocol == &protocol_quakedp || cls.protocol == &protocol_nehahramovie || cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3 || cls.protocol == &protocol_dpp1 || cls.protocol == &protocol_dpp2 || cls.protocol == &protocol_dpp3 || cls.protocol == &protocol_dpp4 || cls.protocol == &protocol_dpp5)
                cl.stats[STAT_ITEMS] = MSG_ReadLong(&cl_message);
 
        cl.onground = (bits & SU_ONGROUND) != 0;
        cl.inwater = (bits & SU_INWATER) != 0;
 
-       if (cls.protocol == PROTOCOL_DARKPLACES5)
+       if (cls.protocol == &protocol_dpp5)
        {
                cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadShort(&cl_message) : 0;
                cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadShort(&cl_message) : 0;
@@ -2217,11 +2086,11 @@ static void CL_ParseClientdata (void)
                cl.stats[STAT_CELLS] = MSG_ReadShort(&cl_message);
                cl.stats[STAT_ACTIVEWEAPON] = (unsigned short) MSG_ReadShort(&cl_message);
        }
-       else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
+       else if (cls.protocol == &protocol_netquake || cls.protocol == &protocol_quakedp || cls.protocol == &protocol_nehahramovie || cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3 || cls.protocol == &protocol_dpp1 || cls.protocol == &protocol_dpp2 || cls.protocol == &protocol_dpp3 || cls.protocol == &protocol_dpp4)
        {
                cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte(&cl_message) : 0;
                cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte(&cl_message) : 0;
-               if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3)
+               if (cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3)
                        cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? (unsigned short)MSG_ReadShort(&cl_message) : 0;
                else
                        cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte(&cl_message) : 0;
@@ -2239,7 +2108,7 @@ static void CL_ParseClientdata (void)
 
        if (bits & SU_VIEWZOOM)
        {
-               if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
+               if (cls.protocol == &protocol_dpp2 || cls.protocol == &protocol_dpp3 || cls.protocol == &protocol_dpp4)
                        cl.stats[STAT_VIEWZOOM] = MSG_ReadByte(&cl_message);
                else
                        cl.stats[STAT_VIEWZOOM] = (unsigned short) MSG_ReadShort(&cl_message);
@@ -2254,7 +2123,7 @@ static void CL_ParseClientdata (void)
 CL_ParseStatic
 =====================
 */
-static void CL_ParseStatic (int large)
+void CL_ParseStatic (int large)
 {
        entity_t *ent;
 
@@ -2294,13 +2163,13 @@ static void CL_ParseStatic (int large)
 CL_ParseStaticSound
 ===================
 */
-static void CL_ParseStaticSound (int large)
+void CL_ParseStaticSound (int large)
 {
        vec3_t          org;
        int                     sound_num, vol, atten;
 
-       MSG_ReadVector(&cl_message, org, cls.protocol);
-       if (large || cls.protocol == PROTOCOL_NEHAHRABJP2)
+       cls.protocol->ReadVector(&cl_message, org);
+       if (large || cls.protocol == &protocol_nehahrabjp2)
                sound_num = (unsigned short) MSG_ReadShort(&cl_message);
        else
                sound_num = MSG_ReadByte(&cl_message);
@@ -2317,12 +2186,12 @@ static void CL_ParseStaticSound (int large)
        S_StaticSound (cl.sound_precache[sound_num], org, vol/255.0f, atten);
 }
 
-static void CL_ParseEffect (void)
+void CL_ParseEffect (void)
 {
        vec3_t          org;
        int                     modelindex, startframe, framecount, framerate;
 
-       MSG_ReadVector(&cl_message, org, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, org);
        modelindex = MSG_ReadByte(&cl_message);
        startframe = MSG_ReadByte(&cl_message);
        framecount = MSG_ReadByte(&cl_message);
@@ -2331,12 +2200,12 @@ static void CL_ParseEffect (void)
        CL_Effect(org, CL_GetModelByIndex(modelindex), startframe, framecount, framerate);
 }
 
-static void CL_ParseEffect2 (void)
+void CL_ParseEffect2 (void)
 {
        vec3_t          org;
        int                     modelindex, startframe, framecount, framerate;
 
-       MSG_ReadVector(&cl_message, org, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, org);
        modelindex = (unsigned short) MSG_ReadShort(&cl_message);
        startframe = (unsigned short) MSG_ReadShort(&cl_message);
        framecount = MSG_ReadByte(&cl_message);
@@ -2390,8 +2259,8 @@ static void CL_ParseBeam (dp_model_t *m, int lightning)
        vec3_t start, end;
 
        ent = (unsigned short) MSG_ReadShort(&cl_message);
-       MSG_ReadVector(&cl_message, start, cls.protocol);
-       MSG_ReadVector(&cl_message, end, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, start);
+       cls.protocol->ReadVector(&cl_message, end);
 
        if (ent >= MAX_EDICTS)
        {
@@ -2402,7 +2271,7 @@ static void CL_ParseBeam (dp_model_t *m, int lightning)
        CL_NewBeam(ent, start, end, m, lightning);
 }
 
-static void CL_ParseTempEntity(void)
+void CL_ParseTempEntity(void)
 {
        int type;
        vec3_t pos, pos2;
@@ -2415,14 +2284,14 @@ static void CL_ParseTempEntity(void)
        unsigned char *tempcolor;
        matrix4x4_t tempmatrix;
 
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
        {
                type = MSG_ReadByte(&cl_message);
                switch (type)
                {
                case QW_TE_WIZSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1);
@@ -2430,7 +2299,7 @@ static void CL_ParseTempEntity(void)
 
                case QW_TE_KNIGHTSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1);
@@ -2438,7 +2307,7 @@ static void CL_ParseTempEntity(void)
 
                case QW_TE_SPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if (rand() % 5)
@@ -2456,7 +2325,7 @@ static void CL_ParseTempEntity(void)
                        break;
                case QW_TE_SUPERSPIKE:
                        // super spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if (rand() % 5)
@@ -2475,7 +2344,7 @@ static void CL_ParseTempEntity(void)
 
                case QW_TE_EXPLOSION:
                        // rocket explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
@@ -2484,7 +2353,7 @@ static void CL_ParseTempEntity(void)
 
                case QW_TE_TAREXPLOSION:
                        // tarbaby explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
@@ -2506,19 +2375,19 @@ static void CL_ParseTempEntity(void)
                        break;
 
                case QW_TE_LAVASPLASH:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
 
                case QW_TE_TELEPORT:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
 
                case QW_TE_GUNSHOT:
                        // bullet hitting wall
                        radius = MSG_ReadByte(&cl_message);
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        VectorSet(pos2, pos[0] + radius, pos[1] + radius, pos[2] + radius);
                        VectorSet(pos, pos[0] - radius, pos[1] - radius, pos[2] - radius);
@@ -2542,13 +2411,13 @@ static void CL_ParseTempEntity(void)
 
                case QW_TE_BLOOD:
                        count = MSG_ReadByte(&cl_message);
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
 
                case QW_TE_LIGHTNINGBLOOD:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_BLOOD, 2.5, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
@@ -2564,7 +2433,7 @@ static void CL_ParseTempEntity(void)
                {
                case TE_WIZSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1);
@@ -2572,7 +2441,7 @@ static void CL_ParseTempEntity(void)
 
                case TE_KNIGHTSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1);
@@ -2580,7 +2449,7 @@ static void CL_ParseTempEntity(void)
 
                case TE_SPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if (rand() % 5)
@@ -2598,7 +2467,7 @@ static void CL_ParseTempEntity(void)
                        break;
                case TE_SPIKEQUAD:
                        // quad spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if (rand() % 5)
@@ -2616,7 +2485,7 @@ static void CL_ParseTempEntity(void)
                        break;
                case TE_SUPERSPIKE:
                        // super spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if (rand() % 5)
@@ -2634,7 +2503,7 @@ static void CL_ParseTempEntity(void)
                        break;
                case TE_SUPERSPIKEQUAD:
                        // quad super spike hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if (rand() % 5)
@@ -2653,7 +2522,7 @@ static void CL_ParseTempEntity(void)
                        // LadyHavoc: added for improved blood splatters
                case TE_BLOOD:
                        // blood puff
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        dir[0] = MSG_ReadChar(&cl_message);
                        dir[1] = MSG_ReadChar(&cl_message);
@@ -2663,7 +2532,7 @@ static void CL_ParseTempEntity(void)
                        break;
                case TE_SPARK:
                        // spark shower
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        dir[0] = MSG_ReadChar(&cl_message);
                        dir[1] = MSG_ReadChar(&cl_message);
@@ -2672,16 +2541,16 @@ static void CL_ParseTempEntity(void)
                        CL_ParticleEffect(EFFECT_TE_SPARK, count, pos, pos, dir, dir, NULL, 0);
                        break;
                case TE_PLASMABURN:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
                        // LadyHavoc: added for improved gore
                case TE_BLOODSHOWER:
                        // vaporized body
-                       MSG_ReadVector(&cl_message, pos, cls.protocol); // mins
-                       MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs
-                       velspeed = MSG_ReadCoord(&cl_message, cls.protocol); // speed
+                       cls.protocol->ReadVector(&cl_message, pos); // mins
+                       cls.protocol->ReadVector(&cl_message, pos2); // maxs
+                       velspeed = cls.protocol->ReadCoord(&cl_message); // speed
                        count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles
                        vel1[0] = -velspeed;
                        vel1[1] = -velspeed;
@@ -2694,21 +2563,21 @@ static void CL_ParseTempEntity(void)
 
                case TE_PARTICLECUBE:
                        // general purpose particle effect
-                       MSG_ReadVector(&cl_message, pos, cls.protocol); // mins
-                       MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs
-                       MSG_ReadVector(&cl_message, dir, cls.protocol); // dir
+                       cls.protocol->ReadVector(&cl_message, pos); // mins
+                       cls.protocol->ReadVector(&cl_message, pos2); // maxs
+                       cls.protocol->ReadVector(&cl_message, dir); // dir
                        count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles
                        colorStart = MSG_ReadByte(&cl_message); // color
                        colorLength = MSG_ReadByte(&cl_message); // gravity (1 or 0)
-                       velspeed = MSG_ReadCoord(&cl_message, cls.protocol); // randomvel
+                       velspeed = cls.protocol->ReadCoord(&cl_message); // randomvel
                        CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength != 0, velspeed);
                        break;
 
                case TE_PARTICLERAIN:
                        // general purpose particle effect
-                       MSG_ReadVector(&cl_message, pos, cls.protocol); // mins
-                       MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs
-                       MSG_ReadVector(&cl_message, dir, cls.protocol); // dir
+                       cls.protocol->ReadVector(&cl_message, pos); // mins
+                       cls.protocol->ReadVector(&cl_message, pos2); // maxs
+                       cls.protocol->ReadVector(&cl_message, dir); // dir
                        count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles
                        colorStart = MSG_ReadByte(&cl_message); // color
                        CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
@@ -2716,9 +2585,9 @@ static void CL_ParseTempEntity(void)
 
                case TE_PARTICLESNOW:
                        // general purpose particle effect
-                       MSG_ReadVector(&cl_message, pos, cls.protocol); // mins
-                       MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs
-                       MSG_ReadVector(&cl_message, dir, cls.protocol); // dir
+                       cls.protocol->ReadVector(&cl_message, pos); // mins
+                       cls.protocol->ReadVector(&cl_message, pos2); // maxs
+                       cls.protocol->ReadVector(&cl_message, dir); // dir
                        count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles
                        colorStart = MSG_ReadByte(&cl_message); // color
                        CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
@@ -2726,7 +2595,7 @@ static void CL_ParseTempEntity(void)
 
                case TE_GUNSHOT:
                        // bullet hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if(cl_sound_ric_gunshot.integer & RIC_GUNSHOT)
@@ -2748,7 +2617,7 @@ static void CL_ParseTempEntity(void)
 
                case TE_GUNSHOTQUAD:
                        // quad bullet hitting wall
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        if(cl_sound_ric_gunshot.integer & RIC_GUNSHOTQUAD)
@@ -2770,7 +2639,7 @@ static void CL_ParseTempEntity(void)
 
                case TE_EXPLOSION:
                        // rocket explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
@@ -2778,7 +2647,7 @@ static void CL_ParseTempEntity(void)
 
                case TE_EXPLOSIONQUAD:
                        // quad rocket explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
@@ -2786,11 +2655,11 @@ static void CL_ParseTempEntity(void)
 
                case TE_EXPLOSION3:
                        // Nehahra movie colored lighting explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
-                       color[0] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f);
-                       color[1] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f);
-                       color[2] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f);
+                       color[0] = cls.protocol->ReadCoord(&cl_message) * (2.0f / 1.0f);
+                       color[1] = cls.protocol->ReadCoord(&cl_message) * (2.0f / 1.0f);
+                       color[2] = cls.protocol->ReadCoord(&cl_message) * (2.0f / 1.0f);
                        CL_ParticleExplosion(pos);
                        Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
                        CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
@@ -2799,7 +2668,7 @@ static void CL_ParseTempEntity(void)
 
                case TE_EXPLOSIONRGB:
                        // colored lighting explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleExplosion(pos);
                        color[0] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f);
@@ -2812,20 +2681,20 @@ static void CL_ParseTempEntity(void)
 
                case TE_TAREXPLOSION:
                        // tarbaby explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
                        break;
 
                case TE_SMALLFLASH:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
 
                case TE_CUSTOMFLASH:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        radius = (MSG_ReadByte(&cl_message) + 1) * 8;
                        velspeed = (MSG_ReadByte(&cl_message) + 1) * (1.0 / 256.0);
@@ -2837,8 +2706,8 @@ static void CL_ParseTempEntity(void)
                        break;
 
                case TE_FLAMEJET:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
-                       MSG_ReadVector(&cl_message, dir, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
+                       cls.protocol->ReadVector(&cl_message, dir);
                        count = MSG_ReadByte(&cl_message);
                        CL_ParticleEffect(EFFECT_TE_FLAMEJET, count, pos, pos, dir, dir, NULL, 0);
                        break;
@@ -2871,18 +2740,18 @@ static void CL_ParseTempEntity(void)
                        break;
 
                case TE_LAVASPLASH:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
 
                case TE_TELEPORT:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
 
                case TE_EXPLOSION2:
                        // color mapped explosion
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        colorStart = MSG_ReadByte(&cl_message);
                        colorLength = MSG_ReadByte(&cl_message);
@@ -2899,30 +2768,30 @@ static void CL_ParseTempEntity(void)
                        break;
 
                case TE_TEI_G3:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
-                       MSG_ReadVector(&cl_message, pos2, cls.protocol);
-                       MSG_ReadVector(&cl_message, dir, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
+                       cls.protocol->ReadVector(&cl_message, pos2);
+                       cls.protocol->ReadVector(&cl_message, dir);
                        CL_ParticleTrail(EFFECT_TE_TEI_G3, 1, pos, pos2, dir, dir, NULL, 0, true, true, NULL, NULL, 1);
                        break;
 
                case TE_TEI_SMOKE:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
-                       MSG_ReadVector(&cl_message, dir, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
+                       cls.protocol->ReadVector(&cl_message, dir);
                        count = MSG_ReadByte(&cl_message);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_TEI_SMOKE, count, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        break;
 
                case TE_TEI_BIGEXPLOSION:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleEffect(EFFECT_TE_TEI_BIGEXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
                        S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
                        break;
 
                case TE_TEI_PLASMAHIT:
-                       MSG_ReadVector(&cl_message, pos, cls.protocol);
-                       MSG_ReadVector(&cl_message, dir, cls.protocol);
+                       cls.protocol->ReadVector(&cl_message, pos);
+                       cls.protocol->ReadVector(&cl_message, dir);
                        count = MSG_ReadByte(&cl_message);
                        CL_FindNonSolidLocation(pos, pos, 5);
                        CL_ParticleEffect(EFFECT_TE_TEI_PLASMAHIT, count, pos, pos, vec3_origin, vec3_origin, NULL, 0);
@@ -2934,7 +2803,7 @@ static void CL_ParseTempEntity(void)
        }
 }
 
-static void CL_ParseTrailParticles(void)
+void CL_ParseTrailParticles(void)
 {
        int entityindex;
        int effectindex;
@@ -2945,28 +2814,28 @@ static void CL_ParseTrailParticles(void)
        if (entityindex >= cl.max_entities)
                CL_ExpandEntities(entityindex);
        effectindex = (unsigned short)MSG_ReadShort(&cl_message);
-       MSG_ReadVector(&cl_message, start, cls.protocol);
-       MSG_ReadVector(&cl_message, end, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, start);
+       cls.protocol->ReadVector(&cl_message, end);
        CL_ParticleTrail(effectindex, 1, start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0, true, true, NULL, NULL, 1);
 }
 
-static void CL_ParsePointParticles(void)
+void CL_ParsePointParticles(void)
 {
        int effectindex, count;
        vec3_t origin, velocity;
        effectindex = (unsigned short)MSG_ReadShort(&cl_message);
-       MSG_ReadVector(&cl_message, origin, cls.protocol);
-       MSG_ReadVector(&cl_message, velocity, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, origin);
+       cls.protocol->ReadVector(&cl_message, velocity);
        count = (unsigned short)MSG_ReadShort(&cl_message);
        CL_ParticleEffect(effectindex, count, origin, origin, velocity, velocity, NULL, 0);
 }
 
-static void CL_ParsePointParticles1(void)
+void CL_ParsePointParticles1(void)
 {
        int effectindex;
        vec3_t origin;
        effectindex = (unsigned short)MSG_ReadShort(&cl_message);
-       MSG_ReadVector(&cl_message, origin, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, origin);
        CL_ParticleEffect(effectindex, 1, origin, origin, vec3_origin, vec3_origin, NULL, 0);
 }
 
@@ -3131,7 +3000,7 @@ static void CL_IPLog_List_f(cmd_state_t *cmd)
 }
 
 // look for anything interesting like player IP addresses or ping reports
-static qbool CL_ExaminePrintString(const char *text)
+qbool CL_ExaminePrintString(const char *text)
 {
        int len;
        const char *t;
@@ -3276,7 +3145,7 @@ static qbool CL_ExaminePrintString(const char *text)
 
 extern cvar_t host_timescale;
 extern cvar_t cl_lerpexcess;
-static void CL_NetworkTimeReceived(double newtime)
+void CL_NetworkTimeReceived(double newtime)
 {
        double timehigh;
        cl.mtime[1] = cl.mtime[0];
@@ -3291,7 +3160,7 @@ static void CL_NetworkTimeReceived(double newtime)
                if (cl.time < newtime - 0.1)
                        cl.mtime[1] = cl.time = newtime;
        }
-       else if (cls.protocol != PROTOCOL_QUAKEWORLD)
+       else if (cls.protocol != &protocol_quakeworld)
        {
                cl.mtime[1] = max(cl.mtime[1], cl.mtime[0] - 0.1);
                if (developer_extra.integer && vid_activewindow)
@@ -3386,13 +3255,10 @@ void CL_ParseServerMessage(void)
 {
        int                     cmd;
        int                     i;
-       protocolversion_t protocol;
+       protocol_t *protocol = cls.protocol;
        unsigned char           cmdlog[32];
        const char              *cmdlogname[32], *temp;
        int                     cmdindex, cmdcount = 0;
-       qbool   qwplayerupdatereceived;
-       qbool   strip_pqc;
-       char vabuf[1024];
 
        // LadyHavoc: moved demo message writing from before the packet parse to
        // after the packet parse so that CL_Stop_f can be called by cl_autodemo
@@ -3419,7 +3285,7 @@ void CL_ParseServerMessage(void)
 
        parsingerror = true;
 
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (protocol == &protocol_quakeworld)
        {
                CL_NetworkTimeReceived(host.realtime); // qw has no clock
 
@@ -3431,369 +3297,29 @@ void CL_ParseServerMessage(void)
 
                cls.servermovesequence = cls.netcon->qw.incoming_sequence;
 
-               qwplayerupdatereceived = false;
-
-               while (1)
-               {
-                       if (cl_message.badread)
-                               Host_Error ("CL_ParseServerMessage: Bad QW server message");
-
-                       cmd = MSG_ReadByte(&cl_message);
-
-                       if (cmd == -1)
-                       {
-                               SHOWNET("END OF MESSAGE");
-                               break;          // end of message
-                       }
-
-                       cmdindex = cmdcount & 31;
-                       cmdcount++;
-                       cmdlog[cmdindex] = cmd;
-
-                       SHOWNET(qw_svc_strings[cmd]);
-                       cmdlogname[cmdindex] = qw_svc_strings[cmd];
-                       if (!cmdlogname[cmdindex])
-                       {
-                               // LadyHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
-                               const char *d = "<unknown>";
-                               cmdlogname[cmdindex] = d;
-                       }
-
-                       // other commands
-                       switch (cmd)
-                       {
-                       default:
-                               {
-                                       char description[32*64], logtemp[64];
-                                       int count;
-                                       strlcpy(description, "packet dump: ", sizeof(description));
-                                       i = cmdcount - 32;
-                                       if (i < 0)
-                                               i = 0;
-                                       count = cmdcount - i;
-                                       i &= 31;
-                                       while(count > 0)
-                                       {
-                                               dpsnprintf(logtemp, sizeof(logtemp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
-                                               strlcat(description, logtemp, sizeof(description));
-                                               count--;
-                                               i++;
-                                               i &= 31;
-                                       }
-                                       description[strlen(description)-1] = '\n'; // replace the last space with a newline
-                                       Con_Print(description);
-                                       Host_Error("CL_ParseServerMessage: Illegible server message");
-                               }
-                               break;
-
-                       case qw_svc_nop:
-                               //Con_Printf("qw_svc_nop\n");
-                               break;
-
-                       case qw_svc_disconnect:
-                               Con_Printf("Server disconnected\n");
-                               if (cls.demonum != -1)
-                                       CL_NextDemo();
-                               else
-                                       CL_Disconnect();
-                               return;
-
-                       case qw_svc_print:
-                               i = MSG_ReadByte(&cl_message);
-                               temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
-                               if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports
-                               {
-                                       if (i == 3) // chat
-                                               CSQC_AddPrintText(va(vabuf, sizeof(vabuf), "\1%s", temp));      //[515]: csqc
-                                       else
-                                               CSQC_AddPrintText(temp);
-                               }
-                               break;
-
-                       case qw_svc_centerprint:
-                               CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));     //[515]: csqc
-                               break;
-
-                       case qw_svc_stufftext:
-                               CL_VM_Parse_StuffCmd(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));        //[515]: csqc
-                               break;
-
-                       case qw_svc_damage:
-                               // svc_damage protocol is identical to nq
-                               V_ParseDamage ();
-                               break;
-
-                       case qw_svc_serverdata:
-                               //Cbuf_Execute(); // make sure any stuffed commands are done
-                               CL_ParseServerInfo();
-                               break;
-
-                       case qw_svc_setangle:
-                               for (i=0 ; i<3 ; i++)
-                                       cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol);
-                               if (!cls.demoplayback)
-                               {
-                                       cl.fixangle[0] = true;
-                                       VectorCopy(cl.viewangles, cl.mviewangles[0]);
-                                       // disable interpolation if this is new
-                                       if (!cl.fixangle[1])
-                                               VectorCopy(cl.viewangles, cl.mviewangles[1]);
-                               }
-                               break;
-
-                       case qw_svc_lightstyle:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.max_lightstyle)
-                               {
-                                       Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES");
-                                       break;
-                               }
-                               strlcpy (cl.lightstyle[i].map,  MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map));
-                               cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
-                               cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
-                               break;
-
-                       case qw_svc_sound:
-                               CL_ParseStartSoundPacket(false);
-                               break;
-
-                       case qw_svc_stopsound:
-                               i = (unsigned short) MSG_ReadShort(&cl_message);
-                               S_StopSound(i>>3, i&7);
-                               break;
-
-                       case qw_svc_updatefrags:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.maxclients)
-                                       Host_Error("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
-                               cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message);
-                               break;
-
-                       case qw_svc_updateping:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.maxclients)
-                                       Host_Error("CL_ParseServerMessage: svc_updateping >= cl.maxclients");
-                               cl.scores[i].qw_ping = MSG_ReadShort(&cl_message);
-                               break;
-
-                       case qw_svc_updatepl:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.maxclients)
-                                       Host_Error("CL_ParseServerMessage: svc_updatepl >= cl.maxclients");
-                               cl.scores[i].qw_packetloss = MSG_ReadByte(&cl_message);
-                               break;
-
-                       case qw_svc_updateentertime:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.maxclients)
-                                       Host_Error("CL_ParseServerMessage: svc_updateentertime >= cl.maxclients");
-                               // seconds ago
-                               cl.scores[i].qw_entertime = cl.time - MSG_ReadFloat(&cl_message);
-                               break;
-
-                       case qw_svc_spawnbaseline:
-                               i = (unsigned short) MSG_ReadShort(&cl_message);
-                               if (i < 0 || i >= MAX_EDICTS)
-                                       Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
-                               if (i >= cl.max_entities)
-                                       CL_ExpandEntities(i);
-                               CL_ParseBaseline(cl.entities + i, false);
-                               break;
-                       case qw_svc_spawnstatic:
-                               CL_ParseStatic(false);
-                               break;
-                       case qw_svc_temp_entity:
-                               if(!CL_VM_Parse_TempEntity())
-                                       CL_ParseTempEntity ();
-                               break;
-
-                       case qw_svc_killedmonster:
-                               cl.stats[STAT_MONSTERS]++;
-                               break;
-
-                       case qw_svc_foundsecret:
-                               cl.stats[STAT_SECRETS]++;
-                               break;
-
-                       case qw_svc_updatestat:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i < 0 || i >= MAX_CL_STATS)
-                                       Host_Error ("svc_updatestat: %i is invalid", i);
-                               cl.stats[i] = MSG_ReadByte(&cl_message);
-                               break;
-
-                       case qw_svc_updatestatlong:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i < 0 || i >= MAX_CL_STATS)
-                                       Host_Error ("svc_updatestatlong: %i is invalid", i);
-                               cl.stats[i] = MSG_ReadLong(&cl_message);
-                               break;
-
-                       case qw_svc_spawnstaticsound:
-                               CL_ParseStaticSound (false);
-                               break;
-
-                       case qw_svc_cdtrack:
-                               cl.cdtrack = cl.looptrack = MSG_ReadByte(&cl_message);
-                               if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
-                                       CDAudio_Play ((unsigned char)cls.forcetrack, true);
-                               else
-                                       CDAudio_Play ((unsigned char)cl.cdtrack, true);
-                               break;
-
-                       case qw_svc_intermission:
-                               if(!cl.intermission)
-                                       cl.completed_time = cl.time;
-                               cl.intermission = 1;
-                               MSG_ReadVector(&cl_message, cl.qw_intermission_origin, cls.protocol);
-                               for (i = 0;i < 3;i++)
-                                       cl.qw_intermission_angles[i] = MSG_ReadAngle(&cl_message, cls.protocol);
-                               break;
-
-                       case qw_svc_finale:
-                               if(!cl.intermission)
-                                       cl.completed_time = cl.time;
-                               cl.intermission = 2;
-                               SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
-                               break;
-
-                       case qw_svc_sellscreen:
-                               Cmd_ExecuteString(&cmd_client, "help", src_local, true);
-                               break;
-
-                       case qw_svc_smallkick:
-                               cl.qw_weaponkick = -2;
-                               break;
-                       case qw_svc_bigkick:
-                               cl.qw_weaponkick = -4;
-                               break;
-
-                       case qw_svc_muzzleflash:
-                               i = (unsigned short) MSG_ReadShort(&cl_message);
-                               // NOTE: in QW this only worked on clients
-                               if (i < 0 || i >= MAX_EDICTS)
-                                       Host_Error("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
-                               if (i >= cl.max_entities)
-                                       CL_ExpandEntities(i);
-                               cl.entities[i].persistent.muzzleflash = 1.0f;
-                               break;
-
-                       case qw_svc_updateuserinfo:
-                               QW_CL_UpdateUserInfo();
-                               break;
-
-                       case qw_svc_setinfo:
-                               QW_CL_SetInfo();
-                               break;
-
-                       case qw_svc_serverinfo:
-                               QW_CL_ServerInfo();
-                               break;
-
-                       case qw_svc_download:
-                               QW_CL_ParseDownload();
-                               break;
-
-                       case qw_svc_playerinfo:
-                               // slightly kill qw player entities now that we know there is
-                               // an update of player entities this frame...
-                               if (!qwplayerupdatereceived)
-                               {
-                                       qwplayerupdatereceived = true;
-                                       for (i = 1;i < cl.maxclients;i++)
-                                               cl.entities_active[i] = false;
-                               }
-                               EntityStateQW_ReadPlayerUpdate();
-                               break;
-
-                       case qw_svc_nails:
-                               QW_CL_ParseNails();
-                               break;
-
-                       case qw_svc_chokecount:
-                               (void) MSG_ReadByte(&cl_message);
-                               // FIXME: apply to netgraph
-                               //for (j = 0;j < i;j++)
-                               //      cl.frames[(cls.netcon->qw.incoming_acknowledged-1-j)&QW_UPDATE_MASK].receivedtime = -2;
-                               break;
-
-                       case qw_svc_modellist:
-                               QW_CL_ParseModelList();
-                               break;
-
-                       case qw_svc_soundlist:
-                               QW_CL_ParseSoundList();
-                               break;
-
-                       case qw_svc_packetentities:
-                               EntityFrameQW_CL_ReadFrame(false);
-                               // first update is the final signon stage
-                               if (cls.signon == SIGNONS - 1)
-                               {
-                                       cls.signon = SIGNONS;
-                                       CL_SignonReply ();
-                               }
-                               break;
-
-                       case qw_svc_deltapacketentities:
-                               EntityFrameQW_CL_ReadFrame(true);
-                               // first update is the final signon stage
-                               if (cls.signon == SIGNONS - 1)
-                               {
-                                       cls.signon = SIGNONS;
-                                       CL_SignonReply ();
-                               }
-                               break;
-
-                       case qw_svc_maxspeed:
-                               cl.movevars_maxspeed = MSG_ReadFloat(&cl_message);
-                               break;
-
-                       case qw_svc_entgravity:
-                               cl.movevars_entgravity = MSG_ReadFloat(&cl_message);
-                               if (!cl.movevars_entgravity)
-                                       cl.movevars_entgravity = 1.0f;
-                               break;
-
-                       case qw_svc_setpause:
-                               cl.paused = MSG_ReadByte(&cl_message) != 0;
-                               if (cl.paused)
-                                       CDAudio_Pause ();
-                               else
-                                       CDAudio_Resume ();
-                               S_PauseGameSounds (cl.paused);
-                               break;
-                       }
-               }
-
-               if (qwplayerupdatereceived)
-               {
-                       // fully kill any player entities that were not updated this frame
-                       for (i = 1;i <= cl.maxclients;i++)
-                               if (!cl.entities_active[i])
-                                       cl.entities[i].state_current.active = false;
-               }
+               cl.qwplayerupdatereceived = false;
        }
-       else
+
+       while (1)
        {
-               while (1)
-               {
-                       if (cl_message.badread)
-                               Host_Error ("CL_ParseServerMessage: Bad server message");
+               if (cl_message.badread)
+                       Host_Error ("CL_ParseServerMessage: Bad server message");
 
-                       cmd = MSG_ReadByte(&cl_message);
+               cmd = MSG_ReadByte(&cl_message);
 
-                       if (cmd == -1)
-                       {
+               if (cmd == -1)
+               {
 //                             R_TimeReport("END OF MESSAGE");
-                               SHOWNET("END OF MESSAGE");
-                               break;          // end of message
-                       }
+                       SHOWNET("END OF MESSAGE");
+                       break;          // end of message
+               }
 
-                       cmdindex = cmdcount & 31;
-                       cmdcount++;
-                       cmdlog[cmdindex] = cmd;
+               cmdindex = cmdcount & 31;
+               cmdcount++;
+               cmdlog[cmdindex] = cmd;
 
+               if(protocol != &protocol_quakeworld)
+               {
                        // if the high bit of the command byte is set, it is a fast update
                        if (cmd & 128)
                        {
@@ -3810,431 +3336,53 @@ void CL_ParseServerMessage(void)
                                EntityFrameQuake_ReadEntity (cmd&127);
                                continue;
                        }
+               }
 
-                       SHOWNET(svc_strings[cmd]);
-                       cmdlogname[cmdindex] = svc_strings[cmd];
+               if(cmd <= protocol->max_svcmsg && protocol->svcmsg[cmd].func)
+               {
+                       SHOWNET(protocol->svcmsg[cmd].name);
+                       cmdlogname[cmdindex] = protocol->svcmsg[cmd].name;
                        if (!cmdlogname[cmdindex])
                        {
                                // LadyHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
                                const char *d = "<unknown>";
                                cmdlogname[cmdindex] = d;
                        }
-
-                       // other commands
-                       switch (cmd)
+                       protocol->svcmsg[cmd].func(protocol);
+               }
+               else
+               {
+                       char description[32*64], tempdesc[64];
+                       int count;
+                       strlcpy (description, "packet dump: ", sizeof(description));
+                       i = cmdcount - 32;
+                       if (i < 0)
+                               i = 0;
+                       count = cmdcount - i;
+                       i &= 31;
+                       while(count > 0)
                        {
-                       default:
-                               {
-                                       char description[32*64], tempdesc[64];
-                                       int count;
-                                       strlcpy (description, "packet dump: ", sizeof(description));
-                                       i = cmdcount - 32;
-                                       if (i < 0)
-                                               i = 0;
-                                       count = cmdcount - i;
-                                       i &= 31;
-                                       while(count > 0)
-                                       {
-                                               dpsnprintf (tempdesc, sizeof (tempdesc), "%3i:%s ", cmdlog[i], cmdlogname[i]);
-                                               strlcat (description, tempdesc, sizeof (description));
-                                               count--;
-                                               i++;
-                                               i &= 31;
-                                       }
-                                       description[strlen(description)-1] = '\n'; // replace the last space with a newline
-                                       Con_Print(description);
-                                       Host_Error ("CL_ParseServerMessage: Illegible server message");
-                               }
-                               break;
-
-                       case svc_nop:
-                               if (cls.signon < SIGNONS)
-                                       Con_Print("<-- server to client keepalive\n");
-                               break;
-
-                       case svc_time:
-                               CL_NetworkTimeReceived(MSG_ReadFloat(&cl_message));
-                               break;
-
-                       case svc_clientdata:
-                               CL_ParseClientdata();
-                               break;
-
-                       case svc_version:
-                               i = MSG_ReadLong(&cl_message);
-                               protocol = Protocol_EnumForNumber(i);
-                               if (protocol == PROTOCOL_UNKNOWN)
-                                       Host_Error("CL_ParseServerMessage: Server is unrecognized protocol number (%i)", i);
-                               // hack for unmarked Nehahra movie demos which had a custom protocol
-                               if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && gamemode == GAME_NEHAHRA)
-                                       protocol = PROTOCOL_NEHAHRAMOVIE;
-                               cls.protocol = protocol;
-                               break;
-
-                       case svc_disconnect:
-                               Con_Printf ("Server disconnected\n");
-                               if (cls.demonum != -1)
-                                       CL_NextDemo ();
-                               else
-                                       CL_Disconnect ();
-                               break;
-
-                       case svc_print:
-                               temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
-                               if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports
-                                       CSQC_AddPrintText(temp);        //[515]: csqc
-                               break;
-
-                       case svc_centerprint:
-                               CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));     //[515]: csqc
-                               break;
-
-                       case svc_stufftext:
-                               temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
-                               /* if(utf8_enable.integer)
-                               {
-                                       strip_pqc = true;
-                                       // we can safely strip and even
-                                       // interpret these in utf8 mode
-                               }
-                               else */ switch(cls.protocol)
-                               {
-                                       case PROTOCOL_QUAKE:
-                                       case PROTOCOL_QUAKEDP:
-                                               // maybe add other protocols if
-                                               // so desired, but not DP7
-                                               strip_pqc = true;
-                                               break;
-                                       case PROTOCOL_DARKPLACES7:
-                                       default:
-                                               // ProQuake does not support
-                                               // these protocols
-                                               strip_pqc = false;
-                                               break;
-                               }
-                               if(strip_pqc)
-                               {
-                                       // skip over ProQuake messages,
-                                       // TODO actually interpret them
-                                       // (they are sbar team score
-                                       // updates), see proquake cl_parse.c
-                                       if(*temp == 0x01)
-                                       {
-                                               ++temp;
-                                               while(*temp >= 0x01 && *temp <= 0x1F)
-                                                       ++temp;
-                                       }
-                               }
-                               CL_VM_Parse_StuffCmd(temp);     //[515]: csqc
-                               break;
-
-                       case svc_damage:
-                               V_ParseDamage ();
-                               break;
-
-                       case svc_serverinfo:
-                               CL_ParseServerInfo ();
-                               break;
-
-                       case svc_setangle:
-                               for (i=0 ; i<3 ; i++)
-                                       cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol);
-                               if (!cls.demoplayback)
-                               {
-                                       cl.fixangle[0] = true;
-                                       VectorCopy(cl.viewangles, cl.mviewangles[0]);
-                                       // disable interpolation if this is new
-                                       if (!cl.fixangle[1])
-                                               VectorCopy(cl.viewangles, cl.mviewangles[1]);
-                               }
-                               break;
-
-                       case svc_setview:
-                               cl.viewentity = (unsigned short)MSG_ReadShort(&cl_message);
-                               if (cl.viewentity >= MAX_EDICTS)
-                                       Host_Error("svc_setview >= MAX_EDICTS");
-                               if (cl.viewentity >= cl.max_entities)
-                                       CL_ExpandEntities(cl.viewentity);
-                               // LadyHavoc: assume first setview recieved is the real player entity
-                               if (!cl.realplayerentity)
-                                       cl.realplayerentity = cl.viewentity;
-                               // update cl.playerentity to this one if it is a valid player
-                               if (cl.viewentity >= 1 && cl.viewentity <= cl.maxclients)
-                                       cl.playerentity = cl.viewentity;
-                               break;
-
-                       case svc_lightstyle:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.max_lightstyle)
-                               {
-                                       Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES");
-                                       break;
-                               }
-                               strlcpy (cl.lightstyle[i].map,  MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map));
-                               cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
-                               cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
-                               break;
-
-                       case svc_sound:
-                               CL_ParseStartSoundPacket(false);
-                               break;
-
-                       case svc_precache:
-                               if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
-                               {
-                                       // was svc_sound2 in protocols 1, 2, 3, removed in 4, 5, changed to svc_precache in 6
-                                       CL_ParseStartSoundPacket(true);
-                               }
-                               else
-                               {
-                                       char *s;
-                                       i = (unsigned short)MSG_ReadShort(&cl_message);
-                                       s = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
-                                       if (i < 32768)
-                                       {
-                                               if (i >= 1 && i < MAX_MODELS)
-                                               {
-                                                       dp_model_t *model = Mod_ForName(s, false, false, s[0] == '*' ? cl.model_name[1] : NULL);
-                                                       if (!model)
-                                                               Con_DPrintf("svc_precache: Mod_ForName(\"%s\") failed\n", s);
-                                                       cl.model_precache[i] = model;
-                                               }
-                                               else
-                                                       Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_MODELS);
-                                       }
-                                       else
-                                       {
-                                               i -= 32768;
-                                               if (i >= 1 && i < MAX_SOUNDS)
-                                               {
-                                                       sfx_t *sfx = S_PrecacheSound (s, true, true);
-                                                       if (!sfx && snd_initialized.integer)
-                                                               Con_DPrintf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s);
-                                                       cl.sound_precache[i] = sfx;
-                                               }
-                                               else
-                                                       Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_SOUNDS);
-                                       }
-                               }
-                               break;
-
-                       case svc_stopsound:
-                               i = (unsigned short) MSG_ReadShort(&cl_message);
-                               S_StopSound(i>>3, i&7);
-                               break;
-
-                       case svc_updatename:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.maxclients)
-                                       Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
-                               strlcpy (cl.scores[i].name, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.scores[i].name));
-                               break;
-
-                       case svc_updatefrags:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.maxclients)
-                                       Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
-                               cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message);
-                               break;
-
-                       case svc_updatecolors:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i >= cl.maxclients)
-                                       Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
-                               cl.scores[i].colors = MSG_ReadByte(&cl_message);
-                               break;
-
-                       case svc_particle:
-                               CL_ParseParticleEffect ();
-                               break;
-
-                       case svc_effect:
-                               CL_ParseEffect ();
-                               break;
-
-                       case svc_effect2:
-                               CL_ParseEffect2 ();
-                               break;
-
-                       case svc_spawnbaseline:
-                               i = (unsigned short) MSG_ReadShort(&cl_message);
-                               if (i < 0 || i >= MAX_EDICTS)
-                                       Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
-                               if (i >= cl.max_entities)
-                                       CL_ExpandEntities(i);
-                               CL_ParseBaseline (cl.entities + i, false);
-                               break;
-                       case svc_spawnbaseline2:
-                               i = (unsigned short) MSG_ReadShort(&cl_message);
-                               if (i < 0 || i >= MAX_EDICTS)
-                                       Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
-                               if (i >= cl.max_entities)
-                                       CL_ExpandEntities(i);
-                               CL_ParseBaseline (cl.entities + i, true);
-                               break;
-                       case svc_spawnstatic:
-                               CL_ParseStatic (false);
-                               break;
-                       case svc_spawnstatic2:
-                               CL_ParseStatic (true);
-                               break;
-                       case svc_temp_entity:
-                               if(!CL_VM_Parse_TempEntity())
-                                       CL_ParseTempEntity ();
-                               break;
-
-                       case svc_setpause:
-                               cl.paused = MSG_ReadByte(&cl_message) != 0;
-                               if (cl.paused)
-                                       CDAudio_Pause ();
-                               else
-                                       CDAudio_Resume ();
-                               S_PauseGameSounds (cl.paused);
-                               break;
-
-                       case svc_signonnum:
-                               i = MSG_ReadByte(&cl_message);
-                               // LadyHavoc: it's rude to kick off the client if they missed the
-                               // reconnect somehow, so allow signon 1 even if at signon 1
-                               if (i <= cls.signon && i != 1)
-                                       Host_Error ("Received signon %i when at %i", i, cls.signon);
-                               cls.signon = i;
-                               CL_SignonReply ();
-                               break;
-
-                       case svc_killedmonster:
-                               cl.stats[STAT_MONSTERS]++;
-                               break;
-
-                       case svc_foundsecret:
-                               cl.stats[STAT_SECRETS]++;
-                               break;
-
-                       case svc_updatestat:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i < 0 || i >= MAX_CL_STATS)
-                                       Host_Error ("svc_updatestat: %i is invalid", i);
-                               cl.stats[i] = MSG_ReadLong(&cl_message);
-                               break;
-
-                       case svc_updatestatubyte:
-                               i = MSG_ReadByte(&cl_message);
-                               if (i < 0 || i >= MAX_CL_STATS)
-                                       Host_Error ("svc_updatestat: %i is invalid", i);
-                               cl.stats[i] = MSG_ReadByte(&cl_message);
-                               break;
-
-                       case svc_spawnstaticsound:
-                               CL_ParseStaticSound (false);
-                               break;
-
-                       case svc_spawnstaticsound2:
-                               CL_ParseStaticSound (true);
-                               break;
-
-                       case svc_cdtrack:
-                               cl.cdtrack = MSG_ReadByte(&cl_message);
-                               cl.looptrack = MSG_ReadByte(&cl_message);
-                               if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
-                                       CDAudio_Play ((unsigned char)cls.forcetrack, true);
-                               else
-                                       CDAudio_Play ((unsigned char)cl.cdtrack, true);
-                               break;
-
-                       case svc_intermission:
-                               if(!cl.intermission)
-                                       cl.completed_time = cl.time;
-                               cl.intermission = 1;
-                               CL_VM_UpdateIntermissionState(cl.intermission);
-                               break;
-
-                       case svc_finale:
-                               if(!cl.intermission)
-                                       cl.completed_time = cl.time;
-                               cl.intermission = 2;
-                               CL_VM_UpdateIntermissionState(cl.intermission);
-                               SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
-                               break;
-
-                       case svc_cutscene:
-                               if(!cl.intermission)
-                                       cl.completed_time = cl.time;
-                               cl.intermission = 3;
-                               CL_VM_UpdateIntermissionState(cl.intermission);
-                               SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
-                               break;
-
-                       case svc_sellscreen:
-                               Cmd_ExecuteString(&cmd_client, "help", src_local, true);
-                               break;
-                       case svc_hidelmp:
-                               if (gamemode == GAME_TENEBRAE)
-                               {
-                                       // repeating particle effect
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       (void) MSG_ReadByte(&cl_message);
-                                       MSG_ReadLong(&cl_message);
-                                       MSG_ReadLong(&cl_message);
-                                       MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
-                               }
-                               else
-                                       SHOWLMP_decodehide();
-                               break;
-                       case svc_showlmp:
-                               if (gamemode == GAME_TENEBRAE)
-                               {
-                                       // particle effect
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       MSG_ReadCoord(&cl_message, cls.protocol);
-                                       (void) MSG_ReadByte(&cl_message);
-                                       MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
-                               }
-                               else
-                                       SHOWLMP_decodeshow();
-                               break;
-                       case svc_skybox:
-                               R_SetSkyBox(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
-                               break;
-                       case svc_entities:
-                               if (cls.signon == SIGNONS - 1)
-                               {
-                                       // first update is the final signon stage
-                                       cls.signon = SIGNONS;
-                                       CL_SignonReply ();
-                               }
-                               if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
-                                       EntityFrame_CL_ReadFrame();
-                               else if (cls.protocol == PROTOCOL_DARKPLACES4)
-                                       EntityFrame4_CL_ReadFrame();
-                               else
-                                       EntityFrame5_CL_ReadFrame();
-                               break;
-                       case svc_csqcentities:
-                               CSQC_ReadEntities();
-                               break;
-                       case svc_downloaddata:
-                               CL_ParseDownload();
-                               break;
-                       case svc_trailparticles:
-                               CL_ParseTrailParticles();
-                               break;
-                       case svc_pointparticles:
-                               CL_ParsePointParticles();
-                               break;
-                       case svc_pointparticles1:
-                               CL_ParsePointParticles1();
-                               break;
+                               dpsnprintf (tempdesc, sizeof (tempdesc), "%3i:%s ", cmdlog[i], cmdlogname[i]);
+                               strlcat (description, tempdesc, sizeof (description));
+                               count--;
+                               i++;
+                               i &= 31;
                        }
-//                     R_TimeReport(svc_strings[cmd]);
+                       description[strlen(description)-1] = '\n'; // replace the last space with a newline
+                       Con_Print(description);
+                       Host_Error ("CL_ParseServerMessage: Illegible server message");
                }
        }
 
+       if (cl.qwplayerupdatereceived)
+       {
+               // fully kill any player entities that were not updated this frame
+               for (i = 1;i <= cl.maxclients;i++)
+                       if (!cl.entities_active[i])
+                               cl.entities[i].state_current.active = false;
+       }
+//                     R_TimeReport(svc_strings[cmd]);
+
        if (cls.signon == SIGNONS)
                CL_UpdateItemsAndWeapon();
 //     R_TimeReport("UpdateItems");
diff --git a/cl_parse.h b/cl_parse.h
new file mode 100644 (file)
index 0000000..8c1437e
--- /dev/null
@@ -0,0 +1,26 @@
+#include "quakedef.h"
+
+void CL_ParseBaseline (entity_t *ent, int large);
+void CL_ParseClientdata (void);
+void CL_ParseStatic (int large);
+void CL_ParseStaticSound (int large);
+void CL_ParseEffect (void);
+void CL_ParseEffect2 (void);
+void CL_ParseServerInfo (void);
+qbool CL_ExaminePrintString(const char *text);
+void CL_ParseStartSoundPacket(int largesoundindex);
+void CL_ParseTempEntity(void);
+void QW_CL_UpdateUserInfo(void);
+void QW_CL_SetInfo(void);
+void QW_CL_ServerInfo(void);
+void QW_CL_ParseDownload(void);
+void QW_CL_ParseModelList(void);
+void QW_CL_ParseNails(void);
+void CL_UpdateItemsAndWeapon(void);
+void QW_CL_ParseSoundList(void);
+void CL_SignonReply (void);
+void CL_NetworkTimeReceived(double newtime);
+void CL_ParseDownload(void);
+void CL_ParseTrailParticles(void);
+void CL_ParsePointParticles(void);
+void CL_ParsePointParticles1(void);
\ No newline at end of file
index f6da360123f5f03a78c9851d8c0d6163ae850c1f..9d46386243e3a8cc6165dfc766dab1b8cbd2d624 100644 (file)
@@ -1769,7 +1769,7 @@ void CL_ParseParticleEffect (void)
        vec3_t org, dir;
        int i, count, msgcount, color;
 
-       MSG_ReadVector(&cl_message, org, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, org);
        for (i=0 ; i<3 ; i++)
                dir[i] = MSG_ReadChar(&cl_message) * (1.0 / 16.0);
        msgcount = MSG_ReadByte(&cl_message);
diff --git a/cl_protocol_basenq.h b/cl_protocol_basenq.h
new file mode 100644 (file)
index 0000000..1f5edba
--- /dev/null
@@ -0,0 +1,336 @@
+#include "quakedef.h"
+#include "client.h"
+#include "protocol.h"
+#include "cl_parse.h"
+#include "cdaudio.h"
+
+static void Netmsg_svc_nop (protocol_t *protocol)
+{
+       if (cls.signon < SIGNONS)
+               Con_Print("<-- server to client keepalive\n");
+
+}
+
+static void Netmsg_svc_disconnect (protocol_t *protocol)
+{
+       Con_Printf ("Server disconnected\n");
+       if (cls.demonum != -1)
+               CL_NextDemo ();
+       else
+               CL_Disconnect ();
+}
+
+static void Netmsg_svc_updatestat (protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i < 0 || i >= MAX_CL_STATS)
+               Host_Error ("svc_updatestat: %i is invalid", i);
+       cl.stats[i] = MSG_ReadLong(&cl_message);
+}
+
+static void Netmsg_svc_version (protocol_t *protocol)          // [int] server version
+{
+       int i = MSG_ReadLong(&cl_message);
+       if (!Protocol_ForNumber(i))
+               Host_Error("CL_ParseServerMessage: Server is unrecognized protocol number (%i)", i);
+       // hack for unmarked Nehahra movie demos which had a custom protocol
+       if (protocol == &protocol_quakedp && cls.demoplayback && gamemode == GAME_NEHAHRA)
+               protocol = &protocol_nehahramovie;
+       cls.protocol = protocol;
+}
+
+static void Netmsg_svc_setview (protocol_t *protocol)          // [short] entity number
+{
+       cl.viewentity = (unsigned short)MSG_ReadShort(&cl_message);
+       if (cl.viewentity >= MAX_EDICTS)
+               Host_Error("svc_setview >= MAX_EDICTS");
+       if (cl.viewentity >= cl.max_entities)
+               CL_ExpandEntities(cl.viewentity);
+       // LadyHavoc: assume first setview recieved is the real player entity
+       if (!cl.realplayerentity)
+               cl.realplayerentity = cl.viewentity;
+       // update cl.playerentity to this one if it is a valid player
+       if (cl.viewentity >= 1 && cl.viewentity <= cl.maxclients)
+               cl.playerentity = cl.viewentity;
+
+}
+
+static void Netmsg_svc_sound (protocol_t *protocol)                    // <see code>
+{
+       CL_ParseStartSoundPacket(false);
+}
+
+static void Netmsg_svc_time (protocol_t *protocol)                     // [float] server time
+{
+       CL_NetworkTimeReceived(MSG_ReadFloat(&cl_message));
+}
+
+static void Netmsg_svc_print (protocol_t *protocol)                    // [string] null terminated string
+{
+       const char *temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
+       if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports
+               CSQC_AddPrintText(temp);        //[515]: csqc
+}
+
+static void Netmsg_svc_stufftext (protocol_t *protocol)                // [string] stuffed into client's console buffer
+{                                                                                      // the string should be \n terminated
+       qbool strip_pqc;
+       const char *temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
+       /* if(utf8_enable.integer)
+       {
+               strip_pqc = true;
+               // we can safely strip and even
+               // interpret these in utf8 mode
+       }
+       else */ switch(cls.protocol->num)
+       {
+               case PROTOCOL_QUAKE:
+                       // maybe add other protocols if
+                       // so desired, but not DP7
+                       strip_pqc = true;
+                       break;
+               default:
+                       // ProQuake does not support
+                       // these protocols
+                       strip_pqc = false;
+                       break;
+       }
+       if(strip_pqc)
+       {
+               // skip over ProQuake messages,
+               // TODO actually interpret them
+               // (they are sbar team score
+               // updates), see proquake cl_parse.c
+               if(*temp == 0x01)
+               {
+                       ++temp;
+                       while(*temp >= 0x01 && *temp <= 0x1F)
+                               ++temp;
+               }
+       }
+       CL_VM_Parse_StuffCmd(temp);     //[515]: csqc
+
+}
+
+static void Netmsg_svc_setangle (protocol_t *protocol)         // [vec3] set the view angle to this absolute value
+{
+       int i;
+       for (i=0 ; i<3 ; i++)
+               cl.viewangles[i] = protocol->ReadAngle(&cl_message);
+       if (!cls.demoplayback)
+       {
+               cl.fixangle[0] = true;
+               VectorCopy(cl.viewangles, cl.mviewangles[0]);
+               // disable interpolation if this is new
+               if (!cl.fixangle[1])
+                       VectorCopy(cl.viewangles, cl.mviewangles[1]);
+       }
+}
+
+static void Netmsg_svc_serverinfo (protocol_t *protocol)               // [int] version
+                                                                                               // [string] signon string
+                                                                                               // [string]..[0]model cache [string]...[0]sounds cache
+                                                                                               // [string]..[0]item cache
+{
+       CL_ParseServerInfo ();
+}
+
+static void Netmsg_svc_lightstyle (protocol_t *protocol)               // [byte] [string]
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.max_lightstyle)
+       {
+               Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES");
+               return;
+       }
+       strlcpy (cl.lightstyle[i].map,  MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map));
+       cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
+       cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
+}
+
+static void Netmsg_svc_updatename (protocol_t *protocol)               // [byte] [string]
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.maxclients)
+               Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
+       strlcpy (cl.scores[i].name, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.scores[i].name));
+}
+
+static void Netmsg_svc_updatefrags (protocol_t *protocol)      // [byte] [short]
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.maxclients)
+               Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
+       cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message);
+}
+
+static void Netmsg_svc_clientdata (protocol_t *protocol)               // <shortbits + data>
+{
+       CL_ParseClientdata();
+}
+
+static void Netmsg_svc_stopsound (protocol_t *protocol)                // <see code>
+{
+       int i = (unsigned short) MSG_ReadShort(&cl_message);
+       S_StopSound(i>>3, i&7);
+}
+
+static void Netmsg_svc_updatecolors (protocol_t *protocol)     // [byte] [byte]
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.maxclients)
+               Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
+       cl.scores[i].colors = MSG_ReadByte(&cl_message);
+
+}
+
+static void Netmsg_svc_particle (protocol_t *protocol)         // [vec3] <variable>
+{
+       CL_ParseParticleEffect ();
+}
+
+static void Netmsg_svc_damage (protocol_t *protocol)                   // [byte] impact [byte] blood [vec3] from
+{
+       V_ParseDamage ();
+}
+
+static void Netmsg_svc_spawnstatic (protocol_t *protocol)
+{
+       CL_ParseStatic (false);
+}
+
+static void Netmsg_svc_spawnbaseline (protocol_t *protocol)
+{
+       int i = (unsigned short) MSG_ReadShort(&cl_message);
+       if (i < 0 || i >= MAX_EDICTS)
+               Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
+       if (i >= cl.max_entities)
+               CL_ExpandEntities(i);
+       CL_ParseBaseline (cl.entities + i, false);
+}
+
+static void Netmsg_svc_temp_entity (protocol_t *protocol)              // <variable>
+{
+       if(!CL_VM_Parse_TempEntity())
+               CL_ParseTempEntity ();  
+}
+
+static void Netmsg_svc_setpause (protocol_t *protocol)
+{
+       cl.paused = MSG_ReadByte(&cl_message) != 0;
+       if (cl.paused)
+               CDAudio_Pause ();
+       else
+               CDAudio_Resume ();
+       S_PauseGameSounds (cl.paused);
+}
+
+static void Netmsg_svc_signonnum (protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       // LadyHavoc: it's rude to kick off the client if they missed the
+       // reconnect somehow, so allow signon 1 even if at signon 1
+       if (i <= cls.signon && i != 1)
+               Host_Error ("Received signon %i when at %i", i, cls.signon);
+       cls.signon = i;
+       CL_SignonReply ();
+}
+
+static void Netmsg_svc_centerprint (protocol_t *protocol)
+{
+       CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));     //[515]: csqc
+}
+
+static void Netmsg_svc_killedmonster (protocol_t *protocol)
+{
+       cl.stats[STAT_MONSTERS]++;
+}
+
+static void Netmsg_svc_foundsecret (protocol_t *protocol)
+{
+       cl.stats[STAT_SECRETS]++;
+}
+
+static void Netmsg_svc_spawnstaticsound (protocol_t *protocol)
+{
+       CL_ParseStaticSound (false);
+}
+
+static void Netmsg_svc_intermission (protocol_t *protocol)
+{
+       if(!cl.intermission)
+               cl.completed_time = cl.time;
+       cl.intermission = 1;
+       CL_VM_UpdateIntermissionState(cl.intermission);
+}
+
+static void Netmsg_svc_finale (protocol_t *protocol)                   // [string] music [string] text
+{
+       if(!cl.intermission)
+               cl.completed_time = cl.time;
+       cl.intermission = 2;
+       CL_VM_UpdateIntermissionState(cl.intermission);
+       SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
+}
+
+static void Netmsg_svc_cdtrack (protocol_t *protocol)                  // [byte] track [byte] looptrack
+{
+       cl.cdtrack = MSG_ReadByte(&cl_message);
+       cl.looptrack = MSG_ReadByte(&cl_message);
+       if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
+               CDAudio_Play ((unsigned char)cls.forcetrack, true);
+       else
+               CDAudio_Play ((unsigned char)cl.cdtrack, true);
+
+}
+
+static void Netmsg_svc_sellscreen (protocol_t *protocol)
+{
+       Cmd_ExecuteString(&cmd_client, "help", src_local, true);
+}
+
+static void Netmsg_svc_cutscene (protocol_t *protocol)
+{
+       if(!cl.intermission)
+               cl.completed_time = cl.time;
+       cl.intermission = 3;
+       CL_VM_UpdateIntermissionState(cl.intermission);
+       SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
+}
+
+#define NETMSG_BASENQ_SVC \
+       {"svc_bad", NULL}, \
+       {"svc_nop", Netmsg_svc_nop}, \
+       {"svc_disconnect", Netmsg_svc_disconnect}, \
+       {"svc_updatestat", Netmsg_svc_updatestat}, \
+       {"svc_version", Netmsg_svc_version}, \
+       {"svc_setview", Netmsg_svc_setview}, \
+       {"svc_sound", Netmsg_svc_sound}, \
+       {"svc_time", Netmsg_svc_time}, \
+       {"svc_print", Netmsg_svc_print}, \
+       {"svc_stufftext", Netmsg_svc_stufftext}, \
+       {"svc_setangle", Netmsg_svc_setangle}, \
+       {"svc_serverinfo", Netmsg_svc_serverinfo}, \
+       {"svc_lightstyle", Netmsg_svc_lightstyle}, \
+       {"svc_updatename", Netmsg_svc_updatename}, \
+       {"svc_updatefrags", Netmsg_svc_updatefrags}, \
+       {"svc_clientdata", Netmsg_svc_clientdata}, \
+       {"svc_stopsound", Netmsg_svc_stopsound}, \
+       {"svc_updatecolors", Netmsg_svc_updatecolors}, \
+       {"svc_particle", Netmsg_svc_particle}, \
+       {"svc_damage",Netmsg_svc_damage}, \
+       {"svc_spawnstatic", Netmsg_svc_spawnstatic}, \
+       {"OBSOLETE svc_spawnbinary", NULL}, \
+       {"svc_spawnbaseline", Netmsg_svc_spawnbaseline}, \
+       {"svc_temp_entity", Netmsg_svc_temp_entity}, \
+       {"svc_setpause", Netmsg_svc_setpause}, \
+       {"svc_signonnum", Netmsg_svc_signonnum}, \
+       {"svc_centerprint", Netmsg_svc_centerprint}, \
+       {"svc_killedmonster", Netmsg_svc_killedmonster}, \
+       {"svc_foundsecret", Netmsg_svc_foundsecret}, \
+       {"svc_spawnstaticsound", Netmsg_svc_spawnstaticsound}, \
+       {"svc_intermission", Netmsg_svc_intermission}, \
+       {"svc_finale", Netmsg_svc_finale}, \
+       {"svc_cdtrack", Netmsg_svc_cdtrack}, \
+       {"svc_sellscreen", Netmsg_svc_sellscreen}, \
+       {"svc_cutscene", Netmsg_svc_cutscene}
diff --git a/cl_protocol_baseqw.h b/cl_protocol_baseqw.h
new file mode 100644 (file)
index 0000000..f834615
--- /dev/null
@@ -0,0 +1,336 @@
+#include "quakedef.h"
+#include "client.h"
+#include "protocol.h"
+#include "cl_parse.h"
+#include "cdaudio.h"
+
+static void Netmsg_svc_nop(protocol_t *protocol)
+{
+       //Con_Printf("qw_svc_nop\n");
+}
+
+static void Netmsg_svc_disconnect(protocol_t *protocol)
+{
+       Con_Printf("Server disconnected\n");
+       if (cls.demonum != -1)
+               CL_NextDemo();
+       else
+               CL_Disconnect();
+       return;
+}
+
+static void Netmsg_svc_print(protocol_t *protocol)
+{
+       char vabuf[1024];
+       int i = MSG_ReadByte(&cl_message);
+       char *temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
+       if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports
+       {
+               if (i == 3) // chat
+                       CSQC_AddPrintText(va(vabuf, sizeof(vabuf), "\1%s", temp));      //[515]: csqc
+               else
+                       CSQC_AddPrintText(temp);
+       }
+}
+
+static void Netmsg_svc_centerprint(protocol_t *protocol)
+{
+       CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));     //[515]: csqc
+}
+
+static void Netmsg_svc_stufftext(protocol_t *protocol)
+{
+       CL_VM_Parse_StuffCmd(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));        //[515]: csqc
+}
+
+static void Netmsg_svc_damage(protocol_t *protocol)
+{
+       // svc_damage protocol is identical to nq
+       V_ParseDamage ();
+}
+
+static void Netmsg_svc_serverdata(protocol_t *protocol)
+{
+       //Cbuf_Execute(); // make sure any stuffed commands are done
+       CL_ParseServerInfo();
+}
+
+static void Netmsg_svc_setangle(protocol_t *protocol)
+{
+       int i;
+       for (i=0 ; i<3 ; i++)
+               cl.viewangles[i] = protocol->ReadAngle(&cl_message);
+       if (!cls.demoplayback)
+       {
+               cl.fixangle[0] = true;
+               VectorCopy(cl.viewangles, cl.mviewangles[0]);
+               // disable interpolation if this is new
+               if (!cl.fixangle[1])
+                       VectorCopy(cl.viewangles, cl.mviewangles[1]);
+       }
+}
+
+static void Netmsg_svc_lightstyle(protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.max_lightstyle)
+       {
+               Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES");
+               return;
+       }
+       strlcpy (cl.lightstyle[i].map,  MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map));
+       cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
+       cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
+}
+
+static void Netmsg_svc_sound(protocol_t *protocol)
+{
+       CL_ParseStartSoundPacket(false);
+}
+
+static void Netmsg_svc_stopsound(protocol_t *protocol)
+{
+       int i = (unsigned short) MSG_ReadShort(&cl_message);
+       S_StopSound(i>>3, i&7);
+}
+
+static void Netmsg_svc_updatefrags(protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.maxclients)
+               Host_Error("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
+       cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message);
+}
+
+static void Netmsg_svc_updateping(protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.maxclients)
+               Host_Error("CL_ParseServerMessage: svc_updateping >= cl.maxclients");
+       cl.scores[i].qw_ping = MSG_ReadShort(&cl_message);
+}
+
+static void Netmsg_svc_updatepl(protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.maxclients)
+               Host_Error("CL_ParseServerMessage: svc_updatepl >= cl.maxclients");
+       cl.scores[i].qw_packetloss = MSG_ReadByte(&cl_message);
+}
+
+static void Netmsg_svc_updateentertime(protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i >= cl.maxclients)
+               Host_Error("CL_ParseServerMessage: svc_updateentertime >= cl.maxclients");
+       // seconds ago
+       cl.scores[i].qw_entertime = cl.time - MSG_ReadFloat(&cl_message);
+}
+
+static void Netmsg_svc_spawnbaseline(protocol_t *protocol)
+{
+       int i = (unsigned short) MSG_ReadShort(&cl_message);
+       if (i < 0 || i >= MAX_EDICTS)
+               Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
+       if (i >= cl.max_entities)
+               CL_ExpandEntities(i);
+       CL_ParseBaseline(cl.entities + i, false);
+}
+static void Netmsg_svc_spawnstatic(protocol_t *protocol)
+{
+       CL_ParseStatic(false);
+}
+static void Netmsg_svc_temp_entity(protocol_t *protocol)
+{
+       if(!CL_VM_Parse_TempEntity())
+               CL_ParseTempEntity ();
+}
+
+static void Netmsg_svc_killedmonster(protocol_t *protocol)
+{
+       cl.stats[STAT_MONSTERS]++;
+}
+
+static void Netmsg_svc_foundsecret(protocol_t *protocol)
+{
+       cl.stats[STAT_SECRETS]++;
+}
+
+static void Netmsg_svc_updatestat(protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i < 0 || i >= MAX_CL_STATS)
+               Host_Error ("svc_updatestat: %i is invalid", i);
+       cl.stats[i] = MSG_ReadByte(&cl_message);
+}
+
+static void Netmsg_svc_updatestatlong(protocol_t *protocol)
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i < 0 || i >= MAX_CL_STATS)
+               Host_Error ("svc_updatestatlong: %i is invalid", i);
+       cl.stats[i] = MSG_ReadLong(&cl_message);
+}
+
+static void Netmsg_svc_spawnstaticsound(protocol_t *protocol)
+{
+       CL_ParseStaticSound (false);
+}
+
+static void Netmsg_svc_cdtrack(protocol_t *protocol)
+{
+       cl.cdtrack = cl.looptrack = MSG_ReadByte(&cl_message);
+#ifdef CONFIG_CD
+       if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
+               CDAudio_Play ((unsigned char)cls.forcetrack, true);
+       else
+               CDAudio_Play ((unsigned char)cl.cdtrack, true);
+#endif
+}
+
+static void Netmsg_svc_intermission(protocol_t *protocol)
+{
+       int i;
+       if(!cl.intermission)
+               cl.completed_time = cl.time;
+       cl.intermission = 1;
+       protocol->ReadVector(&cl_message, cl.qw_intermission_origin);
+       for (i = 0;i < 3;i++)
+               cl.qw_intermission_angles[i] = protocol->ReadAngle(&cl_message);
+}
+
+static void Netmsg_svc_finale(protocol_t *protocol)
+{
+       if(!cl.intermission)
+               cl.completed_time = cl.time;
+       cl.intermission = 2;
+       SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
+}
+
+static void Netmsg_svc_sellscreen(protocol_t *protocol)
+{
+       Cmd_ExecuteString (&cmd_client, "help", src_local, true);
+}
+
+static void Netmsg_svc_smallkick(protocol_t *protocol)
+{
+       cl.qw_weaponkick = -2;
+}
+static void Netmsg_svc_bigkick(protocol_t *protocol)
+{
+       cl.qw_weaponkick = -4;
+}
+
+static void Netmsg_svc_muzzleflash(protocol_t *protocol)
+{
+       int i = (unsigned short) MSG_ReadShort(&cl_message);
+       // NOTE: in QW this only worked on clients
+       if (i < 0 || i >= MAX_EDICTS)
+               Host_Error("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
+       if (i >= cl.max_entities)
+               CL_ExpandEntities(i);
+       cl.entities[i].persistent.muzzleflash = 1.0f;
+}
+
+static void Netmsg_svc_updateuserinfo(protocol_t *protocol)
+{
+       QW_CL_UpdateUserInfo();
+}
+
+static void Netmsg_svc_setinfo(protocol_t *protocol)
+{
+       QW_CL_SetInfo();
+}
+
+static void Netmsg_svc_serverinfo(protocol_t *protocol)
+{
+       QW_CL_ServerInfo();
+}
+
+static void Netmsg_svc_download(protocol_t *protocol)
+{
+       QW_CL_ParseDownload();
+}
+
+static void Netmsg_svc_playerinfo(protocol_t *protocol)
+{
+       int i;
+       // slightly kill qw player entities now that we know there is
+       // an update of player entities this frame...
+       if (!cl.qwplayerupdatereceived)
+       {
+               cl.qwplayerupdatereceived = true;
+               for (i = 1;i < cl.maxclients;i++)
+                       cl.entities_active[i] = false;
+       }
+       EntityStateQW_ReadPlayerUpdate();
+}
+
+static void Netmsg_svc_nails(protocol_t *protocol)
+{
+       QW_CL_ParseNails();
+}
+
+static void Netmsg_svc_chokecount(protocol_t *protocol)
+{
+       (void) MSG_ReadByte(&cl_message);
+       // FIXME: apply to netgraph
+       //for (j = 0;j < i;j++)
+       //      cl.frames[(cls.netcon->qw.incoming_acknowledged-1-j)&QW_UPDATE_MASK].receivedtime = -2;
+}
+
+static void Netmsg_svc_modellist(protocol_t *protocol)
+{
+       QW_CL_ParseModelList();
+}
+
+static void Netmsg_svc_soundlist(protocol_t *protocol)
+{
+       QW_CL_ParseSoundList();
+}
+
+static void Netmsg_svc_packetentities(protocol_t *protocol)
+{
+       EntityFrameQW_CL_ReadFrame(false);
+       // first update is the final signon stage
+       if (cls.signon == SIGNONS - 1)
+       {
+               cls.signon = SIGNONS;
+               CL_SignonReply ();
+       }
+}
+
+static void Netmsg_svc_deltapacketentities(protocol_t *protocol)
+{
+       EntityFrameQW_CL_ReadFrame(true);
+       // first update is the final signon stage
+       if (cls.signon == SIGNONS - 1)
+       {
+               cls.signon = SIGNONS;
+               CL_SignonReply ();
+       }
+}
+
+static void Netmsg_svc_maxspeed(protocol_t *protocol)
+{
+       cl.movevars_maxspeed = MSG_ReadFloat(&cl_message);
+}
+
+static void Netmsg_svc_entgravity(protocol_t *protocol)
+{
+       cl.movevars_entgravity = MSG_ReadFloat(&cl_message);
+       if (!cl.movevars_entgravity)
+               cl.movevars_entgravity = 1.0f;
+}
+
+static void Netmsg_svc_setpause(protocol_t *protocol)
+{
+       cl.paused = MSG_ReadByte(&cl_message) != 0;
+#ifdef CONFIG_CD
+       if (cl.paused)
+               CDAudio_Pause ();
+       else
+               CDAudio_Resume ();
+#endif
+       S_PauseGameSounds (cl.paused);
+}
\ No newline at end of file
diff --git a/cl_protocol_dpp7.c b/cl_protocol_dpp7.c
new file mode 100644 (file)
index 0000000..f019e01
--- /dev/null
@@ -0,0 +1,7 @@
+#include "quakedef.h"
+#include "cl_protocol_ext.h"
+
+protocol_netmsg_t netmsg_dpext_svc[] =
+{
+       NETMSG_DPEXT_SVC
+};
\ No newline at end of file
diff --git a/cl_protocol_ext.h b/cl_protocol_ext.h
new file mode 100644 (file)
index 0000000..80d05fc
--- /dev/null
@@ -0,0 +1,191 @@
+#include "cl_protocol_basenq.h"
+
+static void Netmsg_svc_showlmp (protocol_t *protocol)  // [string] iconlabel [string] lmpfile [short] x [short] y
+{
+       if (gamemode == GAME_TENEBRAE)
+       {
+               // particle effect
+               protocol->ReadCoord(&cl_message);
+               protocol->ReadCoord(&cl_message);
+               protocol->ReadCoord(&cl_message);
+               (void) MSG_ReadByte(&cl_message);
+               MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
+       }
+       else
+               SHOWLMP_decodeshow();
+}
+
+static void Netmsg_svc_hidelmp (protocol_t *protocol)  // [string] iconlabel
+{
+       if (gamemode == GAME_TENEBRAE)
+       {
+               // repeating particle effect
+               protocol->ReadCoord(&cl_message);
+               protocol->ReadCoord(&cl_message);
+               protocol->ReadCoord(&cl_message);
+               protocol->ReadCoord(&cl_message);
+               protocol->ReadCoord(&cl_message);
+               protocol->ReadCoord(&cl_message);
+               (void) MSG_ReadByte(&cl_message);
+               MSG_ReadLong(&cl_message);
+               MSG_ReadLong(&cl_message);
+               MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
+       }
+       else
+               SHOWLMP_decodehide();
+}
+
+static void Netmsg_svc_skybox (protocol_t *protocol) // [string] skyname
+{
+       R_SetSkyBox(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
+}
+
+static void Netmsg_svc_downloaddata (protocol_t *protocol) //                          50              // [int] start [short] size [variable length] data
+{
+       CL_ParseDownload();
+}
+
+static void Netmsg_svc_updatestatubyte (protocol_t *protocol) //                       51              // [byte] stat [byte] value
+{
+       int i = MSG_ReadByte(&cl_message);
+       if (i < 0 || i >= MAX_CL_STATS)
+               Host_Error ("svc_updatestat: %i is invalid", i);
+       cl.stats[i] = MSG_ReadByte(&cl_message);
+}
+
+static void Netmsg_svc_effect (protocol_t *protocol) //                        52              // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
+{
+       CL_ParseEffect ();
+}
+
+static void Netmsg_svc_effect2 (protocol_t *protocol) //                       53              // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
+{
+       CL_ParseEffect2 ();
+}
+
+// FIXME: Lazy
+static void Netmsg_svc_precache (protocol_t *protocol) //                      54              // short soundindex instead of byte
+{
+       if (protocol->num == PROTOCOL_DARKPLACES1 || protocol->num == PROTOCOL_DARKPLACES2 || protocol->num == PROTOCOL_DARKPLACES3)
+       {
+               // was svc_sound2 in protocols 1, 2, 3, removed in 4, 5, changed to svc_precache in 6
+               CL_ParseStartSoundPacket(true);
+       }
+       else
+       {
+               // was svc_sound2 in protocols 1, 2, 3, removed in 4, 5, changed to svc_precache in 6
+               int i = (unsigned short)MSG_ReadShort(&cl_message);
+               char *s = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
+               if (i < 32768)
+               {
+                       if (i >= 1 && i < MAX_MODELS)
+                       {
+                               dp_model_t *model = Mod_ForName(s, false, false, s[0] == '*' ? cl.model_name[1] : NULL);
+                               if (!model)
+                                       Con_DPrintf("svc_precache: Mod_ForName(\"%s\") failed\n", s);
+                               cl.model_precache[i] = model;
+                       }
+                       else
+                               Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_MODELS);
+               }
+               else
+               {
+                       i -= 32768;
+                       if (i >= 1 && i < MAX_SOUNDS)
+                       {
+                               sfx_t *sfx = S_PrecacheSound (s, true, true);
+                               if (!sfx && snd_initialized.integer)
+                                       Con_DPrintf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s);
+                               cl.sound_precache[i] = sfx;
+                       }
+                       else
+                               Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_SOUNDS);
+               }
+       }
+}
+
+static void Netmsg_svc_spawnbaseline2 (protocol_t *protocol) //        55              // short modelindex instead of byte
+{
+       int i = (unsigned short) MSG_ReadShort(&cl_message);
+       if (i < 0 || i >= MAX_EDICTS)
+               Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
+       if (i >= cl.max_entities)
+               CL_ExpandEntities(i);
+       CL_ParseBaseline (cl.entities + i, true);
+}
+
+static void Netmsg_svc_spawnstatic2 (protocol_t *protocol) //          56              // short modelindex instead of byte
+{
+       CL_ParseStatic (true);
+}
+
+static void Netmsg_svc_entities (protocol_t *protocol) //                      57              // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata
+{
+       if (cls.signon == SIGNONS - 1)
+       {
+               // first update is the final signon stage
+               cls.signon = SIGNONS;
+               CL_SignonReply ();
+       }
+       if (protocol == &protocol_dpp1 || protocol == &protocol_dpp2 || protocol == &protocol_dpp3)
+               EntityFrame_CL_ReadFrame();
+       else if (protocol == &protocol_dpp4)
+               EntityFrame4_CL_ReadFrame();
+       else
+               EntityFrame5_CL_ReadFrame();
+}
+
+static void Netmsg_svc_csqcentities (protocol_t *protocol) //          58              // [short] entnum [variable length] entitydata ... [short] 0x0000
+{
+       CSQC_ReadEntities();
+}
+
+static void Netmsg_svc_spawnstaticsound2 (protocol_t *protocol) //     59              // [coord3] [short] samp [byte] vol [byte] aten
+{
+       CL_ParseStaticSound (true);
+}
+
+static void Netmsg_svc_trailparticles (protocol_t *protocol) //        60              // [short] entnum [short] effectnum [vector] start [vector] end
+{
+       CL_ParseTrailParticles();
+}
+
+static void Netmsg_svc_pointparticles (protocol_t *protocol) //        61              // [short] effectnum [vector] start [vector] velocity [short] count
+{
+       CL_ParsePointParticles();
+}
+
+static void Netmsg_svc_pointparticles1 (protocol_t *protocol) //       62              // [short] effectnum [vector] start, same as Netmsg_svc_pointparticles except velocity is zero and count is 1
+{
+       CL_ParsePointParticles1();
+}
+#define NETMSG_DPEXT_SVC \
+       NETMSG_BASENQ_SVC, \
+       {"svc_showlmp", Netmsg_svc_showlmp}, \
+       {"svc_hidelmp", Netmsg_svc_hidelmp}, \
+       {"svc_skybox", Netmsg_svc_skybox}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"", NULL}, \
+       {"svc_downloaddata", Netmsg_svc_downloaddata}, \
+       {"svc_updatestatubyte", Netmsg_svc_updatestatubyte}, \
+       {"svc_effect", Netmsg_svc_effect}, \
+       {"svc_effect2", Netmsg_svc_effect2}, \
+       {"svc_sound2", Netmsg_svc_precache}, \
+       {"svc_spawnbaseline2", Netmsg_svc_spawnbaseline2}, \
+       {"svc_spawnstatic2", Netmsg_svc_spawnstatic2}, \
+       {"svc_entities", Netmsg_svc_entities}, \
+       {"svc_csqcentities", Netmsg_svc_csqcentities}, \
+       {"svc_spawnstaticsound2", Netmsg_svc_spawnstaticsound2}, \
+       {"svc_trailparticles", Netmsg_svc_trailparticles}, \
+       {"svc_pointparticles", Netmsg_svc_pointparticles}, \
+       {"svc_pointparticles1", Netmsg_svc_pointparticles1}
diff --git a/cl_protocol_nq.c b/cl_protocol_nq.c
new file mode 100644 (file)
index 0000000..8578d7c
--- /dev/null
@@ -0,0 +1,8 @@
+#include "quakedef.h"
+#include "protocol.h"
+#include "cl_protocol_basenq.h"
+
+protocol_netmsg_t netmsg_nq_svc[] =
+{
+       NETMSG_BASENQ_SVC
+};
diff --git a/cl_protocol_qw.c b/cl_protocol_qw.c
new file mode 100644 (file)
index 0000000..28f1cb6
--- /dev/null
@@ -0,0 +1,59 @@
+#include "cl_protocol_baseqw.h"
+
+protocol_netmsg_t netmsg_qw_svc[] =
+{
+       {"svc_bad", NULL},                                      // 0
+       {"svc_nop", Netmsg_svc_nop},                                    // 1
+       {"svc_disconnect", Netmsg_svc_disconnect},                      // 2
+       {"svc_updatestat", Netmsg_svc_updatestat},                      // 3    // [byte] [byte]
+       {"", NULL},                                                             // 4
+       {"svc_setview", NULL},                          // 5    // [short] entity number
+       {"svc_sound", Netmsg_svc_sound},                                        // 6    // <see code>
+       {"", NULL},                                                             // 7
+       {"svc_print", Netmsg_svc_print},                                        // 8    // [byte] id [string] null terminated string
+       {"svc_stufftext", Netmsg_svc_stufftext},                                // 9    // [string] stuffed into client's console buffer
+       {"svc_setangle", Netmsg_svc_setangle},                          // 10   // [angle3] set the view angle to this absolute value
+       {"svc_serverdata", Netmsg_svc_serverdata},                      // 11   // [long] protocol ...
+       {"svc_lightstyle", Netmsg_svc_lightstyle},                      // 12   // [byte] [string]
+       {"", NULL},                                                             // 13
+       {"svc_updatefrags", Netmsg_svc_updatefrags},                    // 14   // [byte] [short]
+       {"", NULL},                                                             // 15
+       {"svc_stopsound", Netmsg_svc_stopsound},                                // 16   // <see code>
+       {"", NULL},                                                             // 17
+       {"", NULL},                                                             // 18
+       {"svc_damage", Netmsg_svc_damage},                              // 19
+       {"svc_spawnstatic", Netmsg_svc_spawnstatic},                    // 20
+       {"", NULL},                                                             // 21
+       {"svc_spawnbaseline", Netmsg_svc_spawnbaseline},                        // 22
+       {"svc_temp_entity", Netmsg_svc_temp_entity},                    // 23   // variable
+       {"svc_setpause", Netmsg_svc_setpause},                          // 24   // [byte] on / off
+       {"", NULL},                                                             // 25
+       {"svc_centerprint", Netmsg_svc_centerprint},                    // 26   // [string] to put in center of the screen
+       {"svc_killedmonster", Netmsg_svc_killedmonster},                        // 27
+       {"svc_foundsecret", Netmsg_svc_foundsecret},                    // 28
+       {"svc_spawnstaticsound", Netmsg_svc_spawnstaticsound},          // 29   // [coord3] [byte] samp [byte] vol [byte] aten
+       {"svc_intermission", Netmsg_svc_intermission},                  // 30           // [vec3_t] origin [vec3_t] angle
+       {"svc_finale", Netmsg_svc_finale},                              // 31           // [string] text
+       {"svc_cdtrack", Netmsg_svc_cdtrack},                            // 32           // [byte] track
+       {"svc_sellscreen", Netmsg_svc_sellscreen},                      // 33
+       {"svc_smallkick", Netmsg_svc_smallkick},                                // 34           // set client punchangle to 2
+       {"svc_bigkick", Netmsg_svc_bigkick},                            // 35           // set client punchangle to 4
+       {"svc_updateping", Netmsg_svc_updateping},                      // 36           // [byte] [short]
+       {"svc_updateentertime", Netmsg_svc_updateentertime},            // 37           // [byte] [float]
+       {"svc_updatestatlong", Netmsg_svc_updatestatlong},              // 38           // [byte] [long]
+       {"svc_muzzleflash", Netmsg_svc_muzzleflash},                    // 39           // [short] entity
+       {"svc_updateuserinfo", Netmsg_svc_updateuserinfo},              // 40           // [byte] slot [long] uid
+       {"svc_download", Netmsg_svc_download},                          // 41           // [short] size [size bytes]
+       {"svc_playerinfo", Netmsg_svc_playerinfo},                      // 42           // variable
+       {"svc_nails", Netmsg_svc_nails},                                        // 43           // [byte] num [48 bits] xyzpy 12 12 12 4 8
+       {"svc_chokecount", Netmsg_svc_chokecount},                      // 44           // [byte] packets choked
+       {"svc_modellist", Netmsg_svc_modellist},                                // 45           // [strings]
+       {"svc_soundlist", Netmsg_svc_soundlist},                                // 46           // [strings]
+       {"svc_packetentities", Netmsg_svc_packetentities},              // 47           // [...]
+       {"svc_deltapacketentities", Netmsg_svc_deltapacketentities},    // 48           // [...]
+       {"svc_maxspeed", Netmsg_svc_maxspeed},                          // 49           // maxspeed change, for prediction
+       {"svc_entgravity", Netmsg_svc_entgravity},                      // 50           // gravity change, for prediction
+       {"svc_setinfo", Netmsg_svc_setinfo},                            // 51           // setinfo on a client
+       {"svc_serverinfo", Netmsg_svc_serverinfo},                      // 52           // serverinfo
+       {"svc_updatepl", Netmsg_svc_updatepl}                           // 53           // [byte] [byte]
+};
index dfdd04a030197a2dd3fe380a8df87a799c79319b..8d91497547e12b5e355306371811f2ca2bc882d5 100644 (file)
@@ -523,7 +523,7 @@ static int SCR_DrawQWDownload(int offset)
                cls.qw_downloadspeedtime = host.realtime;
                cls.qw_downloadspeedcount = 0;
        }
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
                dpsnprintf(temp, sizeof(temp), "Downloading %s %3i%% (%i) at %i bytes/s", cls.qw_downloadname, cls.qw_downloadpercent, cls.qw_downloadmemorycursize, cls.qw_downloadspeedrate);
        else
                dpsnprintf(temp, sizeof(temp), "Downloading %s %3i%% (%i/%i) at %i bytes/s", cls.qw_downloadname, cls.qw_downloadpercent, cls.qw_downloadmemorycursize, cls.qw_downloadmemorymaxsize, cls.qw_downloadspeedrate);
index 1d124533c450fb6158f9c7400d8b0752542a4145..9c9295baa1fbe569e5d8470e783ffb44155d967e 100644 (file)
--- a/client.h
+++ b/client.h
@@ -863,7 +863,7 @@ typedef struct client_static_s
        lhnetaddress_t rcon_address;
        // protocol version of the server we're connected to
        // (kept outside client_state_t because it's used between levels)
-       protocolversion_t protocol;
+       protocol_t *protocol;
 
 #define MAX_RCONS 16
        int rcon_trying;
@@ -1452,6 +1452,8 @@ typedef struct client_state_s
 
        // used by EntityState5_ReadUpdate
        skeleton_t *engineskeletonobjects;
+
+       qbool qwplayerupdatereceived;
 }
 client_state_t;
 
index c8c8123ba902adcb8745e195fce5b95242a87d1f..36580888a6dd623bf8cd6a5e0a5d82ffac00c6a3 100644 (file)
@@ -1663,14 +1663,14 @@ static void VM_CL_ReadLong (prvm_prog_t *prog)
 static void VM_CL_ReadCoord (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(&cl_message, cls.protocol);
+       PRVM_G_FLOAT(OFS_RETURN) = cls.protocol->ReadCoord(&cl_message);
 }
 
 //#365 float() readangle (EXT_CSQC)
 static void VM_CL_ReadAngle (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(&cl_message, cls.protocol);
+       PRVM_G_FLOAT(OFS_RETURN) = cls.protocol->ReadAngle(&cl_message);
 }
 
 //#366 string() readstring (EXT_CSQC)
index 0de4fc677032e548d7da4969da6138edc069156c..63d857f2d12581475785673e17f0dfc12f68fbe8 100644 (file)
--- a/com_msg.c
+++ b/com_msg.c
@@ -201,23 +201,25 @@ void MSG_WriteCoord32f (sizebuf_t *sb, float f)
        MSG_WriteFloat (sb, f);
 }
 
-void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
-{
-       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
-               MSG_WriteCoord13i (sb, f);
-       else if (protocol == PROTOCOL_DARKPLACES1)
-               MSG_WriteCoord32f (sb, f);
-       else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
-               MSG_WriteCoord16i (sb, f);
-       else
-               MSG_WriteCoord32f (sb, f);
+void MSG_WriteVector13i (sizebuf_t *sb, const vec3_t v)
+{
+       MSG_WriteCoord13i (sb, v[0]);
+       MSG_WriteCoord13i (sb, v[1]);
+       MSG_WriteCoord13i (sb, v[2]);
+}
+
+void MSG_WriteVector16i (sizebuf_t *sb, const vec3_t v)
+{
+       MSG_WriteCoord16i (sb, v[0]);
+       MSG_WriteCoord16i (sb, v[1]);
+       MSG_WriteCoord16i (sb, v[2]);
 }
 
-void MSG_WriteVector (sizebuf_t *sb, const vec3_t v, protocolversion_t protocol)
+void MSG_WriteVector32f (sizebuf_t *sb, const vec3_t v)
 {
-       MSG_WriteCoord (sb, v[0], protocol);
-       MSG_WriteCoord (sb, v[1], protocol);
-       MSG_WriteCoord (sb, v[2], protocol);
+       MSG_WriteCoord32f (sb, v[0]);
+       MSG_WriteCoord32f (sb, v[1]);
+       MSG_WriteCoord32f (sb, v[2]);
 }
 
 // LadyHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
@@ -242,14 +244,6 @@ void MSG_WriteAngle32f (sizebuf_t *sb, float f)
        MSG_WriteFloat (sb, f);
 }
 
-void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
-{
-       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
-               MSG_WriteAngle8i (sb, f);
-       else
-               MSG_WriteAngle16i (sb, f);
-}
-
 //
 // reading functions
 //
@@ -381,23 +375,25 @@ float MSG_ReadCoord32f (sizebuf_t *sb)
        return MSG_ReadLittleFloat(sb);
 }
 
-float MSG_ReadCoord (sizebuf_t *sb, protocolversion_t protocol)
+void MSG_ReadVector13i (sizebuf_t *sb, vec3_t v)
 {
-       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
-               return MSG_ReadCoord13i(sb);
-       else if (protocol == PROTOCOL_DARKPLACES1)
-               return MSG_ReadCoord32f(sb);
-       else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
-               return MSG_ReadCoord16i(sb);
-       else
-               return MSG_ReadCoord32f(sb);
+       v[0] = MSG_ReadCoord13i(sb);
+       v[1] = MSG_ReadCoord13i(sb);
+       v[2] = MSG_ReadCoord13i(sb);
 }
 
-void MSG_ReadVector (sizebuf_t *sb, vec3_t v, protocolversion_t protocol)
+void MSG_ReadVector16i (sizebuf_t *sb, vec3_t v)
 {
-       v[0] = MSG_ReadCoord(sb, protocol);
-       v[1] = MSG_ReadCoord(sb, protocol);
-       v[2] = MSG_ReadCoord(sb, protocol);
+       v[0] = MSG_ReadCoord16i(sb);
+       v[1] = MSG_ReadCoord16i(sb);
+       v[2] = MSG_ReadCoord16i(sb);
+}
+
+void MSG_ReadVector32f (sizebuf_t *sb, vec3_t v)
+{
+       v[0] = MSG_ReadCoord32f(sb);
+       v[1] = MSG_ReadCoord32f(sb);
+       v[2] = MSG_ReadCoord32f(sb);
 }
 
 // LadyHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
@@ -414,12 +410,4 @@ float MSG_ReadAngle16i (sizebuf_t *sb)
 float MSG_ReadAngle32f (sizebuf_t *sb)
 {
        return MSG_ReadFloat (sb);
-}
-
-float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol)
-{
-       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
-               return MSG_ReadAngle8i (sb);
-       else
-               return MSG_ReadAngle16i (sb);
-}
+}
\ No newline at end of file
index d11b141cb9d92c491a42cf33dca9c65a910bbf42..11e444ee4e529ff731fac31b2934b2a74d7d6a3f 100644 (file)
--- a/common.h
+++ b/common.h
@@ -121,28 +121,6 @@ void StoreLittleShort (unsigned char *buffer, unsigned short i);
 
 //============================================================================
 
-// these versions are purely for internal use, never sent in network protocol
-// (use Protocol_EnumForNumber and Protocol_NumberToEnum to convert)
-typedef enum protocolversion_e
-{
-       PROTOCOL_UNKNOWN,
-       PROTOCOL_DARKPLACES7, ///< added QuakeWorld-style movement protocol to allow more consistent prediction
-       PROTOCOL_DARKPLACES6, ///< various changes
-       PROTOCOL_DARKPLACES5, ///< uses EntityFrame5 entity snapshot encoder/decoder which is based on a Tribes networking article at http://www.garagegames.com/articles/networking1/
-       PROTOCOL_DARKPLACES4, ///< various changes
-       PROTOCOL_DARKPLACES3, ///< uses EntityFrame4 entity snapshot encoder/decoder which is broken, this attempted to do partial snapshot updates on a QuakeWorld-like protocol, but it is broken and impossible to fix
-       PROTOCOL_DARKPLACES2, ///< various changes
-       PROTOCOL_DARKPLACES1, ///< uses EntityFrame entity snapshot encoder/decoder which is a QuakeWorld-like entity snapshot delta compression method
-       PROTOCOL_QUAKEDP, ///< darkplaces extended quake protocol (used by TomazQuake and others), backwards compatible as long as no extended features are used
-       PROTOCOL_NEHAHRAMOVIE, ///< Nehahra movie protocol, a big nasty hack dating back to early days of the Quake Standards Group (but only ever used by neh_gl.exe), this is potentially backwards compatible with quake protocol as long as no extended features are used (but in actuality the neh_gl.exe which wrote this protocol ALWAYS wrote the extended information)
-       PROTOCOL_QUAKE, ///< quake (aka netquake/normalquake/nq) protocol
-       PROTOCOL_QUAKEWORLD, ///< quakeworld protocol
-       PROTOCOL_NEHAHRABJP, ///< same as QUAKEDP but with 16bit modelindex
-       PROTOCOL_NEHAHRABJP2, ///< same as NEHAHRABJP but with 16bit soundindex
-       PROTOCOL_NEHAHRABJP3 ///< same as NEHAHRABJP2 but with some changes
-}
-protocolversion_t;
-
 /*! \name Message IO functions.
  * Handles byte ordering and avoids alignment errors
  * @{
@@ -162,9 +140,9 @@ void MSG_WriteAngle32f (sizebuf_t *sb, vec_t f);
 void MSG_WriteCoord13i (sizebuf_t *sb, vec_t f);
 void MSG_WriteCoord16i (sizebuf_t *sb, vec_t f);
 void MSG_WriteCoord32f (sizebuf_t *sb, vec_t f);
-void MSG_WriteCoord (sizebuf_t *sb, vec_t f, protocolversion_t protocol);
-void MSG_WriteVector (sizebuf_t *sb, const vec3_t v, protocolversion_t protocol);
-void MSG_WriteAngle (sizebuf_t *sb, vec_t f, protocolversion_t protocol);
+void MSG_WriteVector13i (sizebuf_t *sb, const vec3_t v);
+void MSG_WriteVector16i (sizebuf_t *sb, const vec3_t v);
+void MSG_WriteVector32f (sizebuf_t *sb, const vec3_t v);
 
 void MSG_BeginReading (sizebuf_t *sb);
 int MSG_ReadLittleShort (sizebuf_t *sb);
@@ -188,9 +166,9 @@ float MSG_ReadAngle32f (sizebuf_t *sb);
 float MSG_ReadCoord13i (sizebuf_t *sb);
 float MSG_ReadCoord16i (sizebuf_t *sb);
 float MSG_ReadCoord32f (sizebuf_t *sb);
-float MSG_ReadCoord (sizebuf_t *sb, protocolversion_t protocol);
-void MSG_ReadVector (sizebuf_t *sb, vec3_t v, protocolversion_t protocol);
-float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol);
+void MSG_ReadVector13i (sizebuf_t *sb, vec3_t v);
+void MSG_ReadVector16i (sizebuf_t *sb, vec3_t v);
+void MSG_ReadVector32f (sizebuf_t *sb, vec3_t v);
 //@}
 //============================================================================
 
index 21453faea0f2e5f6cb3b543c02bbfe46eaefba84..456b1b14dddc199de67634dfa797ce8789632af8 100644 (file)
--- a/csprogs.c
+++ b/csprogs.c
@@ -401,7 +401,7 @@ qbool CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
         &&  (entrender->alpha >= 1)
         && !(renderflags & RF_NOSHADOW)
         && !(entrender->flags & RENDER_VIEWMODEL)
-        && (!(entrender->flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer)))
+        && (!(entrender->flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != &protocol_nehahramovie && !cl_noplayershadow.integer)))
                entrender->flags |= RENDER_SHADOW;
        if (entrender->flags & RENDER_VIEWMODEL)
                entrender->flags |= RENDER_NOSELFSHADOW;
@@ -1102,7 +1102,7 @@ void CL_VM_Init (void)
                        i = 0;
 
                        CL_CutDemo(&demobuf, &demofilesize);
-                       while(MakeDownloadPacket(csqc_progname.string, csprogsdata, (size_t)csprogsdatasize, csprogsdatacrc, i++, &sb, cls.protocol))
+                       while(MakeDownloadPacket(csqc_progname.string, csprogsdata, (size_t)csprogsdatasize, csprogsdatacrc, i++, &sb, cls.protocol->num))
                                CL_WriteDemoMessage(&sb);
                        CL_PasteDemo(&demobuf, &demofilesize);
 
index 4e76b8952358836ed90330d837a72b541a07dd79..13e25c7684fbbef7801501a8e0298f8b3bec3634 100644 (file)
@@ -6975,7 +6975,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qboo
        rsurface.skeleton = ent->skeleton;
        memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
        rsurface.ent_skinnum = ent->skinnum;
-       rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
+       rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == &protocol_quakeworld && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
        rsurface.ent_flags = ent->flags;
        if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
                rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
index 20c6ec3c2b63130335c5b16d6faeb4d5769c5907..7df34688cac9caa272a04ca77c5b450406249f50 100644 (file)
@@ -91,6 +91,9 @@ OBJ_COMMON= \
        cl_main.o \
        cl_parse.o \
        cl_particles.o \
+       cl_protocol_dpp7.o \
+       cl_protocol_nq.o \
+       cl_protocol_qw.o \
        cl_screen.o \
        cl_video.o \
        cl_video_libavw.o \
@@ -162,6 +165,7 @@ OBJ_COMMON= \
        sv_main.o \
        sv_move.o \
        sv_phys.o \
+       sv_protocol.o \
        sv_save.o \
        sv_send.o \
        sv_user.o \
index a8fdbb6eb84905f9a24a05d87d5dab322ef02b9a..ee92c2f5bc91eda10f930f3754083c27a7d8c22f 100644 (file)
@@ -748,13 +748,13 @@ static void VM_M_WriteLong (prvm_prog_t *prog)
 static void VM_M_WriteAngle (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteAngle);
-       MSG_WriteAngle (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
+       sv.protocol->WriteAngle (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0));
 }
 
 static void VM_M_WriteCoord (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteCoord);
-       MSG_WriteCoord (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
+       sv.protocol->WriteCoord(VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0));
 }
 
 static void VM_M_WriteString (prvm_prog_t *prog)
index f406012df2416908abbb71258a1aae597901d009..639072a8930535c20644eb01ca14fb5a8e3285a6 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
 #include "quakedef.h"
+#include "protocol.h"
 #include "thread.h"
 #include "lhnet.h"
 
@@ -723,7 +724,7 @@ static int NetConn_AddCryptoFlag(crypto_t *crypto)
        return flag;
 }
 
-int NetConn_Transmit(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate, int burstsize, qbool quakesignon_suppressreliables)
+int NetConn_Transmit(netconn_t *conn, sizebuf_t *data, protocol_t *protocol, int rate, int burstsize, qbool quakesignon_suppressreliables)
 {
        int totallen = 0;
        unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
@@ -737,7 +738,7 @@ int NetConn_Transmit(netconn_t *conn, sizebuf_t *data, protocolversion_t protoco
 
        conn->outgoing_netgraph[conn->outgoing_packetcounter].cleartime = conn->cleartime;
 
-       if (protocol == PROTOCOL_QUAKEWORLD)
+       if (protocol == &protocol_quakeworld)
        {
                int packetLen;
                qbool sendreliable;
@@ -1195,7 +1196,7 @@ void NetConn_UpdateSockets(void)
        }
 }
 
-static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, size_t length, protocolversion_t protocol, double newtimeout)
+static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, size_t length, protocol_t *protocol, double newtimeout)
 {
        int originallength = (int)length;
        unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
@@ -1204,7 +1205,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
        if (length < 8)
                return 0;
 
-       if (protocol == PROTOCOL_QUAKEWORLD)
+       if (protocol == &protocol_quakeworld)
        {
                unsigned int sequence, sequence_ack;
                qbool reliable_ack, reliable_message;
@@ -1505,7 +1506,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
        return 0;
 }
 
-static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, protocolversion_t initialprotocol)
+static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, protocol_t *initialprotocol)
 {
        crypto_t *crypto;
        cls.connect_trying = false;
@@ -1547,9 +1548,9 @@ static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_
        cls.protocol = initialprotocol;
        // reset move sequence numbering on this new connection
        cls.servermovesequence = 0;
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
                CL_ForwardToServer("new");
-       if (cls.protocol == PROTOCOL_QUAKE)
+       if (cls.protocol == &protocol_netquake)
        {
                // write a keepalive (clc_nop) as it seems to greatly improve the
                // chances of connecting to a netquake server
@@ -1769,7 +1770,7 @@ static void NetConn_ClientParsePacket_ServerList_ParseDPList(lhnetaddress_t *sen
                if (serverlist_consoleoutput && developer_networking.integer)
                        Con_Printf("Requesting info from DarkPlaces server %s\n", ipstring);
                
-               if( !NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_DARKPLACES7, ipstring, false ) ) {
+               if( !NetConn_ClientParsePacket_ServerList_PrepareQuery( protocol_dpp7.num, ipstring, false ) ) {
                        break;
                }
 
@@ -1927,7 +1928,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 #ifdef CONFIG_MENU
                        M_Update_Return_Reason("Accepted");
 #endif
-                       NetConn_ConnectionEstablished(mysocket, peeraddress, PROTOCOL_DARKPLACES3);
+                       NetConn_ConnectionEstablished(mysocket, peeraddress, &protocol_dpp3);
                        return true;
                }
                if (length > 7 && !memcmp(string, "reject ", 7) && cls.connect_trying)
@@ -2073,7 +2074,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        if (serverlist_consoleoutput && developer_networking.integer)
                                                Con_Printf("Requesting info from QuakeWorld server %s\n", ipstring);
                                        
-                                       if( !NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_QUAKEWORLD, ipstring, false ) ) {
+                                       if( !NetConn_ClientParsePacket_ServerList_PrepareQuery( protocol_quakeworld.num, ipstring, false ) ) {
                                                break;
                                        }
 
@@ -2136,7 +2137,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 #ifdef CONFIG_MENU
                        M_Update_Return_Reason("QuakeWorld Accepted");
 #endif
-                       NetConn_ConnectionEstablished(mysocket, peeraddress, PROTOCOL_QUAKEWORLD);
+                       NetConn_ConnectionEstablished(mysocket, peeraddress, &protocol_quakeworld);
                        return true;
                }
                if (length > 2 && !memcmp(string, "n\\", 2))
@@ -2202,7 +2203,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                return true;
        }
        // quakeworld ingame packet
-       if (fromserver && cls.protocol == PROTOCOL_QUAKEWORLD && length >= 8 && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol, net_messagetimeout.value)) == 2)
+       if (fromserver && cls.protocol == &protocol_quakeworld && length >= 8 && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol, net_messagetimeout.value)) == 2)
        {
                ret = 0;
                CL_ParseServerMessage();
@@ -2256,7 +2257,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 #ifdef CONFIG_MENU
                                M_Update_Return_Reason("Accepted");
 #endif
-                               NetConn_ConnectionEstablished(mysocket, &clientportaddress, PROTOCOL_QUAKE);
+                               NetConn_ConnectionEstablished(mysocket, &clientportaddress, &protocol_netquake);
                        }
                        break;
                case CCREP_REJECT:
@@ -3316,7 +3317,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
        // protocol
        // (this protects more modern protocols against being used for
        //  Quake packet flood Denial Of Service attacks)
-       if (length >= 5 && (i = BuffBigLong(data)) && (i & (~NETFLAG_LENGTH_MASK)) == (int)NETFLAG_CTL && (i & NETFLAG_LENGTH_MASK) == length && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3) && !ENCRYPTION_REQUIRED)
+       if (length >= 5 && (i = BuffBigLong(data)) && (i & (~NETFLAG_LENGTH_MASK)) == (int)NETFLAG_CTL && (i & NETFLAG_LENGTH_MASK) == length && (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3 || sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3) && !ENCRYPTION_REQUIRED)
        {
                int c;
                int protocolnumber;
@@ -3697,7 +3698,7 @@ void NetConn_QueryMasters(qbool querydp, qbool queryqw)
                                        if(LHNETADDRESS_GetAddressType(&favorites[j]) == af)
                                        {
                                                if(LHNETADDRESS_ToString(&favorites[j], request, sizeof(request), true))
-                                                       NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_DARKPLACES7, request, true );
+                                                       NetConn_ClientParsePacket_ServerList_PrepareQuery( protocol_dpp7.num, request, true );
                                        }
                                }
                        }
@@ -3747,7 +3748,7 @@ void NetConn_QueryMasters(qbool querydp, qbool queryqw)
                                                if(LHNETADDRESS_ToString(&favorites[j], request, sizeof(request), true))
                                                {
                                                        NetConn_WriteString(cl_sockets[i], "\377\377\377\377status\n", &favorites[j]);
-                                                       NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_QUAKEWORLD, request, true );
+                                                       NetConn_ClientParsePacket_ServerList_PrepareQuery( protocol_quakeworld.num, request, true );
                                                }
                                        }
                                }
@@ -3803,7 +3804,7 @@ static void Net_Heartbeat_f(cmd_state_t *cmd)
 
 static void PrintStats(netconn_t *conn)
 {
-       if ((cls.state == ca_connected && cls.protocol == PROTOCOL_QUAKEWORLD) || (sv.active && sv.protocol == PROTOCOL_QUAKEWORLD))
+       if ((cls.state == ca_connected && cls.protocol == &protocol_quakeworld) || (sv.active && sv.protocol == &protocol_quakeworld))
                Con_Printf("address=%21s canSend=%u sendSeq=%6u recvSeq=%6u\n", conn->address, !conn->sendMessageLength, conn->outgoing_unreliable_sequence, conn->qw.incoming_sequence);
        else
                Con_Printf("address=%21s canSend=%u sendSeq=%6u recvSeq=%6u\n", conn->address, !conn->sendMessageLength, conn->nq.sendSequence, conn->nq.receiveSequence);
index ceba2e3e311bb312de3ecdbfb3ed49a312561cd1..c36682d2c9880e088241a6b308dacdf74ecf9fa2 100755 (executable)
--- a/netconn.h
+++ b/netconn.h
@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define NET_H
 
 #include "lhnet.h"
+#include "protocol.h"
 
 #define NET_HEADERSIZE         (2 * sizeof(unsigned int))
 
@@ -431,7 +432,7 @@ extern cvar_t net_usesizelimit;
 extern cvar_t net_burstreserve;
 
 qbool NetConn_CanSend(netconn_t *conn);
-int NetConn_Transmit(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate, int burstsize, qbool quakesignon_suppressreliables);
+int NetConn_Transmit(netconn_t *conn, sizebuf_t *data, protocol_t *protocol, int rate, int burstsize, qbool quakesignon_suppressreliables);
 qbool NetConn_HaveClientPorts(void);
 qbool NetConn_HaveServerPorts(void);
 void NetConn_CloseClientPorts(void);
index 8bdb00514a07270a93d30062deb92ea4cc1672f0..f0a6917c05a97849f5f13b3a33356668420fcf8b 100644 (file)
@@ -39,80 +39,249 @@ entity_state_t defaultstate =
 
 // LadyHavoc: I own protocol ranges 96, 97, 3500-3599
 
-struct protocolversioninfo_s
+protocol_t protocol_netquake =
 {
-       int number;
-       protocolversion_t version;
-       const char *name;
-}
-protocolversioninfo[] =
-{
-       { 3504, PROTOCOL_DARKPLACES7 , "DP7"},
-       { 3503, PROTOCOL_DARKPLACES6 , "DP6"},
-       { 3502, PROTOCOL_DARKPLACES5 , "DP5"},
-       { 3501, PROTOCOL_DARKPLACES4 , "DP4"},
-       { 3500, PROTOCOL_DARKPLACES3 , "DP3"},
-       {   97, PROTOCOL_DARKPLACES2 , "DP2"},
-       {   96, PROTOCOL_DARKPLACES1 , "DP1"},
-       {   15, PROTOCOL_QUAKEDP     , "QUAKEDP"},
-       {   15, PROTOCOL_QUAKE       , "QUAKE"},
-       {   28, PROTOCOL_QUAKEWORLD  , "QW"},
-       {  250, PROTOCOL_NEHAHRAMOVIE, "NEHAHRAMOVIE"},
-       {10000, PROTOCOL_NEHAHRABJP  , "NEHAHRABJP"},
-       {10001, PROTOCOL_NEHAHRABJP2 , "NEHAHRABJP2"},
-       {10002, PROTOCOL_NEHAHRABJP3 , "NEHAHRABJP3"},
-       {    0, PROTOCOL_UNKNOWN     , NULL}
-};
-
-protocolversion_t Protocol_EnumForName(const char *s)
+       .name = "QUAKE",
+       .num = 15,
+       .WriteCoord = MSG_WriteCoord13i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector13i,
+       .ReadCoord = MSG_ReadCoord13i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector13i,
+       .max_svcmsg = 34,
+       .svcmsg = netmsg_nq_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_quakedp =
 {
-       int i;
-       for (i = 0;protocolversioninfo[i].name;i++)
-               if (!strcasecmp(s, protocolversioninfo[i].name))
-                       return protocolversioninfo[i].version;
-       return PROTOCOL_UNKNOWN;
-}
+       .name = "QUAKEDP",
+       .num = 15,
+       .WriteCoord = MSG_WriteCoord13i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector13i,
+       .ReadCoord = MSG_ReadCoord13i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector13i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
 
-const char *Protocol_NameForEnum(protocolversion_t p)
+protocol_t protocol_quakeworld =
 {
-       int i;
-       for (i = 0;protocolversioninfo[i].name;i++)
-               if (protocolversioninfo[i].version == p)
-                       return protocolversioninfo[i].name;
-       return "UNKNOWN";
-}
+       .name = "QW",
+       .num = 28,
+       .WriteCoord = MSG_WriteCoord13i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector13i,
+       .ReadCoord = MSG_ReadCoord13i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector13i,
+       .max_svcmsg = 53,
+       .svcmsg = netmsg_qw_svc,
+       .max_clcmsg = 59,
+       .clcmsg = NULL
+};
 
-protocolversion_t Protocol_EnumForNumber(int n)
+protocol_t protocol_dpp1 =
 {
-       int i;
-       for (i = 0;protocolversioninfo[i].name;i++)
-               if (protocolversioninfo[i].number == n)
-                       return protocolversioninfo[i].version;
-       return PROTOCOL_UNKNOWN;
-}
+       .name = "DP1",
+       .num = 96,
+       .WriteCoord = MSG_WriteCoord32f,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector32f,
+       .ReadCoord = MSG_ReadCoord32f,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector32f,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
 
-int Protocol_NumberForEnum(protocolversion_t p)
+protocol_t protocol_dpp2 =
 {
-       int i;
-       for (i = 0;protocolversioninfo[i].name;i++)
-               if (protocolversioninfo[i].version == p)
-                       return protocolversioninfo[i].number;
-       return 0;
-}
+       .name = "DP2",
+       .num = 97,
+       .WriteCoord = MSG_WriteCoord16i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector16i,
+       .ReadCoord = MSG_ReadCoord16i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector16i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
 
-void Protocol_Names(char *buffer, size_t buffersize)
+protocol_t protocol_dpp3 =
 {
-       int i;
-       if (buffersize < 1)
-               return;
-       buffer[0] = 0;
-       for (i = 0;protocolversioninfo[i].name;i++)
-       {
-               if (i > 1)
-                       strlcat(buffer, " ", buffersize);
-               strlcat(buffer, protocolversioninfo[i].name, buffersize);
-       }
-}
+       .name = "DP3",
+       .num = 3500,
+       .WriteCoord = MSG_WriteCoord16i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector16i,
+       .ReadCoord = MSG_ReadCoord16i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector16i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_dpp4 =
+{
+       .name = "DP4",
+       .num = 3501,
+       .WriteCoord = MSG_WriteCoord16i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector16i,
+       .ReadCoord = MSG_ReadCoord16i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector16i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_dpp5 =
+{
+       .name = "DP5",
+       .num = 3502,
+       .WriteCoord = MSG_WriteCoord32f,
+       .WriteAngle = MSG_WriteAngle16i,
+       .WriteVector = MSG_WriteVector32f,
+       .ReadCoord = MSG_ReadCoord32f,
+       .ReadAngle = MSG_ReadAngle16i,
+       .ReadVector = MSG_ReadVector32f,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_dpp6 =
+{
+       .name = "DP6",
+       .num = 3503,
+       .WriteCoord = MSG_WriteCoord32f,
+       .WriteAngle = MSG_WriteAngle16i,
+       .WriteVector = MSG_WriteVector32f,
+       .ReadCoord = MSG_ReadCoord32f,
+       .ReadAngle = MSG_ReadAngle16i,
+       .ReadVector = MSG_ReadVector32f,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_dpp7 =
+{
+       .name = "DP7",
+       .num = 3504,
+       .WriteCoord = MSG_WriteCoord32f,
+       .WriteAngle = MSG_WriteAngle16i,
+       .WriteVector = MSG_WriteVector32f,
+       .ReadCoord = MSG_ReadCoord32f,
+       .ReadAngle = MSG_ReadAngle16i,
+       .ReadVector = MSG_ReadVector32f,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+
+};
+
+protocol_t protocol_nehahramovie =
+{
+       .name = "NEHAHRAMOVIE",
+       .num = 250,
+       .WriteCoord = MSG_WriteCoord13i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector13i,
+       .ReadCoord = MSG_ReadCoord13i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector13i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_nehahrabjp =
+{
+       .name = "NEHAHRABJP",
+       .num = 10000,
+       .WriteCoord = MSG_WriteCoord13i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector13i,
+       .ReadCoord = MSG_ReadCoord13i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector13i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_nehahrabjp2 =
+{
+       .name = "NEHAHRABJP2",
+       .num = 10001,
+       .WriteCoord = MSG_WriteCoord13i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector13i,
+       .ReadCoord = MSG_ReadCoord13i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector13i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t protocol_nehahrabjp3 =
+{
+       .name = "NEHAHRABJP3",
+       .num = 10002,
+       .WriteCoord = MSG_WriteCoord13i,
+       .WriteAngle = MSG_WriteAngle8i,
+       .WriteVector = MSG_WriteVector13i,
+       .ReadCoord = MSG_ReadCoord13i,
+       .ReadAngle = MSG_ReadAngle8i,
+       .ReadVector = MSG_ReadVector13i,
+       .max_svcmsg = 62,
+       .svcmsg = netmsg_dpext_svc,
+       .max_clcmsg = 59,
+       .clcmsg = netmsg_base_clc
+};
+
+protocol_t *protocols[] =
+{
+       &protocol_netquake,
+       &protocol_quakedp,
+       &protocol_quakeworld,
+       &protocol_dpp1,
+       &protocol_dpp2,
+       &protocol_dpp3,
+       &protocol_dpp4,
+       &protocol_dpp5,
+       &protocol_dpp6,
+       &protocol_dpp7,
+       &protocol_nehahramovie,
+       &protocol_nehahrabjp,
+       &protocol_nehahrabjp2,
+       &protocol_nehahrabjp3,
+       NULL
+};
 
 void Protocol_UpdateClientStats(const int *stats)
 {
@@ -147,6 +316,42 @@ STAT_VIEWZOOM, // this rarely changes
 -1,
 };
 
+protocol_t *Protocol_ForName(const char *name)
+{
+       int i;
+       for(i = 0; &protocols[i]; i++)
+       {
+               if(!strncmp(name, protocols[i]->name, strlen(protocols[i]->name)))
+                       break;
+       }
+       return protocols[i];
+}
+
+protocol_t *Protocol_ForNumber(int num)
+{
+       int i;
+       for(i = 0; &protocols[i]; i++)
+       {
+               if(protocols[i]->num == num)
+                       break;
+       }
+       return protocols[i];
+}
+
+void Protocol_Names(char *buffer, size_t buffersize)
+{
+       int i;
+       if (buffersize < 1)
+               return;
+       buffer[0] = 0;
+       for (i = 0; protocols[i]; i++)
+       {
+               if (i > 1)
+                       strlcat(buffer, " ", buffersize);
+               strlcat(buffer, protocols[i]->name, buffersize);
+       }
+}
+
 void Protocol_WriteStatsReliable(void)
 {
        int i, j;
@@ -165,7 +370,7 @@ void Protocol_WriteStatsReliable(void)
                {
                        host_client->statsdeltabits[i >> 3] -= (1 << (i & 7));
                        // send the stat as a byte if possible
-                       if (sv.protocol == PROTOCOL_QUAKEWORLD)
+                       if (sv.protocol == &protocol_quakeworld)
                        {
                                if (host_client->stats[i] >= 0 && host_client->stats[i] < 256)
                                {
index 3fa39244bad2f56d0e23a579645fd08b44d43bc6..3df4f28e2540b82c0443bcf5d3bb6727bba20233 100644 (file)
@@ -22,12 +22,81 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #ifndef PROTOCOL_H
 #define PROTOCOL_H
 
-// protocolversion_t is defined in common.h
-
-protocolversion_t Protocol_EnumForName(const char *s);
-const char *Protocol_NameForEnum(protocolversion_t p);
-protocolversion_t Protocol_EnumForNumber(int n);
-int Protocol_NumberForEnum(protocolversion_t p);
+enum
+{
+       PROTOCOL_UNKNOWN,
+       PROTOCOL_QUAKE = 15, ///< quake (aka netquake/normalquake/nq) protocol
+       PROTOCOL_QUAKEDP = 15, ///< darkplaces extended quake protocol (used by TomazQuake and others), backwards compatible as long as no extended features are used
+       PROTOCOL_QUAKEWORLD = 28, ///< quakeworld protocol
+       PROTOCOL_DARKPLACES1 = 96, ///< uses EntityFrame entity snapshot encoder/decoder which is a QuakeWorld-like entity snapshot delta compression method
+       PROTOCOL_DARKPLACES2 = 97, ///< various changes
+       PROTOCOL_NEHAHRAMOVIE = 250, ///< Nehahra movie protocol, a big nasty hack dating back to early days of the Quake Standards Group (but only ever used by neh_gl.exe), this is potentially backwards compatible with quake protocol as long as no extended features are used (but in actuality the neh_gl.exe which wrote this protocol ALWAYS wrote the extended information)
+       PROTOCOL_DARKPLACES3 = 3500, ///< uses EntityFrame4 entity snapshot encoder/decoder which is broken, this attempted to do partial snapshot updates on a QuakeWorld-like protocol, but it is broken and impossible to fix
+       PROTOCOL_DARKPLACES4 = 3501, ///< various changes
+       PROTOCOL_DARKPLACES5 = 3502, ///< uses EntityFrame5 entity snapshot encoder/decoder which is based on a Tribes networking article at http://www.garagegames.com/articles/networking1/
+       PROTOCOL_DARKPLACES6 = 3503, ///< various changes
+       PROTOCOL_DARKPLACES7 = 3504, ///< added QuakeWorld-style movement protocol to allow more consistent prediction
+       PROTOCOL_NEHAHRABJP = 10000, ///< same as QUAKEDP but with 16bit modelindex
+       PROTOCOL_NEHAHRABJP2 = 10001, ///< same as NEHAHRABJP but with 16bit soundindex
+       PROTOCOL_NEHAHRABJP3 = 10002 ///< same as NEHAHRABJP2 but with some changes
+};
+
+typedef struct protocol_netmsg_s protocol_netmsg_t;
+typedef struct protocol_s protocol_t;
+
+struct protocol_s
+{
+       const char *name;
+       const int num;
+
+       void (*WriteCoord)(sizebuf_t *, float);
+       void (*WriteAngle)(sizebuf_t *, float);
+       void (*WriteVector)(sizebuf_t *, const vec3_t);
+       float (*ReadCoord)(sizebuf_t *);
+       float (*ReadAngle)(sizebuf_t *);
+       void (*ReadVector)(sizebuf_t *, vec3_t);
+
+       // TODO: Other info?
+       const int max_svcmsg;
+       struct protocol_netmsg_s *svcmsg;
+       const int max_clcmsg;
+       struct protocol_netmsg_s *clcmsg;
+};
+
+struct protocol_netmsg_s
+{
+       const char *name;
+       void (*func)(struct protocol_s *);
+};
+
+typedef struct protocol_s protocol_t;
+typedef struct protocol_netmsg_s protocol_netmsg_t;
+
+extern protocol_t protocol_netquake;
+extern protocol_t protocol_quakedp;
+extern protocol_t protocol_quakeworld;
+extern protocol_t protocol_dpp1;
+extern protocol_t protocol_dpp2;
+extern protocol_t protocol_dpp3;
+extern protocol_t protocol_dpp4;
+extern protocol_t protocol_dpp5;
+extern protocol_t protocol_dpp6;
+extern protocol_t protocol_dpp7;
+extern protocol_t protocol_nehahramovie;
+extern protocol_t protocol_nehahrabjp;
+extern protocol_t protocol_nehahrabjp2;
+extern protocol_t protocol_nehahrabjp3;
+
+extern protocol_netmsg_t netmsg_nq_svc[];
+extern protocol_netmsg_t netmsg_qw_svc[];
+extern protocol_netmsg_t netmsg_dpext_svc[];
+extern protocol_netmsg_t netmsg_base_clc[];
+
+#define PF_PREDICTION (1<<0)
+#define PF_MOVE_CROUCH (1<<1)
+
+protocol_t *Protocol_ForName(const char *name);
+protocol_t *Protocol_ForNumber(int num);
 void Protocol_Names(char *buffer, size_t buffersize);
 
 #define ENTITYSIZEPROFILING_START(msg, num, flags) \
@@ -278,9 +347,12 @@ void Protocol_Names(char *buffer, size_t buffersize);
 //
 #define        clc_bad                 0
 #define        clc_nop                 1
-#define        clc_disconnect  2
-#define        clc_move                3                       // [usercmd_t]
+#define        clc_disconnect  2               // (NETQUAKE)
+#define        clc_move                3               // [usercmd_t]
 #define        clc_stringcmd   4               // [string] message
+#define clc_delta              5               // (QUAKEWORLD) [byte] sequence number, requests delta compression of message
+#define clc_tmove              6               // (QUAKEWORLD) teleport request, spectator only
+#define clc_upload             7               // (QUAKEWORLD) teleport request, spectator only
 
 // LadyHavoc: my clc_ range, 50-59
 #define clc_ackframe   50              // [int] framenumber
@@ -453,7 +525,7 @@ qbool EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, co
 void EntityFrameQuake_ISeeDeadEntities(void);
 
 /*
-PROTOCOL_DARKPLACES3
+&protocol_dpp3
 server updates entities according to some (unmentioned) scheme.
 
 a frame consists of all visible entities, some of which are up to date,
@@ -485,7 +557,7 @@ if server receives ack message in put packet it performs these steps:
 */
 
 /*
-PROTOCOL_DARKPLACES4
+&protocol_dpp4
 a frame consists of some visible entities in a range (this is stored as start and end, note that end may be less than start if it wrapped).
 
 these entities are stored in a range (firstentity/endentity) of structs in the entitydata[] buffer.
@@ -906,15 +978,7 @@ extern cvar_t developer_networkentities;
 #define qw_svc_setinfo                 51              // setinfo on a client
 #define qw_svc_serverinfo              52              // serverinfo
 #define qw_svc_updatepl                        53              // [byte] [byte]
-// QUAKEWORLD
-// client to server
-#define qw_clc_bad                     0
-#define qw_clc_nop                     1
-#define qw_clc_move                    3               // [[usercmd_t]
-#define qw_clc_stringcmd       4               // [string] message
-#define qw_clc_delta           5               // [byte] sequence number, requests delta compression of message
-#define qw_clc_tmove           6               // teleport request, spectator only
-#define qw_clc_upload          7               // teleport request, spectator only
+
 // QUAKEWORLD
 // playerinfo flags from server
 // playerinfo always sends: playernum, flags, origin[] and framenumber
diff --git a/sbar.c b/sbar.c
index 6fc6c327cbd3855abedacd3debdbc97dc809091f..5c5835645d2b685d88b3a63fc40ee60488b22166 100644 (file)
--- a/sbar.c
+++ b/sbar.c
@@ -1809,7 +1809,7 @@ static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
                if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
                        myself = true;
 
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
        {
                if (s->qw_spectator)
                {
@@ -1874,12 +1874,12 @@ void Sbar_DeathmatchOverlay (void)
        if (cl.last_ping_request < host.realtime - 2 && cls.netcon)
        {
                cl.last_ping_request = host.realtime;
-               if (cls.protocol == PROTOCOL_QUAKEWORLD)
+               if (cls.protocol == &protocol_quakeworld)
                {
-                       MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+                       MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
                        MSG_WriteString(&cls.netcon->message, "pings");
                }
-               else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
+               else if (cls.protocol == &protocol_netquake || cls.protocol == &protocol_quakedp || cls.protocol == &protocol_nehahramovie || cls.protocol == &protocol_nehahrabjp || cls.protocol == &protocol_nehahrabjp2 || cls.protocol == &protocol_nehahrabjp3 || cls.protocol == &protocol_dpp1 || cls.protocol == &protocol_dpp2 || cls.protocol == &protocol_dpp3 || cls.protocol == &protocol_dpp4 || cls.protocol == &protocol_dpp5 || cls.protocol == &protocol_dpp6/* || cls.protocol == &protocol_dpp7*/)
                {
                        // these servers usually lack the pings command and so a less efficient "ping" command must be sent, which on modern DP servers will also reply with a pingplreport command after the ping listing
                        static int ping_anyway_counter = 0;
@@ -1911,7 +1911,7 @@ void Sbar_DeathmatchOverlay (void)
        ymin = 8;
        ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
 
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
                xmin = (int) (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->maxwidth) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
        else
                xmin = (int) (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->maxwidth) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
@@ -1924,7 +1924,7 @@ void Sbar_DeathmatchOverlay (void)
 
        // draw the text
        y = 40;
-       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (cls.protocol == &protocol_quakeworld)
        {
                DrawQ_String(xmin, y, va(vabuf, sizeof(vabuf), "ping pl%% time frags team  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
        }
index b3ab98a280d49ccae4931de91061ba53aaaf3250..f6b5b5f8af0cdfeecd6a857a284ebe4e1c490982 100644 (file)
--- a/server.h
+++ b/server.h
@@ -85,7 +85,7 @@ typedef struct server_s
        qbool loadgame;
 
        /// one of the PROTOCOL_ values
-       protocolversion_t protocol;
+       protocol_t *protocol;
 
        double time;
 
index aab18140bfab0036098ff91f81b7a1bd2766ee45..6933c16e5dc6627dff6c913d64339a1329404a78 100644 (file)
@@ -1566,7 +1566,7 @@ static void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int
        // If it's a static sound
        if (isstatic)
        {
-               if (sfx->loopstart >= sfx->total_length && (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEWORLD))
+               if (sfx->loopstart >= sfx->total_length && (cls.protocol == &protocol_netquake || cls.protocol == &protocol_quakeworld))
                        Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name);
                target_chan->distfade = attenuation / (64.0f * snd_soundradius.value);
        }
index 27847ffb3b3948c4bc30cc4051dd4a056c7689b8..9740c4378840fb3214310a9049d5ab5651020370 100644 (file)
@@ -674,7 +674,7 @@ static void SV_Pings_f(cmd_state_t *cmd)
        if (!host_client->netconnection)
                return;
 
-       if (sv.protocol != PROTOCOL_QUAKEWORLD)
+       if (sv.protocol != &protocol_quakeworld)
        {
                MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
                MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
@@ -696,7 +696,7 @@ static void SV_Pings_f(cmd_state_t *cmd)
                movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
                ping = (int)floor(svs.clients[i].ping*1000+0.5);
                ping = bound(0, ping, 9999);
-               if (sv.protocol == PROTOCOL_QUAKEWORLD)
+               if (sv.protocol == &protocol_quakeworld)
                {
                        // send qw_svc_updateping and qw_svc_updatepl messages
                        MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
@@ -714,7 +714,7 @@ static void SV_Pings_f(cmd_state_t *cmd)
                        MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
                }
        }
-       if (sv.protocol != PROTOCOL_QUAKEWORLD)
+       if (sv.protocol != &protocol_quakeworld)
                MSG_WriteString(&host_client->netconnection->message, "\n");
 }
 
@@ -818,7 +818,7 @@ static void SV_Status_f(cmd_state_t *cmd)
                        players++;
        print ("host:     %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
        print ("version:  %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
-       print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
+       print ("protocol: %i (%s)\n", sv.protocol->num, sv.protocol->name);
        print ("map:      %s\n", sv.name);
        print ("timing:   %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
        print ("players:  %i active (%i max)\n\n", players, svs.maxclients);
@@ -885,7 +885,7 @@ static void SV_Status_f(cmd_state_t *cmd)
                
                if (in == 0) // default layout
                {
-                       if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
+                       if (sv.protocol == &protocol_netquake && svs.maxclients <= 99)
                        {
                                // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
                                print ("#%-2u %-16.16s  %3i  %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
index 8e732cd561570f8dba8162b5b0b245ea547f2b94..34186e9d867cc9a6e783f1318f84b26e5dae5725 100644 (file)
--- a/sv_ents.c
+++ b/sv_ents.c
@@ -84,7 +84,7 @@ void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits)
 
 void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits)
 {
-       if (sv.protocol == PROTOCOL_DARKPLACES2)
+       if (sv.protocol == &protocol_dpp2)
        {
                if (bits & E_ORIGIN1)
                        MSG_WriteCoord16i(msg, ent->origin[0]);
@@ -117,7 +117,7 @@ void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned
                                MSG_WriteCoord32f(msg, ent->origin[2]);
                }
        }
-       if ((sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4) && (ent->flags & RENDER_LOWPRECISION))
+       if ((sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4) && (ent->flags & RENDER_LOWPRECISION))
        {
                if (bits & E_ANGLE1)
                        MSG_WriteAngle8i(msg, ent->angles[0]);
@@ -159,7 +159,7 @@ void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned
                MSG_WriteByte(msg, ent->glowsize);
        if (bits & E_GLOWCOLOR)
                MSG_WriteByte(msg, ent->glowcolor);
-       if (sv.protocol == PROTOCOL_DARKPLACES2)
+       if (sv.protocol == &protocol_dpp2)
                if (bits & E_FLAGS)
                        MSG_WriteByte(msg, ent->flags);
        if (bits & E_TAGATTACHMENT)
index 98be9b367a7bde18580f28ae5f88a60b6b0c393d..bed601f1d79b28d11d1289263d27fc328b595f9c 100644 (file)
@@ -516,7 +516,7 @@ qbool EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database
 
        packetlog = NULL;
        // write stat updates
-       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3 && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5)
+       if (sv.protocol != &protocol_netquake && sv.protocol != &protocol_quakedp && sv.protocol != &protocol_nehahramovie && sv.protocol != &protocol_nehahrabjp && sv.protocol != &protocol_nehahrabjp2 && sv.protocol != &protocol_nehahrabjp3 && sv.protocol != &protocol_dpp1 && sv.protocol != &protocol_dpp2 && sv.protocol != &protocol_dpp3 && sv.protocol != &protocol_dpp4 && sv.protocol != &protocol_dpp5)
        {
                for (i = 0;i < MAX_CL_STATS && msg->cursize + 6 + 11 <= maxsize;i++)
                {
@@ -569,7 +569,7 @@ qbool EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database
        d->latestframenum = framenum;
        MSG_WriteByte(msg, svc_entities);
        MSG_WriteLong(msg, framenum);
-       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5 && sv.protocol != PROTOCOL_DARKPLACES6)
+       if (sv.protocol != &protocol_netquake && sv.protocol != &protocol_quakedp && sv.protocol != &protocol_nehahramovie && sv.protocol != &protocol_dpp1 && sv.protocol != &protocol_dpp2 && sv.protocol != &protocol_dpp3 && sv.protocol != &protocol_dpp4 && sv.protocol != &protocol_dpp5 && sv.protocol != &protocol_dpp6)
                MSG_WriteLong(msg, movesequence);
        for (priority = ENTITYFRAME5_PRIORITYLEVELS - 1;priority >= 0 && packetlog->numstates < ENTITYFRAME5_MAXSTATES;priority--)
        {
index 8db8a62398756a0737f60261205e277d864affe8..1d6454170715aa1fc95bf8cb4ccc812614efc002 100644 (file)
@@ -71,7 +71,7 @@ qbool EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, co
                if (baseline.modelindex != s->modelindex)
                {
                        bits |= U_MODEL;
-                       if ((s->modelindex & 0xFF00) && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
+                       if ((s->modelindex & 0xFF00) && sv.protocol != &protocol_nehahrabjp && sv.protocol != &protocol_nehahrabjp2 && sv.protocol != &protocol_nehahrabjp3)
                                bits |= U_MODEL2;
                }
                if (baseline.alpha != s->alpha)
@@ -86,9 +86,9 @@ qbool EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, co
                        bits |= U_COLORMOD;
 
                // if extensions are disabled, clear the relevant update flags
-               if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+               if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_nehahramovie)
                        bits &= 0x7FFF;
-               if (sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+               if (sv.protocol == &protocol_nehahramovie)
                        if (s->alpha != 255 || s->effects & EF_FULLBRIGHT)
                                bits |= U_EXTEND1;
 
@@ -106,7 +106,7 @@ qbool EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, co
 
                        MSG_WriteByte (&buf, bits);
                        if (bits & U_MOREBITS)          MSG_WriteByte(&buf, bits>>8);
-                       if (sv.protocol != PROTOCOL_NEHAHRAMOVIE)
+                       if (sv.protocol != &protocol_nehahramovie)
                        {
                                if (bits & U_EXTEND1)   MSG_WriteByte(&buf, bits>>16);
                                if (bits & U_EXTEND2)   MSG_WriteByte(&buf, bits>>24);
@@ -116,7 +116,7 @@ qbool EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, co
 
                        if (bits & U_MODEL)
                        {
-                               if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+                               if (sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                                        MSG_WriteShort(&buf, s->modelindex);
                                else
                                        MSG_WriteByte(&buf, s->modelindex);
@@ -125,12 +125,12 @@ qbool EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, co
                        if (bits & U_COLORMAP)          MSG_WriteByte(&buf, s->colormap);
                        if (bits & U_SKIN)                      MSG_WriteByte(&buf, s->skin);
                        if (bits & U_EFFECTS)           MSG_WriteByte(&buf, s->effects);
-                       if (bits & U_ORIGIN1)           MSG_WriteCoord(&buf, s->origin[0], sv.protocol);
-                       if (bits & U_ANGLE1)            MSG_WriteAngle(&buf, s->angles[0], sv.protocol);
-                       if (bits & U_ORIGIN2)           MSG_WriteCoord(&buf, s->origin[1], sv.protocol);
-                       if (bits & U_ANGLE2)            MSG_WriteAngle(&buf, s->angles[1], sv.protocol);
-                       if (bits & U_ORIGIN3)           MSG_WriteCoord(&buf, s->origin[2], sv.protocol);
-                       if (bits & U_ANGLE3)            MSG_WriteAngle(&buf, s->angles[2], sv.protocol);
+                       if (bits & U_ORIGIN1)           sv.protocol->WriteCoord(&buf, s->origin[0]);
+                       if (bits & U_ANGLE1)            sv.protocol->WriteAngle(&buf, s->angles[0]);
+                       if (bits & U_ORIGIN2)           sv.protocol->WriteCoord(&buf, s->origin[1]);
+                       if (bits & U_ANGLE2)            sv.protocol->WriteAngle(&buf, s->angles[1]);
+                       if (bits & U_ORIGIN3)           sv.protocol->WriteCoord(&buf, s->origin[2]);
+                       if (bits & U_ANGLE3)            sv.protocol->WriteAngle(&buf, s->angles[2]);
                        if (bits & U_ALPHA)                     MSG_WriteByte(&buf, s->alpha);
                        if (bits & U_SCALE)                     MSG_WriteByte(&buf, s->scale);
                        if (bits & U_EFFECTS2)          MSG_WriteByte(&buf, s->effects >> 8);
@@ -141,7 +141,7 @@ qbool EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, co
                        if (bits & U_MODEL2)            MSG_WriteByte(&buf, s->modelindex >> 8);
 
                        // the nasty protocol
-                       if ((bits & U_EXTEND1) && sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+                       if ((bits & U_EXTEND1) && sv.protocol == &protocol_nehahramovie)
                        {
                                if (s->effects & EF_FULLBRIGHT)
                                {
index 789b7dd058436636a0d15ce9553d6dac0330335c..75b2f1b4e001731cf04489bd8c2ebcd85b10a326 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -670,9 +670,7 @@ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
        if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
                return;
        MSG_WriteByte (&sv.datagram, svc_particle);
-       MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
-       MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
-       MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
+       sv.protocol->WriteVector(&sv.datagram, org);
        for (i=0 ; i<3 ; i++)
                MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
        MSG_WriteByte (&sv.datagram, count);
@@ -694,9 +692,7 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount,
                if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
                        return;
                MSG_WriteByte (&sv.datagram, svc_effect2);
-               MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
-               MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
-               MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
+               sv.protocol->WriteVector(&sv.datagram, org);
                MSG_WriteShort (&sv.datagram, modelindex);
                MSG_WriteShort (&sv.datagram, startframe);
                MSG_WriteByte (&sv.datagram, framecount);
@@ -707,9 +703,7 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount,
                if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
                        return;
                MSG_WriteByte (&sv.datagram, svc_effect);
-               MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
-               MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
-               MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
+               sv.protocol->WriteVector(&sv.datagram, org);
                MSG_WriteByte (&sv.datagram, modelindex);
                MSG_WriteByte (&sv.datagram, startframe);
                MSG_WriteByte (&sv.datagram, framecount);
@@ -800,12 +794,12 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int n
        }
        else
                MSG_WriteShort (dest, (ent<<3) | channel);
-       if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2)
+       if ((field_mask & SND_LARGESOUND) || sv.protocol == &protocol_nehahrabjp2)
                MSG_WriteShort (dest, sound_num);
        else
                MSG_WriteByte (dest, sound_num);
        for (i = 0;i < 3;i++)
-               MSG_WriteCoord (dest, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]), sv.protocol);
+               sv.protocol->WriteCoord (dest, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]));
 
        // TODO do we have to do anything here when dest is &sv.reliable_datagram?
        if(!reliable)
@@ -827,7 +821,7 @@ function, therefore the check for it is omitted.
 */
 void SV_StartPointSound (vec3_t origin, const char *sample, int nvolume, float attenuation, float speed)
 {
-       int sound_num, field_mask, i, speed4000;
+       int sound_num, field_mask, speed4000;
 
        if (nvolume < 0 || nvolume > 255)
        {
@@ -875,8 +869,7 @@ void SV_StartPointSound (vec3_t origin, const char *sample, int nvolume, float a
                MSG_WriteShort (&sv.datagram, sound_num);
        else
                MSG_WriteByte (&sv.datagram, sound_num);
-       for (i = 0;i < 3;i++)
-               MSG_WriteCoord (&sv.datagram, origin[i], sv.protocol);
+       sv.protocol->WriteVector(&sv.datagram, origin);
        SV_FlushBroadcastMessages();
 }
 
@@ -928,11 +921,11 @@ void SV_SendServerinfo (client_t *client)
        memset(client->stats, 0, sizeof(client->stats));
        memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
 
-       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
+       if (sv.protocol != &protocol_netquake && sv.protocol != &protocol_quakedp && sv.protocol != &protocol_nehahramovie && sv.protocol != &protocol_nehahrabjp && sv.protocol != &protocol_nehahrabjp2 && sv.protocol != &protocol_nehahrabjp3)
        {
-               if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
+               if (sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3)
                        client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
-               else if (sv.protocol == PROTOCOL_DARKPLACES4)
+               else if (sv.protocol == &protocol_dpp4)
                        client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
                else
                        client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
@@ -994,7 +987,7 @@ void SV_SendServerinfo (client_t *client)
                        sb.data = (unsigned char *) buf;
                        sb.maxsize = sizeof(buf);
                        k = 0;
-                       while(MakeDownloadPacket(sv.csqc_progname, svs.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, k++, &sb, sv.protocol))
+                       while(MakeDownloadPacket(sv.csqc_progname, svs.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, k++, &sb, sv.protocol->num))
                                SV_WriteDemoMessage(client, &sb, false);
                }
 
@@ -1024,7 +1017,7 @@ void SV_SendServerinfo (client_t *client)
        }
 
        MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
-       MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
+       MSG_WriteLong (&client->netconnection->message, sv.protocol->num);
        MSG_WriteByte (&client->netconnection->message, svs.maxclients);
 
        if (!coop.integer && deathmatch.integer)
@@ -1822,7 +1815,7 @@ static void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                // always send world submodels in newer protocols because they don't
                // generate much traffic (in old protocols they hog bandwidth)
                // but only if sv_cullentities_nevercullbmodels is off
-               else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
+               else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie))
                {
                        // entity has survived every check so far, check if visible
                        ed = PRVM_EDICT_NUM(s->number);
@@ -2150,7 +2143,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_save));
                MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_take));
                for (i=0 ; i<3 ; i++)
-                       MSG_WriteCoord (msg, PRVM_serveredictvector(other, origin)[i] + 0.5*(PRVM_serveredictvector(other, mins)[i] + PRVM_serveredictvector(other, maxs)[i]), sv.protocol);
+                       sv.protocol->WriteCoord (msg, PRVM_serveredictvector(other, origin)[i] + 0.5*(PRVM_serveredictvector(other, mins)[i] + PRVM_serveredictvector(other, maxs)[i]));
 
                PRVM_serveredictfloat(ent, dmg_take) = 0;
                PRVM_serveredictfloat(ent, dmg_save) = 0;
@@ -2177,7 +2170,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        {
                MSG_WriteByte (msg, svc_setangle);
                for (i=0 ; i < 3 ; i++)
-                       MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
+                       sv.protocol->WriteAngle (msg, host_client->fixangle_angles[i]);
                host_client->fixangle_angles_set = false;
        }
 
@@ -2214,7 +2207,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        {
                if (PRVM_serveredictvector(ent, punchangle)[i])
                        bits |= (SU_PUNCH1<<i);
-               if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
+               if (sv.protocol != &protocol_netquake && sv.protocol != &protocol_quakedp && sv.protocol != &protocol_nehahramovie && sv.protocol != &protocol_nehahrabjp && sv.protocol != &protocol_nehahrabjp2 && sv.protocol != &protocol_nehahrabjp3)
                        if (punchvector[i])
                                bits |= (SU_PUNCHVEC1<<i);
                if (PRVM_serveredictvector(ent, velocity)[i])
@@ -2289,15 +2282,15 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
        }
 
-       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+       if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3 || sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4 || sv.protocol == &protocol_dpp5)
        {
                if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
                bits |= SU_ITEMS;
                if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
                if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
                bits |= SU_WEAPON;
-               // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
-               if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+               // FIXME: which protocols support this?  does &protocol_dpp3 support viewzoom?
+               if (sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4 || sv.protocol == &protocol_dpp5)
                        if (viewzoom != 255)
                                bits |= SU_VIEWZOOM;
        }
@@ -2325,21 +2318,21 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        {
                if (bits & (SU_PUNCH1<<i))
                {
-                       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+                       if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                                MSG_WriteChar(msg, (int)PRVM_serveredictvector(ent, punchangle)[i]);
                        else
                                MSG_WriteAngle16i(msg, PRVM_serveredictvector(ent, punchangle)[i]);
                }
                if (bits & (SU_PUNCHVEC1<<i))
                {
-                       if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+                       if (sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4)
                                MSG_WriteCoord16i(msg, punchvector[i]);
                        else
                                MSG_WriteCoord32f(msg, punchvector[i]);
                }
                if (bits & (SU_VELOCITY1<<i))
                {
-                       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+                       if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3 || sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4)
                                MSG_WriteChar(msg, (int)(PRVM_serveredictvector(ent, velocity)[i] * (1.0f / 16.0f)));
                        else
                                MSG_WriteCoord32f(msg, PRVM_serveredictvector(ent, velocity)[i]);
@@ -2349,7 +2342,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        if (bits & SU_ITEMS)
                MSG_WriteLong (msg, stats[STAT_ITEMS]);
 
-       if (sv.protocol == PROTOCOL_DARKPLACES5)
+       if (sv.protocol == &protocol_dpp5)
        {
                if (bits & SU_WEAPONFRAME)
                        MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
@@ -2367,7 +2360,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                if (bits & SU_VIEWZOOM)
                        MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
        }
-       else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+       else if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3 || sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4)
        {
                if (bits & SU_WEAPONFRAME)
                        MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
@@ -2375,7 +2368,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                        MSG_WriteByte (msg, stats[STAT_ARMOR]);
                if (bits & SU_WEAPON)
                {
-                       if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+                       if (sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                                MSG_WriteShort (msg, stats[STAT_WEAPON]);
                        else
                                MSG_WriteByte (msg, stats[STAT_WEAPON]);
@@ -2397,7 +2390,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                        MSG_WriteByte (msg, stats[STAT_ACTIVEWEAPON]);
                if (bits & SU_VIEWZOOM)
                {
-                       if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+                       if (sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4)
                                MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
                        else
                                MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
@@ -2473,7 +2466,7 @@ static void SV_SendClientDatagram (client_t *client)
        if (!NetConn_CanSend(client->netconnection))
                return;
 
-       // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
+       // &protocol_dpp5 and later support packet size limiting of updates
        maxrate = max(NET_MINRATE, sv_maxrate.integer);
        if (sv_maxrate.integer != maxrate)
                Cvar_SetValueQuick(&sv_maxrate, maxrate);
@@ -2482,10 +2475,9 @@ static void SV_SendClientDatagram (client_t *client)
        // (how long to wait before sending another, based on this packet's size)
        clientrate = bound(NET_MINRATE, client->rate, maxrate);
 
-       switch (sv.protocol)
+       switch (sv.protocol->num)
        {
        case PROTOCOL_QUAKE:
-       case PROTOCOL_QUAKEDP:
        case PROTOCOL_NEHAHRAMOVIE:
        case PROTOCOL_NEHAHRABJP:
        case PROTOCOL_NEHAHRABJP2:
@@ -2735,7 +2727,7 @@ void SV_SendClientMessages(void)
 {
        int i, prepared = false;
 
-       if (sv.protocol == PROTOCOL_QUAKEWORLD)
+       if (sv.protocol == &protocol_quakeworld)
                Sys_Error("SV_SendClientMessages: no quakeworld support\n");
 
        SV_FlushBroadcastMessages();
@@ -3023,7 +3015,7 @@ SV_ModelIndex
 */
 int SV_ModelIndex(const char *s, int precachemode)
 {
-       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_MODELS);
+       int i, limit = ((sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3) ? 256 : MAX_MODELS);
        char filename[MAX_QPATH];
        if (!s || !*s)
                return 0;
@@ -3037,7 +3029,7 @@ int SV_ModelIndex(const char *s, int precachemode)
                {
                        if (precachemode)
                        {
-                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
+                               if (sv.state != ss_loading && (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3 || sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4 || sv.protocol == &protocol_dpp5))
                                {
                                        Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
                                        return 0;
@@ -3086,7 +3078,7 @@ SV_SoundIndex
 */
 int SV_SoundIndex(const char *s, int precachemode)
 {
-       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_SOUNDS);
+       int i, limit = ((sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3) ? 256 : MAX_SOUNDS);
        char filename[MAX_QPATH];
        if (!s || !*s)
                return 0;
@@ -3100,7 +3092,7 @@ int SV_SoundIndex(const char *s, int precachemode)
                {
                        if (precachemode)
                        {
-                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
+                               if (sv.state != ss_loading && (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3 || sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4 || sv.protocol == &protocol_dpp5))
                                {
                                        Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
                                        return 0;
@@ -3278,7 +3270,7 @@ static void SV_CreateBaseline (void)
                if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
                {
                        large = true;
-                       if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+                       if (sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                                large = false;
                }
 
@@ -3294,7 +3286,7 @@ static void SV_CreateBaseline (void)
                        MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
                        MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
                }
-               else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+               else if (sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                {
                        MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
                        MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
@@ -3308,8 +3300,8 @@ static void SV_CreateBaseline (void)
                MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
                for (i=0 ; i<3 ; i++)
                {
-                       MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
-                       MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
+                       sv.protocol->WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i]);
+                       sv.protocol->WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i]);
                }
        }
 }
@@ -3533,13 +3525,13 @@ void SV_SpawnServer (const char *map)
        Cvar_SetQuick(&sv_worldnamenoextension, sv.worldnamenoextension);
        Cvar_SetQuick(&sv_worldbasename, sv.worldbasename);
 
-       sv.protocol = Protocol_EnumForName(sv_protocolname.string);
-       if (sv.protocol == PROTOCOL_UNKNOWN)
+       sv.protocol = Protocol_ForName(sv_protocolname.string);
+       if (!sv.protocol)
        {
                char buffer[1024];
                Protocol_Names(buffer, sizeof(buffer));
                Con_Printf(CON_ERROR "Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
-               sv.protocol = PROTOCOL_QUAKE;
+               sv.protocol = &protocol_netquake;
        }
 
 // load progs to get entity field count
@@ -3660,7 +3652,7 @@ void SV_SpawnServer (const char *map)
                Mod_PurgeUnused();
 
 // create a baseline for more efficient communications
-       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+       if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                SV_CreateBaseline ();
 
        sv.state = ss_active; // LadyHavoc: workaround for svc_precache bug
@@ -3917,13 +3909,13 @@ static void SV_VM_Setup(void)
        prog->builtins = vm_sv_builtins;
        prog->numbuiltins = vm_sv_numbuiltins;
        prog->max_edicts = 512;
-       if (sv.protocol == PROTOCOL_QUAKE)
+       if (sv.protocol == &protocol_netquake)
                prog->limit_edicts = 640; // before quake mission pack 1 this was 512
-       else if (sv.protocol == PROTOCOL_QUAKEDP)
+       else if (sv.protocol == &protocol_quakedp)
                prog->limit_edicts = 2048; // guessing
-       else if (sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+       else if (sv.protocol == &protocol_nehahramovie)
                prog->limit_edicts = 2048; // guessing!
-       else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+       else if (sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                prog->limit_edicts = 4096; // guessing!
        else
                prog->limit_edicts = MAX_EDICTS;
diff --git a/sv_protocol.c b/sv_protocol.c
new file mode 100644 (file)
index 0000000..13cae8c
--- /dev/null
@@ -0,0 +1,66 @@
+#include "quakedef.h"
+#include "sv_protocol_base.h"
+
+protocol_netmsg_t netmsg_base_clc[] =
+{
+       {"clc_bad", NULL},
+       {"clc_nop", Netmsg_clc_nop},
+       {"clc_disconnect", Netmsg_clc_disconnect},
+       {"clc_move", Netmsg_clc_move},
+       {"clc_stringcmd", Netmsg_clc_stringcmd},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {NULL, NULL},
+       {"clc_ackframe", Netmsg_clc_ackframe},
+       {"clc_ackdownloaddata", Netmsg_clc_ackdownloaddata},
+       {"clc_unusedlh2", NULL},
+       {"clc_unusedlh3", NULL},
+       {"clc_unusedlh4", NULL},
+       {"clc_unusedlh5", NULL},
+       {"clc_unusedlh6", NULL},
+       {"clc_unusedlh7", NULL},
+       {"clc_unusedlh8", NULL},
+       {"clc_unusedlh9", NULL}
+};
\ No newline at end of file
diff --git a/sv_protocol_base.h b/sv_protocol_base.h
new file mode 100644 (file)
index 0000000..e76e02b
--- /dev/null
@@ -0,0 +1,142 @@
+#include "quakedef.h"
+#include "server.h"
+#include "protocol.h"
+#include "sv_user.h"
+
+static void Netmsg_clc_nop(protocol_t *protocol)
+{
+}
+
+static void Netmsg_clc_stringcmd(protocol_t *protocol)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       char *s, *p, *q;
+
+       // allow reliable messages now as the client is done with initial loading
+       if (host_client->sendsignon == 2)
+               host_client->sendsignon = 0;
+       s = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring));
+       q = NULL;
+       for(p = s; *p; ++p) switch(*p)
+       {
+               case 10:
+               case 13:
+                       if(!q)
+                               q = p;
+                       break;
+               default:
+                       if(q)
+                               goto clc_stringcmd_invalid; // newline seen, THEN something else -> possible exploit
+                       break;
+       }
+       if(q)
+               *q = 0;
+       if (strncasecmp(s, "spawn", 5) == 0
+               || strncasecmp(s, "begin", 5) == 0
+               || strncasecmp(s, "prespawn", 8) == 0)
+               Cmd_ExecuteString (&cmd_serverfromclient, s, src_client, true);
+       else if (PRVM_serverfunction(SV_ParseClientCommand))
+       {
+               int restorevm_tempstringsbuf_cursize;
+               restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
+               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, s);
+               PRVM_serverglobalfloat(time) = sv.time;
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
+               prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ParseClientCommand), "QC function SV_ParseClientCommand is missing");
+               prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+       }
+       else
+               Cmd_ExecuteString (&cmd_serverfromclient, s, src_client, true);
+       return;
+
+clc_stringcmd_invalid:
+       Con_Printf("Received invalid stringcmd from %s\n", host_client->name);
+       if(developer.integer > 0)
+               Com_HexDumpToConsole((unsigned char *) s, (int)strlen(s));
+       return;
+}
+
+static void Netmsg_clc_disconnect(protocol_t *protocol)
+{
+       SV_DropClient (false); // client wants to disconnect
+}
+
+static void Netmsg_clc_move(protocol_t *protocol)
+{
+       SV_ReadClientMove();
+}
+
+static void Netmsg_clc_ackdownloaddata(protocol_t *protocol)
+{
+       int start = MSG_ReadLong(&sv_message);
+       int num = MSG_ReadShort(&sv_message);
+       if (host_client->download_file && host_client->download_started)
+       {
+               if (host_client->download_expectedposition == start)
+               {
+                       int size = (int)FS_FileSize(host_client->download_file);
+                       // a data block was successfully received by the client,
+                       // update the expected position on the next data block
+                       host_client->download_expectedposition = start + num;
+                       // if this was the last data block of the file, it's done
+                       if (host_client->download_expectedposition >= FS_FileSize(host_client->download_file))
+                       {
+                               // tell the client that the download finished
+                               // we need to calculate the crc now
+                               //
+                               // note: at this point the OS probably has the file
+                               // entirely in memory, so this is a faster operation
+                               // now than it was when the download started.
+                               //
+                               // it is also preferable to do this at the end of the
+                               // download rather than the start because it reduces
+                               // potential for Denial Of Service attacks against the
+                               // server.
+                               int crc;
+                               unsigned char *temp;
+                               FS_Seek(host_client->download_file, 0, SEEK_SET);
+                               temp = (unsigned char *) Mem_Alloc(tempmempool, size);
+                               FS_Read(host_client->download_file, temp, size);
+                               crc = CRC_Block(temp, size);
+                               Mem_Free(temp);
+                               // calculated crc, send the file info to the client
+                               // (so that it can verify the data)
+                               SV_ClientCommands("\ncl_downloadfinished %i %i %s\n", size, crc, host_client->download_name);
+                               Con_DPrintf("Download of %s by %s has finished\n", host_client->download_name, host_client->name);
+                               FS_Close(host_client->download_file);
+                               host_client->download_file = NULL;
+                               host_client->download_name[0] = 0;
+                               host_client->download_expectedposition = 0;
+                               host_client->download_started = false;
+                       }
+               }
+               else
+               {
+                       // a data block was lost, reset to the expected position
+                       // and resume sending from there
+                       FS_Seek(host_client->download_file, host_client->download_expectedposition, SEEK_SET);
+               }
+       }
+}
+
+static void Netmsg_clc_ackframe(protocol_t *protocol)
+{
+       int num;
+       if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       num = MSG_ReadLong(&sv_message);
+       if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       if (developer_networkentities.integer >= 10)
+               Con_Printf("recv clc_ackframe %i\n", num);
+       // if the client hasn't progressed through signons yet,
+       // ignore any clc_ackframes we get (they're probably from the
+       // previous level)
+       if (host_client->begun && host_client->latestframenum < num)
+       {
+               int i;
+               for (i = host_client->latestframenum + 1;i < num;i++)
+                       if (!SV_FrameLost(i))
+                               break;
+               SV_FrameAck(num);
+               host_client->latestframenum = num;
+       }
+}
index 7f14e19f8fe85242b3ddb0a6869e536f0914d6e3..fd6759d7baa6b10417603a4bfd66cbaf2c698fd6 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "sv_demo.h"
+#include "sv_user.h"
 #define DEBUGMOVES 0
 
 static usercmd_t usercmd;
@@ -179,16 +180,16 @@ void SV_Spawn_f(cmd_state_t *cmd)
        if (sv.loadgame)
        {
                MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
-               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[0], sv.protocol);
-               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[1], sv.protocol);
-               MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
+               sv.protocol->WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[0]);
+               sv.protocol->WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[1]);
+               sv.protocol->WriteAngle (&host_client->netconnection->message, 0);
        }
        else
        {
                MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
-               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[0], sv.protocol);
-               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[1], sv.protocol);
-               MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
+               sv.protocol->WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[0]);
+               sv.protocol->WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[1]);
+               sv.protocol->WriteAngle (&host_client->netconnection->message, 0);
        }
 
        SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
@@ -651,7 +652,7 @@ SV_ReadClientMove
 */
 int sv_numreadmoves = 0;
 usercmd_t sv_readmoves[CL_MAX_USERCMDS];
-static void SV_ReadClientMove (void)
+void SV_ReadClientMove (void)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i;
@@ -663,7 +664,7 @@ static void SV_ReadClientMove (void)
        if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
 
        // read ping time
-       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3 && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5 && sv.protocol != PROTOCOL_DARKPLACES6)
+       if (sv.protocol != &protocol_netquake && sv.protocol != &protocol_quakedp && sv.protocol != &protocol_nehahramovie && sv.protocol != &protocol_nehahrabjp && sv.protocol != &protocol_nehahrabjp2 && sv.protocol != &protocol_nehahrabjp3 && sv.protocol != &protocol_dpp1 && sv.protocol != &protocol_dpp2 && sv.protocol != &protocol_dpp3 && sv.protocol != &protocol_dpp4 && sv.protocol != &protocol_dpp5 && sv.protocol != &protocol_dpp6)
                move->sequence = MSG_ReadLong(&sv_message);
        move->time = move->clienttime = MSG_ReadFloat(&sv_message);
        if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
@@ -679,11 +680,11 @@ static void SV_ReadClientMove (void)
        // read current angles
        for (i = 0;i < 3;i++)
        {
-               if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+               if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                        move->viewangles[i] = MSG_ReadAngle8i(&sv_message);
-               else if (sv.protocol == PROTOCOL_DARKPLACES1)
+               else if (sv.protocol == &protocol_dpp1)
                        move->viewangles[i] = MSG_ReadAngle16i(&sv_message);
-               else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
+               else if (sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3)
                        move->viewangles[i] = MSG_ReadAngle32f(&sv_message);
                else
                        move->viewangles[i] = MSG_ReadAngle16i(&sv_message);
@@ -699,7 +700,7 @@ static void SV_ReadClientMove (void)
        // read buttons
        // be sure to bitwise OR them into the move->buttons because we want to
        // accumulate button presses from multiple packets per actual move
-       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+       if (sv.protocol == &protocol_netquake || sv.protocol == &protocol_quakedp || sv.protocol == &protocol_nehahramovie || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3 || sv.protocol == &protocol_dpp1 || sv.protocol == &protocol_dpp2 || sv.protocol == &protocol_dpp3 || sv.protocol == &protocol_dpp4 || sv.protocol == &protocol_dpp5)
                move->buttons = MSG_ReadByte(&sv_message);
        else
                move->buttons = MSG_ReadLong(&sv_message);
@@ -710,7 +711,7 @@ static void SV_ReadClientMove (void)
        if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
 
        // PRYDON_CLIENTCURSOR
-       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3 && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5)
+       if (sv.protocol != &protocol_netquake && sv.protocol != &protocol_quakedp && sv.protocol != &protocol_nehahramovie && sv.protocol != &protocol_nehahrabjp && sv.protocol != &protocol_nehahrabjp2 && sv.protocol != &protocol_nehahrabjp3 && sv.protocol != &protocol_dpp1 && sv.protocol != &protocol_dpp2 && sv.protocol != &protocol_dpp3 && sv.protocol != &protocol_dpp4 && sv.protocol != &protocol_dpp5)
        {
                // 30 bytes
                move->cursor_screen[0] = MSG_ReadShort(&sv_message) * (1.0f / 32767.0f);
@@ -973,7 +974,7 @@ void SV_ApplyClientMove (void)
        PRVM_serveredictfloat(host_client->edict, ping_movementloss) = movementloss / (float) NETGRAPH_PACKETS;
 }
 
-static qbool SV_FrameLost(int framenum)
+qbool SV_FrameLost(int framenum)
 {
        if (host_client->entitydatabase5)
        {
@@ -987,7 +988,7 @@ static qbool SV_FrameLost(int framenum)
        return false;
 }
 
-static void SV_FrameAck(int framenum)
+void SV_FrameAck(int framenum)
 {
        if (host_client->entitydatabase)
                EntityFrame_AckFrame(host_client->entitydatabase, framenum);
@@ -1004,9 +1005,8 @@ SV_ReadClientMessage
 */
 void SV_ReadClientMessage(void)
 {
-       prvm_prog_t *prog = SVVM_prog;
-       int netcmd, num, start;
-       char *s, *p, *q;
+       int netcmd;
+       protocol_t *protocol = sv.protocol;
 
        if(sv_autodemo_perclient.integer >= 2)
                SV_WriteDemoMessage(host_client, &(host_client->netconnection->message), true);
@@ -1014,7 +1014,7 @@ void SV_ReadClientMessage(void)
        //MSG_BeginReading ();
        sv_numreadmoves = 0;
 
-       for(;;)
+       while(host_client)
        {
                if (!host_client->active)
                {
@@ -1038,143 +1038,16 @@ void SV_ReadClientMessage(void)
                        SV_ExecuteClientMoves();
                        break;
                }
-
-               switch (netcmd)
+               if(!netcmd || netcmd >= protocol->max_clcmsg || !protocol->clcmsg[netcmd].func)
                {
-               default:
                        Con_Printf("SV_ReadClientMessage: unknown command char %i (at offset 0x%x)\n", netcmd, sv_message.readcount);
                        if (developer_networking.integer)
                                Com_HexDumpToConsole(sv_message.data, sv_message.cursize);
                        SV_DropClient (false);
                        return;
-
-               case clc_nop:
-                       break;
-
-               case clc_stringcmd:
-                       // allow reliable messages now as the client is done with initial loading
-                       if (host_client->sendsignon == 2)
-                               host_client->sendsignon = 0;
-                       s = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring));
-                       q = NULL;
-                       for(p = s; *p; ++p) switch(*p)
-                       {
-                               case 10:
-                               case 13:
-                                       if(!q)
-                                               q = p;
-                                       break;
-                               default:
-                                       if(q)
-                                               goto clc_stringcmd_invalid; // newline seen, THEN something else -> possible exploit
-                                       break;
-                       }
-                       if(q)
-                               *q = 0;
-                       if (strncasecmp(s, "spawn", 5) == 0
-                        || strncasecmp(s, "begin", 5) == 0
-                        || strncasecmp(s, "prespawn", 8) == 0)
-                               Cmd_ExecuteString (&cmd_serverfromclient, s, src_client, true);
-                       else if (PRVM_serverfunction(SV_ParseClientCommand))
-                       {
-                               int restorevm_tempstringsbuf_cursize;
-                               restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
-                               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, s);
-                               PRVM_serverglobalfloat(time) = sv.time;
-                               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
-                               prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ParseClientCommand), "QC function SV_ParseClientCommand is missing");
-                               prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
-                       }
-                       else
-                               Cmd_ExecuteString (&cmd_serverfromclient, s, src_client, true);
-                       break;
-
-clc_stringcmd_invalid:
-                       Con_Printf("Received invalid stringcmd from %s\n", host_client->name);
-                       if(developer.integer > 0)
-                               Com_HexDumpToConsole((unsigned char *) s, (int)strlen(s));
-                       break;
-
-               case clc_disconnect:
-                       SV_DropClient (false); // client wants to disconnect
-                       return;
-
-               case clc_move:
-                       SV_ReadClientMove();
-                       break;
-
-               case clc_ackdownloaddata:
-                       start = MSG_ReadLong(&sv_message);
-                       num = MSG_ReadShort(&sv_message);
-                       if (host_client->download_file && host_client->download_started)
-                       {
-                               if (host_client->download_expectedposition == start)
-                               {
-                                       int size = (int)FS_FileSize(host_client->download_file);
-                                       // a data block was successfully received by the client,
-                                       // update the expected position on the next data block
-                                       host_client->download_expectedposition = start + num;
-                                       // if this was the last data block of the file, it's done
-                                       if (host_client->download_expectedposition >= FS_FileSize(host_client->download_file))
-                                       {
-                                               // tell the client that the download finished
-                                               // we need to calculate the crc now
-                                               //
-                                               // note: at this point the OS probably has the file
-                                               // entirely in memory, so this is a faster operation
-                                               // now than it was when the download started.
-                                               //
-                                               // it is also preferable to do this at the end of the
-                                               // download rather than the start because it reduces
-                                               // potential for Denial Of Service attacks against the
-                                               // server.
-                                               int crc;
-                                               unsigned char *temp;
-                                               FS_Seek(host_client->download_file, 0, SEEK_SET);
-                                               temp = (unsigned char *) Mem_Alloc(tempmempool, size);
-                                               FS_Read(host_client->download_file, temp, size);
-                                               crc = CRC_Block(temp, size);
-                                               Mem_Free(temp);
-                                               // calculated crc, send the file info to the client
-                                               // (so that it can verify the data)
-                                               SV_ClientCommands("\ncl_downloadfinished %i %i %s\n", size, crc, host_client->download_name);
-                                               Con_DPrintf("Download of %s by %s has finished\n", host_client->download_name, host_client->name);
-                                               FS_Close(host_client->download_file);
-                                               host_client->download_file = NULL;
-                                               host_client->download_name[0] = 0;
-                                               host_client->download_expectedposition = 0;
-                                               host_client->download_started = false;
-                                       }
-                               }
-                               else
-                               {
-                                       // a data block was lost, reset to the expected position
-                                       // and resume sending from there
-                                       FS_Seek(host_client->download_file, host_client->download_expectedposition, SEEK_SET);
-                               }
-                       }
-                       break;
-
-               case clc_ackframe:
-                       if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
-                       num = MSG_ReadLong(&sv_message);
-                       if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
-                       if (developer_networkentities.integer >= 10)
-                               Con_Printf("recv clc_ackframe %i\n", num);
-                       // if the client hasn't progressed through signons yet,
-                       // ignore any clc_ackframes we get (they're probably from the
-                       // previous level)
-                       if (host_client->begun && host_client->latestframenum < num)
-                       {
-                               int i;
-                               for (i = host_client->latestframenum + 1;i < num;i++)
-                                       if (!SV_FrameLost(i))
-                                               break;
-                               SV_FrameAck(num);
-                               host_client->latestframenum = num;
-                       }
-                       break;
                }
+               else
+                       protocol->clcmsg[netcmd].func(protocol);
        }
 }
 
diff --git a/sv_user.h b/sv_user.h
new file mode 100644 (file)
index 0000000..d60b053
--- /dev/null
+++ b/sv_user.h
@@ -0,0 +1,5 @@
+#include "qtypes.h"
+
+void SV_ReadClientMove (void);
+qbool SV_FrameLost(int framenum);
+void SV_FrameAck(int framenum);
\ No newline at end of file
index 634de8147fe65a72a8a18bd2e5a10a97ab6a4c7b..ffb9af8e93f6deb32059003b6c58ba992a9c052b 100644 (file)
@@ -495,9 +495,9 @@ static void VM_SV_ambientsound(prvm_prog_t *prog)
        else
                MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
 
-       MSG_WriteVector(&sv.signon, pos, sv.protocol);
+       sv.protocol->WriteVector(&sv.signon, pos);
 
-       if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+       if (large || sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
                MSG_WriteShort (&sv.signon, soundnum);
        else
                MSG_WriteByte (&sv.signon, soundnum);
@@ -1451,13 +1451,13 @@ static void VM_SV_WriteLong(prvm_prog_t *prog)
 static void VM_SV_WriteAngle(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
-       MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
+       sv.protocol->WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1));
 }
 
 static void VM_SV_WriteCoord(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
-       MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
+       sv.protocol->WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1));
 }
 
 static void VM_SV_WriteString(prvm_prog_t *prog)
@@ -1548,7 +1548,7 @@ static void VM_SV_makestatic(prvm_prog_t *prog)
                MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
                MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
-       else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+       else if (sv.protocol == &protocol_nehahrabjp || sv.protocol == &protocol_nehahrabjp2 || sv.protocol == &protocol_nehahrabjp3)
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic);
                MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
@@ -1565,8 +1565,8 @@ static void VM_SV_makestatic(prvm_prog_t *prog)
        MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
        for (i=0 ; i<3 ; i++)
        {
-               MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
-               MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
+               sv.protocol->WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i]);
+               sv.protocol->WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i]);
        }
 
 // throw the entity away now
@@ -1880,9 +1880,9 @@ static void VM_SV_te_blood(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_BLOOD);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // velocity
        MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
        MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
@@ -1900,15 +1900,15 @@ static void VM_SV_te_bloodshower(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
        // min
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // speed
-       MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
        // count
        MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
        SV_FlushBroadcastMessages();
@@ -1920,9 +1920,9 @@ static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // color
        MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
        MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
@@ -1938,17 +1938,17 @@ static void VM_SV_te_particlecube(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
        // min
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // velocity
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2]);
        // count
        MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -1956,7 +1956,7 @@ static void VM_SV_te_particlecube(prvm_prog_t *prog)
        // gravity true/false
        MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
        // randomvel
-       MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6));
        SV_FlushBroadcastMessages();
 }
 
@@ -1968,17 +1968,17 @@ static void VM_SV_te_particlerain(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
        // min
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // velocity
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2]);
        // count
        MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -1994,17 +1994,17 @@ static void VM_SV_te_particlesnow(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
        // min
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // velocity
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2]);
        // count
        MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -2020,9 +2020,9 @@ static void VM_SV_te_spark(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPARK);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // velocity
        MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
        MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
@@ -2038,9 +2038,9 @@ static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2050,9 +2050,9 @@ static void VM_SV_te_spikequad(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2062,9 +2062,9 @@ static void VM_SV_te_superspikequad(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2074,9 +2074,9 @@ static void VM_SV_te_explosionquad(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2086,9 +2086,9 @@ static void VM_SV_te_smallflash(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2100,9 +2100,9 @@ static void VM_SV_te_customflash(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // radius
        MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
        // lifetime
@@ -2120,9 +2120,9 @@ static void VM_SV_te_gunshot(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2132,9 +2132,9 @@ static void VM_SV_te_spike(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPIKE);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2144,9 +2144,9 @@ static void VM_SV_te_superspike(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2156,9 +2156,9 @@ static void VM_SV_te_explosion(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2168,9 +2168,9 @@ static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2180,9 +2180,9 @@ static void VM_SV_te_wizspike(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2192,9 +2192,9 @@ static void VM_SV_te_knightspike(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2204,9 +2204,9 @@ static void VM_SV_te_lavasplash(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2216,9 +2216,9 @@ static void VM_SV_te_teleport(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_TELEPORT);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2228,9 +2228,9 @@ static void VM_SV_te_explosion2(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
        // origin
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // color
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
@@ -2245,13 +2245,13 @@ static void VM_SV_te_lightning1(prvm_prog_t *prog)
        // owner entity
        MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2263,13 +2263,13 @@ static void VM_SV_te_lightning2(prvm_prog_t *prog)
        // owner entity
        MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2281,13 +2281,13 @@ static void VM_SV_te_lightning3(prvm_prog_t *prog)
        // owner entity
        MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2299,13 +2299,13 @@ static void VM_SV_te_beam(prvm_prog_t *prog)
        // owner entity
        MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2314,9 +2314,9 @@ static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
        VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        SV_FlushBroadcastMessages();
 }
 
@@ -2326,13 +2326,13 @@ static void VM_SV_te_flamejet(prvm_prog_t *prog)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
        // org
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2]);
        // vel
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
-       MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1]);
+       sv.protocol->WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2]);
        // count
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
        SV_FlushBroadcastMessages();
@@ -2834,8 +2834,8 @@ static void VM_SV_trailparticles(prvm_prog_t *prog)
        MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
        VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
-       MSG_WriteVector(&sv.datagram, start, sv.protocol);
-       MSG_WriteVector(&sv.datagram, end, sv.protocol);
+       sv.protocol->WriteVector(&sv.datagram, start);
+       sv.protocol->WriteVector(&sv.datagram, end);
        SV_FlushBroadcastMessages();
 }
 
@@ -2858,15 +2858,15 @@ static void VM_SV_pointparticles(prvm_prog_t *prog)
                // 1+2+12=15 bytes
                MSG_WriteByte(&sv.datagram, svc_pointparticles1);
                MSG_WriteShort(&sv.datagram, effectnum);
-               MSG_WriteVector(&sv.datagram, org, sv.protocol);
+               sv.protocol->WriteVector(&sv.datagram, org);
        }
        else
        {
                // 1+2+12+12+2=29 bytes
                MSG_WriteByte(&sv.datagram, svc_pointparticles);
                MSG_WriteShort(&sv.datagram, effectnum);
-               MSG_WriteVector(&sv.datagram, org, sv.protocol);
-               MSG_WriteVector(&sv.datagram, vel, sv.protocol);
+               sv.protocol->WriteVector(&sv.datagram, org);
+               sv.protocol->WriteVector(&sv.datagram, vel);
                MSG_WriteShort(&sv.datagram, count);
        }
 
diff --git a/view.c b/view.c
index 938ee2da7ceec6ccd402630dea202a7f5ce60147..57c53dd88aa2dd0f81f7301123eccad6a68b1841 100644 (file)
--- a/view.c
+++ b/view.c
@@ -268,7 +268,7 @@ void V_ParseDamage (void)
 
        armor = MSG_ReadByte(&cl_message);
        blood = MSG_ReadByte(&cl_message);
-       MSG_ReadVector(&cl_message, from, cls.protocol);
+       cls.protocol->ReadVector(&cl_message, from);
 
        // Send the Dmg Globals to CSQC
        CL_VM_UpdateDmgGlobals(blood, armor, from);
@@ -523,7 +523,7 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa
        if (clintermission)
        {
                // entity is a fixed camera, just copy the matrix
-               if (cls.protocol == PROTOCOL_QUAKEWORLD)
+               if (cls.protocol == &protocol_quakeworld)
                        Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.qw_intermission_origin[0], cl.qw_intermission_origin[1], cl.qw_intermission_origin[2], cl.qw_intermission_angles[0], cl.qw_intermission_angles[1], cl.qw_intermission_angles[2], 1);
                else
                {