new entity protocol, GREATLY improved over quake, massive net traffic reduction
authorlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 18 Feb 2002 06:35:09 +0000 (06:35 +0000)
committerlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 18 Feb 2002 06:35:09 +0000 (06:35 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@1534 d7cf8633-e32d-0410-b094-e92efae38249

15 files changed:
chase.c
cl_input.c
cl_main.c
cl_parse.c
client.h
common.c
common.h
pr_cmds.c
progs.h
protocol.c
protocol.h
server.h
sv_main.c
sv_user.c
view.c

diff --git a/chase.c b/chase.c
index 13c9aa5..1a9da00 100644 (file)
--- a/chase.c
+++ b/chase.c
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "quakedef.h"
 
 cvar_t chase_back = {CVAR_SAVE, "chase_back", "48"};
-cvar_t chase_up = {CVAR_SAVE, "chase_up", "48"};
+cvar_t chase_up = {CVAR_SAVE, "chase_up", "24"};
 cvar_t chase_active = {CVAR_SAVE, "chase_active", "0"};
 
 void Chase_Init (void)
index 481f843..11975ce 100644 (file)
@@ -392,7 +392,7 @@ void CL_SendMove (usercmd_t *cmd)
                for (i=0 ; i<3 ; i++)
                        MSG_WriteAngle (&buf, cl.viewangles[i]);
        }
-       
+
     MSG_WriteShort (&buf, forwardmove);
     MSG_WriteShort (&buf, sidemove);
     MSG_WriteShort (&buf, upmove);
@@ -402,11 +402,11 @@ void CL_SendMove (usercmd_t *cmd)
 // send button bits
 //
        bits = 0;
-       
+
        if ( in_attack.state & 3 )
                bits |= 1;
        in_attack.state &= ~2;
-       
+
        if (in_jump.state & 3)
                bits |= 2;
        in_jump.state &= ~2;
@@ -417,12 +417,20 @@ void CL_SendMove (usercmd_t *cmd)
        if (in_button6.state & 3) bits |=  32;in_button6.state &= ~2;
        if (in_button7.state & 3) bits |=  64;in_button7.state &= ~2;
        if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2;
-       
+
     MSG_WriteByte (&buf, bits);
 
     MSG_WriteByte (&buf, in_impulse);
        in_impulse = 0;
 
+       // LordHavoc: should we ack this on receipt instead?  would waste net bandwidth though
+       i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase);
+       if (i > 0)
+       {
+               MSG_WriteByte (&buf, clc_ackentities);
+               MSG_WriteLong (&buf, i);
+       }
+
 //
 // deliver the message
 //
index c2f433c..8eab435 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -287,44 +287,24 @@ should be put at.
 */
 static float CL_LerpPoint (void)
 {
-       float   f, frac;
+       float   f;
 
-       f = cl.mtime[0] - cl.mtime[1];
+       // dropped packet, or start of demo
+       if (cl.mtime[1] < cl.mtime[0] - 0.1)
+               cl.mtime[1] = cl.mtime[0] - 0.1;
+
+       cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
 
        // LordHavoc: lerp in listen games as the server is being capped below the client (usually)
+       f = cl.mtime[0] - cl.mtime[1];
        if (!f || cl_nolerp.integer || cls.timedemo || (sv.active && svs.maxclients == 1))
        {
                cl.time = cl.mtime[0];
                return 1;
        }
 
-       if (f > 0.1)
-       {       // dropped packet, or start of demo
-               cl.mtime[1] = cl.mtime[0] - 0.1;
-               f = 0.1;
-       }
-       frac = (cl.time - cl.mtime[1]) / f;
-//     Con_Printf ("frac: %f\n",frac);
-       if (frac < 0)
-       {
-               if (frac < -0.01)
-               {
-                       cl.time = cl.mtime[1];
-//                     Con_Printf ("low frac\n");
-               }
-               frac = 0;
-       }
-       else if (frac > 1)
-       {
-               if (frac > 1.01)
-               {
-                       cl.time = cl.mtime[0];
-//                     Con_Printf ("high frac\n");
-               }
-               frac = 1;
-       }
-
-       return frac;
+       f = (cl.time - cl.mtime[1]) / f;
+       return bound(0, f, 1);
 }
 
 static void CL_RelinkStaticEntities(void)
@@ -355,8 +335,6 @@ static void CL_RelinkNetworkEntities()
        else
                bobjoffset = 0;
 
-       CL_RelinkStaticEntities();
-
 // start on the entity after the world
        for (i = 1, ent = cl_entities + 1;i < MAX_EDICTS /*cl.num_entities*/;i++, ent++)
        {
@@ -648,13 +626,22 @@ static void CL_RelinkNetworkEntities()
        }
 }
 
-static void CL_LerpPlayerVelocity (void)
+void CL_LerpPlayerEye(float frac)
 {
-       int i;
-       float frac, d;
+       if (cl.entitydatabase.numframes)
+       {
+               cl.viewentorigin[0] = cl.viewentoriginold[0] + frac * (cl.viewentoriginnew[0] - cl.viewentoriginold[0]);
+               cl.viewentorigin[1] = cl.viewentoriginold[1] + frac * (cl.viewentoriginnew[1] - cl.viewentoriginold[1]);
+               cl.viewentorigin[2] = cl.viewentoriginold[2] + frac * (cl.viewentoriginnew[2] - cl.viewentoriginold[2]);
+       }
+       else
+               VectorCopy (cl_entities[cl.viewentity].render.origin, cl.viewentorigin);
+}
 
-       // fraction from previous network update to current
-       frac = CL_LerpPoint ();
+static void CL_LerpPlayerVelocity (float frac)
+{
+       int i;
+       float d;
 
        for (i = 0;i < 3;i++)
                cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
@@ -751,13 +738,21 @@ static void CL_RelinkEffects()
 
 void CL_RelinkEntities (void)
 {
+       float frac;
+
+       // fraction from previous network update to current
+       frac = CL_LerpPoint ();
+
        CL_DecayLights ();
-       CL_LerpPlayerVelocity();
+       CL_RelinkStaticEntities();
        CL_RelinkNetworkEntities();
        TraceLine_ScanForBModels();
        CL_RelinkEffects();
        CL_MoveParticles();
        CL_UpdateTEnts();
+
+       CL_LerpPlayerEye(frac);
+       CL_LerpPlayerVelocity(frac);
 }
 
 
index 4719d72..aac1a73 100644 (file)
@@ -48,7 +48,7 @@ char *svc_strings[128] =
        "svc_updatecolors",     // [byte] [byte]
        "svc_particle",         // [vec3] <variable>
        "svc_damage",                   // [byte] impact [byte] blood [vec3] from
-       
+
        "svc_spawnstatic",
        "OBSOLETE svc_spawnbinary",
        "svc_spawnbaseline",
@@ -99,7 +99,7 @@ void CL_Parse_Init(void)
 }
 
 qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
