rewrote protocol version system (including splitting PROTOCOL_QUAKE into PROTOCOL_QUA...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 24 May 2005 21:37:32 +0000 (21:37 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 24 May 2005 21:37:32 +0000 (21:37 +0000)
made server able to host PROTOCOL_NEHAHRAMOVIE protocol for completeness
added PROTOCOL_DARKPLACES7 protocol (still in development, not enabled by default) which allows players to use QW-style movement messages (makes prediction rock solid but has speedcheat/lagaport potential)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5326 d7cf8633-e32d-0410-b094-e92efae38249

15 files changed:
cl_input.c
cl_parse.c
client.h
common.c
common.h
host.c
host_cmd.c
netconn.h
progs.h
protocol.c
protocol.h
server.h
sv_main.c
sv_phys.c
sv_user.c

index b46bb14..f926dd3 100644 (file)
@@ -498,7 +498,6 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
        int crouch;
        int onground;
        double edgefriction;
-       double simulatedtime;
        double frametime;
        double t;
        vec_t wishspeed;
@@ -524,16 +523,25 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
        // remove stale queue items
        n = cl.movement_numqueue;
        cl.movement_numqueue = 0;
-       // calculate time to execute for
-       simulatedtime = cl.mtime[0] + cl_movement_latency.value / 1000.0;
-       for (i = 0;i < n;i++)
-               if (cl.movement_queue[i].time >= cl.mtime[0] && cl.movement_queue[i].time <= simulatedtime)
-                       cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       if (cl.servermovesequence)
+       {
+               for (i = 0;i < n;i++)
+                       if (cl.movement_queue[i].sequence > cl.servermovesequence)
+                               cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       }
+       else
+       {
+               double simulatedtime = cl.mtime[0] + cl_movement_latency.value / 1000.0;
+               for (i = 0;i < n;i++)
+                       if (cl.movement_queue[i].time >= cl.mtime[0] && cl.movement_queue[i].time <= simulatedtime)
+                               cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       }
        // add to input queue if there is room
-       if (cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]) && cl.mtime[0] > cl.mtime[1])
+       if (cl_movement.integer && cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]) && cl.mtime[0] > cl.mtime[1])
        {
                // add to input queue
-               cl.movement_queue[cl.movement_numqueue].time = simulatedtime;
+               cl.movement_queue[cl.movement_numqueue].sequence = cl.movesequence;
+               cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value / 1000.0;
                cl.movement_queue[cl.movement_numqueue].frametime = cl.mtime[0] - cl.mtime[1];
                VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
                cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
@@ -560,7 +568,7 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
        // replay input queue, and remove any stale queue items
        // note: this relies on the fact there's always one queue item at the end
        // abort if client movement is disabled
-       cl.movement = cl_movement.integer && cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback;
+       cl.movement = /*cl_movement.integer && */cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback;
        if (!cl.movement)
                cl.movement_numqueue = 0;
        for (i = 0;i < cl.movement_numqueue;i++)
@@ -815,18 +823,79 @@ void CL_SendMove(void)
        if (++cl.movemessages >= 2)
        {
                // send the movement message
-               // PROTOCOL_QUAKE       clc_move = 16 bytes total
-               // PROTOCOL_DARKPLACES1 clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES2 clc_move = 25 bytes total
-               // PROTOCOL_DARKPLACES3 clc_move = 25 bytes total
-               // PROTOCOL_DARKPLACES4 clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES5 clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES6 clc_move = 52 bytes total
-               // 5 bytes
-               MSG_WriteByte (&buf, clc_move);
-               MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
-               if (cl.protocol == PROTOCOL_DARKPLACES6)
+               // PROTOCOL_QUAKE        clc_move = 16 bytes total
+               // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
+               // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
+               // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
+               // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
+               // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
+               // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
+               // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
+               // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
+               // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total
+               if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
+                       // 3 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle8i (&buf, cl.viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, forwardmove);
+                       MSG_WriteCoord16i (&buf, sidemove);
+                       MSG_WriteCoord16i (&buf, upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, bits);
+                       MSG_WriteByte (&buf, in_impulse);
+               }
+               else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
+                       // 12 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle32f (&buf, cl.viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, forwardmove);
+                       MSG_WriteCoord16i (&buf, sidemove);
+                       MSG_WriteCoord16i (&buf, upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, bits);
+                       MSG_WriteByte (&buf, in_impulse);
+               }
+               else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
+                       // 6 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle16i (&buf, cl.viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, forwardmove);
+                       MSG_WriteCoord16i (&buf, sidemove);
+                       MSG_WriteCoord16i (&buf, upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, bits);
+                       MSG_WriteByte (&buf, in_impulse);
+               }
+               else
                {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       if (cl.protocol != PROTOCOL_DARKPLACES6)
+                       {
+                               if (cl_movement.integer)
+                               {
+                                       cl.movesequence++;
+                                       MSG_WriteLong (&buf, cl.movesequence);
+                               }
+                               else
+                                       MSG_WriteLong (&buf, 0);
+                       }
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
                        // 6 bytes
                        for (i = 0;i < 3;i++)
                                MSG_WriteAngle16i (&buf, cl.viewangles[i]);
@@ -849,36 +918,6 @@ void CL_SendMove(void)
                        MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
                        MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
                }
-               else
-               {
-                       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
-                       {
-                               // 3 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle8i (&buf, cl.viewangles[i]);
-                       }
-                       else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
-                       {
-                               // 12 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle32f (&buf, cl.viewangles[i]);
-                       }
-                       else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
-                       {
-                               // 6 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle16i (&buf, cl.viewangles[i]);
-                       }
-                       else
-                               Host_Error("CL_SendMove: unknown cl.protocol %i\n", cl.protocol);
-                       // 6 bytes
-                       MSG_WriteCoord16i (&buf, forwardmove);
-                       MSG_WriteCoord16i (&buf, sidemove);
-                       MSG_WriteCoord16i (&buf, upmove);
-                       // 2 bytes
-                       MSG_WriteByte (&buf, bits);
-                       MSG_WriteByte (&buf, in_impulse);
-               }
        }
 
 #if MOVEAVERAGING
@@ -901,6 +940,7 @@ void CL_SendMove(void)
        }
 
        // PROTOCOL_DARKPLACES6 = 67 bytes per packet
+       // PROTOCOL_DARKPLACES7 = 71 bytes per packet
 
        // deliver the message
        if (cls.demoplayback)
index 50a1e13..232ae69 100644 (file)
@@ -331,6 +331,7 @@ void CL_ParseServerInfo (void)
 {
        char *str;
        int i;
+       protocolversion_t protocol;
        int nummodels, numsounds;
        entity_t *ent;
 
@@ -346,16 +347,17 @@ void CL_ParseServerInfo (void)
 
 // parse protocol version number
        i = MSG_ReadLong ();
-       // hack for unmarked Nehahra movie demos which had a custom protocol
-       if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
-               i = PROTOCOL_NEHAHRAMOVIE;
-       if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_DARKPLACES6 && i != PROTOCOL_NEHAHRAMOVIE)
+       protocol = Protocol_EnumForNumber(i);
+       if (protocol == PROTOCOL_UNKNOWN)
        {
-               Host_Error("CL_ParseServerInfo: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), %i (DP5), %i (DP6), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_DARKPLACES5, PROTOCOL_DARKPLACES6, PROTOCOL_NEHAHRAMOVIE);
+               Host_Error("CL_ParseServerInfo: Server is unrecognized protocol number (%i)\n", i);
                return;
        }
-       cl.protocol = i;
-       Con_DPrintf("Server protocol is %i\n", cl.protocol);
+       // hack for unmarked Nehahra movie demos which had a custom protocol
+       if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && demo_nehahra.integer)
+               protocol = PROTOCOL_NEHAHRAMOVIE;
+       cl.protocol = protocol;
+       Con_DPrintf("Server protocol is %s\n", Protocol_NameForEnum(cl.protocol));
 
 // parse maxclients
        cl.maxclients = MSG_ReadByte ();
@@ -618,7 +620,7 @@ void CL_ParseClientdata (void)
        VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
        cl.mviewzoom[1] = cl.mviewzoom[0];
 
-       if (cl.protocol != PROTOCOL_DARKPLACES6)
+       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
        {
                cl.stats[STAT_VIEWHEIGHT] = DEFAULT_VIEWHEIGHT;
                cl.stats[STAT_ITEMS] = 0;
@@ -652,44 +654,35 @@ void CL_ParseClientdata (void)
        {
                if (bits & (SU_PUNCH1<<i) )
                {
-                       if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6)
-                               cl.mpunchangle[0][i] = MSG_ReadAngle16i();
-                       else if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
+                       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
                                cl.mpunchangle[0][i] = MSG_ReadChar();
                        else
-                               Host_Error("CL_ParseClientData: unknown cl.protocol %i\n", cl.protocol);
+                               cl.mpunchangle[0][i] = MSG_ReadAngle16i();
                }
                if (bits & (SU_PUNCHVEC1<<i))
                {
                        if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
                                cl.mpunchvector[0][i] = MSG_ReadCoord16i();
-                       else if (cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6)
-                               cl.mpunchvector[0][i] = MSG_ReadCoord32f();
                        else
-                               Host_Error("CL_ParseClientData: unknown cl.protocol %i\n", cl.protocol);
+                               cl.mpunchvector[0][i] = MSG_ReadCoord32f();
                }
                if (bits & (SU_VELOCITY1<<i) )
                {
-                       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
+                       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
                                cl.mvelocity[0][i] = MSG_ReadChar()*16;
-                       else if (cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6)
-                               cl.mvelocity[0][i] = MSG_ReadCoord32f();
                        else
-                               Host_Error("CL_ParseClientData: unknown cl.protocol %i\n", cl.protocol);
+                               cl.mvelocity[0][i] = MSG_ReadCoord32f();
                }
        }
 
        // LordHavoc: hipnotic demos don't have this bit set but should
-       if (bits & SU_ITEMS || cl.protocol != PROTOCOL_DARKPLACES6)
+       if (bits & SU_ITEMS || cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
                cl.stats[STAT_ITEMS] = MSG_ReadLong ();
 
        cl.onground = (bits & SU_ONGROUND) != 0;
        cl.inwater = (bits & SU_INWATER) != 0;
 
-       if (cl.protocol == PROTOCOL_DARKPLACES6)
-       {
-       }
-       else if (cl.protocol == PROTOCOL_DARKPLACES5)
+       if (cl.protocol == PROTOCOL_DARKPLACES5)
        {
                cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadShort() : 0;
                cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadShort() : 0;
@@ -702,7 +695,7 @@ void CL_ParseClientdata (void)
                cl.stats[STAT_CELLS] = MSG_ReadShort();
                cl.stats[STAT_ACTIVEWEAPON] = (unsigned short) MSG_ReadShort ();
        }
-       else
+       else if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
        {
                cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
                cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
@@ -721,10 +714,10 @@ void CL_ParseClientdata (void)
 
        if (bits & SU_VIEWZOOM)
        {
-               if (cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6)
-                       cl.stats[STAT_VIEWZOOM] = (unsigned short) MSG_ReadShort();
-               else
+               if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
                        cl.stats[STAT_VIEWZOOM] = MSG_ReadByte();
+               else
+                       cl.stats[STAT_VIEWZOOM] = (unsigned short) MSG_ReadShort();
        }
 
        // check for important changes
@@ -1340,6 +1333,7 @@ void CL_ParseServerMessage(void)
 {
        int                     cmd;
        int                     i;
+       protocolversion_t protocol;
        qbyte           cmdlog[32];
        char            *cmdlogname[32], *temp;
        int                     cmdindex, cmdcount = 0;
@@ -1453,12 +1447,13 @@ void CL_ParseServerMessage(void)
 
                case svc_version:
                        i = MSG_ReadLong ();
+                       protocol = Protocol_EnumForNumber(i);
+                       if (protocol == PROTOCOL_UNKNOWN)
+                               Host_Error("CL_ParseServerMessage: Server is unrecognized protocol number (%i)\n", i);
                        // hack for unmarked Nehahra movie demos which had a custom protocol
-                       if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
-                               i = PROTOCOL_NEHAHRAMOVIE;
-                       if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_DARKPLACES6 && i != PROTOCOL_NEHAHRAMOVIE)
-                               Host_Error("CL_ParseServerMessage: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), %i (DP5), %i (DP6), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_DARKPLACES5, PROTOCOL_DARKPLACES6, PROTOCOL_NEHAHRAMOVIE);
-                       cl.protocol = i;
+                       if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && demo_nehahra.integer)
+                               protocol = PROTOCOL_NEHAHRAMOVIE;
+                       cl.protocol = protocol;
                        break;
 
                case svc_disconnect:
@@ -1753,10 +1748,8 @@ void CL_ParseServerMessage(void)
                                EntityFrame_CL_ReadFrame();
                        else if (cl.protocol == PROTOCOL_DARKPLACES4)
                                EntityFrame4_CL_ReadFrame();
-                       else if (cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6)
-                               EntityFrame5_CL_ReadFrame();
                        else
-                               Host_Error("CL_ParseServerMessage: svc_entities: unknown cl.protocol %i\n", cl.protocol);
+                               EntityFrame5_CL_ReadFrame();
                        break;
                }
        }
index 60cd20e..0e81031 100644 (file)
--- a/client.h
+++ b/client.h
@@ -351,6 +351,7 @@ typedef struct
        double receivetime;
        int buttons;
        int impulse;
+       int sequence;
 } usercmd_t;
 
 typedef struct
@@ -459,6 +460,7 @@ typedef struct client_movementqueue_s
 {
        double time;
        float frametime;
+       int sequence;
        float viewangles[3];
        float move[3];
        qboolean jump;
@@ -531,6 +533,8 @@ typedef struct
        // queue of proposed moves
        int movement_numqueue;
        client_movementqueue_t movement_queue[256];
+       int movesequence;
+       int servermovesequence;
 
 // pitch drifting vars
        float idealpitch;
@@ -596,7 +600,7 @@ typedef struct
        scoreboard_t *scores;
 
        // protocol version of the server we're connected to
-       int protocol;
+       protocolversion_t protocol;
 
        // entity database stuff
        // latest received entity frame numbers
index 0c8dc3f..0eabf12 100644 (file)
--- a/common.c
+++ b/common.c
@@ -273,19 +273,21 @@ void MSG_WriteCoord32f (sizebuf_t *sb, float f)
        MSG_WriteFloat (sb, f);
 }
 