-qboolean dpprotocol; // LordHavoc: whether or not the current network stream is the enhanced DarkPlaces protocol
+int dpprotocol; // LordHavoc: version of network protocol, or 0 if not DarkPlaces
 
 /*
 ===============
@@ -360,9 +360,9 @@ void CL_ParseServerInfo (void)
 
 // parse protocol version number
        i = MSG_ReadLong ();
-       if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
+       if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != 250)
        {
-               Con_Printf ("Server returned version %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
+               Con_Printf ("Server is protocol %i, not %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, PROTOCOL_VERSION);
                return;
        }
        Nehahrademcompatibility = false;
@@ -370,7 +370,9 @@ void CL_ParseServerInfo (void)
                Nehahrademcompatibility = true;
        if (cls.demoplayback && demo_nehahra.integer)
                Nehahrademcompatibility = true;
-       dpprotocol = i == DPPROTOCOL_VERSION;
+       dpprotocol = i;
+       if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2)
+               dpprotocol = 0;
 
 // parse maxclients
        cl.maxclients = MSG_ReadByte ();
@@ -533,12 +535,6 @@ void CL_ParseUpdate (int bits)
        entity_t *ent;
        entity_state_t new;
 
-       if (cls.signon == SIGNONS - 1)
-       {       // first update is the final signon stage
-               cls.signon = SIGNONS;
-               CL_SignonReply ();
-       }
-
        if (bits & U_MOREBITS)
                bits |= (MSG_ReadByte()<<8);
        if ((bits & U_EXTEND1) && (!Nehahrademcompatibility))
@@ -660,6 +656,27 @@ void CL_ParseUpdate (int bits)
        }
 }
 
+void CL_ReadEntityFrame(void)
+{
+       entity_t *ent;
+       entity_state_t *s;
+       entity_frame_t entityframe;
+       int i;
+       EntityFrame_Read(&cl.entitydatabase);
+       EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
+       for (i = 0;i < entityframe.numentities;i++)
+       {
+               s = &entityframe.entitydata[i];
+               entkill[s->number] = 0;
+               ent = &cl_entities[s->number];
+               memcpy(&ent->state_previous, &ent->state_current, sizeof(*s));
+               memcpy(&ent->state_current, s, sizeof(*s));
+               ent->state_current.time = cl.mtime[0];
+       }
+       VectorCopy(cl.viewentoriginnew, cl.viewentoriginold);
+       VectorCopy(entityframe.eye, cl.viewentoriginnew);
+}
+
 char *bitprofilenames[32] =
 {
        "U_MOREBITS",
@@ -801,7 +818,7 @@ void CL_ParseClientdata (int bits)
                else
                        cl.punchangle[i] = 0;
                if (bits & (SU_PUNCHVEC1<<i))
-                       cl.punchvector[i] = MSG_ReadFloatCoord();
+                       cl.punchvector[i] = MSG_ReadCoord();
                else
                        cl.punchvector[i] = 0;
                if (bits & (SU_VELOCITY1<<i) )
@@ -889,7 +906,7 @@ void CL_ParseStaticSound (int large)
                sound_num = MSG_ReadByte ();
        vol = MSG_ReadByte ();
        atten = MSG_ReadByte ();
-       
+
        S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
 }
 
@@ -938,7 +955,7 @@ void CL_ParseServerMessage (void)
        byte            cmdlog[32];
        char            *cmdlogname[32], *temp;
        int                     cmdindex, cmdcount = 0;
-       
+
 //
 // if recording demos, copy the message out
 //
@@ -946,8 +963,8 @@ void CL_ParseServerMessage (void)
                Con_Printf ("%i ",net_message.cursize);
        else if (cl_shownet.integer == 2)
                Con_Printf ("------------------\n");
-       
-       cl.onground = false;    // unless the server says otherwise     
+
+       cl.onground = false;    // unless the server says otherwise
 //
 // parse the message
 //
@@ -955,7 +972,7 @@ void CL_ParseServerMessage (void)
 
        entitiesupdated = false;
        CL_EntityUpdateSetup();
-       
+
        while (1)
        {
                if (msg_badread)
@@ -980,6 +997,11 @@ void CL_ParseServerMessage (void)
                        temp = "entity";
                        cmdlogname[cmdindex] = temp;
                        SHOWNET("fast update");
+                       if (cls.signon == SIGNONS - 1)
+                       {       // first update is the final signon stage
+                               cls.signon = SIGNONS;
+                               CL_SignonReply ();
+                       }
                        CL_ParseUpdate (cmd&127);
                        continue;
                }
@@ -1038,16 +1060,18 @@ void CL_ParseServerMessage (void)
 
                case svc_version:
                        i = MSG_ReadLong ();
-                       if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
-                               Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
+                       if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != 250)
+                               Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, PROTOCOL_VERSION);
                        Nehahrademcompatibility = false;
                        if (i == 250)
                                Nehahrademcompatibility = true;
                        if (cls.demoplayback && demo_nehahra.integer)
                                Nehahrademcompatibility = true;
-                       dpprotocol = i == DPPROTOCOL_VERSION;
+                       dpprotocol = i;
+                       if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2)
+                               dpprotocol = 0;
                        break;
-                       
+
                case svc_disconnect:
                        Host_EndGame ("Server disconnected\n");
 
@@ -1071,16 +1095,16 @@ void CL_ParseServerMessage (void)
                        CL_ParseServerInfo ();
 //                     vid.recalc_refdef = true;       // leave intermission full screen
                        break;
-                       
+
                case svc_setangle:
                        for (i=0 ; i<3 ; i++)
                                cl.viewangles[i] = MSG_ReadAngle ();
                        break;
-                       
+
                case svc_setview:
                        cl.viewentity = MSG_ReadShort ();
                        break;
-                                       
+
                case svc_lightstyle:
                        i = MSG_ReadByte ();
                        if (i >= MAX_LIGHTSTYLES)
@@ -1115,7 +1139,7 @@ void CL_ParseServerMessage (void)
                        if (i >= cl.maxclients)
                                Host_Error ("CL_ParseServerMessage: svc_updatefrags >= MAX_SCOREBOARD");
                        cl.scores[i].frags = MSG_ReadShort ();
-                       break;                  
+                       break;
 
                case svc_updatecolors:
                        i = MSG_ReadByte ();
@@ -1123,7 +1147,7 @@ void CL_ParseServerMessage (void)
                                Host_Error ("CL_ParseServerMessage: svc_updatecolors >= MAX_SCOREBOARD");
                        cl.scores[i].colors = MSG_ReadByte ();
                        break;
-                       
+
                case svc_particle:
                        CL_ParseParticleEffect ();
                        break;
@@ -1163,7 +1187,7 @@ void CL_ParseServerMessage (void)
                        else
                                CDAudio_Resume ();
                        break;
-                       
+
                case svc_signonnum:
                        i = MSG_ReadByte ();
                        if (i <= cls.signon)
@@ -1221,7 +1245,7 @@ void CL_ParseServerMessage (void)
                        cl.intermission = 3;
                        cl.completed_time = cl.time;
 //                     vid.recalc_refdef = true;       // go to full screen
-                       SCR_CenterPrint (MSG_ReadString ());                    
+                       SCR_CenterPrint (MSG_ReadString ());
                        break;
 
                case svc_sellscreen:
@@ -1255,6 +1279,14 @@ void CL_ParseServerMessage (void)
                                        CL_CGVM_ParseNetwork(cgamenetbuffer, length);
                        }
                        break;
+               case svc_entities:
+                       if (cls.signon == SIGNONS - 1)
+                       {       // first update is the final signon stage
+                               cls.signon = SIGNONS;
+                               CL_SignonReply ();
+                       }
+                       CL_ReadEntityFrame();
+                       break;
                }
        }
 
index 5e2831d..afc4945 100644 (file)
--- a/client.h
+++ b/client.h
@@ -274,6 +274,12 @@ typedef struct
 
 // frag scoreboard
        scoreboard_t    *scores;                // [cl.maxclients]
+
+       vec3_t          viewentorigin;
+
+       // entity database stuff
+       vec3_t          viewentoriginold, viewentoriginnew;
+       entity_database_t entitydatabase;
 }
 client_state_t;
 
index 404d73e..4468bba 100644 (file)
--- a/common.c
+++ b/common.c
@@ -549,19 +549,26 @@ void MSG_WriteString (sizebuf_t *sb, char *s)
                SZ_Write (sb, s, strlen(s)+1);
 }
 
-// used by server (always dpprotocol)
-// moved to common.h as #define
-/*
-void MSG_WriteFloatCoord (sizebuf_t *sb, float f)
+// used by server (always latest dpprotocol)
+void MSG_WriteDPCoord (sizebuf_t *sb, float f)
 {
-       MSG_WriteFloat(sb, f);
+       if (f >= 0)
+               MSG_WriteShort (sb, (int)(f + 0.5f));
+       else
+               MSG_WriteShort (sb, (int)(f - 0.5f));
 }
-*/
 
 // used by client
 void MSG_WriteCoord (sizebuf_t *sb, float f)
 {
-       if (dpprotocol)
+       if (dpprotocol == DPPROTOCOL_VERSION2)
+       {
+               if (f >= 0)
+                       MSG_WriteShort (sb, (int)(f + 0.5f));
+               else
+                       MSG_WriteShort (sb, (int)(f - 0.5f));
+       }
+       else if (dpprotocol == DPPROTOCOL_VERSION1)
                MSG_WriteFloat(sb, f);
        else
        {
@@ -606,7 +613,7 @@ void MSG_BeginReading (void)
 int MSG_ReadChar (void)
 {
        int     c;
-       
+
        // LordHavoc: minor optimization
        if (msg_readcount >= net_message.cursize)
 //     if (msg_readcount+1 > net_message.cursize)
@@ -614,7 +621,7 @@ int MSG_ReadChar (void)
                msg_badread = true;
                return -1;
        }
-               
+
        c = (signed char)net_message.data[msg_readcount];
        msg_readcount++;
 
@@ -624,7 +631,7 @@ int MSG_ReadChar (void)
 int MSG_ReadByte (void)
 {
        int     c;
-       
+
        // LordHavoc: minor optimization
        if (msg_readcount >= net_message.cursize)
 //     if (msg_readcount+1 > net_message.cursize)
@@ -635,7 +642,7 @@ int MSG_ReadByte (void)
 
        c = (unsigned char)net_message.data[msg_readcount];
        msg_readcount++;
-       
+
        return c;
 }
 */
@@ -649,19 +656,19 @@ int MSG_ReadShort (void)
                msg_badread = true;
                return -1;
        }
-               
+
        c = (short)(net_message.data[msg_readcount]
        + (net_message.data[msg_readcount+1]<<8));
-       
+
        msg_readcount += 2;
-       
+
        return c;
 }
 
 int MSG_ReadLong (void)
 {
        int     c;
-       
+
        if (msg_readcount+4 > net_message.cursize)
        {
                msg_badread = true;
@@ -672,9 +679,9 @@ int MSG_ReadLong (void)
        + (net_message.data[msg_readcount+1]<<8)
        + (net_message.data[msg_readcount+2]<<16)
        + (net_message.data[msg_readcount+3]<<24);
-       
+
        msg_readcount += 4;
-       
+
        return c;
 }
 
@@ -686,23 +693,23 @@ float MSG_ReadFloat (void)
                float   f;
                int     l;
        } dat;