-void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol)
+void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
 {
-       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_NEHAHRAMOVIE)
+       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE)
                MSG_WriteCoord13i (sb, f);
-       else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
+       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
-               Host_Error("MSG_WriteCoord: unknown protocol\n");
+               MSG_WriteCoord32f (sb, f);
+       //else
+       //      Host_Error("MSG_WriteCoord: unknown protocol\n");
 }
 
-void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol)
+void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
 {
        MSG_WriteCoord (sb, v[0], protocol);
        MSG_WriteCoord (sb, v[1], protocol);
@@ -314,12 +316,12 @@ void MSG_WriteAngle32f (sizebuf_t *sb, float f)
        MSG_WriteFloat (sb, f);
 }
 
-void MSG_WriteAngle (sizebuf_t *sb, float f, int protocol)
+void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
 {
-       if (protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
-               MSG_WriteAngle16i (sb, f);
-       else
+       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
                MSG_WriteAngle8i (sb, f);
+       else
+               MSG_WriteAngle16i (sb, f);
 }
 
 //
@@ -445,19 +447,19 @@ float MSG_ReadCoord32f (void)
        return MSG_ReadLittleFloat();
 }
 
-float MSG_ReadCoord (int protocol)
+float MSG_ReadCoord (protocolversion_t protocol)
 {
-       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_NEHAHRAMOVIE)
+       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE)
                return MSG_ReadCoord13i();
-       else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
+       else if (protocol == PROTOCOL_DARKPLACES1)
                return MSG_ReadCoord32f();
        else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
                return MSG_ReadCoord16i();
-       Host_Error("MSG_ReadCoord: unknown protocol\n");
-       return 0;
+       else
+               return MSG_ReadCoord32f();
 }
 
-void MSG_ReadVector (float *v, int protocol)
+void MSG_ReadVector (float *v, protocolversion_t protocol)
 {
        v[0] = MSG_ReadCoord(protocol);
        v[1] = MSG_ReadCoord(protocol);
@@ -480,12 +482,12 @@ float MSG_ReadAngle32f (void)
        return MSG_ReadFloat ();
 }
 
-float MSG_ReadAngle (int protocol)
+float MSG_ReadAngle (protocolversion_t protocol)
 {
-       if (protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
-               return MSG_ReadAngle16i ();
-       else
+       if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
                return MSG_ReadAngle8i ();
+       else
+               return MSG_ReadAngle16i ();
 }
 
 
index 8994079..419ae22 100644 (file)
--- a/common.h
+++ b/common.h
@@ -112,6 +112,24 @@ unsigned short BuffLittleShort (const qbyte *buffer);
 
 //============================================================================
 
+// 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_QUAKE, // quake (aka netquake/normalquake/nq) protocol
+       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_DARKPLACES1, // uses EntityFrame_ entity snapshot encoder/decoder which is a QuakeWorld-like entity snapshot delta compression method
+       PROTOCOL_DARKPLACES2, // 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_DARKPLACES4, // 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_DARKPLACES6, // various changes
+       PROTOCOL_DARKPLACES7, // added QuakeWorld-style movement protocol to allow more consistent prediction
+}
+protocolversion_t;
+
 void MSG_WriteChar (sizebuf_t *sb, int c);
 void MSG_WriteByte (sizebuf_t *sb, int c);
 void MSG_WriteShort (sizebuf_t *sb, int c);
@@ -124,9 +142,9 @@ void MSG_WriteAngle32f (sizebuf_t *sb, float f);
 void MSG_WriteCoord13i (sizebuf_t *sb, float f);
 void MSG_WriteCoord16i (sizebuf_t *sb, float f);
 void MSG_WriteCoord32f (sizebuf_t *sb, float f);
-void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol);
-void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol);
-void MSG_WriteAngle (sizebuf_t *sb, float f, int protocol);
+void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol);
+void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol);
+void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol);
 
 extern int                     msg_readcount;
 extern qboolean        msg_badread;            // set if a read goes beyond end of message
@@ -153,9 +171,9 @@ float MSG_ReadAngle32f (void);
 float MSG_ReadCoord13i (void);
 float MSG_ReadCoord16i (void);
 float MSG_ReadCoord32f (void);
-float MSG_ReadCoord (int protocol);
-void MSG_ReadVector (float *v, int protocol);
-float MSG_ReadAngle (int protocol);
+float MSG_ReadCoord (protocolversion_t protocol);
+void MSG_ReadVector (float *v, protocolversion_t protocol);
+float MSG_ReadAngle (protocolversion_t protocol);
 
 //============================================================================
 
diff --git a/host.c b/host.c
index c076d67..3a39f26 100644 (file)
--- a/host.c
+++ b/host.c
@@ -687,8 +687,6 @@ void Host_ServerFrame (void)
                if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive)))
                        sv.frametime = 0;
 
-               pr_global_struct->frametime = sv.frametime;
-
                // set the time and clear the general datagram
                SV_ClearDatagram();
 