-       
+
        dat.b[0] =      net_message.data[msg_readcount];
        dat.b[1] =      net_message.data[msg_readcount+1];
        dat.b[2] =      net_message.data[msg_readcount+2];
        dat.b[3] =      net_message.data[msg_readcount+3];
        msg_readcount += 4;
-       
+
        dat.l = LittleLong (dat.l);
 
-       return dat.f;   
+       return dat.f;
 }
 
 char *MSG_ReadString (void)
 {
        static char     string[2048];
        int             l,c;
-       
+
        l = 0;
        do
        {
@@ -712,25 +719,24 @@ char *MSG_ReadString (void)
                string[l] = c;
                l++;
        } while (l < sizeof(string)-1);
-       
+
        string[l] = 0;
-       
+
        return string;
 }
 
-// used by server (always dpprotocol)
-// moved to common.h as #define
-/*
-float MSG_ReadFloatCoord (void)
+// used by server (always latest dpprotocol)
+float MSG_ReadDPCoord (void)
 {
-       return MSG_ReadFloat();
+       return (signed short) MSG_ReadShort();
 }
-*/
 
 // used by client
 float MSG_ReadCoord (void)
 {
-       if (dpprotocol)
+       if (dpprotocol == DPPROTOCOL_VERSION2)
+               return (signed short) MSG_ReadShort();
+       else if (dpprotocol == DPPROTOCOL_VERSION1)
                return MSG_ReadFloat();
        else
                return MSG_ReadShort() * (1.0f/8.0f);
index 7d084f4..85aba74 100644 (file)
--- a/common.h
+++ b/common.h
@@ -93,8 +93,7 @@ void MSG_WriteString (sizebuf_t *sb, char *s);
 void MSG_WriteCoord (sizebuf_t *sb, float f);
 void MSG_WriteAngle (sizebuf_t *sb, float f);
 void MSG_WritePreciseAngle (sizebuf_t *sb, float f);
-
-#define MSG_WriteFloatCoord MSG_WriteFloat
+void MSG_WriteDPCoord (sizebuf_t *sb, float f);
 
 extern int                     msg_readcount;
 extern qboolean        msg_badread;            // set if a read goes beyond end of message
@@ -115,14 +114,14 @@ char *MSG_ReadString (void);
 float MSG_ReadCoord (void);
 //float MSG_ReadAngle (void);
 
-#define MSG_ReadFloatCoord MSG_ReadFloat
+float MSG_ReadDPCoord (void);
 
 #define MSG_ReadAngle() (MSG_ReadByte() * (360.0f / 256.0f))
 #define MSG_ReadPreciseAngle() (MSG_ReadShort() * (360.0f / 65536.0f))
 
 #define MSG_ReadVector(v) {(v)[0] = MSG_ReadCoord();(v)[1] = MSG_ReadCoord();(v)[2] = MSG_ReadCoord();}
 
-extern qboolean dpprotocol;
+extern int dpprotocol;
 
 //============================================================================
 
index 9bafca0..1665e49 100644 (file)
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -665,7 +665,7 @@ void PF_ambientsound (void)
                MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
 
        for (i=0 ; i<3 ; i++)
-               MSG_WriteFloatCoord(&sv.signon, pos[i]);
+               MSG_WriteDPCoord(&sv.signon, pos[i]);
 
        if (large)
                MSG_WriteShort (&sv.signon, soundnum);
@@ -1813,7 +1813,7 @@ void PF_WriteAngle (void)
 
 void PF_WriteCoord (void)
 {
-       MSG_WriteFloatCoord (WriteDest(), G_FLOAT(OFS_PARM1));
+       MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
 }
 
 void PF_WriteString (void)
@@ -1859,7 +1859,7 @@ void PF_makestatic (void)
        MSG_WriteByte (&sv.signon, ent->v.skin);
        for (i=0 ; i<3 ; i++)
        {
-               MSG_WriteFloatCoord(&sv.signon, ent->v.origin[i]);
+               MSG_WriteDPCoord(&sv.signon, ent->v.origin[i]);
                MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
        }
 
@@ -2163,9 +2163,9 @@ void PF_te_blood (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_BLOOD);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // velocity
        MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
        MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
@@ -2181,15 +2181,15 @@ void PF_te_bloodshower (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
        // min
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // speed
-       MSG_WriteFloatCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
+       MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
 }
@@ -2199,9 +2199,9 @@ void PF_te_explosionrgb (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // color
        MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
        MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
@@ -2215,17 +2215,17 @@ void PF_te_particlecube (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
        // min
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // velocity
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -2233,7 +2233,7 @@ void PF_te_particlecube (void)
        // gravity true/false
        MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
        // randomvel
-       MSG_WriteFloatCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
+       MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
 }
 
 void PF_te_particlerain (void)
@@ -2243,17 +2243,17 @@ void PF_te_particlerain (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
        // min
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // velocity
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -2267,17 +2267,17 @@ void PF_te_particlesnow (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
        // min
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // max
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // velocity
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -2291,9 +2291,9 @@ void PF_te_spark (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPARK);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // velocity
        MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
        MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
@@ -2307,9 +2307,9 @@ void PF_te_gunshotquad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_spikequad (void)
@@ -2317,9 +2317,9 @@ void PF_te_spikequad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_superspikequad (void)
@@ -2327,9 +2327,9 @@ void PF_te_superspikequad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_explosionquad (void)
@@ -2337,9 +2337,9 @@ void PF_te_explosionquad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_smallflash (void)
@@ -2347,9 +2347,9 @@ void PF_te_smallflash (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_customflash (void)
@@ -2359,9 +2359,9 @@ void PF_te_customflash (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // radius
        MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
        // lifetime
@@ -2377,9 +2377,9 @@ void PF_te_gunshot (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_spike (void)
@@ -2387,9 +2387,9 @@ void PF_te_spike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPIKE);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_superspike (void)
@@ -2397,9 +2397,9 @@ void PF_te_superspike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_explosion (void)
@@ -2407,9 +2407,9 @@ void PF_te_explosion (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_tarexplosion (void)
@@ -2417,9 +2417,9 @@ void PF_te_tarexplosion (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_wizspike (void)
@@ -2427,9 +2427,9 @@ void PF_te_wizspike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_knightspike (void)
@@ -2437,9 +2437,9 @@ void PF_te_knightspike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_lavasplash (void)
@@ -2447,9 +2447,9 @@ void PF_te_lavasplash (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_teleport (void)
@@ -2457,9 +2457,9 @@ void PF_te_teleport (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_TELEPORT);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_te_explosion2 (void)
@@ -2467,9 +2467,9 @@ void PF_te_explosion2 (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
        // origin
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
        // color
        MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
 }
@@ -2481,13 +2481,13 @@ void PF_te_lightning1 (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
 }
 
 void PF_te_lightning2 (void)
@@ -2497,13 +2497,13 @@ void PF_te_lightning2 (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
 }
 
 void PF_te_lightning3 (void)
@@ -2513,13 +2513,13 @@ void PF_te_lightning3 (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
 }
 
 void PF_te_beam (void)
@@ -2529,22 +2529,22 @@ void PF_te_beam (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
        // end
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
 }
 
 void PF_te_plasmaburn (void)
 {
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
-       MSG_WriteFloatCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+       MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
 }
 
 void PF_Fixme (void)
diff --git a/progs.h b/progs.h
index c1b60e7..bf96058 100644 (file)
--- a/progs.h
+++ b/progs.h
@@ -43,8 +43,10 @@ typedef struct edict_s
        qboolean        free;
        link_t          area;
 
+#ifdef QUAKEENTITIES
        entity_state_t  baseline;
        entity_state_t  deltabaseline; // LordHavoc: previous frame
+#endif
 
        float           freetime;                       // sv.time when the object was freed
        entvars_t       v;                                      // C exported fields from progs
index fc5981a..be9c9e7 100644 (file)
@@ -3,6 +3,7 @@
 
 void ClearStateToDefault(entity_state_t *s)
 {
+       s->active = 0;
        s->time = 0;
        VectorClear(s->origin);
        VectorClear(s->angles);
@@ -16,29 +17,28 @@ void ClearStateToDefault(entity_state_t *s)
        s->glowsize = 0;
        s->glowcolor = 254;
        s->flags = 0;
-       s->active = 0;
 }
 
 // (server) clears the database to contain no frames (thus delta compression compresses against nothing)
 void EntityFrame_ClearDatabase(entity_database_t *d)
 {
        memset(d, 0, sizeof(*d));
-       d->ackframe = -1;
 }
 
 // (server and client) removes frames older than 'frame' from database
 void EntityFrame_AckFrame(entity_database_t *d, int frame)
 {
        int i;
-       for (i = 0;i < d->numframes && d->frames[i].framenum >= frame;i++);
+       if (d->ackframe < frame)
+               d->ackframe = frame;
+       for (i = 0;i < d->numframes && d->frames[i].framenum < frame;i++);
        // ignore outdated frame acks (out of order packets)
        if (i == 0)
                return;
-       d->ackframe = frame;
        d->numframes -= i;
        // if some queue is left, slide it down to beginning of array
        if (d->numframes)
-               memcpy(&d->frames[0], &d->frames[i], sizeof(d->frames[0]) * d->numframes);
+               memmove(&d->frames[0], &d->frames[i], sizeof(d->frames[0]) * d->numframes);
 }
 
 // (server) clears frame, to prepare for adding entities
@@ -60,12 +60,13 @@ entity_state_t *EntityFrame_NewEntity(entity_frame_t *f, int number)
        return e;
 }
 
+// (server and client) reads a frame from the database
 void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f)
 {
        int i, n;
        memset(f, 0, sizeof(*f));
        for (i = 0;i < d->numframes && d->frames[i].framenum < framenum;i++);
-       if (framenum == d->frames[i].framenum)
+       if (i < d->numframes && framenum == d->frames[i].framenum)
        {
                f->framenum = framenum;
                f->numentities = d->frames[i].endentity - d->frames[i].firstentity;
@@ -75,6 +76,7 @@ void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *
                memcpy(f->entitydata, d->entitydata + d->frames[i].firstentity % MAX_ENTITY_DATABASE, sizeof(*f->entitydata) * n);
                if (f->numentities > n)
                        memcpy(f->entitydata + n, d->entitydata, sizeof(*f->entitydata) * (f->numentities - n));
+               VectorCopy(d->eye, f->eye);
        }
        else
                f->framenum = -1;
@@ -85,6 +87,9 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f)
 {
        int n, e;
        entity_frameinfo_t *info;
+
+       VectorCopy(f->eye, d->eye);
+
        // figure out how many entity slots are used already
        if (d->numframes)
        {
@@ -98,12 +103,27 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f)
 
        info = &d->frames[d->numframes];
        info->framenum = f->framenum;
+       e = -1000;
+       // make sure we check the newly added frame as well, but we haven't incremented numframes yet
+       for (n = 0;n <= d->numframes;n++)
+       {
+               if (e >= d->frames[n].framenum)
+               {
+                       if (e == f->framenum)
+                               Con_Printf("EntityFrame_AddFrame: tried to add out of sequence frame to database\n");
+                       else
+                               Con_Printf("EntityFrame_AddFrame: out of sequence frames in database\n");
+                       return;
+               }
+               e = d->frames[n].framenum;
+       }
        // if database still has frames after that...
        if (d->numframes)
                info->firstentity = d->frames[d->numframes - 1].endentity;
        else
                info->firstentity = 0;
        info->endentity = info->firstentity + f->numentities;
+       d->numframes++;
 
        n = info->firstentity % MAX_ENTITY_DATABASE;
        e = MAX_ENTITY_DATABASE - n;
@@ -115,7 +135,7 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f)
 }
 
 // (server) writes a frame to network stream
-void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, int newframe, sizebuf_t *msg)
+void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg)
 {
        int i, onum, bits, number;
        entity_frame_t deltaframe, *o = &deltaframe;
@@ -124,10 +144,10 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, int newframe, si
        EntityFrame_AddFrame(d, f);
 
        ClearStateToDefault(&baseline);
-       EntityFrame_FetchFrame(d, d->ackframe, o);
+       EntityFrame_FetchFrame(d, d->ackframe > 0 ? d->ackframe : -1, o);
        MSG_WriteByte (msg, svc_entities);
        MSG_WriteLong (msg, o->framenum);
-       MSG_WriteLong (msg, newframe);
+       MSG_WriteLong (msg, f->framenum);
        MSG_WriteFloat (msg, f->eye[0]);
        MSG_WriteFloat (msg, f->eye[1]);
        MSG_WriteFloat (msg, f->eye[2]);
@@ -155,17 +175,17 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, int newframe, si
                        delta = &baseline;
                }
                bits = 0;
-               if (ent->origin[0] != delta->origin[0])
+               if ((int) ent->origin[0] != (int) delta->origin[0])
                        bits |= E_ORIGIN1;
-               if (ent->origin[1] != delta->origin[1])
+               if ((int) ent->origin[1] != (int) delta->origin[1])
                        bits |= E_ORIGIN2;
-               if (ent->origin[2] != delta->origin[2])
+               if ((int) ent->origin[2] != (int) delta->origin[2])
                        bits |= E_ORIGIN3;
-               if (ent->angles[0] != delta->angles[0])
+               if ((byte) (ent->angles[0] * (256.0f / 360.0f)) != (byte) (delta->angles[0] * (256.0f / 360.0f)))
                        bits |= E_ANGLE1;
-               if (ent->angles[1] != delta->angles[1])
+               if ((byte) (ent->angles[1] * (256.0f / 360.0f)) != (byte) (delta->angles[1] * (256.0f / 360.0f)))
                        bits |= E_ANGLE2;
-               if (ent->angles[2] != delta->angles[2])
+               if ((byte) (ent->angles[2] * (256.0f / 360.0f)) != (byte) (delta->angles[2] * (256.0f / 360.0f)))
                        bits |= E_ANGLE3;
                if ((ent->modelindex ^ delta->modelindex) & 0x00FF)
                        bits |= E_MODEL1;
@@ -216,11 +236,11 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, int newframe, si
                                }
                        }
                        if (bits & E_ORIGIN1)
-                               MSG_WriteFloat(msg, ent->origin[0]);
+                               MSG_WriteShort(msg, ent->origin[0]);
                        if (bits & E_ORIGIN2)
-                               MSG_WriteFloat(msg, ent->origin[1]);
+                               MSG_WriteShort(msg, ent->origin[1]);
                        if (bits & E_ORIGIN3)
-                               MSG_WriteFloat(msg, ent->origin[2]);
+                               MSG_WriteShort(msg, ent->origin[2]);
                        if (bits & E_ANGLE1)
                                MSG_WriteAngle(msg, ent->angles[0]);
                        if (bits & E_ANGLE2)
@@ -266,26 +286,25 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, int newframe, si
 // (client) reads a frame from network stream
 void EntityFrame_Read(entity_database_t *d)
 {
-       int newframenum, deltaframenum, onum, number, removed, bits;
+       int number, removed, bits;
        entity_frame_t framedata, *f = &framedata, deltaframedata, *delta = &deltaframedata;
-       entity_state_t *e, baseline;
+       entity_state_t *e, baseline, *old, *oldend;
 
        ClearStateToDefault(&baseline);
        memset(f, 0, sizeof(*f));
        // read the frame header info
        f->time = cl.mtime[0];
-       deltaframenum = MSG_ReadLong();
-       newframenum = MSG_ReadLong();
+       number = MSG_ReadLong();
+       f->framenum = MSG_ReadLong();
        f->eye[0] = MSG_ReadFloat();
        f->eye[1] = MSG_ReadFloat();
        f->eye[2] = MSG_ReadFloat();
-       EntityFrame_AckFrame(d, deltaframenum);
-       EntityFrame_FetchFrame(d, deltaframenum, delta);
-       f->framenum = newframenum;
-       onum = 0;
-       f->numentities = 0;
+       EntityFrame_AckFrame(d, number);
+       EntityFrame_FetchFrame(d, number, delta);
+       old = delta->entitydata;
+       oldend = old + delta->numentities;
        // read entities until we hit the magic 0xFFFF end tag
-       while ((number = MSG_ReadShort()) != 0xFFFF)
+       while ((number = (unsigned short) MSG_ReadShort()) != 0xFFFF)
        {
                if (msg_badread)
                        Host_Error("EntityFrame_Read: read error\n");
@@ -295,41 +314,44 @@ void EntityFrame_Read(entity_database_t *d)
                        Host_Error("EntityFrame_Read: number (%i) >= MAX_EDICTS (%i)\n", number, MAX_EDICTS);
 
                // seek to entity, while copying any skipped entities (assume unchanged)
-               while (onum < delta->numentities && delta->entitydata[onum].number < number)
+               while (old < oldend && old->number < number)
                {
                        if (f->numentities >= MAX_ENTITY_DATABASE)
                                Host_Error("EntityFrame_Read: entity list too big\n");
-                       memcpy(f->entitydata + f->numentities, delta->entitydata + onum, sizeof(entity_state_t));
-                       onum++;
+                       memcpy(f->entitydata + f->numentities, old, sizeof(entity_state_t));
+                       f->entitydata[f->numentities].time = cl.mtime[0];
+                       old++;
                        f->numentities++;
                }
                if (removed)
                {
-                       if (onum < delta->numentities && delta->entitydata[onum].number == number)
-                               onum++;
+                       if (old < oldend && old->number == number)
+                               old++;
                        else
-                               Con_Printf("EntityFrame_Read: REMOVE on unused entity!\n");
+                               Con_Printf("EntityFrame_Read: REMOVE on unused entity %i\n", number);
                }
                else
                {
                        if (f->numentities >= MAX_ENTITY_DATABASE)
                                Host_Error("EntityFrame_Read: entity list too big\n");
-                       if (onum < delta->numentities && delta->entitydata[onum].number == number)
+
+                       // reserve this slot
+                       e = f->entitydata + f->numentities++;
+
+                       if (old < oldend && old->number == number)
                        {
                                // delta from old entity
-                               memcpy(f->entitydata + f->numentities, delta->entitydata + onum++, sizeof(*e));
+                               memcpy(e, old++, sizeof(*e));
                        }
                        else
                        {
                                // delta from baseline
-                               memcpy(f->entitydata + f->numentities, &baseline, sizeof(*e));
+                               memcpy(e, &baseline, sizeof(*e));
                        }
 
-                       // reserve this slot
-                       e = f->entitydata + f->numentities++;
-
                        e->active = true;
                        e->time = cl.mtime[0];
+                       e->number = number;
 
                        bits = MSG_ReadByte();
                        if (bits & E_EXTEND1)
@@ -344,11 +366,11 @@ void EntityFrame_Read(entity_database_t *d)
                        }
 
                        if (bits & E_ORIGIN1)
-                               e->origin[0] = MSG_ReadFloat();
+                               e->origin[0] = (signed short) MSG_ReadShort();
                        if (bits & E_ORIGIN2)
-                               e->origin[1] = MSG_ReadFloat();
+                               e->origin[1] = (signed short) MSG_ReadShort();
                        if (bits & E_ORIGIN3)
-                               e->origin[2] = MSG_ReadFloat();
+                               e->origin[2] = (signed short) MSG_ReadShort();
                        if (bits & E_ANGLE1)
                                e->angles[0] = MSG_ReadAngle();
                        if (bits & E_ANGLE2)
@@ -383,22 +405,27 @@ void EntityFrame_Read(entity_database_t *d)
                                e->flags = MSG_ReadByte();
                }
        }
-       while (onum < delta->numentities)
+       while (old < oldend)
        {
                if (f->numentities >= MAX_ENTITY_DATABASE)
                        Host_Error("EntityFrame_Read: entity list too big\n");
-               memcpy(f->entitydata + f->numentities, delta->entitydata + onum, sizeof(entity_state_t));
-               onum++;
+               memcpy(f->entitydata + f->numentities, old, sizeof(entity_state_t));
+               f->entitydata[f->numentities].time = cl.mtime[0];
+               old++;
                f->numentities++;
        }
        EntityFrame_AddFrame(d, f);
 }
 
-void EntityFrame_FetchEye(entity_database_t *d, vec3_t eye, double time)
+/*
+// (client) reads (and interpolates) the eye location from the database,
+// given a current time
+int EntityFrame_FetchEye(entity_database_t *d, vec3_t eye, double time)
 {
        float frac;
        if (d->numframes == 0)
-               Host_Error("EntityFrame_FetchEye: no frames\n");
+               return false;
+//             Host_Error("EntityFrame_FetchEye: no frames\n");
        if (d->numframes > 1 && d->frames[d->numframes - 2].time != d->frames[d->numframes - 1].time)
        {
                frac = (time - d->frames[d->numframes - 2].time) / (d->frames[d->numframes - 1].time - d->frames[d->numframes - 2].time);
@@ -408,6 +435,7 @@ void EntityFrame_FetchEye(entity_database_t *d, vec3_t eye, double time)
        }
        else
                VectorCopy(d->frames[0].eye, eye);
+       return true;
 }
 
 // (client) fetchs an entity from a frame, index is the index into the frame's entity list, returns false if index is out of bounds
@@ -433,3 +461,13 @@ int EntityFrame_FetchEntityByNumber(entity_frame_t *f, entity_state_t *e, int nu
        ClearStateToDefault(e);
        return false;
 }
+*/
+
+// (client) returns the frame number of the most recent frame recieved
+int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d)
+{
+       if (d->numframes)
+               return d->frames[d->numframes - 1].framenum;
+       else
+               return -1;
+}
index 0df3b28..f07830f 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -20,7 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // protocol.h -- communications protocols
 
 #define        PROTOCOL_VERSION        15