index 702d149..d68b251 100644 (file)
@@ -45,7 +45,6 @@ Host_Status_f
 */
 void Host_Status_f (void)
 {
-       const char *protocolname;
        client_t *client;
        int seconds, minutes, hours = 0, j, players;
        void (*print) (const char *fmt, ...);
@@ -67,18 +66,7 @@ void Host_Status_f (void)
                        players++;
        print ("host:     %s\n", Cvar_VariableString ("hostname"));
        print ("version:  %s build %s\n", gamename, buildstring);
-       switch(sv.protocol)
-       {
-               case PROTOCOL_QUAKE: protocolname = sv.netquakecompatible ? "QUAKE" : "QUAKEDP";break;
-               case PROTOCOL_DARKPLACES1: protocolname = "PROTOCOL_DARKPLACES1";break;
-               case PROTOCOL_DARKPLACES2: protocolname = "PROTOCOL_DARKPLACES2";break;
-               case PROTOCOL_DARKPLACES3: protocolname = "PROTOCOL_DARKPLACES3";break;
-               case PROTOCOL_DARKPLACES4: protocolname = "PROTOCOL_DARKPLACES4";break;
-               case PROTOCOL_DARKPLACES5: protocolname = "PROTOCOL_DARKPLACES5";break;
-               case PROTOCOL_DARKPLACES6: protocolname = "PROTOCOL_DARKPLACES6";break;
-               default: protocolname = "PROTOCOL_UNKNOWN";break;
-       }
-       print ("protocol: %i (%s)\n", sv.protocol, protocolname);
+       print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
        print ("map:      %s\n", sv.name);
        print ("players:  %i active (%i max)\n\n", players, svs.maxclients);
        for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
index d958db4..72c257d 100755 (executable)
--- a/netconn.h
+++ b/netconn.h
@@ -116,7 +116,7 @@ typedef struct netconn_s
 
        lhnetsocket_t *mysocket;
        lhnetaddress_t peeraddress;
-       
+
        // this is mostly identical to qsocket_t from quake
 
        // if this time is reached, kick off peer
@@ -155,7 +155,7 @@ extern int playercolor;
 #define SERVERLIST_ANDMASKCOUNT                5
 #define SERVERLIST_ORMASKCOUNT         5
 
-typedef enum 
+typedef enum
 {
        // SLMO_CONTAINS is the default for strings
        // SLMO_GREATEREQUAL is the default for numbers (also used when OP == CONTAINS or NOTCONTAINS
@@ -193,7 +193,7 @@ typedef struct
        int protocol;
 } serverlist_info_t;
 
-typedef enum 
+typedef enum
 {
        SLIF_CNAME,
        SLIF_PING,
@@ -210,12 +210,12 @@ typedef enum
 typedef struct
 {
        // used to determine whether this entry should be included into the final view
-       qboolean finished; 
+       qboolean finished;
        // used to calculate ping when update comes in
        double querytime;
 
        serverlist_info_t info;
-       
+
        // legacy stuff
        char line1[128];
        char line2[128];
@@ -237,7 +237,7 @@ extern qboolean serverlist_sortdescending;
 extern int serverlist_viewcount;
 extern serverlist_entry_t *serverlist_viewlist[SERVERLIST_VIEWLISTSIZE];
 
-extern int serverlist_cachecount; 
+extern int serverlist_cachecount;
 
 extern qboolean serverlist_consoleoutput;
 
diff --git a/progs.h b/progs.h
index e4ea141..2a2605c 100644 (file)
--- a/progs.h
+++ b/progs.h
@@ -57,7 +57,7 @@ typedef struct edict_engineprivate_s
        // we should avoid extensive checking on entities already encountered
        int areagridmarknumber;
 
-       // PROTOCOL_QUAKE
+       // PROTOCOL_QUAKE, PROTOCOL_QUAKEDP, PROTOCOL_NEHAHRAMOVIE
        // baseline values
        entity_state_t baseline;
 
index eafd3e7..cb7fda6 100644 (file)
@@ -35,6 +35,71 @@ entity_state_t defaultstate =
        {0,0}//unsigned char unused[2]; // !
 };
 
+// LordHavoc: I own protocol ranges 96, 97, 3500-3599
+
+struct
+{
+       int number;
+       const char *name;
+}
+protocolversioninfo[] =
+{
+       {0, "UNKNOWN"},
+       {15, "QUAKE"},
+       {15, "QUAKEDP"},
+       {250, "NEHAHRAMOVIE"},
+       {96, "DARKPLACES1"},
+       {97, "DARKPLACES2"},
+       {3500, "DARKPLACES3"},
+       {3501, "DARKPLACES4"},
+       {3502, "DARKPLACES5"},
+       {3503, "DARKPLACES6"},
+       {3504, "DARKPLACES7"},
+       {0, NULL}
+};
+
+protocolversion_t Protocol_EnumForName(const char *s)
+{
+       int i;
+       for (i = 1;protocolversioninfo[i].name;i++)
+               if (!strcasecmp(s, protocolversioninfo[i].name))
+                       return i;
+       return PROTOCOL_UNKNOWN;
+}
+
+const char *Protocol_NameForEnum(protocolversion_t p)
+{
+       return protocolversioninfo[p].name;
+}
+
+protocolversion_t Protocol_EnumForNumber(int n)
+{
+       int i;
+       for (i = 1;protocolversioninfo[i].name;i++)
+               if (protocolversioninfo[i].number == n)
+                       return i;
+       return PROTOCOL_UNKNOWN;
+}
+
+int Protocol_NumberForEnum(protocolversion_t p)
+{
+       return protocolversioninfo[p].number;
+}
+
+void Protocol_Names(char *buffer, size_t buffersize)
+{
+       int i;
+       if (buffersize < 1)
+               return;
+       buffer[0] = 0;
+       for (i = 1;protocolversioninfo[i].name;i++)
+       {
+               if (i > 1)
+                       strlcat(buffer, " ", sizeof(buffer));
+               strlcat(buffer, protocolversioninfo[i].name, sizeof(buffer));
+       }
+}
+
 // keep track of quake entities because they need to be killed if they get stale
 int cl_lastquakeentity = 0;
 qbyte cl_isquakeentity[MAX_EDICTS];
@@ -250,8 +315,11 @@ void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_sta
                        bits |= U_GLOWCOLOR;
 
                // if extensions are disabled, clear the relevant update flags
-               if (sv.netquakecompatible)
+               if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
                        bits &= 0x7FFF;
+               if (sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+                       if (s->alpha != 255 || s->effects & EF_FULLBRIGHT)
+                               bits |= U_EXTEND1;
 
                // write the message
                if (bits >= 16777216)
@@ -289,6 +357,22 @@ void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_sta
                if (bits & U_FRAME2)            MSG_WriteByte(&buf, s->frame >> 8);
                if (bits & U_MODEL2)            MSG_WriteByte(&buf, s->modelindex >> 8);
 
+               // the nasty protocol
+               if ((bits & U_EXTEND1) && sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+               {
+                       if (s->effects & EF_FULLBRIGHT)
+                       {
+                               MSG_WriteFloat(&buf, 2); // QSG protocol version
+                               MSG_WriteFloat(&buf, s->alpha <= 0 ? 0 : (s->alpha >= 255 ? 1 : s->alpha * (1.0f / 255.0f))); // alpha
+                               MSG_WriteFloat(&buf, 1); // fullbright
+                       }
+                       else
+                       {
+                               MSG_WriteFloat(&buf, 1); // QSG protocol version
+                               MSG_WriteFloat(&buf, s->alpha <= 0 ? 0 : (s->alpha >= 255 ? 1 : s->alpha * (1.0f / 255.0f))); // alpha
+                       }
+               }
+
                // if the commit is full, we're done this frame
                if (msg->cursize + buf.cursize > msg->maxsize)
                {
@@ -392,7 +476,7 @@ void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned
                if (bits & E_ORIGIN3)
                        MSG_WriteCoord16i(msg, ent->origin[2]);
        }
-       else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
+       else
        {
                // LordHavoc: have to write flags first, as they can modify protocol
                if (bits & E_FLAGS)
@@ -416,23 +500,23 @@ void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned
                                MSG_WriteCoord32f(msg, ent->origin[2]);
                }
        }
-       if ((sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) && !(ent->flags & RENDER_LOWPRECISION))
+       if ((sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4) && (ent->flags & RENDER_LOWPRECISION))
        {
                if (bits & E_ANGLE1)
-                       MSG_WriteAngle16i(msg, ent->angles[0]);
+                       MSG_WriteAngle8i(msg, ent->angles[0]);
                if (bits & E_ANGLE2)
-                       MSG_WriteAngle16i(msg, ent->angles[1]);
+                       MSG_WriteAngle8i(msg, ent->angles[1]);
                if (bits & E_ANGLE3)
-                       MSG_WriteAngle16i(msg, ent->angles[2]);
+                       MSG_WriteAngle8i(msg, ent->angles[2]);
        }
        else
        {
                if (bits & E_ANGLE1)
-                       MSG_WriteAngle8i(msg, ent->angles[0]);
+                       MSG_WriteAngle16i(msg, ent->angles[0]);
                if (bits & E_ANGLE2)
-                       MSG_WriteAngle8i(msg, ent->angles[1]);
+                       MSG_WriteAngle16i(msg, ent->angles[1]);
                if (bits & E_ANGLE3)
-                       MSG_WriteAngle8i(msg, ent->angles[2]);
+                       MSG_WriteAngle16i(msg, ent->angles[2]);
        }
        if (bits & E_MODEL1)
                MSG_WriteByte(msg, ent->modelindex & 0xFF);
@@ -532,7 +616,7 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
                if (bits & E_ORIGIN3)
                        e->origin[2] = MSG_ReadCoord16i();
        }
-       else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6)
+       else
        {
                if (bits & E_FLAGS)
                        e->flags = MSG_ReadByte();
@@ -555,25 +639,23 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
                                e->origin[2] = MSG_ReadCoord32f();
                }
        }