-#define        DPPROTOCOL_VERSION      96
+#define        DPPROTOCOL_VERSION1     96
+#define        DPPROTOCOL_VERSION2     97
 
 // model effects
 #define        EF_ROCKET       1                       // leave a trail
@@ -202,6 +203,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define        svc_hidelmp                     36              // [string] slotname
 #define        svc_skybox                      37              // [string] skyname
 
+// LordHavoc: my svc_ range, 50-59
 #define svc_cgame                      50              // [short] length [bytes] data
 #define svc_fog                                51              // unfinished and obsolete
 #define svc_effect                     52              // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
@@ -222,6 +224,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define        clc_move                3                       // [usercmd_t]
 #define        clc_stringcmd   4               // [string] message
 
+// LordHavoc: my clc_ range, 50-59
+#define clc_ackentities        50              // [int] framenumber
+#define clc_unusedlh1  51
+#define clc_unusedlh2  52
+#define clc_unusedlh3  53
+#define clc_unusedlh4  54
+#define clc_unusedlh5  55
+#define clc_unusedlh6  56
+#define clc_unusedlh7  57
+#define clc_unusedlh8  58
+#define clc_unusedlh9  59
 
 //
 // temp entity events
@@ -240,7 +253,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define        TE_TELEPORT                     11 // [vector] origin
 #define TE_EXPLOSION2          12 // [vector] origin [byte] startcolor [byte] colorcount
 