-       else
-               Host_Error("EntityState_ReadFields: unknown cl.protocol %i\n", cl.protocol);
-       if ((cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6) && !(e->flags & RENDER_LOWPRECISION))
+       if ((cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4) && (e->flags & RENDER_LOWPRECISION))
        {
                if (bits & E_ANGLE1)
-                       e->angles[0] = MSG_ReadAngle16i();
+                       e->angles[0] = MSG_ReadAngle8i();
                if (bits & E_ANGLE2)
-                       e->angles[1] = MSG_ReadAngle16i();
+                       e->angles[1] = MSG_ReadAngle8i();
                if (bits & E_ANGLE3)
-                       e->angles[2] = MSG_ReadAngle16i();
+                       e->angles[2] = MSG_ReadAngle8i();
        }
        else
        {
                if (bits & E_ANGLE1)
-                       e->angles[0] = MSG_ReadAngle8i();
+                       e->angles[0] = MSG_ReadAngle16i();
                if (bits & E_ANGLE2)
-                       e->angles[1] = MSG_ReadAngle8i();
+                       e->angles[1] = MSG_ReadAngle16i();
                if (bits & E_ANGLE3)
-                       e->angles[2] = MSG_ReadAngle8i();
+                       e->angles[2] = MSG_ReadAngle16i();
        }
        if (bits & E_MODEL1)
                e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte();
@@ -1815,6 +1897,8 @@ void EntityFrame5_CL_ReadFrame(void)
        for (i = 0;i < LATESTFRAMENUMS-1;i++)
                cl.latestframenums[i] = cl.latestframenums[i+1];
        cl.latestframenums[LATESTFRAMENUMS-1] = MSG_ReadLong();
+       if (cl.protocol != PROTOCOL_QUAKE && cl.protocol != PROTOCOL_QUAKEDP && cl.protocol != PROTOCOL_NEHAHRAMOVIE && cl.protocol != PROTOCOL_DARKPLACES1 && cl.protocol != PROTOCOL_DARKPLACES2 && cl.protocol != PROTOCOL_DARKPLACES3 && cl.protocol != PROTOCOL_DARKPLACES4 && cl.protocol != PROTOCOL_DARKPLACES5 && cl.protocol != PROTOCOL_DARKPLACES6)
+               cl.servermovesequence = MSG_ReadLong();
        // read entity numbers until we find a 0x8000
        // (which would be remove world entity, but is actually a terminator)
        while ((n = (unsigned short)MSG_ReadShort()) != 0x8000 && !msg_badread)
@@ -1933,7 +2017,7 @@ void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum)
 int entityframe5_prioritychaincounts[E5_PROTOCOL_PRIORITYLEVELS];
 unsigned short entityframe5_prioritychains[E5_PROTOCOL_PRIORITYLEVELS][ENTITYFRAME5_MAXSTATES];
 
-void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int *stats)
+void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int *stats, int movesequence)
 {
        const entity_state_t *n;
        int i, num, l, framenum, packetlognumber, priority;
@@ -2038,7 +2122,7 @@ void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int num
        packetlog->packetnumber = framenum;
        packetlog->numstates = 0;
        // write stat updates
-       if (sv.protocol == PROTOCOL_DARKPLACES6)
+       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)
        {
                for (i = 0;i < MAX_CL_STATS;i++)
                {
@@ -2065,6 +2149,8 @@ void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int num
        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)
+               MSG_WriteLong(msg, movesequence);
        for (priority = E5_PROTOCOL_PRIORITYLEVELS - 1;priority >= 0 && packetlog->numstates < ENTITYFRAME5_MAXSTATES;priority--)
        {
                for (i = 0;i < entityframe5_prioritychaincounts[priority] && packetlog->numstates < ENTITYFRAME5_MAXSTATES;i++)
index b0ff854..b749fe6 100644 (file)
@@ -22,27 +22,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #ifndef PROTOCOL_H
 #define PROTOCOL_H
 
-// LordHavoc: I own protocol ranges 96, 97, 3500-3599
+// protocolversion_t is defined in common.h
 
-// quake or darkplaces extended quake entity protocol
-// (still used by TomazQuake and others)
-#define        PROTOCOL_QUAKE 15
-
-// neh_gl entity protocol
-// (failed QSG protocol, used only by nehahra movie)
-#define        PROTOCOL_NEHAHRAMOVIE 250
-
-// entityframe protocol
-#define        PROTOCOL_DARKPLACES1 96
-#define        PROTOCOL_DARKPLACES2 97
-
-// entityframe4 protocol
-#define        PROTOCOL_DARKPLACES3 3500
-#define PROTOCOL_DARKPLACES4 3501
-
-// entityframe5 protocol
-#define PROTOCOL_DARKPLACES5 3502
-#define PROTOCOL_DARKPLACES6 3503
+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);
+void Protocol_Names(char *buffer, size_t buffersize);
 
 // model effects
 #define        EF_ROCKET       1                       // leave a trail
@@ -767,7 +753,7 @@ int EntityState5_DeltaBitsForState(entity_state_t *o, entity_state_t *n);
 void EntityFrame5_CL_ReadFrame(void);
 void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum);
 void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum);
-void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int *stats);
+void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int *stats, int movesequence);
 
 extern cvar_t developer_networkentities;
 
index a62603c..a35b42c 100644 (file)
--- a/server.h
+++ b/server.h
@@ -48,9 +48,7 @@ typedef struct
        qboolean loadgame;
 
        // one of the PROTOCOL_ values
-       int protocol;
-       // this disables extensions when using PROTOCOL_QUAKE
-       qboolean netquakecompatible;
+       protocolversion_t protocol;
 
        // used for running multiple steps in one frame, etc
        double timer;
@@ -134,6 +132,7 @@ typedef struct client_s
        // communications handle
        netconn_t *netconnection;
 
+       int movesequence;
        // movement
        usercmd_t cmd;
        // intended motion calced from cmd
index 74d9da5..d1aeb0b 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -21,9 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-// select which protocol to host, by name
-// this is named the same as PROTOCOL_DARKPLACES6 for example, minus the PROTOCOL_ prefix
-cvar_t sv_protocolname = {0, "sv_protocolname", "DARKPLACES6"};
+// select which protocol to host, this is fed to Protocol_EnumForName
+cvar_t sv_protocolname = {0, "sv_protocolname", "DARKPLACES7"};
 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0"};
 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"};
 
@@ -310,12 +309,15 @@ void SV_SendServerinfo (client_t *client)
        if (client->entitydatabase5)
                EntityFrame5_FreeDatabase(client->entitydatabase5);
 