-// PGM 01/21/97 
+// PGM 01/21/97
 #define TE_BEAM                                13 // [entity] entity [vector] start [vector] end
 // PGM 01/21/97 
 
@@ -296,7 +309,6 @@ entity_state_t;
 typedef struct
 {
        double time;
-       vec3_t eye;
        int framenum;
        int firstentity; // index into entitydata, modulo MAX_ENTITY_DATABASE
        int endentity; // index into entitydata, firstentity + numentities
@@ -318,6 +330,7 @@ typedef struct
        // the only reason this system is used is to avoid copying memory when frames are removed
        int numframes;
        int ackframe; // server only: last acknowledged frame
+       vec3_t eye;
        entity_frameinfo_t frames[MAX_ENTITY_HISTORY];
        entity_state_t entitydata[MAX_ENTITY_DATABASE];
 }
@@ -389,14 +402,21 @@ void EntityFrame_AckFrame(entity_database_t *d, int frame);
 void EntityFrame_Clear(entity_frame_t *f, vec3_t eye);
 // (server) allocates an entity slot in frame, returns NULL if full
 entity_state_t *EntityFrame_NewEntity(entity_frame_t *f, int number);
+// (server and client) reads a frame from the database
+void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f);
 // (server and client) adds a entity_frame to the database, for future
 // reference
 void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f);
 // (server) writes a frame to network stream
-void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, int newframe, sizebuf_t *msg);
+void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg);
 // (client) reads a frame from network stream
 void EntityFrame_Read(entity_database_t *d);
+// (client) reads (and interpolates) the eye location from the database,
+// given a current time
+//int EntityFrame_FetchEye(entity_database_t *d, vec3_t eye, double time);
 // (client) fetchs an entity from the frame by index into the entity list
-int EntityFrame_FetchEntityByIndex(entity_frame_t *f, entity_state_t *e, int index);
+//int EntityFrame_FetchEntityByIndex(entity_frame_t *f, entity_state_t *e, int index);
 // (client) fetchs an entity from the frame by entity number
-int EntityFrame_FetchEntityByNumber(entity_frame_t *f, entity_state_t *e, int number);
+//int EntityFrame_FetchEntityByNumber(entity_frame_t *f, entity_state_t *e, int number);
+// (client) returns the frame number of the most recent frame recieved
+int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d);
index 69be043..273b3de 100644 (file)
--- a/server.h
+++ b/server.h
@@ -108,9 +108,17 @@ typedef struct client_s
        int                             old_frags;
        int                             pmodel;
 
+#ifdef QUAKEENTITIES
        // delta compression state
        float                   nextfullupdate[MAX_EDICTS];
-       float                   lastvisible[MAX_EDICTS];
+#endif
+       // visibility state
+       float                   visibletime[MAX_EDICTS];
+
+#ifndef QUAKEENTITIES
+       entity_database_t entitydatabase;
+       int                             entityframenumber; // incremented each time an entity frame is sent
+#endif
 } client_t;
 
 
index 34ac546..1ea395f 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -89,9 +89,9 @@ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
        if (sv.datagram.cursize > MAX_DATAGRAM-16)
                return;
        MSG_WriteByte (&sv.datagram, svc_particle);
-       MSG_WriteFloatCoord (&sv.datagram, org[0]);
-       MSG_WriteFloatCoord (&sv.datagram, org[1]);
-       MSG_WriteFloatCoord (&sv.datagram, org[2]);
+       MSG_WriteDPCoord (&sv.datagram, org[0]);
+       MSG_WriteDPCoord (&sv.datagram, org[1]);
+       MSG_WriteDPCoord (&sv.datagram, org[2]);
        for (i=0 ; i<3 ; i++)
        {
                v = dir[i]*16;
@@ -119,9 +119,9 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount,
        if (modelindex >= 256 || startframe >= 256)
        {
                MSG_WriteByte (&sv.datagram, svc_effect2);
-               MSG_WriteFloatCoord (&sv.datagram, org[0]);
-               MSG_WriteFloatCoord (&sv.datagram, org[1]);
-               MSG_WriteFloatCoord (&sv.datagram, org[2]);
+               MSG_WriteDPCoord (&sv.datagram, org[0]);
+               MSG_WriteDPCoord (&sv.datagram, org[1]);
+               MSG_WriteDPCoord (&sv.datagram, org[2]);
                MSG_WriteShort (&sv.datagram, modelindex);
                MSG_WriteShort (&sv.datagram, startframe);
                MSG_WriteByte (&sv.datagram, framecount);
@@ -130,9 +130,9 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount,
        else
        {
                MSG_WriteByte (&sv.datagram, svc_effect);
-               MSG_WriteFloatCoord (&sv.datagram, org[0]);
-               MSG_WriteFloatCoord (&sv.datagram, org[1]);
-               MSG_WriteFloatCoord (&sv.datagram, org[2]);
+               MSG_WriteDPCoord (&sv.datagram, org[0]);
+               MSG_WriteDPCoord (&sv.datagram, org[1]);
+               MSG_WriteDPCoord (&sv.datagram, org[2]);
                MSG_WriteByte (&sv.datagram, modelindex);
                MSG_WriteByte (&sv.datagram, startframe);
                MSG_WriteByte (&sv.datagram, framecount);
@@ -213,7 +213,7 @@ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
        else
                MSG_WriteByte (&sv.datagram, sound_num);
        for (i=0 ; i<3 ; i++)
-               MSG_WriteFloatCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));
+               MSG_WriteDPCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));
 }
 
 /*
@@ -237,12 +237,16 @@ void SV_SendServerinfo (client_t *client)
        char                    **s;
        char                    message[2048];
 
+       // LordHavoc: clear entityframe tracking
+       client->entityframenumber = 0;
+       EntityFrame_ClearDatabase(&client->entitydatabase);
+
        MSG_WriteByte (&client->message, svc_print);
        sprintf (message, "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, pr_crc);
        MSG_WriteString (&client->message,message);
 
        MSG_WriteByte (&client->message, svc_serverinfo);
-       MSG_WriteLong (&client->message, DPPROTOCOL_VERSION);
+       MSG_WriteLong (&client->message, DPPROTOCOL_VERSION2);
        MSG_WriteByte (&client->message, svs.maxclients);
 
        if (!coop.integer && deathmatch.integer)
@@ -498,6 +502,7 @@ SV_WriteEntitiesToClient
 
 =============
 */
+#ifdef QUAKEENTITIES
 void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
 {
        int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects;
@@ -669,10 +674,10 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                                SV_RecursiveHullCheck (sv.worldmodel->hulls->firstclipnode, 0, 1, testeye, testorigin);
 
                                if (trace.fraction == 1)
-                                       client->lastvisible[e] = realtime;
+                                       client->visibletime[e] = realtime + 1;
                                else
                                {
-                                       if (realtime - client->lastvisible[e] >= 1)
+                                       if (realtime > client->visibletime[e])
                                        {
                                                culled_trace++;
                                                continue;
@@ -735,7 +740,7 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                        for (;e < sv.num_edicts;e++)
                        {
                                client->nextfullupdate[e] = -1;
-                               client->lastvisible[e] = -1;
+                               client->visibletime[e] = -1;
                        }
                        return;
                }
@@ -835,11 +840,11 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
                if (bits & U_COLORMAP)  MSG_WriteByte (msg, ent->v.colormap);
                if (bits & U_SKIN)              MSG_WriteByte (msg, ent->v.skin);
                if (bits & U_EFFECTS)   MSG_WriteByte (msg, ent->v.effects);
-               if (bits & U_ORIGIN1)   MSG_WriteFloatCoord (msg, origin[0]);
+               if (bits & U_ORIGIN1)   MSG_WriteDPCoord (msg, origin[0]);
                if (bits & U_ANGLE1)    MSG_WriteAngle(msg, angles[0]);
-               if (bits & U_ORIGIN2)   MSG_WriteFloatCoord (msg, origin[1]);
+               if (bits & U_ORIGIN2)   MSG_WriteDPCoord (msg, origin[1]);
                if (bits & U_ANGLE2)    MSG_WriteAngle(msg, angles[1]);
-               if (bits & U_ORIGIN3)   MSG_WriteFloatCoord (msg, origin[2]);
+               if (bits & U_ORIGIN3)   MSG_WriteDPCoord (msg, origin[2]);
                if (bits & U_ANGLE3)    MSG_WriteAngle(msg, angles[2]);
 
                // LordHavoc: new stuff
@@ -855,6 +860,259 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
        if (sv_cullentities_stats.integer)
                Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d portal %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_portal + culled_trace, culled_pvs, culled_portal, culled_trace);
 }