-       if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
-               client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
-       if (sv.protocol == PROTOCOL_DARKPLACES4)
-               client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
-       if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
-               client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
+       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
+       {
+               if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
+                       client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
+               else if (sv.protocol == PROTOCOL_DARKPLACES4)
+                       client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
+               else
+                       client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
+       }
 
        SZ_Clear (&client->message);
        MSG_WriteByte (&client->message, svc_print);
@@ -323,7 +325,7 @@ void SV_SendServerinfo (client_t *client)
        MSG_WriteString (&client->message,message);
 
        MSG_WriteByte (&client->message, svc_serverinfo);
-       MSG_WriteLong (&client->message, sv.protocol);
+       MSG_WriteLong (&client->message, Protocol_NumberForEnum(sv.protocol));
        MSG_WriteByte (&client->message, svs.maxclients);
 
        if (!coop.integer && deathmatch.integer)
@@ -668,7 +670,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                        return;
                // always send world submodels, they don't generate much traffic
                // except in PROTOCOL_QUAKE where they hog bandwidth like crazy
-               else if (!(s->effects & EF_NODEPTHTEST) && (!(isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') || sv.protocol == PROTOCOL_QUAKE))
+               else if (!(s->effects & EF_NODEPTHTEST) && (!(isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') || (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)))
                {
                        Mod_CheckLoaded(model);
                        // entity has survived every check so far, check if visible
@@ -811,7 +813,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg,
                Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace);
 
        if (client->entitydatabase5)
-               EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats);
+               EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
        else if (client->entitydatabase4)
                EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
        else if (client->entitydatabase)
@@ -916,7 +918,7 @@ void SV_WriteClientdataToMessage (client_t *client, edict_t *ent, sizebuf_t *msg
        {
                if (ent->v->punchangle[i])
                        bits |= (SU_PUNCH1<<i);
-               if (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_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
                        if (punchvector[i])
                                bits |= (SU_PUNCHVEC1<<i);
                if (ent->v->velocity[i])
@@ -944,7 +946,7 @@ void SV_WriteClientdataToMessage (client_t *client, edict_t *ent, sizebuf_t *msg
        //stats[STAT_SECRETS] = pr_global_struct->found_secrets;
        //stats[STAT_MONSTERS] = pr_global_struct->killed_monsters;
 
-       if (sv.protocol != PROTOCOL_DARKPLACES6)
+       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)
        {
                if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
                bits |= SU_ITEMS;
@@ -952,7 +954,7 @@ void SV_WriteClientdataToMessage (client_t *client, edict_t *ent, sizebuf_t *msg
                if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
                bits |= SU_WEAPON;
                // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
-               if (sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+               if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
                        if (viewzoom != 255)
                                bits |= SU_VIEWZOOM;
        }
@@ -980,26 +982,23 @@ void SV_WriteClientdataToMessage (client_t *client, edict_t *ent, sizebuf_t *msg
        {
                if (bits & (SU_PUNCH1<<i))
                {
-                       if (sv.protocol == PROTOCOL_QUAKE)
+                       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
                                MSG_WriteChar(msg, ent->v->punchangle[i]);
-                       else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
+                       else
                                MSG_WriteAngle16i(msg, ent->v->punchangle[i]);
                }
-               if (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 (bits & (SU_PUNCHVEC1<<i))
                {
-                       if (bits & (SU_PUNCHVEC1<<i))
-                       {
-                               if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
-                                       MSG_WriteCoord16i(msg, punchvector[i]);
-                               else if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
-                                       MSG_WriteCoord32f(msg, punchvector[i]);
-                       }
+                       if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+                               MSG_WriteCoord16i(msg, punchvector[i]);
+                       else
+                               MSG_WriteCoord32f(msg, punchvector[i]);
                }
                if (bits & (SU_VELOCITY1<<i))
                {
                        if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
                                MSG_WriteChar(msg, ent->v->velocity[i] * (1.0f / 16.0f));
-                       else if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
+                       else
                                MSG_WriteCoord32f(msg, ent->v->velocity[i]);
                }
        }
@@ -1025,7 +1024,7 @@ void SV_WriteClientdataToMessage (client_t *client, edict_t *ent, sizebuf_t *msg
                if (bits & SU_VIEWZOOM)
                        MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
        }
-       else if (sv.protocol != PROTOCOL_DARKPLACES6)
+       else 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)
        {
                if (bits & SU_WEAPONFRAME)
                        MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
@@ -1050,9 +1049,9 @@ void SV_WriteClientdataToMessage (client_t *client, edict_t *ent, sizebuf_t *msg
                        MSG_WriteByte (msg, stats[STAT_WEAPON]);
                if (bits & SU_VIEWZOOM)
                {
-                       if (sv.protocol == PROTOCOL_DARKPLACES4)
+                       if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
                                MSG_WriteByte (msg, min(stats[STAT_VIEWZOOM], 255));
-                       else if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
+                       else
                                MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
                }
        }
@@ -1076,9 +1075,17 @@ qboolean SV_SendClientDatagram (client_t *client)
                maxsize = sizeof(sv_sendclientdatagram_buf);
                maxsize2 = sizeof(sv_sendclientdatagram_buf);
        }
-       else if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
+       else 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)
        {
-               // PROTOCOL_DARKPLACES5 supports packet size limiting of updates
+               // no rate limiting support on older protocols because dp protocols
+               // 1-4 kick the client off if they overflow, and quake protocol shows
+               // less than the full entity set if rate limited
+               maxsize = 1400;
+               maxsize2 = 1400;
+       }
+       else
+       {
+               // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
                maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
                if (sv_maxrate.integer != maxrate)
                        Cvar_SetValueQuick(&sv_maxrate, maxrate);
@@ -1088,14 +1095,6 @@ qboolean SV_SendClientDatagram (client_t *client)
                maxsize = bound(100, rate, 1400);
                maxsize2 = 1400;
        }
-       else
-       {
-               // no rate limiting support on older protocols because dp protocols
-               // 1-4 kick the client off if they overflow, and quake protocol shows
-               // less than the full entity set if rate limited
-               maxsize = 1400;
-               maxsize2 = 1400;
-       }
 
        msg.data = sv_sendclientdatagram_buf;
        msg.maxsize = maxsize;
@@ -1336,7 +1335,7 @@ SV_ModelIndex
 */
 int SV_ModelIndex(const char *s, int precachemode)
 {
-       int i, limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
+       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
        char filename[MAX_QPATH];
        if (!s || !*s)
                return 0;
@@ -1350,7 +1349,7 @@ int SV_ModelIndex(const char *s, int precachemode)
                {
                        if (precachemode)
                        {
-                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || 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_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))
                                {
                                        Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
                                        return 0;
@@ -1359,7 +1358,7 @@ int SV_ModelIndex(const char *s, int precachemode)
                                        Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
                                strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
                                sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
-                               if (sv.protocol == PROTOCOL_DARKPLACES6 && sv.state != ss_loading)
+                               if (sv.state != ss_loading)
                                {
                                        MSG_WriteByte(&sv.reliable_datagram, svc_precache);
                                        MSG_WriteShort(&sv.reliable_datagram, i);
@@ -1385,7 +1384,7 @@ SV_SoundIndex
 */
 int SV_SoundIndex(const char *s, int precachemode)
 {
-       int i, limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
+       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
        char filename[MAX_QPATH];
        if (!s || !*s)
                return 0;
@@ -1399,7 +1398,7 @@ int SV_SoundIndex(const char *s, int precachemode)
                {
                        if (precachemode)
                        {
-                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || 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_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))
                                {
                                        Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
                                        return 0;
@@ -1407,7 +1406,7 @@ int SV_SoundIndex(const char *s, int precachemode)
                                if (precachemode == 1)
                                        Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
                                strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
-                               if (sv.protocol == PROTOCOL_DARKPLACES6 && sv.state != ss_loading)
+                               if (sv.state != ss_loading)
                                {
                                        MSG_WriteByte(&sv.reliable_datagram, svc_precache);
                                        MSG_WriteShort(&sv.reliable_datagram, i + 32768);
@@ -1661,30 +1660,13 @@ void SV_SpawnServer (const char *server)
 
        strlcpy (sv.name, server, sizeof (sv.name));
 
-       sv.netquakecompatible = false;
-       if (!strcasecmp(sv_protocolname.string, "QUAKE"))
+       sv.protocol = Protocol_EnumForName(sv_protocolname.string);
+       if (sv.protocol == PROTOCOL_UNKNOWN)
        {
+               char buffer[1024];
+               Protocol_Names(buffer, sizeof(buffer));
+               Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
                sv.protocol = PROTOCOL_QUAKE;
-               sv.netquakecompatible = true;
-       }
-       else if (!strcasecmp(sv_protocolname.string, "QUAKEDP"))
-               sv.protocol = PROTOCOL_QUAKE;
-       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES1"))
-               sv.protocol = PROTOCOL_DARKPLACES1;
-       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES2"))
-               sv.protocol = PROTOCOL_DARKPLACES2;
-       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES3"))
-               sv.protocol = PROTOCOL_DARKPLACES3;
-       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES4"))
-               sv.protocol = PROTOCOL_DARKPLACES4;
-       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES5"))
-               sv.protocol = PROTOCOL_DARKPLACES5;
-       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES6"))
-               sv.protocol = PROTOCOL_DARKPLACES6;
-       else
-       {
-               sv.protocol = PROTOCOL_DARKPLACES6;
-               Con_Printf("Unknown sv_protocolname \"%s\", valid values are QUAKE, QUAKEDP, DARKPLACES1, DARKPLACES2, DARKPLACES3, DARKPLACES4, DARKPLACES5, DARKPLACES6, falling back to DARKPLACES6 protocol\n", sv_protocolname.string);
        }
 
 // load progs to get entity field count
@@ -1803,14 +1785,14 @@ void SV_SpawnServer (const char *server)
 // run two frames to allow everything to settle
        for (i = 0;i < 2;i++)
        {
-               sv.frametime = pr_global_struct->frametime = host_frametime = 0.1;
+               sv.frametime = host_frametime = 0.1;
                SV_Physics ();
        }
 
        Mod_PurgeUnused();
 
 // create a baseline for more efficient communications
-       if (sv.protocol == PROTOCOL_QUAKE)
+       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
                SV_CreateBaseline ();
 
 // send serverinfo to all connected clients
index 24513b0..f02cf84 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -1340,6 +1340,121 @@ void SV_Physics_Step (edict_t *ent)
 
 //============================================================================
 
+void SV_Physics_Entity (edict_t *ent, qboolean runmove)
+{
+       int i = ent - sv.edicts;
+       if (i >= 1 && i <= svs.maxclients)
+       {
+               // apply the latest accepted move to the entity fields
+               SV_ApplyClientMove();
+               // make sure the velocity is sane (not a NaN)
+               SV_CheckVelocity(ent);
+               // LordHavoc: QuakeC replacement for SV_ClientThink (player movement)
+               if (SV_PlayerPhysicsQC)
+               {
+                       pr_global_struct->time = sv.time;
+                       pr_global_struct->self = EDICT_TO_PROG(ent);
+                       PR_ExecuteProgram ((func_t)(SV_PlayerPhysicsQC - pr_functions), "QC function SV_PlayerPhysics is missing");
+               }
+               else
+                       SV_ClientThink ();
+               // make sure the velocity is sane (not a NaN)
+               SV_CheckVelocity(ent);
+               // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
+               // player_run/player_stand1 does not horribly malfunction if the
+               // velocity becomes a number that is both == 0 and != 0
+               // (sounds to me like NaN but to be absolutely safe...)
+               if (DotProduct(ent->v->velocity, ent->v->velocity) < 0.0001)
+                       VectorClear(ent->v->velocity);
+               // call standard client pre-think
+               pr_global_struct->time = sv.time;
+               pr_global_struct->self = EDICT_TO_PROG(ent);
+               PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
+               SV_CheckVelocity (ent);
+       }
+
+       // LordHavoc: merged client and normal entity physics
+       switch ((int) ent->v->movetype)
+       {
+       case MOVETYPE_PUSH:
+       case MOVETYPE_FAKEPUSH:
+               SV_Physics_Pusher (ent);
+               break;
+       case MOVETYPE_NONE:
+               // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
+               if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
+                       SV_RunThink (ent);
+               break;
+       case MOVETYPE_FOLLOW:
+               SV_Physics_Follow (ent);
+               break;
+       case MOVETYPE_NOCLIP:
+               if (SV_RunThink(ent))
+               {
+                       SV_CheckWater(ent);
+                       VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
+                       VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
+               }
+               // relink normal entities here, players always get relinked so don't relink twice
+               if (!(i > 0 && i <= svs.maxclients))
+                       SV_LinkEdict(ent, false);
+               break;
+       case MOVETYPE_STEP:
+               SV_Physics_Step (ent);
+               break;
+       case MOVETYPE_WALK:
+               if (SV_RunThink (ent))
+               {
+                       if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
+                               SV_AddGravity (ent);
+                       SV_CheckStuck (ent);
+                       SV_WalkMove (ent);
+                       // relink normal entities here, players always get relinked so don't relink twice
+                       if (!(i > 0 && i <= svs.maxclients))
+                               SV_LinkEdict (ent, true);
+               }
+               break;
+       case MOVETYPE_TOSS:
+       case MOVETYPE_BOUNCE:
+       case MOVETYPE_BOUNCEMISSILE:
+       case MOVETYPE_FLYMISSILE:
+               // regular thinking
+               if (SV_RunThink (ent) && runmove)
+                       SV_Physics_Toss (ent);
+               break;
+       case MOVETYPE_FLY:
+               if (SV_RunThink (ent) && runmove)
+               {
+                       if (i > 0 && i <= svs.maxclients)
+                       {
+                               SV_CheckWater (ent);
+                               SV_WalkMove (ent);
+                       }
+                       else
+                               SV_Physics_Toss (ent);
+               }
+               break;
+       default:
+               Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
+               break;
+       }
+
+       if (i >= 1 && i <= svs.maxclients)
+       {
+               SV_CheckVelocity (ent);
+
+               // call standard player post-think
+               SV_LinkEdict (ent, true);
+
+               SV_CheckVelocity (ent);
+
+               pr_global_struct->time = sv.time;
+               pr_global_struct->self = EDICT_TO_PROG(ent);
+               PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
+       }
+}
+
+
 /*
 ================
 SV_Physics
@@ -1356,6 +1471,7 @@ void SV_Physics (void)
        pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
        pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
        pr_global_struct->time = sv.time;
+       pr_global_struct->frametime = sv.frametime;
        PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
 
        newnum_edicts = 0;
@@ -1386,115 +1502,13 @@ void SV_Physics (void)
                                continue;
                        }
                        // connected slot
-                       // apply the latest accepted move to the entity fields
-                       SV_ApplyClientMove();
-                       // make sure the velocity is sane (not a NaN)
-                       SV_CheckVelocity(ent);
-                       // LordHavoc: QuakeC replacement for SV_ClientThink (player movement)
-                       if (SV_PlayerPhysicsQC)
-                       {
-                               pr_global_struct->time = sv.time;
-                               pr_global_struct->self = EDICT_TO_PROG(ent);
-                               PR_ExecuteProgram ((func_t)(SV_PlayerPhysicsQC - pr_functions), "QC function SV_PlayerPhysics is missing");
-                       }
-                       else
-                               SV_ClientThink ();
-                       // make sure the velocity is sane (not a NaN)
-                       SV_CheckVelocity(ent);
-                       // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
-                       // player_run/player_stand1 does not horribly malfunction if the
-                       // velocity becomes a number that is both == 0 and != 0
-                       // (sounds to me like NaN but to be absolutely safe...)
-                       if (DotProduct(ent->v->velocity, ent->v->velocity) < 0.0001)
-                               VectorClear(ent->v->velocity);
-                       // call standard client pre-think
-                       pr_global_struct->time = sv.time;
-                       pr_global_struct->self = EDICT_TO_PROG(ent);
-                       PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
-                       SV_CheckVelocity (ent);
+                       if (host_client->movesequence)
+                               continue; // return if running asynchronously
                }
                else if (sv_freezenonclients.integer)
                        continue;
 
-               // LordHavoc: merged client and normal entity physics
-               switch ((int) ent->v->movetype)
-               {
-               case MOVETYPE_PUSH:
-               case MOVETYPE_FAKEPUSH:
-                       SV_Physics_Pusher (ent);
-                       break;
-               case MOVETYPE_NONE:
-                       // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
-                       if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
-                               SV_RunThink (ent);
-                       break;
-               case MOVETYPE_FOLLOW:
-                       SV_Physics_Follow (ent);
-                       break;
-               case MOVETYPE_NOCLIP:
-                       if (SV_RunThink(ent))
-                       {
-                               SV_CheckWater(ent);
-                               VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
-                               VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
-                       }
-                       // relink normal entities here, players always get relinked so don't relink twice
-                       if (!(i > 0 && i <= svs.maxclients))
-                               SV_LinkEdict(ent, false);
-                       break;
-               case MOVETYPE_STEP:
-                       SV_Physics_Step (ent);
-                       break;
-               case MOVETYPE_WALK:
-                       if (SV_RunThink (ent))
-                       {
-                               if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
-                                       SV_AddGravity (ent);
-                               SV_CheckStuck (ent);
-                               SV_WalkMove (ent);
-                               // relink normal entities here, players always get relinked so don't relink twice
-                               if (!(i > 0 && i <= svs.maxclients))
-                                       SV_LinkEdict (ent, true);
-                       }
-                       break;
-               case MOVETYPE_TOSS:
-               case MOVETYPE_BOUNCE:
-               case MOVETYPE_BOUNCEMISSILE:
-               case MOVETYPE_FLYMISSILE:
-                       // regular thinking
-                       if (SV_RunThink (ent) && runmove[i])
-                               SV_Physics_Toss (ent);
-                       break;
-               case MOVETYPE_FLY:
-                       if (SV_RunThink (ent) && runmove[i])
-                       {
-                               if (i > 0 && i <= svs.maxclients)
-                               {
-                                       SV_CheckWater (ent);
-                                       SV_WalkMove (ent);
-                               }
-                               else
-                                       SV_Physics_Toss (ent);
-                       }
-                       break;
-               default:
-                       Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
-                       break;
-               }
-
-               if (i >= 1 && i <= svs.maxclients)
-               {
-                       SV_CheckVelocity (ent);
-
-                       // call standard player post-think
-                       SV_LinkEdict (ent, true);
-
-                       SV_CheckVelocity (ent);
-
-                       pr_global_struct->time = sv.time;
-                       pr_global_struct->self = EDICT_TO_PROG(ent);
-                       PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
-               }
+               SV_Physics_Entity(ent, runmove[i]);
        }
 
        if (pr_global_struct->force_retouch > 0)
index 96ed45f..b9d44e9 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -602,17 +602,21 @@ void SV_ClientThink(void)
 SV_ReadClientMove
 ===================
 */
-extern cvar_t cl_movement_latency;
+extern void SV_Physics_Entity (edict_t *ent, qboolean runmove);
 void SV_ReadClientMove (void)
 {
        int i;
+       double oldmovetime;
        usercmd_t *move = &host_client->cmd;
 
+       oldmovetime = move->time;
        memset(move, 0, sizeof(usercmd_t));
 
        if (msg_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_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5 && sv.protocol != PROTOCOL_DARKPLACES6)
+               move->sequence = MSG_ReadLong ();
        move->time = MSG_ReadFloat ();
        if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        move->receivetime = sv.time;
@@ -620,11 +624,13 @@ void SV_ReadClientMove (void)
        // read current angles
        for (i = 0;i < 3;i++)
        {
-               if (sv.protocol == PROTOCOL_QUAKE)
+               if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
                        move->viewangles[i] = MSG_ReadAngle8i();
+               else if (sv.protocol == PROTOCOL_DARKPLACES1)
+                       move->viewangles[i] = MSG_ReadAngle16i();
                else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
                        move->viewangles[i] = MSG_ReadAngle32f();
-               else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6)
+               else
                        move->viewangles[i] = MSG_ReadAngle16i();
        }
        if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
@@ -636,10 +642,10 @@ void SV_ReadClientMove (void)
        if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
 
        // read buttons
-       if (sv.protocol == PROTOCOL_DARKPLACES6)
-               move->buttons = MSG_ReadLong ();
-       else
+       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)
                move->buttons = MSG_ReadByte ();
+       else
+               move->buttons = MSG_ReadLong ();
        if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
 
        // read impulse
@@ -649,7 +655,7 @@ void SV_ReadClientMove (void)
        if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
 
        // PRYDON_CLIENTCURSOR
-       if (sv.protocol == PROTOCOL_DARKPLACES6)
+       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)
        {
                // 30 bytes
                move->cursor_screen[0] = MSG_ReadShort() * (1.0f / 32767.0f);
@@ -672,6 +678,23 @@ void SV_ReadClientMove (void)
                        move->cursor_entitynumber = 0;
                if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        }
+
+       if (!host_client->spawned)
+               memset(move, 0, sizeof(*move));
+       else
+       {
+               host_client->movesequence = move->sequence;
+               if (host_client->movesequence)
+               {
+                       double frametime = move->time - oldmovetime;
+                       double oldframetime = pr_global_struct->frametime;
+                       if (frametime > 0.1)
+                               frametime = 0.1;
+                       pr_global_struct->frametime = frametime;
+                       SV_Physics_Entity(host_client->edict, true);
+                       pr_global_struct->frametime = oldframetime;
+               }
+       }
 }
 
 void SV_ApplyClientMove (void)