+#else
+void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
+{
+       int e, clentnum, flags, alpha, glowcolor, glowsize, scale, effects;
+       int culled_pvs, culled_portal, culled_trace, visibleentities, totalentities;
+       byte *pvs;
+       vec3_t org, origin, angles, entmins, entmaxs;
+       edict_t *ent;
+       eval_t *val;
+       trace_t trace;
+       model_t *model;
+       double testeye[3];
+       double testorigin[3];
+       entity_frame_t entityframe;
+       entity_state_t *s;
+
+       if (client->sendsignon)
+               return;
+
+       Mod_CheckLoaded(sv.worldmodel);
+
+// find the client's PVS
+       VectorAdd (clent->v.origin, clent->v.view_ofs, testeye);
+       VectorCopy (testeye, org);
+       pvs = SV_FatPVS (org);
+       EntityFrame_Clear(&entityframe, org);
+
+       culled_pvs = 0;
+       culled_portal = 0;
+       culled_trace = 0;
+       visibleentities = 0;
+       totalentities = 0;
+
+       clentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
+       // send all entities that touch the pvs
+       ent = NEXT_EDICT(sv.edicts);
+       for (e = 1;e < sv.num_edicts;e++, ent = NEXT_EDICT(ent))
+       {
+               flags = 0;
+
+               if (ent != clent) // LordHavoc: always send player
+               {
+                       if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
+                       {
+                               if (val->edict == clentnum)
+                                       flags |= RENDER_VIEWMODEL; // show relative to the view
+                               else
+                               {
+                                       // don't show to anyone else
+                                       continue;
+                               }
+                       }
+                       else
+                       {
+                               // LordHavoc: never draw something told not to display to this client
+                               if ((val = GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)) && val->edict == clentnum)
+                                       continue;
+                               if ((val = GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)) && val->edict && val->edict != clentnum)
+                                       continue;
+                       }
+               }
+
+               glowsize = 0;
+
+               if ((val = GETEDICTFIELDVALUE(ent, eval_glow_size)))
+                       glowsize = (int) val->_float >> 2;
+               glowsize = bound(0, glowsize, 255);
+
+               if ((val = GETEDICTFIELDVALUE(ent, eval_glow_trail)))
+               if (val->_float != 0)
+                       flags |= RENDER_GLOWTRAIL;
+
+               if (ent->v.modelindex >= 0 && ent->v.modelindex < MAX_MODELS && pr_strings[ent->v.model])
+               {
+                       model = sv.models[(int)ent->v.modelindex];
+                       Mod_CheckLoaded(model);
+               }
+               else
+               {
+                       model = NULL;
+                       if (ent != clent) // LordHavoc: always send player
+                               if (glowsize == 0 && (flags & RENDER_GLOWTRAIL) == 0) // no effects
+                                       continue;
+               }
+
+               VectorCopy(ent->v.angles, angles);
+               if (DotProduct(ent->v.velocity, ent->v.velocity) >= 1.0f && host_client->latency >= 0.01f)
+               {
+                       VectorMA(ent->v.origin, host_client->latency, ent->v.velocity, origin);
+                       // LordHavoc: trace predicted movement to avoid putting things in walls
+                       trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, origin, MOVE_NORMAL, ent);
+                       VectorCopy(trace.endpos, origin);
+               }
+               else
+               {
+                       VectorCopy(ent->v.origin, origin);
+               }
+
+               // ent has survived every check so far, check if it is visible
+               // always send embedded brush models, they don't generate much traffic
+               if (ent != clent && ((flags & RENDER_VIEWMODEL) == 0) && (model == NULL || model->type != mod_brush || model->name[0] != '*'))
+               {
+                       // use the predicted origin
+                       entmins[0] = origin[0] - 1.0f;
+                       entmins[1] = origin[1] - 1.0f;
+                       entmins[2] = origin[2] - 1.0f;
+                       entmaxs[0] = origin[0] + 1.0f;
+                       entmaxs[1] = origin[1] + 1.0f;
+                       entmaxs[2] = origin[2] + 1.0f;
+                       // using the model's bounding box to ensure things are visible regardless of their physics box
+                       if (model)
+                       {
+                               if (ent->v.angles[0] || ent->v.angles[2]) // pitch and roll
+                               {
+                                       VectorAdd(entmins, model->rotatedmins, entmins);
+                                       VectorAdd(entmaxs, model->rotatedmaxs, entmaxs);
+                               }
+                               else if (ent->v.angles[1])
+                               {
+                                       VectorAdd(entmins, model->yawmins, entmins);
+                                       VectorAdd(entmaxs, model->yawmaxs, entmaxs);
+                               }
+                               else
+                               {
+                                       VectorAdd(entmins, model->normalmins, entmins);
+                                       VectorAdd(entmaxs, model->normalmaxs, entmaxs);
+                               }
+                       }
+
+                       totalentities++;
+
+                       // if not touching a visible leaf
+                       if (sv_cullentities_pvs.integer && !SV_BoxTouchingPVS(pvs, entmins, entmaxs, sv.worldmodel->nodes))
+                       {
+                               culled_pvs++;
+                               continue;
+                       }
+
+                       // or not visible through the portals
+                       if (sv_cullentities_portal.integer && !Portal_CheckBox(sv.worldmodel, org, entmins, entmaxs))
+                       {
+                               culled_portal++;
+                               continue;
+                       }
+
+                       if (sv_cullentities_trace.integer)
+                       {
+                               // LordHavoc: test random offsets, to maximize chance of detection
+                               testorigin[0] = lhrandom(entmins[0], entmaxs[0]);
+                               testorigin[1] = lhrandom(entmins[1], entmaxs[1]);
+                               testorigin[2] = lhrandom(entmins[2], entmaxs[2]);
+
+                               memset (&trace, 0, sizeof(trace_t));
+                               trace.fraction = 1;
+                               trace.allsolid = true;
+                               VectorCopy(testorigin, trace.endpos);
+
+                               VectorCopy(org, RecursiveHullCheckInfo.start);
+                               VectorSubtract(testorigin, testeye, RecursiveHullCheckInfo.dist);
+                               RecursiveHullCheckInfo.hull = sv.worldmodel->hulls;
+                               RecursiveHullCheckInfo.trace = &trace;
+                               SV_RecursiveHullCheck (sv.worldmodel->hulls->firstclipnode, 0, 1, testeye, testorigin);
+
+                               if (trace.fraction == 1)
+                                       client->visibletime[e] = realtime + 1;
+                               else
+                               {
+                                       if (realtime > client->visibletime[e])
+                                       {
+                                               culled_trace++;
+                                               continue;
+                                       }
+                               }
+                       }
+                       visibleentities++;
+               }
+
+               alpha = 255;
+               scale = 16;
+               glowcolor = 254;
+               effects = ent->v.effects;
+
+               if ((val = GETEDICTFIELDVALUE(ent, eval_alpha)))
+               if (val->_float != 0)
+                       alpha = (int) (val->_float * 255.0);
+
+               // HalfLife support
+               if ((val = GETEDICTFIELDVALUE(ent, eval_renderamt)))
+               if (val->_float != 0)
+                       alpha = (int) val->_float;
+
+               if (alpha == 0)
+                       alpha = 255;
+               alpha = bound(0, alpha, 255);
+
+               if ((val = GETEDICTFIELDVALUE(ent, eval_scale)))
+               if ((scale = (int) (val->_float * 16.0)) == 0) scale = 16;
+               if (scale < 0) scale = 0;
+               if (scale > 255) scale = 255;
+
+               if ((val = GETEDICTFIELDVALUE(ent, eval_glow_color)))
+               if (val->_float != 0)
+                       glowcolor = (int) val->_float;
+
+               if ((val = GETEDICTFIELDVALUE(ent, eval_fullbright)))
+               if (val->_float != 0)
+                       effects |= EF_FULLBRIGHT;
+
+               if (ent != clent)
+               {
+                       if (glowsize == 0 && (flags & RENDER_GLOWTRAIL) == 0) // no effects
+                       {
+                               if (model) // model
+                               {
+                                       // don't send if flagged for NODRAW and there are no effects
+                                       if (model->flags == 0 && ((effects & EF_NODRAW) || scale <= 0 || alpha <= 0))
+                                               continue;
+                               }
+                               else // no model and no effects
+                                       continue;
+                       }
+               }
+
+               if ((val = GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)) && val->edict == clentnum)
+                       flags |= RENDER_EXTERIORMODEL;
+
+               if (ent->v.movetype == MOVETYPE_STEP)
+                       flags |= RENDER_STEP;
+
+               s = EntityFrame_NewEntity(&entityframe, e);
+               // if we run out of space, abort
+               if (!s)
+                       break;
+               VectorCopy(origin, s->origin);
+               VectorCopy(angles, s->angles);
+               s->colormap = ent->v.colormap;
+               s->skin = ent->v.skin;
+               s->frame = ent->v.frame;
+               s->modelindex = ent->v.modelindex;
+               s->effects = effects;
+               s->alpha = alpha;
+               s->scale = scale;
+               s->glowsize = glowsize;
+               s->glowcolor = glowcolor;
+               s->flags = flags;
+       }
+       entityframe.framenum = ++client->entityframenumber;
+       EntityFrame_Write(&client->entitydatabase, &entityframe, msg);
+
+       if (sv_cullentities_stats.integer)
+               Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d portal %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_portal + culled_trace, culled_pvs, culled_portal, culled_trace);
+}
+#endif
 
 /*
 =============
@@ -897,7 +1155,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
                MSG_WriteByte (msg, ent->v.dmg_save);
                MSG_WriteByte (msg, ent->v.dmg_take);
                for (i=0 ; i<3 ; i++)
-                       MSG_WriteFloatCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));
+                       MSG_WriteDPCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));
 
                ent->v.dmg_take = 0;
                ent->v.dmg_save = 0;
@@ -919,7 +1177,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
 
        bits = 0;
 
-       if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)
+       //if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)
                bits |= SU_VIEWHEIGHT;
 
        if (ent->v.idealpitch)
@@ -981,7 +1239,8 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
                MSG_WriteByte(msg, bits >> 24);
 
        if (bits & SU_VIEWHEIGHT)
-               MSG_WriteChar (msg, ent->v.view_ofs[2]);
+               //MSG_WriteChar (msg, ent->v.view_ofs[2]);
+               MSG_WriteChar (msg, 0);
 
        if (bits & SU_IDEALPITCH)
                MSG_WriteChar (msg, ent->v.idealpitch);
@@ -991,7 +1250,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
                if (bits & (SU_PUNCH1<<i))
                        MSG_WritePreciseAngle(msg, ent->v.punchangle[i]); // dpprotocol
                if (bits & (SU_PUNCHVEC1<<i)) // dpprotocol
-                       MSG_WriteFloatCoord(msg, punchvector[i]); // dpprotocol
+                       MSG_WriteDPCoord(msg, punchvector[i]); // dpprotocol
                if (bits & (SU_VELOCITY1<<i))
                        MSG_WriteChar (msg, ent->v.velocity[i]/16);
        }
@@ -1233,6 +1492,7 @@ int SV_ModelIndex (char *name)
        return i;
 }
 
+#ifdef SV_QUAKEENTITIES
 /*
 ================
 SV_CreateBaseline
@@ -1299,11 +1559,12 @@ void SV_CreateBaseline (void)
                MSG_WriteByte (&sv.signon, svent->baseline.skin);
                for (i=0 ; i<3 ; i++)
                {
-                       MSG_WriteFloatCoord(&sv.signon, svent->baseline.origin[i]);
+                       MSG_WriteDPCoord(&sv.signon, svent->baseline.origin[i]);
                        MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);
                }
        }
 }
+#endif
 
 
 /*
@@ -1504,8 +1765,10 @@ void SV_SpawnServer (char *server)
 
        Mod_PurgeUnused();
 
+#ifdef QUAKEENTITIES
 // create a baseline for more efficient communications
        SV_CreateBaseline ();
+#endif
 
 // send serverinfo to all connected clients
        for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
index 3f30641..1fc0773 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -76,7 +76,7 @@ void SV_SetIdealPitch (void)
                bottom[0] = top[0];
                bottom[1] = top[1];
                bottom[2] = top[2] - 160;
-               
+
                tr = SV_Move (top, vec3_origin, vec3_origin, bottom, MOVE_NOMONSTERS, sv_player);
                if (tr.allsolid)
                        return; // looking at a wall, leave ideal the way is was
@@ -232,7 +232,7 @@ void DropPunchAngle (void)
        eval_t  *val;
        
        len = VectorNormalizeLength (sv_player->v.punchangle);
-       
+
        len -= 10*sv.frametime;
        if (len < 0)
                len = 0;
@@ -607,6 +607,10 @@ nextmsg:
                        case clc_move:
                                SV_ReadClientMove (&host_client->cmd);
                                break;
+
+                       case clc_ackentities:
+                               EntityFrame_AckFrame(&host_client->entitydatabase, MSG_ReadLong());
+                               break;
                        }
                }
        } while (ret == 1);
diff --git a/view.c b/view.c
index 0dd0676..9ca7209 100644 (file)
--- a/view.c
+++ b/view.c
@@ -76,7 +76,7 @@ float V_CalcRoll (vec3_t angles, vec3_t velocity)
        side = DotProduct (velocity, right);
        sign = side < 0 ? -1 : 1;
        side = fabs(side);
-       
+
        value = cl_rollangle.value;
 //     if (cl.inwater)
 //             value *= 6;
@@ -499,17 +499,19 @@ void V_CalcRefdef (void)
 
        V_DriftPitch ();
 
-       VectorCopy (ent->render.origin, r_refdef.vieworg);
+       VectorCopy (cl.viewentorigin, r_refdef.vieworg);
        if (!intimerefresh)
                VectorCopy (cl.viewangles, r_refdef.viewangles);
 
        if (cl.intermission)
        {
                view->render.model = NULL;
+               VectorCopy (ent->render.angles, r_refdef.viewangles);
                V_AddIdle (1);
        }
        else if (chase_active.value)
        {
+               r_refdef.vieworg[2] += cl.viewheight;
                Chase_Update ();
                V_AddIdle (v_idlescale.value);
        }
@@ -544,9 +546,10 @@ void V_CalcRefdef (void)
                // set up gun
                view->state_current.modelindex = cl.stats[STAT_WEAPON];
                view->state_current.frame = cl.stats[STAT_WEAPONFRAME];
-               view->render.origin[0] = ent->render.origin[0] + bob * 0.4 * forward[0];
-               view->render.origin[1] = ent->render.origin[1] + bob * 0.4 * forward[1];
-               view->render.origin[2] = ent->render.origin[2] + bob * 0.4 * forward[2] + cl.viewheight + bob;
+               VectorCopy(r_refdef.vieworg, view->render.origin);
+               //view->render.origin[0] = ent->render.origin[0] + bob * 0.4 * forward[0];
+               //view->render.origin[1] = ent->render.origin[1] + bob * 0.4 * forward[1];
+               //view->render.origin[2] = ent->render.origin[2] + bob * 0.4 * forward[2] + cl.viewheight + bob;
                view->render.angles[PITCH] = -r_refdef.viewangles[PITCH] - v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
                view->render.angles[YAW] = r_refdef.viewangles[YAW] - v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
                view->render.angles[ROLL] = r_refdef.viewangles[ROLL] - v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;