PROTOCOL_DARKPLACES5
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 14 Sep 2004 22:41:10 +0000 (22:41 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 14 Sep 2004 22:41:10 +0000 (22:41 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@4499 d7cf8633-e32d-0410-b094-e92efae38249

24 files changed:
cgamevm.c
cl_demo.c
cl_input.c
cl_main.c
cl_parse.c
cl_particles.c
client.h
common.c
common.h
host.c
host_cmd.c
menu.c
model_brush.h
netconn.c
pr_cmds.c
progs.h
protocol.c
protocol.h
prvm_cmds.c
quakedef.h
server.h
sv_main.c
sv_user.c
view.c

index 3188197..277c7eb 100644 (file)
--- a/cgamevm.c
+++ b/cgamevm.c
@@ -87,7 +87,7 @@ unsigned char CGVM_MSG_ReadByte(void)
 
 short CGVM_MSG_ReadShort(void)
 {
-       int num;
+       short num;
        num = CGVM_MSG_ReadByte() | (CGVM_MSG_ReadByte() << 8);
        return num;
 }
index be9bf40..2b7f060 100644 (file)
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -42,7 +42,6 @@ CL_NextDemo
 Called to play the next demo in the demo loop
 =====================
 */
-extern void Call_MR_ToggleMenu_f (void);
 void CL_NextDemo (void)
 {
        char    str[1024];
@@ -57,9 +56,6 @@ void CL_NextDemo (void)
                {
                        Con_Print("No demos listed with startdemos\n");
                        cls.demonum = -1;
-                       // put up menu instead of staring at console
-                       if (key_dest != key_menu)
-                               Call_MR_ToggleMenu_f();
                        return;
                }
        }
index e3d964d..f8593c2 100644 (file)
@@ -385,38 +385,33 @@ void CL_SendMove(usercmd_t *cmd)
 
        MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
 
-       if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
+       if (cl.protocol == PROTOCOL_QUAKE)
        {
                for (i = 0;i < 3;i++)
-                       MSG_WriteFloat (&buf, cl.viewangles[i]);
+                       MSG_WriteAngle8i (&buf, cl.viewangles[i]);
        }
-       else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
+       else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
        {
-               for (i=0 ; i<3 ; i++)
-                       MSG_WritePreciseAngle (&buf, cl.viewangles[i]);
+               for (i = 0;i < 3;i++)
+                       MSG_WriteAngle32f (&buf, cl.viewangles[i]);
        }
-       else
+       else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
        {
-               for (i=0 ; i<3 ; i++)
-                       MSG_WriteAngle (&buf, cl.viewangles[i]);
+               for (i = 0;i < 3;i++)
+                       MSG_WriteAngle16i (&buf, cl.viewangles[i]);
        }
 
-       MSG_WriteShort (&buf, forwardmove);
-       MSG_WriteShort (&buf, sidemove);
-       MSG_WriteShort (&buf, upmove);
+       MSG_WriteCoord16i (&buf, forwardmove);
+       MSG_WriteCoord16i (&buf, sidemove);
+       MSG_WriteCoord16i (&buf, upmove);
 
        forwardmove = sidemove = upmove = 0;
        // 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;
        // LordHavoc: added 6 new buttons
+       if (in_attack.state  & 3) bits |=   1;in_attack.state  &= ~2;
+       if (in_jump.state    & 3) bits |=   2;in_jump.state    &= ~2;
        if (in_button3.state & 3) bits |=   4;in_button3.state &= ~2;
        if (in_button4.state & 3) bits |=   8;in_button4.state &= ~2;
        if (in_button5.state & 3) bits |=  16;in_button5.state &= ~2;
@@ -432,14 +427,17 @@ void CL_SendMove(usercmd_t *cmd)
        if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
        {
                // LordHavoc: should we ack this on receipt instead?  would waste net bandwidth though
-               i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase);
-               if (i > 0)
+               if (cl.entitydatabase)
                {
-                       MSG_WriteByte(&buf, clc_ackentities);
-                       MSG_WriteLong(&buf, i);
+                       i = EntityFrame_MostRecentlyRecievedFrameNum(cl.entitydatabase);
+                       if (i > 0)
+                       {
+                               MSG_WriteByte(&buf, clc_ackentities);
+                               MSG_WriteLong(&buf, i);
+                       }
                }
        }
-       else
+       else if (cl.protocol == PROTOCOL_DARKPLACES4)
        {
                if (cl.entitydatabase4)
                {
@@ -452,6 +450,16 @@ void CL_SendMove(usercmd_t *cmd)
                        MSG_WriteLong(&buf, i);
                }
        }
+       else if (cl.protocol == PROTOCOL_DARKPLACES5)
+       {
+               i = cl.latestframenum;
+               if (cl_nodelta.integer)
+                       i = -1;
+               if (developer_networkentities.integer >= 1)
+                       Con_Printf("send clc_ackentities %i\n", i);
+               MSG_WriteByte(&buf, clc_ackentities);
+               MSG_WriteLong(&buf, i);
+       }
 
        // deliver the message
        if (cls.demoplayback)
index 86a7e89..1006559 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -145,9 +145,9 @@ void CL_ClearState(void)
        // LordHavoc: have to set up the baseline info for alpha and other stuff
        for (i = 0;i < cl_max_entities;i++)
        {
-               ClearStateToDefault(&cl_entities[i].state_baseline);
-               ClearStateToDefault(&cl_entities[i].state_previous);
-               ClearStateToDefault(&cl_entities[i].state_current);
+               cl_entities[i].state_baseline = defaultstate;
+               cl_entities[i].state_previous = defaultstate;
+               cl_entities[i].state_current = defaultstate;
        }
 
        CL_CGVM_Clear();
@@ -904,7 +904,7 @@ static void CL_RelinkNetworkEntities(void)
 
        ent = &cl.viewent;
        ent->state_previous = ent->state_current;
-       ClearStateToDefault(&ent->state_current);
+       ent->state_current = defaultstate;
        ent->state_current.time = cl.time;
        ent->state_current.number = -1;
        ent->state_current.active = true;
index fae7906..e92bb5f 100644 (file)
@@ -150,7 +150,7 @@ void CL_ParseStartSoundPacket(int largesoundindex)
        if (ent >= MAX_EDICTS)
                Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
 
-       MSG_ReadVector(pos);
+       MSG_ReadVector(pos, cl.protocol);
 
        S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
 }
@@ -312,7 +312,6 @@ Con_DPrintf("CL_SignonReply: %i\n", cls.signon);
 CL_ParseServerInfo
 ==================
 */
-qbyte entlife[MAX_EDICTS];
 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
@@ -449,8 +448,6 @@ void CL_ParseServerInfo (void)
        Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
        Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
        CL_BoundingBoxForEntity(&ent->render);
-       // clear entlife array
-       memset(entlife, 0, MAX_EDICTS);
 
        cl_num_entities = 1;
 
@@ -498,6 +495,7 @@ void CL_ValidateState(entity_state_t *s)
 void CL_MoveLerpEntityStates(entity_t *ent)
 {
        float odelta[3], adelta[3];
+       CL_ValidateState(&ent->state_current);
        VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
        VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
        if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
@@ -539,168 +537,14 @@ void CL_MoveLerpEntityStates(entity_t *ent)
        }
 }
 
-/*
-==================
-CL_ParseUpdate
-
-Parse an entity update message from the server
-If an entities model or origin changes from frame to frame, it must be
-relinked.  Other attributes can change without relinking.
-==================
-*/
-void CL_ParseUpdate (int bits)
-{
-       int num;
-       entity_t *ent;
-       entity_state_t new;
-
-       if (bits & U_MOREBITS)
-               bits |= (MSG_ReadByte()<<8);
-       if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
-       {
-               bits |= MSG_ReadByte() << 16;
-               if (bits & U_EXTEND2)
-                       bits |= MSG_ReadByte() << 24;
-       }
-
-       if (bits & U_LONGENTITY)
-               num = (unsigned) MSG_ReadShort ();
-       else
-               num = (unsigned) MSG_ReadByte ();
-
-       if (num >= MAX_EDICTS)
-               Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
-       if (num < 1)
-               Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
-
-       ent = cl_entities + num;
-
-       // note: this inherits the 'active' state of the baseline chosen
-       // (state_baseline is always active, state_current may not be active if
-       // the entity was missing in the last frame)
-       if (bits & U_DELTA)
-               new = ent->state_current;
-       else
-       {
-               new = ent->state_baseline;
-               new.active = true;
-       }
-
-       new.number = num;
-       new.time = cl.mtime[0];
-       new.flags = 0;
-       if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
-       if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
-       if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
-       if (bits & U_SKIN)              new.skin = MSG_ReadByte();
-       if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
-       if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
-       if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
-       if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
-       if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
-       if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
-       if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
-       if (bits & U_STEP)              new.flags |= RENDER_STEP;
-       if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
-       if (bits & U_SCALE)             new.scale = MSG_ReadByte();
-       if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
-       if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
-       // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
-       if (bits & U_COLORMOD)  MSG_ReadByte();
-       if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
-       if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
-       if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
-
-       // LordHavoc: to allow playback of the Nehahra movie
-       if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
-       {
-               // LordHavoc: evil format
-               int i = MSG_ReadFloat();
-               int j = MSG_ReadFloat() * 255.0f;
-               if (i == 2)
-               {
-                       i = MSG_ReadFloat();
-                       if (i)
-                               new.effects |= EF_FULLBRIGHT;
-               }
-               if (j < 0)
-                       new.alpha = 0;
-               else if (j == 0 || j >= 255)
-                       new.alpha = 255;
-               else
-                       new.alpha = j;
-       }
-
-       if (new.active)
-               CL_ValidateState(&new);
-
-       ent->state_previous = ent->state_current;
-       ent->state_current = new;
-       if (ent->state_current.active)
-       {
-               CL_MoveLerpEntityStates(ent);
-               cl_entities_active[ent->state_current.number] = true;
-               // mark as visible (no kill this frame)
-               entlife[ent->state_current.number] = 2;
-       }
-}
-
-static entity_frame_t entityframe;
-extern mempool_t *cl_entities_mempool;
 void CL_ReadEntityFrame(void)
 {
        if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
-       {
-               int i;
-               entity_t *ent;
-               EntityFrame_Read(&cl.entitydatabase);
-               EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
-               for (i = 0;i < entityframe.numentities;i++)
-               {
-                       // copy the states
-                       ent = &cl_entities[entityframe.entitydata[i].number];
-                       ent->state_previous = ent->state_current;
-                       ent->state_current = entityframe.entitydata[i];
-                       CL_MoveLerpEntityStates(ent);
-                       // the entity lives again...
-                       entlife[ent->state_current.number] = 2;
-                       cl_entities_active[ent->state_current.number] = true;
-               }
-       }
-       else
-       {
-               if (!cl.entitydatabase4)
-                       cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
-               EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
-       }
-}
-
-void CL_EntityUpdateSetup(void)
-{
-}
-
-void CL_EntityUpdateEnd(void)
-{
-       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
-       {
-               int i;
-               // disable entities that disappeared this frame
-               for (i = 1;i < MAX_EDICTS;i++)
-               {
-                       // clear only the entities that were active last frame but not this
-                       // frame, don't waste time clearing all entities (which would cause
-                       // cache misses)
-                       if (entlife[i])
-                       {
-                               entlife[i]--;
-                               if (!entlife[i])
-                                       cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
-                       }
-               }
-       }
+               EntityFrame_CL_ReadFrame();
+       else if (cl.protocol == PROTOCOL_DARKPLACES4)
+               EntityFrame4_CL_ReadFrame();
+       else if (cl.protocol == PROTOCOL_DARKPLACES5)
+               EntityFrame5_CL_ReadFrame();
 }
 
 /*
@@ -712,7 +556,8 @@ void CL_ParseBaseline (entity_t *ent, int large)
 {
        int i;
 
-       ClearStateToDefault(&ent->state_baseline);
+       ent->state_baseline = defaultstate;
+       // FIXME: set ent->state_baseline.number?
        ent->state_baseline.active = true;
        if (large)
        {
@@ -728,8 +573,8 @@ void CL_ParseBaseline (entity_t *ent, int large)
        ent->state_baseline.skin = MSG_ReadByte();
        for (i = 0;i < 3;i++)
        {
-               ent->state_baseline.origin[i] = MSG_ReadCoord ();
-               ent->state_baseline.angles[i] = MSG_ReadAngle ();
+               ent->state_baseline.origin[i] = MSG_ReadCoord(cl.protocol);
+               ent->state_baseline.angles[i] = MSG_ReadAngle8i();
        }
        CL_ValidateState(&ent->state_baseline);
        ent->state_previous = ent->state_current = ent->state_baseline;
@@ -764,46 +609,41 @@ void CL_ParseClientdata (int bits)
                cl.idealpitch = 0;
 
        VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
-       if (cl.protocol == PROTOCOL_DARKPLACES5)
+       for (i = 0;i < 3;i++)
        {
-               for (i = 0;i < 3;i++)
+               if (bits & (SU_PUNCH1<<i) )
                {
-                       if (bits & (SU_PUNCH1<<i) )
-                               cl.punchangle[i] = MSG_ReadPreciseAngle();
-                       else
-                               cl.punchangle[i] = 0;
-                       if (bits & (SU_PUNCHVEC1<<i))
-                               cl.punchvector[i] = MSG_ReadFloat();
-                       else
-                               cl.punchvector[i] = 0;
-                       if (bits & (SU_VELOCITY1<<i) )
-                               cl.mvelocity[0][i] = MSG_ReadFloat();
+                       if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
+                               cl.punchangle[i] = MSG_ReadAngle16i();
+                       else if (cl.protocol == PROTOCOL_QUAKE)
+                               cl.punchangle[i] = MSG_ReadChar();
                        else
-                               cl.mvelocity[0][i] = 0;
+                               Host_Error("CL_ParseClientData: unknown cl.protocol\n");
                }
-       }
-       else
-       {
-               for (i = 0;i < 3;i++)
+               else
+                       cl.punchangle[i] = 0;
+               if (bits & (SU_PUNCHVEC1<<i))
                {
-                       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.punchangle[i] = MSG_ReadPreciseAngle();
-                               else
-                                       cl.punchangle[i] = MSG_ReadChar();
-                       }
+                       if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
+                               cl.punchvector[i] = MSG_ReadCoord16i();
+                       else if (cl.protocol == PROTOCOL_DARKPLACES5)
+                               cl.punchvector[i] = MSG_ReadCoord32f();
                        else
-                               cl.punchangle[i] = 0;
-                       if (bits & (SU_PUNCHVEC1<<i))
-                               cl.punchvector[i] = MSG_ReadCoord();
-                       else
-                               cl.punchvector[i] = 0;
-                       if (bits & (SU_VELOCITY1<<i) )
+                               Host_Error("CL_ParseClientData: unknown cl.protocol\n");
+               }
+               else
+                       cl.punchvector[i] = 0;
+               if (bits & (SU_VELOCITY1<<i) )
+               {
+                       if (cl.protocol == PROTOCOL_QUAKE || 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.mvelocity[0][i] = MSG_ReadCoord32f();
                        else
-                               cl.mvelocity[0][i] = 0;
+                               Host_Error("CL_ParseClientData: unknown cl.protocol\n");
                }
+               else
+                       cl.mvelocity[0][i] = 0;
        }
 
        i = MSG_ReadLong ();
@@ -818,21 +658,45 @@ void CL_ParseClientdata (int bits)
        cl.onground = (bits & SU_ONGROUND) != 0;
        cl.inwater = (bits & SU_INWATER) != 0;
 
-       cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
-       cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
-       cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
-       cl.stats[STAT_HEALTH] = MSG_ReadShort();
-       cl.stats[STAT_AMMO] = MSG_ReadByte();
-
-       cl.stats[STAT_SHELLS] = MSG_ReadByte();
-       cl.stats[STAT_NAILS] = MSG_ReadByte();
-       cl.stats[STAT_ROCKETS] = MSG_ReadByte();
-       cl.stats[STAT_CELLS] = MSG_ReadByte();
-
-       i = MSG_ReadByte ();
+       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;
+               cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadShort() : 0;
+               cl.stats[STAT_HEALTH] = MSG_ReadShort();
+               cl.stats[STAT_AMMO] = MSG_ReadShort();
+
+               cl.stats[STAT_SHELLS] = MSG_ReadShort();
+               cl.stats[STAT_NAILS] = MSG_ReadShort();
+               cl.stats[STAT_ROCKETS] = MSG_ReadShort();
+               cl.stats[STAT_CELLS] = MSG_ReadShort();
+               //cl.stats[STAT_GENERIC1] = MSG_ReadShort();
+               //cl.stats[STAT_GENERIC2] = MSG_ReadShort();
+               //cl.stats[STAT_GENERIC3] = MSG_ReadShort();
+               //cl.stats[STAT_GENERIC4] = MSG_ReadShort();
+               //cl.stats[STAT_GENERIC5] = MSG_ReadShort();
+               //cl.stats[STAT_GENERIC6] = MSG_ReadShort();
+
+               i = (unsigned short) MSG_ReadShort ();
+       }
+       else
+       {
+               cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
+               cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
+               cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
+               cl.stats[STAT_HEALTH] = MSG_ReadShort();
+               cl.stats[STAT_AMMO] = MSG_ReadByte();
+       
+               cl.stats[STAT_SHELLS] = MSG_ReadByte();
+               cl.stats[STAT_NAILS] = MSG_ReadByte();
+               cl.stats[STAT_ROCKETS] = MSG_ReadByte();
+               cl.stats[STAT_CELLS] = MSG_ReadByte();
+
+               i = MSG_ReadByte ();
+               if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
+                       i = (1<<i);
+       }
 
-       if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
-               i = (1<<i);
        // GAME_NEXUIZ hud needs weapon change time
        // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
        // like other modes
@@ -843,7 +707,10 @@ void CL_ParseClientdata (int bits)
        cl.viewzoomold = cl.viewzoomnew; // for interpolation
        if (bits & SU_VIEWZOOM)
        {
-               i = MSG_ReadByte();
+               if (cl.protocol == PROTOCOL_DARKPLACES5)
+                       i = (unsigned short) MSG_ReadShort();
+               else
+                       i = MSG_ReadByte();
                if (i < 2)
                        i = 2;
                cl.viewzoomnew = (float) i * (1.0f / 255.0f);
@@ -901,7 +768,7 @@ void CL_ParseStaticSound (int large)
        vec3_t          org;
        int                     sound_num, vol, atten;
 
-       MSG_ReadVector(org);
+       MSG_ReadVector(org, cl.protocol);
        if (large)
                sound_num = (unsigned short) MSG_ReadShort ();
        else
@@ -917,7 +784,7 @@ void CL_ParseEffect (void)
        vec3_t          org;
        int                     modelindex, startframe, framecount, framerate;
 
-       MSG_ReadVector(org);
+       MSG_ReadVector(org, cl.protocol);
        modelindex = MSG_ReadByte ();
        startframe = MSG_ReadByte ();
        framecount = MSG_ReadByte ();
@@ -931,9 +798,9 @@ void CL_ParseEffect2 (void)
        vec3_t          org;
        int                     modelindex, startframe, framecount, framerate;
 
-       MSG_ReadVector(org);
-       modelindex = MSG_ReadShort ();
-       startframe = MSG_ReadShort ();
+       MSG_ReadVector(org, cl.protocol);
+       modelindex = (unsigned short) MSG_ReadShort ();
+       startframe = (unsigned short) MSG_ReadShort ();
        framecount = MSG_ReadByte ();
        framerate = MSG_ReadByte ();
 
@@ -975,9 +842,9 @@ void CL_ParseBeam (model_t *m, int lightning)
        vec3_t start, end;
        beam_t *b;
 
-       ent = MSG_ReadShort ();
-       MSG_ReadVector(start);
-       MSG_ReadVector(end);
+       ent = (unsigned short) MSG_ReadShort ();
+       MSG_ReadVector(start, cl.protocol);
+       MSG_ReadVector(end, cl.protocol);
 
        if (ent >= MAX_EDICTS)
        {
@@ -1037,7 +904,7 @@ void CL_ParseTempEntity(void)
        {
        case TE_WIZSPIKE:
                // spike hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
                CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1);
@@ -1047,7 +914,7 @@ void CL_ParseTempEntity(void)
 
        case TE_KNIGHTSPIKE:
                // spike hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
                CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1);
@@ -1057,7 +924,7 @@ void CL_ParseTempEntity(void)
 
        case TE_SPIKE:
                // spike hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                // LordHavoc: changed to spark shower
                CL_SparkShower(pos, vec3_origin, 15);
@@ -1076,7 +943,7 @@ void CL_ParseTempEntity(void)
                break;
        case TE_SPIKEQUAD:
                // quad spike hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                // LordHavoc: changed to spark shower
                CL_SparkShower(pos, vec3_origin, 15);
@@ -1098,7 +965,7 @@ void CL_ParseTempEntity(void)
                break;
        case TE_SUPERSPIKE:
                // super spike hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                // LordHavoc: changed to dust shower
                CL_SparkShower(pos, vec3_origin, 30);
@@ -1117,7 +984,7 @@ void CL_ParseTempEntity(void)
                break;
        case TE_SUPERSPIKEQUAD:
                // quad super spike hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                // LordHavoc: changed to dust shower
                CL_SparkShower(pos, vec3_origin, 30);
@@ -1139,7 +1006,7 @@ void CL_ParseTempEntity(void)
                // LordHavoc: added for improved blood splatters
        case TE_BLOOD:
                // blood puff
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                dir[0] = MSG_ReadChar();
                dir[1] = MSG_ReadChar();
@@ -1149,7 +1016,7 @@ void CL_ParseTempEntity(void)
                break;
        case TE_SPARK:
                // spark shower
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                dir[0] = MSG_ReadChar();
                dir[1] = MSG_ReadChar();
@@ -1158,7 +1025,7 @@ void CL_ParseTempEntity(void)
                CL_SparkShower(pos, dir, count);
                break;
        case TE_PLASMABURN:
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
                CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
@@ -1167,47 +1034,47 @@ void CL_ParseTempEntity(void)
                // LordHavoc: added for improved gore
        case TE_BLOODSHOWER:
                // vaporized body
-               MSG_ReadVector(pos); // mins
-               MSG_ReadVector(pos2); // maxs
-               velspeed = MSG_ReadCoord(); // speed
-               count = MSG_ReadShort(); // number of particles
+               MSG_ReadVector(pos, cl.protocol); // mins
+               MSG_ReadVector(pos2, cl.protocol); // maxs
+               velspeed = MSG_ReadCoord(cl.protocol); // speed
+               count = (unsigned short) MSG_ReadShort(); // number of particles
                CL_BloodShower(pos, pos2, velspeed, count);
                break;
        case TE_PARTICLECUBE:
                // general purpose particle effect
-               MSG_ReadVector(pos); // mins
-               MSG_ReadVector(pos2); // maxs
-               MSG_ReadVector(dir); // dir
-               count = MSG_ReadShort(); // number of particles
+               MSG_ReadVector(pos, cl.protocol); // mins
+               MSG_ReadVector(pos2, cl.protocol); // maxs
+               MSG_ReadVector(dir, cl.protocol); // dir
+               count = (unsigned short) MSG_ReadShort(); // number of particles
                colorStart = MSG_ReadByte(); // color
                colorLength = MSG_ReadByte(); // gravity (1 or 0)
-               velspeed = MSG_ReadCoord(); // randomvel
+               velspeed = MSG_ReadCoord(cl.protocol); // randomvel
                CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
                break;
 
        case TE_PARTICLERAIN:
                // general purpose particle effect
-               MSG_ReadVector(pos); // mins
-               MSG_ReadVector(pos2); // maxs
-               MSG_ReadVector(dir); // dir
-               count = MSG_ReadShort(); // number of particles
+               MSG_ReadVector(pos, cl.protocol); // mins
+               MSG_ReadVector(pos2, cl.protocol); // maxs
+               MSG_ReadVector(dir, cl.protocol); // dir
+               count = (unsigned short) MSG_ReadShort(); // number of particles
                colorStart = MSG_ReadByte(); // color
                CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
                break;
 
        case TE_PARTICLESNOW:
                // general purpose particle effect
-               MSG_ReadVector(pos); // mins
-               MSG_ReadVector(pos2); // maxs
-               MSG_ReadVector(dir); // dir
-               count = MSG_ReadShort(); // number of particles
+               MSG_ReadVector(pos, cl.protocol); // mins
+               MSG_ReadVector(pos2, cl.protocol); // maxs
+               MSG_ReadVector(dir, cl.protocol); // dir
+               count = (unsigned short) MSG_ReadShort(); // number of particles
                colorStart = MSG_ReadByte(); // color
                CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
                break;
 
        case TE_GUNSHOT:
                // bullet hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                // LordHavoc: changed to dust shower
                CL_SparkShower(pos, vec3_origin, 15);
@@ -1215,7 +1082,7 @@ void CL_ParseTempEntity(void)
 
        case TE_GUNSHOTQUAD:
                // quad bullet hitting wall
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                CL_SparkShower(pos, vec3_origin, 15);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
@@ -1224,7 +1091,7 @@ void CL_ParseTempEntity(void)
 
        case TE_EXPLOSION:
                // rocket explosion
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                CL_ParticleExplosion(pos);
                // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
@@ -1235,7 +1102,7 @@ void CL_ParseTempEntity(void)
 
        case TE_EXPLOSIONQUAD:
                // quad rocket explosion
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                CL_ParticleExplosion(pos);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
@@ -1245,20 +1112,20 @@ void CL_ParseTempEntity(void)
 
        case TE_EXPLOSION3:
                // Nehahra movie colored lighting explosion
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                CL_ParticleExplosion(pos);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-               color[0] = MSG_ReadCoord() * (2.0f / 1.0f);
-               color[1] = MSG_ReadCoord() * (2.0f / 1.0f);
-               color[2] = MSG_ReadCoord() * (2.0f / 1.0f);
+               color[0] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
+               color[1] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
+               color[2] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
                CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);  
                S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
 
        case TE_EXPLOSIONRGB:
                // colored lighting explosion
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                CL_ParticleExplosion(pos);
                color[0] = MSG_ReadByte() * (2.0f / 255.0f);
@@ -1271,7 +1138,7 @@ void CL_ParseTempEntity(void)
 
        case TE_TAREXPLOSION:
                // tarbaby explosion
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                CL_BlobExplosion(pos);
 
@@ -1282,14 +1149,14 @@ void CL_ParseTempEntity(void)
                break;
 
        case TE_SMALLFLASH:
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
                CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1);
                break;
 
        case TE_CUSTOMFLASH:
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 4);
                radius = MSG_ReadByte() * 8;
                velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
@@ -1301,8 +1168,8 @@ void CL_ParseTempEntity(void)
                break;
 
        case TE_FLAMEJET:
-               MSG_ReadVector(pos);
-               MSG_ReadVector(dir);
+               MSG_ReadVector(pos, cl.protocol);
+               MSG_ReadVector(dir, cl.protocol);
                count = MSG_ReadByte();
                CL_Flames(pos, dir, count);
                break;
@@ -1343,12 +1210,12 @@ void CL_ParseTempEntity(void)
                break;
 
        case TE_LAVASPLASH:
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_LavaSplash(pos);
                break;
 
        case TE_TELEPORT:
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
                CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
 //             CL_TeleportSplash(pos);
@@ -1356,7 +1223,7 @@ void CL_ParseTempEntity(void)
 
        case TE_EXPLOSION2:
                // color mapped explosion
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                colorStart = MSG_ReadByte();
                colorLength = MSG_ReadByte();
@@ -1371,23 +1238,23 @@ void CL_ParseTempEntity(void)
                break;
 
        case TE_TEI_G3:
-               MSG_ReadVector(pos);
-               MSG_ReadVector(pos2);
-               MSG_ReadVector(dir);
+               MSG_ReadVector(pos, cl.protocol);
+               MSG_ReadVector(pos2, cl.protocol);
+               MSG_ReadVector(dir, cl.protocol);
                CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
                CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
                break;
 
        case TE_TEI_SMOKE:
-               MSG_ReadVector(pos);
-               MSG_ReadVector(dir);
+               MSG_ReadVector(pos, cl.protocol);
+               MSG_ReadVector(dir, cl.protocol);
                count = MSG_ReadByte();
                CL_FindNonSolidLocation(pos, pos, 4);
                CL_Tei_Smoke(pos, dir, count);
                break;
 
        case TE_TEI_BIGEXPLOSION:
-               MSG_ReadVector(pos);
+               MSG_ReadVector(pos, cl.protocol);
                CL_FindNonSolidLocation(pos, pos, 10);
                CL_ParticleExplosion(pos);
                Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
@@ -1396,8 +1263,8 @@ void CL_ParseTempEntity(void)
                break;
 
        case TE_TEI_PLASMAHIT:
-               MSG_ReadVector(pos);
-               MSG_ReadVector(dir);
+               MSG_ReadVector(pos, cl.protocol);
+               MSG_ReadVector(dir, cl.protocol);
                count = MSG_ReadByte();
                CL_FindNonSolidLocation(pos, pos, 5);
                CL_Tei_PlasmaHit(pos, dir, count);
@@ -1471,6 +1338,7 @@ void CL_ParseServerMessage(void)
                // if the high bit of the command byte is set, it is a fast update
                if (cmd & 128)
                {
+                       entitiesupdated = true;
                        // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
                        temp = "entity";
                        cmdlogname[cmdindex] = temp;
@@ -1481,7 +1349,7 @@ void CL_ParseServerMessage(void)
                                cls.signon = SIGNONS;
                                CL_SignonReply ();
                        }
-                       CL_ParseUpdate (cmd&127);
+                       EntityFrameQuake_ReadEntity (cmd&127);
                        continue;
                }
 
@@ -1527,19 +1395,12 @@ void CL_ParseServerMessage(void)
                        break;
 
                case svc_time:
-                       if (!entitiesupdated)
-                       {
-                               // this is a new frame, we'll be seeing entities,
-                               // so prepare for entity updates
-                               CL_EntityUpdateSetup();
-                               entitiesupdated = true;
-                       }
                        cl.mtime[1] = cl.mtime[0];
                        cl.mtime[0] = MSG_ReadFloat ();
                        break;
 
                case svc_clientdata:
-                       i = MSG_ReadShort ();
+                       i = (unsigned short) MSG_ReadShort ();
                        CL_ParseClientdata (i);
                        break;
 
@@ -1583,7 +1444,12 @@ void CL_ParseServerMessage(void)
 
                case svc_setangle:
                        for (i=0 ; i<3 ; i++)
-                               cl.viewangles[i] = MSG_ReadAngle ();
+                       {
+                               if (cl.protocol == PROTOCOL_DARKPLACES5)
+                                       cl.viewangles[i] = MSG_ReadAngle16i ();
+                               else
+                                       cl.viewangles[i] = MSG_ReadAngle8i ();
+                       }
                        break;
 
                case svc_setview:
@@ -1613,7 +1479,7 @@ void CL_ParseServerMessage(void)
                        break;
 
                case svc_stopsound:
-                       i = MSG_ReadShort();
+                       i = (unsigned short) MSG_ReadShort();
                        S_StopSound(i>>3, i&7);
                        break;
 
@@ -1628,7 +1494,7 @@ void CL_ParseServerMessage(void)
                        i = MSG_ReadByte ();
                        if (i >= cl.maxclients)
                                Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
-                       cl.scores[i].frags = MSG_ReadShort ();
+                       cl.scores[i].frags = (unsigned short) MSG_ReadShort ();
                        break;
 
                case svc_updatecolors:
@@ -1651,13 +1517,13 @@ void CL_ParseServerMessage(void)
                        break;
 
                case svc_spawnbaseline:
-                       i = MSG_ReadShort ();
+                       i = (unsigned short) MSG_ReadShort ();
                        if (i < 0 || i >= MAX_EDICTS)
                                Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
                        CL_ParseBaseline (cl_entities + i, false);
                        break;
                case svc_spawnbaseline2:
-                       i = MSG_ReadShort ();
+                       i = (unsigned short) MSG_ReadShort ();
                        if (i < 0 || i >= MAX_EDICTS)
                                Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
                        CL_ParseBaseline (cl_entities + i, true);
@@ -1750,12 +1616,12 @@ void CL_ParseServerMessage(void)
                        if (gamemode == GAME_TENEBRAE)
                        {
                                // repeating particle effect
-                               MSG_ReadCoord();
-                               MSG_ReadCoord();
-                               MSG_ReadCoord();
-                               MSG_ReadCoord();
-                               MSG_ReadCoord();
-                               MSG_ReadCoord();
+                               MSG_ReadCoord(cl.protocol);
+                               MSG_ReadCoord(cl.protocol);
+                               MSG_ReadCoord(cl.protocol);
+                               MSG_ReadCoord(cl.protocol);
+                               MSG_ReadCoord(cl.protocol);
+                               MSG_ReadCoord(cl.protocol);
                                MSG_ReadByte();
                                MSG_ReadLong();
                                MSG_ReadLong();
@@ -1768,9 +1634,9 @@ void CL_ParseServerMessage(void)
                        if (gamemode == GAME_TENEBRAE)
                        {
                                // particle effect
-                               MSG_ReadCoord();
-                               MSG_ReadCoord();
-                               MSG_ReadCoord();
+                               MSG_ReadCoord(cl.protocol);
+                               MSG_ReadCoord(cl.protocol);
+                               MSG_ReadCoord(cl.protocol);
                                MSG_ReadByte();
                                MSG_ReadString();
                        }
@@ -1803,7 +1669,7 @@ void CL_ParseServerMessage(void)
        }
 
        if (entitiesupdated)
-               CL_EntityUpdateEnd();
+               EntityFrameQuake_ISeeDeadEntities();
 
        parsingerror = false;
 }
index 11ec523..d5f9b93 100644 (file)
@@ -612,7 +612,7 @@ void CL_ParseParticleEffect (void)
        vec3_t org, dir;
        int i, count, msgcount, color;
 
-       MSG_ReadVector(org);
+       MSG_ReadVector(org, cl.protocol);
        for (i=0 ; i<3 ; i++)
                dir[i] = MSG_ReadChar () * (1.0/16);
        msgcount = MSG_ReadByte ();
index 55af9a9..38ef0b7 100644 (file)
--- a/client.h
+++ b/client.h
@@ -540,8 +540,10 @@ typedef struct
        int protocol;
 
        // entity database stuff
-       entity_database_t entitydatabase;
-       entity_database4_t *entitydatabase4;
+       // latest received entity frame number
+       int latestframenum;
+       entityframe_database_t *entitydatabase;
+       entityframe4_database_t *entitydatabase4;
 }
 client_state_t;
 
@@ -599,6 +601,7 @@ extern int cl_num_static_entities;
 extern int cl_num_temp_entities;
 extern int cl_num_brushmodel_entities;
 
+extern mempool_t *cl_entities_mempool;
 extern entity_t *cl_entities;
 extern qbyte *cl_entities_active;
 extern entity_t *cl_static_entities;
@@ -652,6 +655,8 @@ void CL_InitInput (void);
 void CL_SendCmd (usercmd_t *cmd);
 void CL_SendMove (usercmd_t *cmd);
 
+void CL_ValidateState(entity_state_t *s);
+void CL_MoveLerpEntityStates(entity_t *ent);
 void CL_LerpUpdate(entity_t *e);
 void CL_ParseTEnt (void);
 void CL_RelinkBeams (void);
index c20ad3f..89d73de 100644 (file)
--- a/common.c
+++ b/common.c
@@ -190,8 +190,15 @@ void MSG_WriteString (sizebuf_t *sb, const char *s)
                SZ_Write (sb, s, strlen(s)+1);
 }
 
-// used by server (always latest PROTOCOL_DARKPLACES)
-void MSG_WriteDPCoord (sizebuf_t *sb, float f)
+void MSG_WriteCoord13i (sizebuf_t *sb, float f)
+{
+       if (f >= 0)
+               MSG_WriteShort (sb, (int)(f * 8.0f + 0.5f));
+       else
+               MSG_WriteShort (sb, (int)(f * 8.0f - 0.5f));
+}
+
+void MSG_WriteCoord16i (sizebuf_t *sb, float f)
 {
        if (f >= 0)
                MSG_WriteShort (sb, (int)(f + 0.5f));
@@ -199,16 +206,32 @@ void MSG_WriteDPCoord (sizebuf_t *sb, float f)
                MSG_WriteShort (sb, (int)(f - 0.5f));
 }
 
-void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
+void MSG_WriteCoord32f (sizebuf_t *sb, float f)
 {
-       if (f >= 0)
-               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
+       MSG_WriteFloat (sb, f);
+}
+
+void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol)
+{
+       if (protocol == PROTOCOL_QUAKE)
+               MSG_WriteCoord13i (sb, f);
+       else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
+               MSG_WriteCoord32f (sb, f);
+       else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
+               MSG_WriteCoord16i (sb, f);
        else
-               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
+               Host_Error("MSG_WriteCoord: unknown protocol\n");
+}
+
+void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol)
+{
+       MSG_WriteCoord (sb, v[0], protocol);
+       MSG_WriteCoord (sb, v[1], protocol);
+       MSG_WriteCoord (sb, v[2], protocol);
 }
 
 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
-void MSG_WriteAngle (sizebuf_t *sb, float f)
+void MSG_WriteAngle8i (sizebuf_t *sb, float f)
 {
        if (f >= 0)
                MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
@@ -216,6 +239,20 @@ void MSG_WriteAngle (sizebuf_t *sb, float f)
                MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
 }
 
+void MSG_WriteAngle16i (sizebuf_t *sb, float f)
+{
+       if (f >= 0)
+               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
+       else
+               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
+}
+
+void MSG_WriteAngle32f (sizebuf_t *sb, float f)
+{
+       MSG_WriteFloat (sb, f);
+}
+
+
 //
 // reading functions
 //
@@ -324,15 +361,54 @@ int MSG_ReadBytes (int numbytes, unsigned char *out)
        return l;
 }
 
-// used by client
-float MSG_ReadCoord (void)
+float MSG_ReadCoord13i (void)
 {
-       if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
-               return (signed short) MSG_ReadLittleShort();
-       else if (cl.protocol == PROTOCOL_DARKPLACES1)
-               return MSG_ReadLittleFloat();
-       else
-               return MSG_ReadLittleShort() * (1.0f/8.0f);
+       return MSG_ReadLittleShort() * (1.0f/8.0f);
+}
+
+float MSG_ReadCoord16i (void)
+{
+       return (signed short) MSG_ReadLittleShort();
+}
+
+float MSG_ReadCoord32f (void)
+{
+       return MSG_ReadLittleFloat();
+}
+
+float MSG_ReadCoord (int protocol)
+{
+       if (protocol == PROTOCOL_QUAKE)
+               return MSG_ReadCoord13i();
+       else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
+               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;
+}
+
+void MSG_ReadVector (float *v, int protocol)
+{
+       v[0] = MSG_ReadCoord(protocol);
+       v[1] = MSG_ReadCoord(protocol);
+       v[2] = MSG_ReadCoord(protocol);
+}
+
+// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
+float MSG_ReadAngle8i (void)
+{
+       return MSG_ReadByte () * (360.0f/256.0f);
+}
+
+float MSG_ReadAngle16i (void)
+{
+       return MSG_ReadShort () * (360.0f/65536.0f);
+}
+
+float MSG_ReadAngle32f (void)
+{
+       return MSG_ReadFloat ();
 }
 
 
index 48116bb..b6272a8 100644 (file)
--- a/common.h
+++ b/common.h
@@ -115,10 +115,14 @@ void MSG_WriteShort (sizebuf_t *sb, int c);
 void MSG_WriteLong (sizebuf_t *sb, int c);
 void MSG_WriteFloat (sizebuf_t *sb, float f);
 void MSG_WriteString (sizebuf_t *sb, const 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);
-void MSG_WriteDPCoord (sizebuf_t *sb, float f);
+void MSG_WriteAngle8i (sizebuf_t *sb, float f);
+void MSG_WriteAngle16i (sizebuf_t *sb, float f);
+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);
 
 extern int                     msg_readcount;
 extern qboolean        msg_badread;            // set if a read goes beyond end of message
@@ -139,12 +143,14 @@ int MSG_ReadBytes (int numbytes, unsigned char *out);
 #define MSG_ReadLong MSG_ReadLittleLong
 #define MSG_ReadFloat MSG_ReadLittleFloat
 
-float MSG_ReadCoord (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())
+float MSG_ReadAngle8i (void);
+float MSG_ReadAngle16i (void);
+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);
 
 //============================================================================
 
diff --git a/host.c b/host.c
index b1ed19b..ee92486 100644 (file)
--- a/host.c
+++ b/host.c
@@ -455,8 +455,12 @@ void SV_DropClient(qboolean crash)
        NetConn_Heartbeat(1);
 
        // free the client now
+       if (host_client->entitydatabase)
+               EntityFrame_FreeDatabase(host_client->entitydatabase);
        if (host_client->entitydatabase4)
                EntityFrame4_FreeDatabase(host_client->entitydatabase4);
+       if (host_client->entitydatabase5)
+               EntityFrame5_FreeDatabase(host_client->entitydatabase5);
        // clear the client struct (this sets active to false)
        memset(host_client, 0, sizeof(*host_client));
 }
index 7ded7c4..bdae5cf 100644 (file)
@@ -50,6 +50,7 @@ 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, ...);
@@ -71,6 +72,17 @@ 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;
+               default: protocolname = "PROTOCOL_UNKNOWN";break;
+       }
+       print ("protocol: %i (%s)\n", sv.protocol, protocolname);
        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++)
@@ -943,10 +955,9 @@ void Host_Color_f(void)
 }
 
 cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000"};
-cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"};
 void Host_Rate_f(void)
 {
-       int rate, maxrate;
+       int rate;
 
        if (Cmd_Argc() != 2)
        {
@@ -965,12 +976,7 @@ void Host_Rate_f(void)
                return;
        }
 
-       maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
-       if (sv_maxrate.integer != maxrate)
-               Cvar_SetValueQuick(&sv_maxrate, maxrate);
-
-       if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
-               host_client->netconnection->rate = bound(NET_MINRATE, rate, maxrate);
+       host_client->netconnection->rate = rate;
 }
 
 /*
@@ -1210,9 +1216,18 @@ void Host_Spawn_f (void)
        // and it won't happen if the game was just loaded, so you wind up
        // with a permanent head tilt
        MSG_WriteByte (&host_client->message, svc_setangle);
-       for (i=0 ; i < 2 ; i++)
-               MSG_WriteAngle (&host_client->message, sv_player->v->angles[i] );
-       MSG_WriteAngle (&host_client->message, 0 );
+       if (sv.protocol == PROTOCOL_DARKPLACES5)
+       {
+               MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[0]);
+               MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[1]);
+               MSG_WriteAngle16i (&host_client->message, 0);
+       }
+       else
+       {
+               MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[0]);
+               MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[1]);
+               MSG_WriteAngle8i (&host_client->message, 0);
+       }
 
        SV_WriteClientdataToMessage (sv_player, &host_client->message);
 
@@ -1778,7 +1793,6 @@ void Host_InitCommands (void)
        Cmd_AddCommand ("color", Host_Color_f);
        Cvar_RegisterVariable (&cl_rate);
        Cmd_AddCommand ("rate", Host_Rate_f);
-       Cvar_RegisterVariable (&sv_maxrate);
        if (gamemode == GAME_NEHAHRA)
        {
                Cvar_RegisterVariable (&cl_pmodel);
diff --git a/menu.c b/menu.c
index c4de8c3..8a1105d 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -3276,9 +3276,6 @@ int maxplayers;
 qboolean m_serverInfoMessage = false;
 double m_serverInfoMessageTime;
 
-extern cvar_t sv_public;
-extern cvar_t sv_maxrate;
-
 void M_Menu_GameOptions_f (void)
 {
        key_dest = key_menu;
index d3865d5..f04ab60 100644 (file)
@@ -756,6 +756,7 @@ q3dpvs_t;
 
 #define CHECKPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] & (1 << ((b) & 7))) : false)
 #define SETPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] |= (1 << ((b) & 7))) : false)
+#define CLEARPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] &= ~(1 << ((b) & 7))) : false)
 
 #endif
 
index 12636d4..591056c 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -1119,21 +1119,16 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length,
                                                                if (clientnum < svs.maxclients)
                                                                {
                                                                        // prepare the client struct
-                                                                       if ((client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool)))
+                                                                       if ((conn = NetConn_Open(mysocket, peeraddress)))
                                                                        {
-                                                                               if ((conn = NetConn_Open(mysocket, peeraddress)))
-                                                                               {
-                                                                                       // allocated connection
-                                                                                       LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true);
-                                                                                       if (developer.integer)
-                                                                                               Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address);
-                                                                                       NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
-                                                                                       // now set up the client
-                                                                                       SV_ConnectClient(clientnum, conn);
-                                                                                       NetConn_Heartbeat(1);
-                                                                               }
-                                                                               else
-                                                                                       EntityFrame4_FreeDatabase(client->entitydatabase4);
+                                                                               // allocated connection
+                                                                               LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true);
+                                                                               if (developer.integer)
+                                                                                       Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address);
+                                                                               NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
+                                                                               // now set up the client
+                                                                               SV_ConnectClient(clientnum, conn);
+                                                                               NetConn_Heartbeat(1);
                                                                        }
                                                                }
                                                                else
index 3465c47..32fe4cf 100644 (file)
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -630,7 +630,7 @@ void PF_ambientsound (void)
        char            *samp;
        float           *pos;
        float           vol, attenuation;
-       int                     i, soundnum, large;
+       int                     soundnum, large;
 
        pos = G_VECTOR (OFS_PARM0);
        samp = G_STRING(OFS_PARM1);
@@ -659,8 +659,7 @@ void PF_ambientsound (void)
        else
                MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
 
-       for (i=0 ; i<3 ; i++)
-               MSG_WriteDPCoord(&sv.signon, pos[i]);
+       MSG_WriteVector(&sv.signon, pos, sv.protocol);
 
        if (large)
                MSG_WriteShort (&sv.signon, soundnum);
@@ -1352,6 +1351,7 @@ void PF_precache_sound (void)
 {
        char    *s;
        int             i;
+       int             limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
 
        if (sv.state != ss_loading)
                PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
@@ -1360,7 +1360,7 @@ void PF_precache_sound (void)
        G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
        PR_CheckEmptyString (s);
 
-       for (i=0 ; i<MAX_SOUNDS ; i++)
+       for (i=0 ; i<limit ; i++)
        {
                if (!sv.sound_precache[i])
                {
@@ -1377,6 +1377,7 @@ void PF_precache_model (void)
 {
        char    *s;
        int             i;
+       int             limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
 
        if (sv.state != ss_loading)
                PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
@@ -1387,7 +1388,7 @@ void PF_precache_model (void)
        G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
        PR_CheckEmptyString (s);
 
-       for (i=0 ; i<MAX_MODELS ; i++)
+       for (i = 0;i < limit;i++)
        {
                if (!sv.model_precache[i])
                {
@@ -1876,12 +1877,15 @@ void PF_WriteLong (void)
 
 void PF_WriteAngle (void)
 {
-       MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
+       if (sv.protocol == PROTOCOL_DARKPLACES5)
+               MSG_WriteAngle16i (WriteDest(), G_FLOAT(OFS_PARM1));
+       else
+               MSG_WriteAngle8i (WriteDest(), G_FLOAT(OFS_PARM1));
 }
 
 void PF_WriteCoord (void)
 {
-       MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
+       MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
 }
 
 void PF_WriteString (void)
@@ -1929,8 +1933,8 @@ void PF_makestatic (void)
        MSG_WriteByte (&sv.signon, ent->v->skin);
        for (i=0 ; i<3 ; i++)
        {
-               MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
-               MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
+               MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
+               MSG_WriteAngle8i(&sv.signon, ent->v->angles[i]);
        }
 
 // throw the entity away now
@@ -2239,12 +2243,16 @@ effect(origin, modelname, startframe, framecount, framerate)
 */
 void PF_effect (void)
 {
+       int i;
        char *s;
        s = G_STRING(OFS_PARM1);
        if (!s || !s[0])
                PF_WARNING("effect: no model specified\n");
 
-       SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
+       i = SV_ModelIndex(s);
+       if (i < 0)
+               PF_WARNING("effect: model not precached\n");
+       SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
 }
 
 void PF_te_blood (void)
@@ -2254,9 +2262,9 @@ void PF_te_blood (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_BLOOD);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // 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));
@@ -2272,15 +2280,15 @@ void PF_te_bloodshower (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
        // min
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // max
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // speed
-       MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
+       MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
 }
@@ -2290,9 +2298,9 @@ void PF_te_explosionrgb (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // 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));
@@ -2306,17 +2314,17 @@ void PF_te_particlecube (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
        // min
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // max
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // velocity
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -2324,7 +2332,7 @@ void PF_te_particlecube (void)
        // gravity true/false
        MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
        // randomvel
-       MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
+       MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
 }
 
 void PF_te_particlerain (void)
@@ -2334,17 +2342,17 @@ void PF_te_particlerain (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
        // min
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // max
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // velocity
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -2358,17 +2366,17 @@ void PF_te_particlesnow (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
        // min
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // max
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // velocity
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
        // count
        MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
        // color
@@ -2382,9 +2390,9 @@ void PF_te_spark (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPARK);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // 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));
@@ -2398,9 +2406,9 @@ void PF_te_gunshotquad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_spikequad (void)
@@ -2408,9 +2416,9 @@ void PF_te_spikequad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_superspikequad (void)
@@ -2418,9 +2426,9 @@ void PF_te_superspikequad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_explosionquad (void)
@@ -2428,9 +2436,9 @@ void PF_te_explosionquad (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_smallflash (void)
@@ -2438,9 +2446,9 @@ void PF_te_smallflash (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_customflash (void)
@@ -2450,9 +2458,9 @@ void PF_te_customflash (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // radius
        MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
        // lifetime
@@ -2468,9 +2476,9 @@ void PF_te_gunshot (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_spike (void)
@@ -2478,9 +2486,9 @@ void PF_te_spike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SPIKE);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_superspike (void)
@@ -2488,9 +2496,9 @@ void PF_te_superspike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_explosion (void)
@@ -2498,9 +2506,9 @@ void PF_te_explosion (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_tarexplosion (void)
@@ -2508,9 +2516,9 @@ void PF_te_tarexplosion (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_wizspike (void)
@@ -2518,9 +2526,9 @@ void PF_te_wizspike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_knightspike (void)
@@ -2528,9 +2536,9 @@ void PF_te_knightspike (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_lavasplash (void)
@@ -2538,9 +2546,9 @@ void PF_te_lavasplash (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_teleport (void)
@@ -2548,9 +2556,9 @@ void PF_te_teleport (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_TELEPORT);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 void PF_te_explosion2 (void)
@@ -2558,9 +2566,9 @@ void PF_te_explosion2 (void)
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
        // origin
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // color
        MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
        MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
@@ -2573,13 +2581,13 @@ void PF_te_lightning1 (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // end
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
 }
 
 void PF_te_lightning2 (void)
@@ -2589,13 +2597,13 @@ void PF_te_lightning2 (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // end
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
 }
 
 void PF_te_lightning3 (void)
@@ -2605,13 +2613,13 @@ void PF_te_lightning3 (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // end
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
 }
 
 void PF_te_beam (void)
@@ -2621,22 +2629,22 @@ void PF_te_beam (void)
        // owner entity
        MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
        // start
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // end
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
 }
 
 void PF_te_plasmaburn (void)
 {
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
        MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
-       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]);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+       MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
 }
 
 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
diff --git a/progs.h b/progs.h
index 18d1588..b157812 100644 (file)
--- a/progs.h
+++ b/progs.h
@@ -57,13 +57,9 @@ typedef struct edict_engineprivate_s
        // we should avoid extensive checking on entities already encountered
        int areagridmarknumber;
 
-       // old entity protocol, not used
-#ifdef QUAKEENTITIES
+       // PROTOCOL_QUAKE
        // baseline values
        entity_state_t baseline;
-       // LordHavoc: previous frame
-       entity_state_t deltabaseline;
-#endif
 
        // LordHavoc: gross hack to make floating items still work
        int suspendedinairflag;
index 2d28852..72870b3 100644 (file)
 // this is 80 bytes
 entity_state_t defaultstate =
 {
-       // ! means this is sent to client
-       0,//double time; // time this state was built (used on client for interpolation)
-       {0,0,0},//float origin[3]; // !
-       {0,0,0},//float angles[3]; // !
-       0,//int number; // ! entity number this state is for
-       0,//int effects; // !
-       0,//unsigned short modelindex; // !
-       0,//unsigned short frame; // !
-       0,//unsigned short tagentity; // !
-       0,//unsigned short specialvisibilityradius; // larger if it has effects/light
-       0,//unsigned short viewmodelforclient;
-       0,//unsigned short exteriormodelforclient; // not shown if first person viewing from this entity, shown in all other cases
-       0,//unsigned short nodrawtoclient;
-       0,//unsigned short drawonlytoclient;
-       {0,0,0,0},//unsigned short light[4]; // ! color*256 (0.00 to 255.996), and radius*1
-       0,//unsigned char active; // ! true if a valid state
-       0,//unsigned char lightstyle; // !
-       0,//unsigned char lightpflags; // !
-       0,//unsigned char colormap; // !
-       0,//unsigned char skin; // ! also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
-       255,//unsigned char alpha; // !
-       16,//unsigned char scale; // !
-       0,//unsigned char glowsize; // !
-       254,//unsigned char glowcolor; // !
-       0,//unsigned char flags; // !
-       0,//unsigned char tagindex; // !
+       // ! means this is not sent to client
+       0,//double time; // ! time this state was built (used on client for interpolation)
+       {0,0,0},//float origin[3];
+       {0,0,0},//float angles[3];
+       0,//int number; // entity number this state is for
+       0,//int effects;
+       0,//unsigned short modelindex;
+       0,//unsigned short frame;
+       0,//unsigned short tagentity;
+       0,//unsigned short specialvisibilityradius; // ! larger if it has effects/light
+       0,//unsigned short viewmodelforclient; // !
+       0,//unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
+       0,//unsigned short nodrawtoclient; // !
+       0,//unsigned short drawonlytoclient; // !
+       {0,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
+       0,//unsigned char active; // true if a valid state
+       0,//unsigned char lightstyle;
+       0,//unsigned char lightpflags;
+       0,//unsigned char colormap;
+       0,//unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
+       255,//unsigned char alpha;
+       16,//unsigned char scale;
+       0,//unsigned char glowsize;
+       254,//unsigned char glowcolor;
+       0,//unsigned char flags;
+       0,//unsigned char tagindex;
+       255,//unsigned char colormod;
        // padding to a multiple of 8 bytes (to align the double time)
-       {0,0,0,0,0}//unsigned char unused[5];
+       {0,0,0,0}//unsigned char unused[4]; // !
 };
 
-void ClearStateToDefault(entity_state_t *s)
+double entityframequake_mtime = 0;
+
+void EntityFrameQuake_ReadEntity(int bits)
 {
-       *s = defaultstate;
+       int num;
+       entity_t *ent;
+       entity_state_t s;
+
+       entityframequake_mtime = cl.mtime[0];
+
+       if (bits & U_MOREBITS)
+               bits |= (MSG_ReadByte()<<8);
+       if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
+       {
+               bits |= MSG_ReadByte() << 16;
+               if (bits & U_EXTEND2)
+                       bits |= MSG_ReadByte() << 24;
+       }
+
+       if (bits & U_LONGENTITY)
+               num = (unsigned short) MSG_ReadShort ();
+       else
+               num = MSG_ReadByte ();
+
+       if (num >= MAX_EDICTS)
+               Host_Error("EntityFrameQuake_ReadEntity: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
+       if (num < 1)
+               Host_Error("EntityFrameQuake_ReadEntity: invalid entity number (%i)\n", num);
+
+       ent = cl_entities + num;
+
+       // note: this inherits the 'active' state of the baseline chosen
+       // (state_baseline is always active, state_current may not be active if
+       // the entity was missing in the last frame)
+       if (bits & U_DELTA)
+               s = ent->state_current;
+       else
+       {
+               s = ent->state_baseline;
+               s.active = true;
+       }
+
+       s.number = num;
+       s.time = cl.mtime[0];
+       s.flags = 0;
+       if (bits & U_MODEL)             s.modelindex = (s.modelindex & 0xFF00) | MSG_ReadByte();
+       if (bits & U_FRAME)             s.frame = (s.frame & 0xFF00) | MSG_ReadByte();
+       if (bits & U_COLORMAP)  s.colormap = MSG_ReadByte();
+       if (bits & U_SKIN)              s.skin = MSG_ReadByte();
+       if (bits & U_EFFECTS)   s.effects = (s.effects & 0xFF00) | MSG_ReadByte();
+       if (bits & U_ORIGIN1)   s.origin[0] = MSG_ReadCoord13i();
+       if (bits & U_ANGLE1)    s.angles[0] = MSG_ReadAngle8i();
+       if (bits & U_ORIGIN2)   s.origin[1] = MSG_ReadCoord13i();
+       if (bits & U_ANGLE2)    s.angles[1] = MSG_ReadAngle8i();
+       if (bits & U_ORIGIN3)   s.origin[2] = MSG_ReadCoord13i();
+       if (bits & U_ANGLE3)    s.angles[2] = MSG_ReadAngle8i();
+       if (bits & U_STEP)              s.flags |= RENDER_STEP;
+       if (bits & U_ALPHA)             s.alpha = MSG_ReadByte();
+       if (bits & U_SCALE)             s.scale = MSG_ReadByte();
+       if (bits & U_EFFECTS2)  s.effects = (s.effects & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_GLOWSIZE)  s.glowsize = MSG_ReadByte();
+       if (bits & U_GLOWCOLOR) s.glowcolor = MSG_ReadByte();
+       if (bits & U_COLORMOD)  s.colormod = MSG_ReadByte();
+       if (bits & U_GLOWTRAIL) s.flags |= RENDER_GLOWTRAIL;
+       if (bits & U_FRAME2)    s.frame = (s.frame & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_MODEL2)    s.modelindex = (s.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_VIEWMODEL) s.flags |= RENDER_VIEWMODEL;
+       if (bits & U_EXTERIORMODEL)     s.flags |= RENDER_EXTERIORMODEL;
+
+       // LordHavoc: to allow playback of the Nehahra movie
+       if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
+       {
+               // LordHavoc: evil format
+               int i = MSG_ReadFloat();
+               int j = MSG_ReadFloat() * 255.0f;
+               if (i == 2)
+               {
+                       i = MSG_ReadFloat();
+                       if (i)
+                               s.effects |= EF_FULLBRIGHT;
+               }
+               if (j < 0)
+                       s.alpha = 0;
+               else if (j == 0 || j >= 255)
+                       s.alpha = 255;
+               else
+                       s.alpha = j;
+       }
+
+       ent->state_previous = ent->state_current;
+       ent->state_current = s;
+       if (ent->state_current.active)
+       {
+               CL_MoveLerpEntityStates(ent);
+               cl_entities_active[ent->state_current.number] = true;
+       }
+
+       if (msg_badread)
+               Host_Error("EntityFrameQuake_ReadEntity: read error\n");
+}
+
+void EntityFrameQuake_ISeeDeadEntities(void)
+{
+       int i;
+       for (i = 0;i < cl_max_entities;i++)
+       {
+               if (cl_entities_active[i] && cl_entities[i].state_current.time != cl.mtime[0])
+               {
+                       cl_entities_active[i] = false;
+                       cl_entities[i].state_current = defaultstate;
+                       cl_entities[i].state_current.number = i;
+               }
+       }
+}
+
+void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_state_t *states)
+{
+       const entity_state_t *s;
+       entity_state_t baseline;
+       int i, bits;
+       sizebuf_t buf;
+       qbyte data[128];
+
+       // prepare the buffer
+       memset(&buf, 0, sizeof(buf));
+       buf.data = data;
+       buf.maxsize = sizeof(data);
+
+       for (i = 0, s = states;i < numstates;i++, s++)
+       {
+               // prepare the buffer
+               SZ_Clear(&buf);
+
+// send an update
+               bits = 0;
+               if (s->number >= 256)
+                       bits |= U_LONGENTITY;
+               if (s->flags & RENDER_STEP)
+                       bits |= U_STEP;
+               if (s->flags & RENDER_VIEWMODEL)
+                       bits |= U_VIEWMODEL;
+               if (s->flags & RENDER_GLOWTRAIL)
+                       bits |= U_GLOWTRAIL;
+               if (s->flags & RENDER_EXTERIORMODEL)
+                       bits |= U_EXTERIORMODEL;
+
+               // LordHavoc: old stuff, but rewritten to have more exact tolerances
+               baseline = sv.edicts[s->number].e->baseline;
+               if (baseline.origin[0] != s->origin[0])
+                       bits |= U_ORIGIN1;
+               if (baseline.origin[1] != s->origin[1])
+                       bits |= U_ORIGIN2;
+               if (baseline.origin[2] != s->origin[2])
+                       bits |= U_ORIGIN3;
+               if (baseline.angles[0] != s->angles[0])
+                       bits |= U_ANGLE1;
+               if (baseline.angles[1] != s->angles[1])
+                       bits |= U_ANGLE2;
+               if (baseline.angles[2] != s->angles[2])
+                       bits |= U_ANGLE3;
+               if (baseline.colormap != s->colormap)
+                       bits |= U_COLORMAP;
+               if (baseline.skin != s->skin)
+                       bits |= U_SKIN;
+               if (baseline.frame != s->frame)
+               {
+                       bits |= U_FRAME;
+                       if (s->frame & 0xFF00)
+                               bits |= U_FRAME2;
+               }
+               if (baseline.effects != s->effects)
+               {
+                       bits |= U_EFFECTS;
+                       if (s->effects & 0xFF00)
+                               bits |= U_EFFECTS2;
+               }
+               if (baseline.modelindex != s->modelindex)
+               {
+                       bits |= U_MODEL;
+                       if (s->modelindex & 0xFF00)
+                               bits |= U_MODEL2;
+               }
+               if (baseline.alpha != s->alpha)
+                       bits |= U_ALPHA;
+               if (baseline.scale != s->scale)
+                       bits |= U_SCALE;
+               if (baseline.glowsize != s->glowsize)
+                       bits |= U_GLOWSIZE;
+               if (baseline.glowcolor != s->glowcolor)
+                       bits |= U_GLOWCOLOR;
+
+               // if extensions are disabled, clear the relevant update flags
+               if (sv.netquakecompatible)
+                       bits &= 0x7FFF;
+
+               // write the message
+               if (bits >= 16777216)
+                       bits |= U_EXTEND2;
+               if (bits >= 65536)
+                       bits |= U_EXTEND1;
+               if (bits >= 256)
+                       bits |= U_MOREBITS;
+               bits |= U_SIGNAL;
+
+               MSG_WriteByte (&buf, bits);
+               if (bits & U_MOREBITS)          MSG_WriteByte(&buf, bits>>8);
+               if (bits & U_EXTEND1)           MSG_WriteByte(&buf, bits>>16);
+               if (bits & U_EXTEND2)           MSG_WriteByte(&buf, bits>>24);
+               if (bits & U_LONGENTITY)        MSG_WriteShort(&buf, s->number);
+               else                                            MSG_WriteByte(&buf, s->number);
+
+               if (bits & U_MODEL)                     MSG_WriteByte(&buf, s->modelindex);
+               if (bits & U_FRAME)                     MSG_WriteByte(&buf, s->frame);
+               if (bits & U_COLORMAP)          MSG_WriteByte(&buf, s->colormap);
+               if (bits & U_SKIN)                      MSG_WriteByte(&buf, s->skin);
+               if (bits & U_EFFECTS)           MSG_WriteByte(&buf, s->effects);
+               if (bits & U_ORIGIN1)           MSG_WriteCoord13i(&buf, s->origin[0]);
+               if (bits & U_ANGLE1)            MSG_WriteAngle8i(&buf, s->angles[0]);
+               if (bits & U_ORIGIN2)           MSG_WriteCoord13i(&buf, s->origin[1]);
+               if (bits & U_ANGLE2)            MSG_WriteAngle8i(&buf, s->angles[1]);
+               if (bits & U_ORIGIN3)           MSG_WriteCoord13i(&buf, s->origin[2]);
+               if (bits & U_ANGLE3)            MSG_WriteAngle8i(&buf, s->angles[2]);
+               if (bits & U_ALPHA)                     MSG_WriteByte(&buf, s->alpha);
+               if (bits & U_SCALE)                     MSG_WriteByte(&buf, s->scale);
+               if (bits & U_EFFECTS2)          MSG_WriteByte(&buf, s->effects >> 8);
+               if (bits & U_GLOWSIZE)          MSG_WriteByte(&buf, s->glowsize);
+               if (bits & U_GLOWCOLOR)         MSG_WriteByte(&buf, s->glowcolor);
+               if (bits & U_COLORMOD)          MSG_WriteByte(&buf, s->colormod);
+               if (bits & U_FRAME2)            MSG_WriteByte(&buf, s->frame >> 8);
+               if (bits & U_MODEL2)            MSG_WriteByte(&buf, s->modelindex >> 8);
+
+               // if the commit is full, we're done this frame
+               if (msg->cursize + buf.cursize > msg->maxsize)
+               {
+                       // next frame we will continue where we left off
+                       break;
+               }
+               // write the message to the packet
+               SZ_Write(msg, buf.data, buf.cursize);
+       }
 }
 
 int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n)
@@ -120,40 +358,58 @@ void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits)
        }
 }
 
-void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int bits)
+void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits)
 {
-       // LordHavoc: have to write flags first, as they can modify protocol
-       if (bits & E_FLAGS)
-               MSG_WriteByte(msg, ent->flags);
-       if (ent->flags & RENDER_LOWPRECISION)
+       if (sv.protocol == PROTOCOL_DARKPLACES2)
        {
                if (bits & E_ORIGIN1)
-                       MSG_WriteShort(msg, ent->origin[0]);
+                       MSG_WriteCoord16i(msg, ent->origin[0]);
                if (bits & E_ORIGIN2)
-                       MSG_WriteShort(msg, ent->origin[1]);
+                       MSG_WriteCoord16i(msg, ent->origin[1]);
                if (bits & E_ORIGIN3)
-                       MSG_WriteShort(msg, ent->origin[2]);
+                       MSG_WriteCoord16i(msg, ent->origin[2]);
+       }
+       else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+       {
+               // LordHavoc: have to write flags first, as they can modify protocol
+               if (bits & E_FLAGS)
+                       MSG_WriteByte(msg, ent->flags);
+               if (ent->flags & RENDER_LOWPRECISION)
+               {
+                       if (bits & E_ORIGIN1)
+                               MSG_WriteCoord16i(msg, ent->origin[0]);
+                       if (bits & E_ORIGIN2)
+                               MSG_WriteCoord16i(msg, ent->origin[1]);
+                       if (bits & E_ORIGIN3)
+                               MSG_WriteCoord16i(msg, ent->origin[2]);
+               }
+               else
+               {
+                       if (bits & E_ORIGIN1)
+                               MSG_WriteCoord32f(msg, ent->origin[0]);
+                       if (bits & E_ORIGIN2)
+                               MSG_WriteCoord32f(msg, ent->origin[1]);
+                       if (bits & E_ORIGIN3)
+                               MSG_WriteCoord32f(msg, ent->origin[2]);
+               }
+       }
+       if (sv.protocol == PROTOCOL_DARKPLACES5 && !(ent->flags & RENDER_LOWPRECISION))
+       {
                if (bits & E_ANGLE1)
-                       MSG_WriteAngle(msg, ent->angles[0]);
+                       MSG_WriteAngle16i(msg, ent->angles[0]);
                if (bits & E_ANGLE2)
-                       MSG_WriteAngle(msg, ent->angles[1]);
+                       MSG_WriteAngle16i(msg, ent->angles[1]);
                if (bits & E_ANGLE3)
-                       MSG_WriteAngle(msg, ent->angles[2]);
+                       MSG_WriteAngle16i(msg, ent->angles[2]);
        }
        else
        {
-               if (bits & E_ORIGIN1)
-                       MSG_WriteFloat(msg, ent->origin[0]);
-               if (bits & E_ORIGIN2)
-                       MSG_WriteFloat(msg, ent->origin[1]);
-               if (bits & E_ORIGIN3)
-                       MSG_WriteFloat(msg, ent->origin[2]);
                if (bits & E_ANGLE1)
-                       MSG_WritePreciseAngle(msg, ent->angles[0]);
+                       MSG_WriteAngle8i(msg, ent->angles[0]);
                if (bits & E_ANGLE2)
-                       MSG_WritePreciseAngle(msg, ent->angles[1]);
+                       MSG_WriteAngle8i(msg, ent->angles[1]);
                if (bits & E_ANGLE3)
-                       MSG_WritePreciseAngle(msg, ent->angles[2]);
+                       MSG_WriteAngle8i(msg, ent->angles[2]);
        }
        if (bits & E_MODEL1)
                MSG_WriteByte(msg, ent->modelindex & 0xFF);
@@ -179,6 +435,9 @@ void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int b
                MSG_WriteByte(msg, ent->glowsize);
        if (bits & E_GLOWCOLOR)
                MSG_WriteByte(msg, ent->glowcolor);
+       if (sv.protocol == PROTOCOL_DARKPLACES2)
+               if (bits & E_FLAGS)
+                       MSG_WriteByte(msg, ent->flags);
        if (bits & E_TAGATTACHMENT)
        {
                MSG_WriteShort(msg, ent->tagentity);
@@ -197,7 +456,7 @@ void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int b
                MSG_WriteByte(msg, ent->lightpflags);
 }
 
-void EntityState_WriteUpdate(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta)
+void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta)
 {
        unsigned int bits;
        if (ent->active)
@@ -244,52 +503,52 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
        if (cl.protocol == PROTOCOL_DARKPLACES2)
        {
                if (bits & E_ORIGIN1)
-                       e->origin[0] = (signed short) MSG_ReadShort();
+                       e->origin[0] = MSG_ReadCoord16i();
                if (bits & E_ORIGIN2)
-                       e->origin[1] = (signed short) MSG_ReadShort();
+                       e->origin[1] = MSG_ReadCoord16i();
                if (bits & E_ORIGIN3)
-                       e->origin[2] = (signed short) MSG_ReadShort();
+                       e->origin[2] = MSG_ReadCoord16i();
        }
-       else
+       else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
        {
                if (bits & E_FLAGS)
                        e->flags = MSG_ReadByte();
-               if (e->flags & RENDER_LOWPRECISION || cl.protocol == PROTOCOL_DARKPLACES2)
+               if (e->flags & RENDER_LOWPRECISION)
                {
                        if (bits & E_ORIGIN1)
-                               e->origin[0] = (signed short) MSG_ReadShort();
+                               e->origin[0] = MSG_ReadCoord16i();
                        if (bits & E_ORIGIN2)
-                               e->origin[1] = (signed short) MSG_ReadShort();
+                               e->origin[1] = MSG_ReadCoord16i();
                        if (bits & E_ORIGIN3)
-                               e->origin[2] = (signed short) MSG_ReadShort();
+                               e->origin[2] = MSG_ReadCoord16i();
                }
                else
                {
                        if (bits & E_ORIGIN1)
-                               e->origin[0] = MSG_ReadFloat();
+                               e->origin[0] = MSG_ReadCoord32f();
                        if (bits & E_ORIGIN2)
-                               e->origin[1] = MSG_ReadFloat();
+                               e->origin[1] = MSG_ReadCoord32f();
                        if (bits & E_ORIGIN3)
-                               e->origin[2] = MSG_ReadFloat();
+                               e->origin[2] = MSG_ReadCoord32f();
                }
        }
        if (cl.protocol == PROTOCOL_DARKPLACES5 && !(e->flags & RENDER_LOWPRECISION))
        {
                if (bits & E_ANGLE1)
-                       e->angles[0] = MSG_ReadPreciseAngle();
+                       e->angles[0] = MSG_ReadAngle16i();
                if (bits & E_ANGLE2)
-                       e->angles[1] = MSG_ReadPreciseAngle();
+                       e->angles[1] = MSG_ReadAngle16i();
                if (bits & E_ANGLE3)
-                       e->angles[2] = MSG_ReadPreciseAngle();
+                       e->angles[2] = MSG_ReadAngle16i();
        }
        else
        {
                if (bits & E_ANGLE1)
-                       e->angles[0] = MSG_ReadAngle();
+                       e->angles[0] = MSG_ReadAngle8i();
                if (bits & E_ANGLE2)
-                       e->angles[1] = MSG_ReadAngle();
+                       e->angles[1] = MSG_ReadAngle8i();
                if (bits & E_ANGLE3)
-                       e->angles[2] = MSG_ReadAngle();
+                       e->angles[2] = MSG_ReadAngle8i();
        }
        if (bits & E_MODEL1)
                e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte();
@@ -320,15 +579,15 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
                        e->flags = MSG_ReadByte();
        if (bits & E_TAGATTACHMENT)
        {
-               e->tagentity = MSG_ReadShort();
+               e->tagentity = (unsigned short) MSG_ReadShort();
                e->tagindex = MSG_ReadByte();
        }
        if (bits & E_LIGHT)
        {
-               e->light[0] = MSG_ReadShort();
-               e->light[1] = MSG_ReadShort();
-               e->light[2] = MSG_ReadShort();
-               e->light[3] = MSG_ReadShort();
+               e->light[0] = (unsigned short) MSG_ReadShort();
+               e->light[1] = (unsigned short) MSG_ReadShort();
+               e->light[2] = (unsigned short) MSG_ReadShort();
+               e->light[3] = (unsigned short) MSG_ReadShort();
        }
        if (bits & E_LIGHTSTYLE)
                e->lightstyle = MSG_ReadByte();
@@ -385,18 +644,30 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
        }
 }
 
+// (client and server) allocates a new empty database
+entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool)
+{
+       return Mem_Alloc(mempool, sizeof(entityframe_database_t));
+}
+
+// (client and server) frees the database
+void EntityFrame_FreeDatabase(entityframe_database_t *d)
+{
+       Mem_Free(d);
+}
+
 // (server) clears the database to contain no frames (thus delta compression compresses against nothing)
-void EntityFrame_ClearDatabase(entity_database_t *d)
+void EntityFrame_ClearDatabase(entityframe_database_t *d)
 {
        memset(d, 0, sizeof(*d));
 }
 
 // (server and client) removes frames older than 'frame' from database
-void EntityFrame_AckFrame(entity_database_t *d, int frame)
+void EntityFrame_AckFrame(entityframe_database_t *d, int frame)
 {
        int i;
-       if (d->ackframe < frame)
-               d->ackframe = frame;
+       if (d->ackframenum < frame)
+               d->ackframenum = frame;
        for (i = 0;i < d->numframes && d->frames[i].framenum < frame;i++);
        // ignore outdated frame acks (out of order packets)
        if (i == 0)
@@ -414,27 +685,13 @@ void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum)
        f->framenum = framenum;
        f->numentities = 0;
        if (eye == NULL)
-       {
                VectorClear(f->eye);
-       }
        else
-       {
                VectorCopy(eye, f->eye);
-       }
-}
-
-// (server) adds an entity to frame
-void EntityFrame_AddEntity(entity_frame_t *f, entity_state_t *s)
-{
-       if (f->numentities < MAX_ENTITY_DATABASE)
-       {
-               f->entitydata[f->numentities] = *s;
-               f->entitydata[f->numentities++].active = true;
-       }
 }
 
 // (server and client) reads a frame from the database
-void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f)
+void EntityFrame_FetchFrame(entityframe_database_t *d, int framenum, entity_frame_t *f)
 {
        int i, n;
        EntityFrame_Clear(f, NULL, -1);
@@ -454,18 +711,18 @@ void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *
 }
 
 // (server and client) adds a entity_frame to the database, for future reference
-void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f)
+void EntityFrame_AddFrame(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata)
 {
        int n, e;
        entity_frameinfo_t *info;
 
-       VectorCopy(f->eye, d->eye);
+       VectorCopy(eye, d->eye);
 
        // figure out how many entity slots are used already
        if (d->numframes)
        {
                n = d->frames[d->numframes - 1].endentity - d->frames[0].firstentity;
-               if (n + f->numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY)
+               if (n + numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY)
                {
                        // ran out of room, dump database
                        EntityFrame_ClearDatabase(d);
@@ -473,14 +730,14 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f)
        }
 
        info = &d->frames[d->numframes];
-       info->framenum = f->framenum;
+       info->framenum = 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)
+                       if (e == framenum)
                                Con_Print("EntityFrame_AddFrame: tried to add out of sequence frame to database\n");
                        else
                                Con_Print("EntityFrame_AddFrame: out of sequence frames in database\n");
@@ -493,40 +750,54 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f)
                info->firstentity = d->frames[d->numframes - 1].endentity;
        else
                info->firstentity = 0;
-       info->endentity = info->firstentity + f->numentities;
+       info->endentity = info->firstentity + numentities;
        d->numframes++;
 
        n = info->firstentity % MAX_ENTITY_DATABASE;
        e = MAX_ENTITY_DATABASE - n;
-       if (e > f->numentities)
-               e = f->numentities;
-       memcpy(d->entitydata + n, f->entitydata, sizeof(entity_state_t) * e);
-       if (f->numentities > e)
-               memcpy(d->entitydata, f->entitydata + e, sizeof(entity_state_t) * (f->numentities - e));
+       if (e > numentities)
+               e = numentities;
+       memcpy(d->entitydata + n, entitydata, sizeof(entity_state_t) * e);
+       if (numentities > e)
+               memcpy(d->entitydata, entitydata + e, sizeof(entity_state_t) * (numentities - e));
 }
 
 // (server) writes a frame to network stream
 static entity_frame_t deltaframe; // FIXME?
-void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg)
+void EntityFrame_WriteFrame(sizebuf_t *msg, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum)
 {
        int i, onum, number;
        entity_frame_t *o = &deltaframe;
-       entity_state_t *ent, *delta;
+       const entity_state_t *ent, *delta;
+       vec3_t eye;
+
+       d->latestframenum++;
+
+       VectorClear(eye);
+       for (i = 0;i < numstates;i++)
+       {
+               if (states[i].number == viewentnum)
+               {
+                       VectorSet(eye, states[i].origin[0], states[i].origin[1], states[i].origin[2] + 22);
+                       break;
+               }
+       }
 
-       EntityFrame_AddFrame(d, f);
+       EntityFrame_AddFrame(d, eye, d->latestframenum, numstates, states);
+
+       EntityFrame_FetchFrame(d, d->ackframenum > 0 ? d->ackframenum : -1, o);
 
-       EntityFrame_FetchFrame(d, d->ackframe > 0 ? d->ackframe : -1, o);
        MSG_WriteByte (msg, svc_entities);
        MSG_WriteLong (msg, o->framenum);
-       MSG_WriteLong (msg, f->framenum);
-       MSG_WriteFloat (msg, f->eye[0]);
-       MSG_WriteFloat (msg, f->eye[1]);
-       MSG_WriteFloat (msg, f->eye[2]);
+       MSG_WriteLong (msg, d->latestframenum);
+       MSG_WriteFloat (msg, eye[0]);
+       MSG_WriteFloat (msg, eye[1]);
+       MSG_WriteFloat (msg, eye[2]);
 
        onum = 0;
-       for (i = 0;i < f->numentities;i++)
+       for (i = 0;i < numstates;i++)
        {
-               ent = f->entitydata + i;
+               ent = states + i;
                number = ent->number;
                for (;onum < o->numentities && o->entitydata[onum].number < number;onum++)
                {
@@ -557,11 +828,16 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg)
 
 // (client) reads a frame from network stream
 static entity_frame_t framedata; // FIXME?
-void EntityFrame_Read(entity_database_t *d)
+void EntityFrame_CL_ReadFrame(void)
 {
-       int number, removed;
+       int i, number, removed;
        entity_frame_t *f = &framedata, *delta = &deltaframe;
        entity_state_t *e, *old, *oldend;
+       entity_t *ent;
+       entityframe_database_t *d;
+       if (!cl.entitydatabase)
+               cl.entitydatabase = EntityFrame_AllocDatabase(cl_entities_mempool);
+       d = cl.entitydatabase;
 
        EntityFrame_Clear(f, NULL, -1);
 
@@ -577,7 +853,7 @@ void EntityFrame_Read(entity_database_t *d)
        old = delta->entitydata;
        oldend = old + delta->numentities;
        // read entities until we hit the magic 0xFFFF end tag
-       while ((number = (unsigned short) MSG_ReadShort()) != 0xFFFF)
+       while ((number = (unsigned short) MSG_ReadShort()) != 0xFFFF && !msg_badread)
        {
                if (msg_badread)
                        Host_Error("EntityFrame_Read: read error\n");
@@ -634,12 +910,42 @@ void EntityFrame_Read(entity_database_t *d)
                f->entitydata[f->numentities] = *old++;
                f->entitydata[f->numentities++].time = cl.mtime[0];
        }
-       EntityFrame_AddFrame(d, f);
+       EntityFrame_AddFrame(d, f->eye, f->framenum, f->numentities, f->entitydata);
+
+       memset(cl_entities_active, 0, cl_max_entities * sizeof(qbyte));
+       number = 1;
+       for (i = 0;i < f->numentities;i++)
+       {
+               for (;number < f->entitydata[i].number;number++)
+               {
+                       if (cl_entities_active[number])
+                       {
+                               cl_entities_active[number] = false;
+                               cl_entities[number].state_current.active = false;
+                       }
+               }
+               // update the entity
+               ent = &cl_entities[number];
+               ent->state_previous = ent->state_current;
+               ent->state_current = f->entitydata[i];
+               CL_MoveLerpEntityStates(ent);
+               // the entity lives again...
+               cl_entities_active[number] = true;
+               number++;
+       }
+       for (;number < cl_max_entities;number++)
+       {
+               if (cl_entities_active[number])
+               {
+                       cl_entities_active[number] = false;
+                       cl_entities[number].state_current.active = false;
+               }
+       }
 }
 
 
 // (client) returns the frame number of the most recent frame recieved
-int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d)
+int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d)
 {
        if (d->numframes)
                return d->frames[d->numframes - 1].framenum;
@@ -652,7 +958,7 @@ int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d)
 
 
 
-entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int number)
+entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number)
 {
        if (d->maxreferenceentities <= number)
        {
@@ -675,7 +981,7 @@ entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int numbe
        return d->referenceentity + number;
 }
 
-void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s)
+void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s)
 {
        // resize commit's entity list if full
        if (d->currentcommit->maxentities <= d->currentcommit->numentities)
@@ -692,9 +998,9 @@ void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s)
        d->currentcommit->entity[d->currentcommit->numentities++] = *s;
 }
 
-entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool)
+entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool)
 {
-       entity_database4_t *d;
+       entityframe4_database_t *d;
        d = Mem_Alloc(pool, sizeof(*d));
        d->mempool = pool;
        EntityFrame4_ResetDatabase(d);
@@ -702,7 +1008,7 @@ entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool)
        return d;
 }
 
-void EntityFrame4_FreeDatabase(entity_database4_t *d)
+void EntityFrame4_FreeDatabase(entityframe4_database_t *d)
 {
        int i;
        for (i = 0;i < MAX_ENTITY_HISTORY;i++)
@@ -713,7 +1019,7 @@ void EntityFrame4_FreeDatabase(entity_database4_t *d)
        Mem_Free(d);
 }
 
-void EntityFrame4_ResetDatabase(entity_database4_t *d)
+void EntityFrame4_ResetDatabase(entityframe4_database_t *d)
 {
        int i;
        d->ackframenum = -1;
@@ -724,7 +1030,7 @@ void EntityFrame4_ResetDatabase(entity_database4_t *d)
                d->referenceentity[i] = defaultstate;
 }
 
-int EntityFrame4_AckFrame(entity_database4_t *d, int framenum)
+int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum)
 {
        int i, j, found;
        entity_database4_commit_t *commit;
@@ -783,43 +1089,20 @@ int EntityFrame4_AckFrame(entity_database4_t *d, int framenum)
        return found;
 }
 
-int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s)
-{
-       qbyte data[128];
-       sizebuf_t buf;
-       entity_state_t *e;
-       // prepare the buffer
-       memset(&buf, 0, sizeof(buf));
-       buf.data = data;
-       buf.maxsize = sizeof(data);
-       // make the update message
-       e = EntityFrame4_GetReferenceEntity(d, s->number);
-       EntityState_WriteUpdate(s, &buf, e);
-       // if the message is empty, skip out now
-       if (!buf.cursize)
-               return true;
-       // if the commit is full, we're done
-       if (msg->cursize + buf.cursize + 2 >= min(msg->maxsize, maxbytes))
-               return false;
-       // add the entity to the commit
-       EntityFrame4_AddCommitEntity(d, s);
-       // write the message to the packet
-       SZ_Write(msg, buf.data, buf.cursize);
-       // carry on
-       return true;
-}
-
-extern void CL_MoveLerpEntityStates(entity_t *ent);
-void EntityFrame4_CL_ReadFrame(entity_database4_t *d)
+void EntityFrame4_CL_ReadFrame(void)
 {
        int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false;
        entity_state_t *s;
+       entityframe4_database_t *d;
+       if (!cl.entitydatabase4)
+               cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
+       d = cl.entitydatabase4;
        // read the number of the frame this refers to
        referenceframenum = MSG_ReadLong();
        // read the number of this frame
        framenum = MSG_ReadLong();
        // read the start number
-       enumber = MSG_ReadShort();
+       enumber = (unsigned short) MSG_ReadShort();
        if (developer_networkentities.integer >= 1)
        {
                Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum);
@@ -931,77 +1214,198 @@ void EntityFrame4_CL_ReadFrame(entity_database4_t *d)
                EntityFrame4_ResetDatabase(d);
 }
 
+void EntityFrame4_WriteFrame(sizebuf_t *msg, entityframe4_database_t *d, int numstates, const entity_state_t *states)
+{
+       const entity_state_t *e, *s;
+       entity_state_t inactiveentitystate;
+       int i, n, startnumber;
+       sizebuf_t buf;
+       qbyte data[128];
 
+       // if there isn't enough space to accomplish anything, skip it
+       if (msg->cursize + 24 > msg->maxsize)
+               return;
 
+       // prepare the buffer
+       memset(&buf, 0, sizeof(buf));
+       buf.data = data;
+       buf.maxsize = sizeof(data);
 
+       for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+               if (!d->commit[i].numentities)
+                       break;
+       // if commit buffer full, just don't bother writing an update this frame
+       if (i == MAX_ENTITY_HISTORY)
+               return;
+       d->currentcommit = d->commit + i;
 
-/*
-int EntityState5_PriorityForChangedBits(int changedbits)
-{
-       if (changedbits & E5_ISACTIVE)
-               return 2;
-       else if (changedbits & (E5_FLAGS | E5_ATTACHMENT | E5_MODEL | E5_SKIN | E5_EXTERIORFORENTITY | E5_COLORMAP | E5_LIGHT | E5_GLOW | E5_EFFECTS | E5_ORIGIN | E5_ANGLES | E5_FRAME | E5_ALPHA | E5_SCALE))
-               return 1;
-       else
-               return 0;
-}
+       // this state's number gets played around with later
+       inactiveentitystate = defaultstate;
 
-void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, sizebuf_t *msg)
-{
-       bits = 0;
-       if (!s->active)
-               MSG_WriteShort(msg, number | 0x8000);
+       d->currentcommit->numentities = 0;
+       d->currentcommit->framenum = ++d->latestframenumber;
+       MSG_WriteByte(msg, svc_entities);
+       MSG_WriteLong(msg, d->referenceframenum);
+       MSG_WriteLong(msg, d->currentcommit->framenum);
+       if (developer_networkentities.integer >= 1)
+       {
+               Con_Printf("send svc_entities num:%i ref:%i (database: ref:%i commits:", d->currentcommit->framenum, d->referenceframenum, d->referenceframenum);
+               for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+                       if (d->commit[i].numentities)
+                               Con_Printf(" %i", d->commit[i].framenum);
+               Con_Print(")\n");
+       }
+       if (d->currententitynumber >= sv.max_edicts)
+               startnumber = 1;
        else
+               startnumber = bound(1, d->currententitynumber, sv.max_edicts - 1);
+       MSG_WriteShort(msg, startnumber);
+       // reset currententitynumber so if the loop does not break it we will
+       // start at beginning next frame (if it does break, it will set it)
+       d->currententitynumber = 1;
+       for (i = 0, n = startnumber;n < sv.max_edicts;n++)
        {
-               bits |= E5_ISACTIVE;
-               if (changedbits & E5_ORIGIN)
+               // find the old state to delta from
+               e = EntityFrame4_GetReferenceEntity(d, n);
+               // prepare the buffer
+               SZ_Clear(&buf);
+               // entity exists, build an update (if empty there is no change)
+               // find the state in the list
+               for (;i < numstates && states[i].number < n;i++);
+               // make the message
+               s = states + i;
+               if (s->number == n)
                {
-                       bits |= E5_ORIGIN;
-                       if (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096)
-                               bits |= E5_ORIGIN32;
+                       // build the update
+                       EntityState_WriteUpdate(s, &buf, e);
                }
-               if (changedbits & E5_ANGLES)
+               else
                {
-                       bits |= E5_ANGLES;
-                       if (!(s->flags & RENDERFLAGS_LOWPRECISION))
-                               bits |= E5_ANGLES16;
+                       inactiveentitystate.number = n;
+                       s = &inactiveentitystate;
+                       if (e->active)
+                       {
+                               // entity used to exist but doesn't anymore, send remove
+                               MSG_WriteShort(&buf, n | 0x8000);
+                       }
                }
-               if (changedbits & E5_MODEL)
+               // if the commit is full, we're done this frame
+               if (msg->cursize + buf.cursize > msg->maxsize - 4)
                {
-                       bits |= E5_MODEL;
-                       if (s->modelindex >= 256)
-                               bits |= E5_MODEL16;
+                       // next frame we will continue where we left off
+                       break;
                }
-               if (changedbits & E5_FRAME)
+               // add the entity to the commit
+               EntityFrame4_AddCommitEntity(d, s);
+               // if the message is empty, skip out now
+               if (buf.cursize)
                {
-                       bits |= E5_FRAME;
-                       if (s->frame >= 256)
-                               bits |= E5_FRAME16;
+                       // write the message to the packet
+                       SZ_Write(msg, buf.data, buf.cursize);
                }
-               if (changedbits & E5_SKIN)
-                       bits |= E5_SKIN;
-               if (changedbits & E5_EFFECTS)
+       }
+       d->currententitynumber = n;
+
+       // remove world message (invalid, and thus a good terminator)
+       MSG_WriteShort(msg, 0x8000);
+       // write the number of the end entity
+       MSG_WriteShort(msg, d->currententitynumber);
+       // just to be sure
+       d->currentcommit = NULL;
+}
+
+
+
+
+#define E5_PROTOCOL_PRIORITYLEVELS 32
+
+entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool)
+{
+       entityframe5_database_t *d;
+       d = Mem_Alloc(pool, sizeof(*d));
+       EntityFrame5_ResetDatabase(d);
+       return d;
+}
+
+void EntityFrame5_FreeDatabase(entityframe5_database_t *d)
+{
+       Mem_Free(d);
+}
+
+void EntityFrame5_ResetDatabase(entityframe5_database_t *d)
+{
+       int i;
+       memset(d, 0, sizeof(*d));
+       d->latestframenum = 0;
+       d->ackframenum = -1;
+       for (i = 0;i < MAX_EDICTS;i++)
+               d->states[i] = defaultstate;
+}
+
+
+int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, entity_state_t *s, int changedbits, int age)
+{
+       int lowprecision, limit, priority;
+       double distance;
+       if (!changedbits)
+               return 0;
+       if (!s->active/* && changedbits & E5_FULLUPDATE*/)
+               return E5_PROTOCOL_PRIORITYLEVELS - 1;
+       // check whole attachment chain to judge relevance to player
+       lowprecision = false;
+       for (limit = 0;limit < 256;limit++)
+       {
+               if (s == view)
+                       return E5_PROTOCOL_PRIORITYLEVELS - 1;
+               if (s->flags & RENDER_VIEWMODEL)
+                       return E5_PROTOCOL_PRIORITYLEVELS - 1;
+               if (s->flags & RENDER_LOWPRECISION)
+                       lowprecision = true;
+               if (!s->tagentity)
                {
-                       bits |= E5_EFFECTS;
-                       if (s->modelindex >= 256)
-                               bits |= E5_MODEL16;
+                       if (VectorCompare(s->origin, view->origin))
+                               return E5_PROTOCOL_PRIORITYLEVELS - 1;
+                       break;
+               }
+               s = d->states + s->tagentity;
+       }
+       if (limit >= 256)
+               Con_Printf("Protocol: Runaway loop recursing tagentity links on entity %i\n", s->number);
+       // it's not a viewmodel for this client
+       distance = VectorDistance(view->origin, s->origin);
+       priority = (E5_PROTOCOL_PRIORITYLEVELS / 2) + age - (int)(distance * (E5_PROTOCOL_PRIORITYLEVELS / 16384.0f));
+       if (lowprecision)
+               priority -= (E5_PROTOCOL_PRIORITYLEVELS / 4);
+       //if (changedbits & E5_FULLUPDATE)
+       //      priority += 4;
+       //if (changedbits & (E5_ATTACHMENT | E5_MODEL | E5_FLAGS | E5_COLORMAP))
+       //      priority += 4;
+       return (int) bound(1, priority, E5_PROTOCOL_PRIORITYLEVELS - 1);
+}
+
+void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg)
+{
+       unsigned int bits = 0;
+       if (!s->active)
+               MSG_WriteShort(msg, number | 0x8000);
+       else
+       {
+               bits = changedbits;
+               if ((bits & E5_ORIGIN) && (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096))
+                       bits |= E5_ORIGIN32;
+               if ((bits & E5_ANGLES) && !(s->flags & RENDER_LOWPRECISION))
+                       bits |= E5_ANGLES16;
+               if ((bits & E5_MODEL) && s->modelindex >= 256)
+                       bits |= E5_MODEL16;
+               if ((bits & E5_FRAME) && s->frame >= 256)
+                       bits |= E5_FRAME16;
+               if (bits & E5_EFFECTS)
+               {
+                       if (s->effects >= 65536)
+                               bits |= E5_EFFECTS32;
+                       else if (s->effects >= 256)
+                               bits |= E5_EFFECTS16;
                }
-               if (changedbits & E5_FLAGS)
-                       bits |= E5_FLAGS;
-               if (changedbits & E5_ALPHA)
-                       bits |= E5_ALPHA;
-               if (changedbits & E5_SCALE)
-                       bits |= E5_SCALE;
-               if (changedbits & E5_ATTACHMENT)
-                       bits |= E5_ATTACHMENT;
-               if (changedbits & E5_EXTERIORFORENTITY)
-                       bits |= E5_EXTERIORFORENTITY;
-               if (changedbits & E5_LIGHT)
-                       bits |= E5_LIGHT;
-               if (changedbits & E5_COLORMAP)
-                       bits |= E5_COLORMAP;
-               if (changedbits & E5_GLOW)
-                       bits |= E5_GLOW;
                if (bits >= 256)
                        bits |= E5_EXTEND1;
                if (bits >= 65536)
@@ -1022,30 +1426,30 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz
                {
                        if (bits & E5_ORIGIN32)
                        {
-                               MSG_WriteFloat(msg, s->origin[0]);
-                               MSG_WriteFloat(msg, s->origin[1]);
-                               MSG_WriteFloat(msg, s->origin[2]);
+                               MSG_WriteCoord32f(msg, s->origin[0]);
+                               MSG_WriteCoord32f(msg, s->origin[1]);
+                               MSG_WriteCoord32f(msg, s->origin[2]);
                        }
                        else
                        {
-                               MSG_WriteShort(msg, (int)floor(s->origin[0] * 8 + 0.5f));
-                               MSG_WriteShort(msg, (int)floor(s->origin[1] * 8 + 0.5f));
-                               MSG_WriteShort(msg, (int)floor(s->origin[2] * 8 + 0.5f));
+                               MSG_WriteCoord13i(msg, s->origin[0]);
+                               MSG_WriteCoord13i(msg, s->origin[1]);
+                               MSG_WriteCoord13i(msg, s->origin[2]);
                        }
                }
                if (bits & E5_ANGLES)
                {
                        if (bits & E5_ANGLES16)
                        {
-                               MSG_WriteShort(msg, (int)floor(s->angles[0] * (65536.0f / 360.0f) + 0.5f));
-                               MSG_WriteShort(msg, (int)floor(s->angles[1] * (65536.0f / 360.0f) + 0.5f));
-                               MSG_WriteShort(msg, (int)floor(s->angles[2] * (65536.0f / 360.0f) + 0.5f));
+                               MSG_WriteAngle16i(msg, s->angles[0]);
+                               MSG_WriteAngle16i(msg, s->angles[1]);
+                               MSG_WriteAngle16i(msg, s->angles[2]);
                        }
                        else
                        {
-                               MSG_WriteByte(msg, (int)floor(s->angles[0] * (256.0f / 360.0f) + 0.5f));
-                               MSG_WriteByte(msg, (int)floor(s->angles[1] * (256.0f / 360.0f) + 0.5f));
-                               MSG_WriteByte(msg, (int)floor(s->angles[2] * (256.0f / 360.0f) + 0.5f));
+                               MSG_WriteAngle8i(msg, s->angles[0]);
+                               MSG_WriteAngle8i(msg, s->angles[1]);
+                               MSG_WriteAngle8i(msg, s->angles[2]);
                        }
                }
                if (bits & E5_MODEL)
@@ -1063,7 +1467,7 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz
                                MSG_WriteByte(msg, s->frame);
                }
                if (bits & E5_SKIN)
-                       MSG_WriteByte(msg, s->flags);
+                       MSG_WriteByte(msg, s->skin);
                if (bits & E5_EFFECTS)
                {
                        if (bits & E5_EFFECTS32)
@@ -1074,25 +1478,25 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz
                                MSG_WriteByte(msg, s->effects);
                }
                if (bits & E5_ALPHA)
-                       MSG_WriteByte(msg, s->flags);
+                       MSG_WriteByte(msg, s->alpha);
                if (bits & E5_SCALE)
-                       MSG_WriteByte(msg, s->flags);
+                       MSG_WriteByte(msg, s->scale);
+               if (bits & E5_COLORMAP)
+                       MSG_WriteByte(msg, s->colormap);
                if (bits & E5_ATTACHMENT)
                {
                        MSG_WriteShort(msg, s->tagentity);
                        MSG_WriteByte(msg, s->tagindex);
                }
-               if (bits & E5_EXTERIORFORENTITY)
-                       MSG_WriteShort(msg, s->tagentity);
                if (bits & E5_LIGHT)
                {
                        MSG_WriteShort(msg, s->light[0]);
                        MSG_WriteShort(msg, s->light[1]);
                        MSG_WriteShort(msg, s->light[2]);
                        MSG_WriteShort(msg, s->light[3]);
+                       MSG_WriteByte(msg, s->lightstyle);
+                       MSG_WriteByte(msg, s->lightpflags);
                }
-               if (bits & E5_COLORMAP)
-                       MSG_WriteByte(msg, s->colormap);
                if (bits & E5_GLOW)
                {
                        MSG_WriteByte(msg, s->glowsize);
@@ -1101,30 +1505,201 @@ void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, siz
        }
 }
 
-int EntityFrame5_ReadUpdate(void)
+void EntityState5_ReadUpdate(entity_state_t *s)
 {
-       number = MSG_ReadShort();
-       e = cl_entities + (number & 0x7FFF);
-       e->state_previous = e->state_current;
-       if (number & 0x8000)
+       int bits;
+       bits = MSG_ReadByte();
+       if (bits & E5_EXTEND1)
        {
-               if (number == 0x8000)
+               bits |= MSG_ReadByte() << 8;
+               if (bits & E5_EXTEND2)
                {
-                       // end of entity list
-                       return false;
+                       bits |= MSG_ReadByte() << 16;
+                       if (bits & E5_EXTEND3)
+                               bits |= MSG_ReadByte() << 24;
                }
-               // remove
-               number &= 0x7FFF;
-               e->state_current = defaultstate;
-               e->state_current.number = number;
-               return true;
        }
-       else
+       if (bits & E5_FULLUPDATE)
+       {
+               *s = defaultstate;
+               s->active = true;
+       }
+       if (bits & E5_FLAGS)
+               s->flags = MSG_ReadByte();
+       if (bits & E5_ORIGIN)
+       {
+               if (bits & E5_ORIGIN32)
+               {
+                       s->origin[0] = MSG_ReadCoord32f();
+                       s->origin[1] = MSG_ReadCoord32f();
+                       s->origin[2] = MSG_ReadCoord32f();
+               }
+               else
+               {
+                       s->origin[0] = MSG_ReadCoord13i();
+                       s->origin[1] = MSG_ReadCoord13i();
+                       s->origin[2] = MSG_ReadCoord13i();
+               }
+       }
+       if (bits & E5_ANGLES)
+       {
+               if (bits & E5_ANGLES16)
+               {
+                       s->angles[0] = MSG_ReadAngle16i(); 
+                       s->angles[1] = MSG_ReadAngle16i(); 
+                       s->angles[2] = MSG_ReadAngle16i(); 
+               }
+               else
+               {
+                       s->angles[0] = MSG_ReadAngle8i(); 
+                       s->angles[1] = MSG_ReadAngle8i(); 
+                       s->angles[2] = MSG_ReadAngle8i(); 
+               }
+       }
+       if (bits & E5_MODEL)
+       {
+               if (bits & E5_MODEL16)
+                       s->modelindex = (unsigned short) MSG_ReadShort();
+               else
+                       s->modelindex = MSG_ReadByte();
+       }
+       if (bits & E5_FRAME)
        {
+               if (bits & E5_FRAME16)
+                       s->frame = (unsigned short) MSG_ReadShort();
+               else
+                       s->frame = MSG_ReadByte();
+       }
+       if (bits & E5_SKIN)
+               s->skin = MSG_ReadByte();
+       if (bits & E5_EFFECTS)
+       {
+               if (bits & E5_EFFECTS32)
+                       s->effects = (unsigned int) MSG_ReadLong();
+               else if (bits & E5_EFFECTS16)
+                       s->effects = (unsigned short) MSG_ReadShort();
+               else
+                       s->effects = MSG_ReadByte();
+       }
+       if (bits & E5_ALPHA)
+               s->alpha = MSG_ReadByte();
+       if (bits & E5_SCALE)
+               s->alpha = MSG_ReadByte();
+       if (bits & E5_COLORMAP)
+               s->colormap = MSG_ReadByte();
+       if (bits & E5_ATTACHMENT)
+       {
+               s->tagentity = (unsigned short) MSG_ReadShort();
+               s->tagindex = MSG_ReadByte();
+       }
+       if (bits & E5_LIGHT)
+       {
+               s->light[0] = (unsigned short) MSG_ReadShort();
+               s->light[1] = (unsigned short) MSG_ReadShort();
+               s->light[2] = (unsigned short) MSG_ReadShort();
+               s->light[3] = (unsigned short) MSG_ReadShort();
+               s->lightstyle = MSG_ReadByte();
+               s->lightpflags = MSG_ReadByte();
+       }
+       if (bits & E5_GLOW)
+       {
+               s->glowsize = MSG_ReadByte();
+               s->glowcolor = MSG_ReadByte();
+       }
+
+
+       if (developer_networkentities.integer >= 2)
+       {
+               Con_Printf("ReadFields e%i", s->number);
+
+               if (bits & E5_ORIGIN)
+                       Con_Printf(" E5_ORIGIN %f %f %f", s->origin[0], s->origin[1], s->origin[2]);
+               if (bits & E5_ANGLES)
+                       Con_Printf(" E5_ANGLES %f %f %f", s->angles[0], s->angles[1], s->angles[2]);
+               if (bits & E5_MODEL)
+                       Con_Printf(" E5_MODEL %i", s->modelindex);
+               if (bits & E5_FRAME)
+                       Con_Printf(" E5_FRAME %i", s->frame);
+               if (bits & E5_SKIN)
+                       Con_Printf(" E5_SKIN %i", s->skin);
+               if (bits & E5_EFFECTS)
+                       Con_Printf(" E5_EFFECTS %i", s->effects);
+               if (bits & E5_FLAGS)
+               {
+                       Con_Printf(" E5_FLAGS %i (", s->flags);
+                       if (s->flags & RENDER_STEP)
+                               Con_Print(" STEP");
+                       if (s->flags & RENDER_GLOWTRAIL)
+                               Con_Print(" GLOWTRAIL");
+                       if (s->flags & RENDER_VIEWMODEL)
+                               Con_Print(" VIEWMODEL");
+                       if (s->flags & RENDER_EXTERIORMODEL)
+                               Con_Print(" EXTERIORMODEL");
+                       if (s->flags & RENDER_LOWPRECISION)
+                               Con_Print(" LOWPRECISION");
+                       if (s->flags & RENDER_COLORMAPPED)
+                               Con_Print(" COLORMAPPED");
+                       if (s->flags & RENDER_SHADOW)
+                               Con_Print(" SHADOW");
+                       if (s->flags & RENDER_LIGHT)
+                               Con_Print(" LIGHT");
+                       Con_Print(")");
+               }
+               if (bits & E5_ALPHA)
+                       Con_Printf(" E5_ALPHA %f", s->alpha / 255.0f);
+               if (bits & E5_SCALE)
+                       Con_Printf(" E5_SCALE %f", s->scale / 16.0f);
+               if (bits & E5_COLORMAP)
+                       Con_Printf(" E5_COLORMAP %i", s->colormap);
+               if (bits & E5_ATTACHMENT)
+                       Con_Printf(" E5_ATTACHMENT e%i:%i", s->tagentity, s->tagindex);
+               if (bits & E5_LIGHT)
+                       Con_Printf(" E5_LIGHT %i:%i:%i:%i %i:%i", s->light[0], s->light[1], s->light[2], s->light[3], s->lightstyle, s->lightpflags);
+               if (bits & E5_GLOW)
+                       Con_Printf(" E5_GLOW %i:%i", s->glowsize * 4, s->glowcolor);
+               Con_Print("\n");
        }
 }
 
-int cl_entityframe5_lastreceivedframenum;
+int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t *n)
+{
+       unsigned int bits = 0;
+       if (n->active)
+       {
+               if (!o->active)
+                       bits |= E5_FULLUPDATE;
+               if (!VectorCompare(o->origin, n->origin))
+                       bits |= E5_ORIGIN;
+               if (!VectorCompare(o->angles, n->angles))
+                       bits |= E5_ANGLES;
+               if (o->modelindex != n->modelindex)
+                       bits |= E5_MODEL;
+               if (o->frame != n->frame)
+                       bits |= E5_FRAME;
+               if (o->skin != n->skin)
+                       bits |= E5_SKIN;
+               if (o->effects != n->effects)
+                       bits |= E5_EFFECTS;
+               if (o->flags != n->flags)
+                       bits |= E5_FLAGS;
+               if (o->alpha != n->alpha)
+                       bits |= E5_ALPHA;
+               if (o->scale != n->scale)
+                       bits |= E5_SCALE;
+               if (o->colormap != n->colormap)
+                       bits |= E5_COLORMAP;
+               if (o->tagentity != n->tagentity || o->tagindex != n->tagindex)
+                       bits |= E5_ATTACHMENT;
+               if (o->light[0] != n->light[0] || o->light[1] != n->light[1] || o->light[2] != n->light[2] || o->light[3] != n->light[3] || o->lightstyle != n->lightstyle || o->lightpflags != n->lightpflags)
+                       bits |= E5_LIGHT;
+               if (o->glowsize != n->glowsize || o->glowcolor != n->glowcolor)
+                       bits |= E5_GLOW;
+       }
+       else
+               if (o->active)
+                       bits |= E5_FULLUPDATE;
+       return bits;
+}
 
 void EntityFrame5_CL_ReadFrame(void)
 {
@@ -1132,10 +1707,10 @@ void EntityFrame5_CL_ReadFrame(void)
        entity_t *ent;
        entity_state_t *s;
        // read the number of this frame to echo back in next input packet
-       cl_entityframe5_lastreceivedframenum = MSG_ReadLong();
+       cl.latestframenum = MSG_ReadLong();
        // read entity numbers until we find a 0x8000
        // (which would be remove world entity, but is actually a terminator)
-       while ((n = MSG_ReadShort()) != 0x8000)
+       while ((n = (unsigned short)MSG_ReadShort()) != 0x8000 && !msg_badread)
        {
                // get the entity number and look it up
                enumber = n & 0x7FFF;
@@ -1152,8 +1727,7 @@ void EntityFrame5_CL_ReadFrame(void)
                else
                {
                        // update entity
-                       s->active = true;
-                       EntityState_ReadFields(s, EntityState_ReadExtendBits());
+                       EntityState5_ReadUpdate(s);
                }
                // set the cl_entities_active flag
                cl_entities_active[enumber] = s->active;
@@ -1175,43 +1749,14 @@ void EntityFrame5_CL_ReadFrame(void)
        }
 }
 
-#define ENTITYFRAME5_MAXPACKETLOGS 64
-#define ENTITYFRAME5_MAXSTATES 128
-
-typedef struct entityframe5_state_s
-{
-       unsigned short entitynumber;
-       qbyte active;
-       qbyte activedirtybit;
-       int dirtybits;
-}
-entityframe5_state_t;
-
-typedef struct entityframe5_packetlog_s
-{
-       int packetnumber;
-       int numstates;
-       entityframe5_state_t states[ENTITYFRAME5_MAXSTATES];
-}
-entityframe5_packetlog_t;
-
-typedef struct entityframe5_s
-{
-       int ackedframenum;
-       entityframe5_packetlog_t packetlog[ENTITYFRAME5_MAXPACKETLOGS];
-       qbyte activedirtybits[(MAX_EDICTS + 7) / 8];
-       int dirtybits[MAX_EDICTS];
-}
-entityframe5_t;
-
-void EntityFrame5_AckFrame(entityframe5_t *d, int framenum)
+void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum)
 {
-       int i, j, k, l, dirtybits, activedirtybit;
-       entityframe5_state_t *s, *s2;
+       int i, j, k, l, bits;
+       entityframe5_changestate_t *s, *s2;
        entityframe5_packetlog_t *p, *p2;
-       if (framenum >= d->ackedframenum)
+       if (framenum <= d->ackframenum)
                return;
-       d->ackedframenum = framenum;
+       d->ackframenum = framenum;
        // scan for packets made obsolete by this ack
        for (i = 0, p = d->packetlog;i < ENTITYFRAME5_MAXPACKETLOGS;i++, p++)
        {
@@ -1225,37 +1770,36 @@ void EntityFrame5_AckFrame(entityframe5_t *d, int framenum)
                // already obsolete due to a later update.
                if (p->packetnumber < framenum)
                {
-                       // packet was lost - merge dirtybits into the main array so they
+                       // packet was lost - merge deltabits into the main array so they
                        // will be re-sent, but only if there is no newer update of that
                        // bit in the logs (as those will arrive before this update)
                        for (j = 0, s = p->states;j < p->numstates;j++, s++)
                        {
-                               activedirtybit = s->activedirtybit;
-                               dirtybits = s->dirtybits;
-                               // check for any newer updates to this entity
-                               for (k = 0, p2 = d->packetlog;k < ENTITYFRAME5_MAXPACKETLOGS;k++, p2++)
+                               // check for any newer updates to this entity and mask off any
+                               // overlapping bits (we don't need to send something again if
+                               // it has already been sent more recently)
+                               bits = s->bits & ~d->deltabits[s->number];
+                               for (k = 0, p2 = d->packetlog;k < ENTITYFRAME5_MAXPACKETLOGS && bits;k++, p2++)
                                {
                                        if (p2->packetnumber > framenum)
                                        {
                                                for (l = 0, s2 = p2->states;l < p2->numstates;l++, p2++)
                                                {
-                                                       if (s2->entitynumber == s->entitynumber)
+                                                       if (s2->number == s->number)
                                                        {
-                                                               activedirtybit &= ~s2->activedirtybit;
-                                                               dirtybits &= ~s2->dirtybits;
+                                                               bits &= ~s2->bits;
                                                                break;
                                                        }
                                                }
-                                               if (!activedirtybit && !dirtybits)
-                                                       break;
                                        }
                                }
                                // if the bits haven't all been cleared, there were some bits
                                // lost with this packet, so set them again now
-                               if (activedirtybit)
-                                       d->activedirtybits[s->entitynumber / 8] |= 1 << (s->entitynumber & 7);
-                               if (dirtybits)
-                                       d->dirtybits[s->entitynumber] |= dirtybits;
+                               if (bits)
+                               {
+                                       d->deltabits[s->number] |= bits;
+                                       d->priorities[s->number] = EntityState5_Priority(d, d->states + viewentnum, d->states + s->number, d->deltabits[s->number], d->latestframenum - d->updateframenum[s->number]);
+                               }
                        }
                }
                // delete this packet log as it is now obsolete
@@ -1263,8 +1807,129 @@ void EntityFrame5_AckFrame(entityframe5_t *d, int framenum)
        }
 }
 
-void EntityFrame5_WriteFrame(sizebuf_t *msg, int numstates, entity_state_t *states)
+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)
 {
+       const entity_state_t *n;
+       int i, num, l, framenum, packetlognumber, priority;
+       sizebuf_t buf;
+       qbyte data[128];
+       entityframe5_packetlog_t *packetlog;
+
+       framenum = d->latestframenum + 1;
+
+       // prepare the buffer
+       memset(&buf, 0, sizeof(buf));
+       buf.data = data;
+       buf.maxsize = sizeof(data);
+
+       // detect changes in states
+       num = 0;
+       for (i = 0, n = states;i < numstates;i++, n++)
+       {
+               // mark gaps in entity numbering as removed entities
+               for (;num < n->number;num++)
+               {
+                       // if the entity used to exist, clear it
+                       if (CHECKPVSBIT(d->visiblebits, num))
+                       {
+                               CLEARPVSBIT(d->visiblebits, num);
+                               d->deltabits[num] = E5_FULLUPDATE;
+                               d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+                               d->states[num] = defaultstate;
+                               d->states[num].number = num;
+                       }
+               }
+               // update the entity state data
+               if (!CHECKPVSBIT(d->visiblebits, num))
+               {
+                       // entity just spawned in, don't let it completely hog priority
+                       // because of being ancient on the first frame
+                       d->updateframenum[num] = framenum;
+               }
+               SETPVSBIT(d->visiblebits, num);
+               d->deltabits[num] |= EntityState5_DeltaBits(d->states + num, n);
+               d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+               d->states[num] = *n;
+               d->states[num].number = num;
+               // advance to next entity so the next iteration doesn't immediately remove it
+               num++;
+       }
+       // all remaining entities are dead
+       for (;num < MAX_EDICTS;num++)
+       {
+               if (CHECKPVSBIT(d->visiblebits, num))
+               {
+                       CLEARPVSBIT(d->visiblebits, num);
+                       d->deltabits[num] = E5_FULLUPDATE;
+                       d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+                       d->states[num] = defaultstate;
+                       d->states[num].number = num;
+               }
+       }
+
+       // build lists of entities by priority level
+       memset(entityframe5_prioritychaincounts, 0, sizeof(entityframe5_prioritychaincounts));
+       l = 0;
+       for (num = 0;num < MAX_EDICTS;num++)
+       {
+               if (d->priorities[num])
+               {
+                       l = num;
+                       priority = d->priorities[num];
+                       if (entityframe5_prioritychaincounts[priority] < ENTITYFRAME5_MAXSTATES)
+                               entityframe5_prioritychains[priority][entityframe5_prioritychaincounts[priority]++] = num;
+               }
+       }
+
+       // return early if there are no entities to send this time
+       if (l == 0)
+               return;
+
+       d->latestframenum = framenum;
+       MSG_WriteByte(msg, svc_entities);
+       MSG_WriteLong(msg, framenum);
+
+       // if packet log is full, an empty update is still written
+       // (otherwise the client might have nothing to ack to remove packetlogs)
+       for (packetlognumber = 0, packetlog = d->packetlog;packetlognumber < ENTITYFRAME5_MAXPACKETLOGS;packetlognumber++, packetlog++)
+               if (packetlog->packetnumber == 0)
+                       break;
+       if (packetlognumber < ENTITYFRAME5_MAXPACKETLOGS)
+       {
+               // write to packet and log
+               packetlog->packetnumber = framenum;
+               packetlog->numstates = 0;
+               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++)
+                       {
+                               num = entityframe5_prioritychains[priority][i];
+                               n = d->states + num;
+                               if (d->deltabits[num] & E5_FULLUPDATE)
+                                       d->deltabits[num] = E5_FULLUPDATE | EntityState5_DeltaBits(&defaultstate, n);
+                               buf.cursize = 0;
+                               EntityState5_WriteUpdate(num, n, d->deltabits[num], &buf);
+                               // if the entity won't fit, try the next one
+                               if (msg->cursize + buf.cursize + 2 > msg->maxsize)
+                                       continue;
+                               // write entity to the packet
+                               SZ_Write(msg, buf.data, buf.cursize);
+                               // mark age on entity for prioritization
+                               d->updateframenum[num] = framenum;
+                               // log entity so deltabits can be restored later if lost
+                               packetlog->states[packetlog->numstates].number = num;
+                               packetlog->states[packetlog->numstates].bits = d->deltabits[num];
+                               packetlog->numstates++;
+                               // clear deltabits and priority so it won't be sent again
+                               d->deltabits[num] = 0;
+                               d->priorities[num] = 0;
+                       }
+               }
+       }
+
+       MSG_WriteShort(msg, 0x8000);
 }
-*/
 
index 3f9e77c..e8fa52f 100644 (file)
@@ -22,14 +22,25 @@ 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
+
+// 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
-// LordHavoc: I think the 96-99 range was going to run out too soon...
-// so here I jump to 3500
+
+// entityframe4 protocol
 #define        PROTOCOL_DARKPLACES3 3500
 #define PROTOCOL_DARKPLACES4 3501
+
+// entityframe5 protocol
 #define PROTOCOL_DARKPLACES5 3502
 
 // model effects
@@ -318,37 +329,48 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // this is 80 bytes
 typedef struct
 {
-       // ! means this is sent to client
-       double time; // time this state was built (used on client for interpolation)
-       float origin[3]; // !
-       float angles[3]; // !
-       int number; // ! entity number this state is for
-       int effects; // !
-       unsigned short modelindex; // !
-       unsigned short frame; // !
-       unsigned short tagentity; // !
-       unsigned short specialvisibilityradius; // larger if it has effects/light
-       unsigned short viewmodelforclient;
-       unsigned short exteriormodelforclient; // not shown if first person viewing from this entity, shown in all other cases
-       unsigned short nodrawtoclient;
-       unsigned short drawonlytoclient;
-       unsigned short light[4]; // ! color*256 (0.00 to 255.996), and radius*1
-       unsigned char active; // ! true if a valid state
-       unsigned char lightstyle; // !
-       unsigned char lightpflags; // !
-       unsigned char colormap; // !
-       unsigned char skin; // ! also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
-       unsigned char alpha; // !
-       unsigned char scale; // !
-       unsigned char glowsize; // !
-       unsigned char glowcolor; // !
-       unsigned char flags; // !
-       unsigned char tagindex; // !
+       // ! means this is not sent to client
+       double time; // ! time this state was built (used on client for interpolation)
+       float origin[3];
+       float angles[3];
+       int number; // entity number this state is for
+       int effects;
+       unsigned short modelindex;
+       unsigned short frame;
+       unsigned short tagentity;
+       unsigned short specialvisibilityradius; // ! larger if it has effects/light
+       unsigned short viewmodelforclient; // !
+       unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
+       unsigned short nodrawtoclient; // !
+       unsigned short drawonlytoclient; // !
+       unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
+       unsigned char active; // true if a valid state
+       unsigned char lightstyle;
+       unsigned char lightpflags;
+       unsigned char colormap;
+       unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
+       unsigned char alpha;
+       unsigned char scale;
+       unsigned char glowsize;
+       unsigned char glowcolor;
+       unsigned char flags;
+       unsigned char tagindex;
+       unsigned char colormod;
        // padding to a multiple of 8 bytes (to align the double time)
-       unsigned char unused[5];
+       unsigned char unused[4];
 }
 entity_state_t;
 
+// baseline state values
+entity_state_t defaultstate;
+// reads a quake entity from the network stream
+void EntityFrameQuake_ReadEntity(int bits);
+// writes a list of quake entities to the network stream
+// (or as many will fit)
+void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_state_t *states);
+// cleans up dead entities each frame after ReadEntity (which doesn't clear unused entities)
+void EntityFrameQuake_ISeeDeadEntities(void);
+
 /*
 PROTOCOL_DARKPLACES3
 server updates entities according to some (unmentioned) scheme.
@@ -429,8 +451,10 @@ typedef struct
        // note: if numframes == 0, insert at start (0 in entitydata)
        // the only reason this system is used is to avoid copying memory when frames are removed
        int numframes;
+       // server only: last sent frame
+       int latestframenum;
        // server only: last acknowledged frame
-       int ackframe;
+       int ackframenum;
        // the current state in the database
        vec3_t eye;
        // table of entities in the entityhistorydata
@@ -438,7 +462,7 @@ typedef struct
        // entities
        entity_state_t entitydata[MAX_ENTITY_DATABASE];
 }
-entity_database_t;
+entityframe_database_t;
 
 // build entity data in this, to pass to entity read/write functions
 typedef struct
@@ -498,44 +522,41 @@ entity_frame_t;
 #define E_UNUSED7              (1<<30)
 #define E_EXTEND4              (1<<31)
 
-// baseline state values
-entity_state_t defaultstate;
-
-// clears a state to baseline values
-void ClearStateToDefault(entity_state_t *s);
 // returns difference between two states as E_ flags
 int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n);
 // write E_ flags to a msg
 void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits);
 // write values for the E_ flagged fields to a msg
-void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int bits);
+void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits);
 // write entity number and E_ flags and their values, or a remove number, describing the change from delta to ent
-void EntityState_WriteUpdate(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta);
+void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta);
 // read E_ flags
 int EntityState_ReadExtendBits(void);
 // read values for E_ flagged fields and apply them to a state
 void EntityState_ReadFields(entity_state_t *e, unsigned int bits);
 
+// (client and server) allocates a new empty database
+entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool);
+// (client and server) frees the database
+void EntityFrame_FreeDatabase(entityframe_database_t *d);
 // (server) clears the database to contain no frames (thus delta compression
 // compresses against nothing)
-void EntityFrame_ClearDatabase(entity_database_t *d);
+void EntityFrame_ClearDatabase(entityframe_database_t *d);
 // (server and client) removes frames older than 'frame' from database
-void EntityFrame_AckFrame(entity_database_t *d, int frame);
+void EntityFrame_AckFrame(entityframe_database_t *d, int frame);
 // (server) clears frame, to prepare for adding entities
 void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum);
-// (server) adds an entity to frame
-void EntityFrame_AddEntity(entity_frame_t *f, entity_state_t *s);
 // (server and client) reads a frame from the database
-void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f);
+void EntityFrame_FetchFrame(entityframe_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);
+void EntityFrame_AddFrame(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata);
 // (server) writes a frame to network stream
-void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg);
+void EntityFrame_WriteFrame(sizebuf_t *msg, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum);
 // (client) reads a frame from network stream
-void EntityFrame_Read(entity_database_t *d);
+void EntityFrame_CL_ReadFrame(void);
 // (client) returns the frame number of the most recent frame recieved
-int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d);
+int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d);
 
 typedef struct entity_database4_commit_s
 {
@@ -567,31 +588,30 @@ typedef struct entity_database4_s
        // (server only) if a commit won't fit entirely, continue where it left
        // off next frame
        int currententitynumber;
+       // (server only)
+       int latestframenumber;
        // (client only) most recently received frame number to be sent in next
        // input update
        int ackframenum;
 }
-entity_database4_t;
+entityframe4_database_t;
 
 // should-be-private functions that aren't
-entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int number);
-void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s);
+entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number);
+void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s);
 
 // allocate a database
-entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool);
+entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool);
 // free a database
-void EntityFrame4_FreeDatabase(entity_database4_t *d);
+void EntityFrame4_FreeDatabase(entityframe4_database_t *d);
 // reset a database (resets compression but does not reallocate anything)
-void EntityFrame4_ResetDatabase(entity_database4_t *d);
+void EntityFrame4_ResetDatabase(entityframe4_database_t *d);
 // updates database to account for a frame-received acknowledgment
-int EntityFrame4_AckFrame(entity_database4_t *d, int framenum);
-
-// write an entity in the frame
-// returns false if full
-int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s);
-
+int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum);
+// writes a frame to the network stream
+void EntityFrame4_WriteFrame(sizebuf_t *msg, entityframe4_database_t *d, int numstates, const entity_state_t *states);
 // reads a frame from the network stream
-void EntityFrame4_CL_ReadFrame(entity_database4_t *d);
+void EntityFrame4_CL_ReadFrame(void);
 
 // reset all entity fields (typically used if status changed)
 #define E5_FULLUPDATE (1<<0)
@@ -617,42 +637,46 @@ void EntityFrame4_CL_ReadFrame(entity_database4_t *d);
 // bits >= (1<<8)
 #define E5_EXTEND1 (1<<7)
 
-// flag
-#define E5_ORIGIN32 (1<<9) 
-// flag
-#define E5_ANGLES16 (1<<10)
-// flag
-#define E5_MODEL16 (1<<11)
 // byte = s->renderflags
-#define E5_FLAGS (1<<6)
+#define E5_FLAGS (1<<8)
 // byte = bound(0, s->alpha * 255, 255)
-#define E5_ALPHA (1<<13)
+#define E5_ALPHA (1<<9)
 // byte = bound(0, s->scale * 16, 255)
-#define E5_SCALE (1<<14)
+#define E5_SCALE (1<<10)
+// flag
+#define E5_ORIGIN32 (1<<11) 
+// flag
+#define E5_ANGLES16 (1<<12)
+// flag
+#define E5_MODEL16 (1<<13)
+// byte = s->colormap
+#define E5_COLORMAP (1<<14)
 // bits >= (1<<16)
 #define E5_EXTEND2 (1<<15)
 
 // short = s->tagentity
 // byte = s->tagindex
 #define E5_ATTACHMENT (1<<16)
-// short = s->exteriormodelforentity
-#define E5_EXTERIORFORENTITY (1<<17)
 // short[4] = s->light[0], s->light[1], s->light[2], s->light[3]
-#define E5_LIGHT (1<<18)
-// byte = s->colormap
-#define E5_COLORMAP (1<<19)
+// byte = s->lightstyle
+// byte = s->lightpflags
+#define E5_LIGHT (1<<17)
 // byte = s->glowsize
 // byte = s->glowcolor
-#define E5_GLOW (1<<20)
+#define E5_GLOW (1<<18)
 // short = s->effects
-#define E5_EFFECTS16 (1<<21)
+#define E5_EFFECTS16 (1<<19)
 // int = s->effects
-#define E5_EFFECTS32 (1<<22)
+#define E5_EFFECTS32 (1<<20)
+// flag
+#define E5_FRAME16 (1<<21)
+// unused
+#define E5_UNUSED22 (1<<22)
 // bits >= (1<<24)
 #define E5_EXTEND3 (1<<23)
 
-// flag
-#define E5_FRAME16 (1<<24)
+// unused
+#define E5_UNUSED24 (1<<24)
 // unused
 #define E5_UNUSED25 (1<<25)
 // unused
@@ -668,24 +692,74 @@ void EntityFrame4_CL_ReadFrame(entity_database4_t *d);
 // bits2 > 0
 #define E5_EXTEND4 (1<<31)
 
-typedef struct entity_database5_client_s
+#define ENTITYFRAME5_MAXPACKETLOGS 64
+#define ENTITYFRAME5_MAXSTATES 1024
+
+typedef struct entityframe5_changestate_s
+{
+       unsigned int number;
+       unsigned int bits;
+}
+entityframe5_changestate_t;
+
+typedef struct entityframe5_packetlog_s
 {
-       qbyte visible[MAX_EDICTS];
-       qbyte visibledelta[MAX_EDICTS];
-       int statedelta[MAX_EDICTS];
+       int packetnumber;
+       int numstates;
+       entityframe5_changestate_t states[ENTITYFRAME5_MAXSTATES];
 }
-entity_database5_t;
+entityframe5_packetlog_t;
 
-typedef struct entity_database5_server_s
+typedef struct entityframe5_database_s
 {
-       // temporary working space for client data building
-       // 0-255 priority level, 0 = don't send
+       // number of the latest message sent to client
+       int latestframenum;
+       // number of the latest message acknowledged by client
+       int ackframenum;
+
+       // logs of all recently sent messages (between acked and latest)
+       entityframe5_packetlog_t packetlog[ENTITYFRAME5_MAXPACKETLOGS];
+
+       // which properties of each entity have changed since last send
+       int deltabits[MAX_EDICTS];
+       // priorities of entities (updated whenever deltabits change)
+       // (derived from deltabits)
        qbyte priorities[MAX_EDICTS];
-       // this is the visible entity numbers, sorted by their priority level
-       int numentitylist;
-       int entitylist[MAX_EDICTS];
+       // last frame this entity was sent on, for prioritzation
+       int updateframenum[MAX_EDICTS];
+
+       // database of current status of all entities
+       // (FIXME: this is 2.5mb per client even if most is unused!)
+       entity_state_t states[MAX_EDICTS];
+       // which entities are currently active
+       // (duplicate of the active bit of every state in states[])
+       // (derived from states)
+       qbyte visiblebits[(MAX_EDICTS+7)/8];
+
+       // old notes
+
+       // this is used to decide which changestates to set each frame
+       //int numvisiblestates;
+       //entity_state_t visiblestates[MAX_EDICTS];
+
+       // sorted changing states that need to be sent to the client
+       // kept sorted in lowest to highest priority order, because this allows
+       // the numchangestates to simply be decremented whenever an state is sent,
+       // rather than a memmove to remove them from the start.
+       //int numchangestates;
+       //entityframe5_changestate_t changestates[MAX_EDICTS];
 }
-entity_database5_server_t;
+entityframe5_database_t;
+
+entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool);
+void EntityFrame5_FreeDatabase(entityframe5_database_t *d);
+void EntityFrame5_ResetDatabase(entityframe5_database_t *d);
+int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, entity_state_t *s, int changedbits, int age);
+void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg);
+int EntityState5_DeltaBitsForState(entity_state_t *o, entity_state_t *n);
+void EntityFrame5_CL_ReadFrame(void);
+void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum);
+void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum);
 
 extern cvar_t developer_networkentities;
 
index 4991e6e..4e7712e 100644 (file)
@@ -1361,12 +1361,12 @@ void VM_WriteLong (void)
 
 void VM_WriteAngle (void)
 {
-       MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
+       MSG_WriteAngle16i (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
 }
 
 void VM_WriteCoord (void)
 {
-       MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
+       MSG_WriteCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
 }
 
 void VM_WriteString (void)
index bb5e784..5165ef9 100644 (file)
@@ -47,7 +47,7 @@ extern char *buildstring;
 
 #define MAX_PACKETFRAGMENT 1024                // max length of packet fragment
 #define NET_MAXMESSAGE 65536
-#define NET_MINRATE            500 // limits "rate" and "sv_maxrate" cvars
+#define NET_MINRATE            1000 // limits "rate" and "sv_maxrate" cvars
 #define NET_MAXRATE            25000 // limits "rate" and "sv_maxrate" cvars
 
 //
index 656781d..8e94e5a 100644 (file)
--- a/server.h
+++ b/server.h
@@ -47,6 +47,11 @@ typedef struct
        // handle connections specially
        qboolean loadgame;
 
+       // one of the PROTOCOL_ values
+       int protocol;
+       // this disables extensions when using PROTOCOL_QUAKE
+       qboolean netquakecompatible;
+
        double time;
 
        double frametime;
@@ -153,16 +158,9 @@ typedef struct client_s
        // prevent animated names
        float nametime;
 
-#ifdef QUAKEENTITIES
-       // delta compression state
-       float nextfullupdate[MAX_EDICTS];
-#elif 0
-       entity_database_t entitydatabase;
-       int entityframenumber; // incremented each time an entity frame is sent
-#else
-       entity_database4_t *entitydatabase4;
-       int entityframenumber; // incremented each time an entity frame is sent
-#endif
+       entityframe_database_t *entitydatabase;
+       entityframe4_database_t *entitydatabase4;
+       entityframe5_database_t *entitydatabase5;
 } client_t;
 
 
@@ -256,6 +254,8 @@ extern cvar_t sv_idealpitchscale;
 extern cvar_t sv_aim;
 extern cvar_t sv_stepheight;
 extern cvar_t sv_jumpstep;
+extern cvar_t sv_public;
+extern cvar_t sv_maxrate;
 
 extern cvar_t sv_gameplayfix_grenadebouncedownslopes;
 extern cvar_t sv_gameplayfix_noairborncorpse;
index 736cee1..b8c14c7 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -21,6 +21,12 @@ 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_DARKPLACES5 for example, minus the PROTOCOL_ prefix
+cvar_t sv_protocolname = {0, "sv_protocolname", "DARKPLACES5"};
+cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0"};
+cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"};
+
 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1"}; // fast but loose
 static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"};
@@ -75,6 +81,9 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
        Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
        Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
+       Cvar_RegisterVariable (&sv_protocolname);
+       Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
+       Cvar_RegisterVariable (&sv_maxrate);
 
        SV_Phys_Init();
        SV_World_Init();
@@ -119,9 +128,9 @@ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
        if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
                return;
        MSG_WriteByte (&sv.datagram, svc_particle);
-       MSG_WriteDPCoord (&sv.datagram, org[0]);
-       MSG_WriteDPCoord (&sv.datagram, org[1]);
-       MSG_WriteDPCoord (&sv.datagram, org[2]);
+       MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
+       MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
+       MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
        for (i=0 ; i<3 ; i++)
        {
                v = dir[i]*16;
@@ -149,9 +158,9 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount,
                if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
                        return;
                MSG_WriteByte (&sv.datagram, svc_effect2);
-               MSG_WriteDPCoord (&sv.datagram, org[0]);
-               MSG_WriteDPCoord (&sv.datagram, org[1]);
-               MSG_WriteDPCoord (&sv.datagram, org[2]);
+               MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
+               MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
+               MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
                MSG_WriteShort (&sv.datagram, modelindex);
                MSG_WriteShort (&sv.datagram, startframe);
                MSG_WriteByte (&sv.datagram, framecount);
@@ -162,9 +171,9 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount,
                if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
                        return;
                MSG_WriteByte (&sv.datagram, svc_effect);
-               MSG_WriteDPCoord (&sv.datagram, org[0]);
-               MSG_WriteDPCoord (&sv.datagram, org[1]);
-               MSG_WriteDPCoord (&sv.datagram, org[2]);
+               MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
+               MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
+               MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
                MSG_WriteByte (&sv.datagram, modelindex);
                MSG_WriteByte (&sv.datagram, startframe);
                MSG_WriteByte (&sv.datagram, framecount);
@@ -245,7 +254,7 @@ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, floa
        else
                MSG_WriteByte (&sv.datagram, sound_num);
        for (i = 0;i < 3;i++)
-               MSG_WriteDPCoord (&sv.datagram, entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i]));
+               MSG_WriteCoord (&sv.datagram, entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i]), sv.protocol);
 }
 
 /*
@@ -272,18 +281,29 @@ void SV_SendServerinfo (client_t *client)
        // edicts get reallocated on level changes, so we need to update it here
        client->edict = EDICT_NUM(client->number + 1);
 
+
        // LordHavoc: clear entityframe tracking
-       client->entityframenumber = 0;
+
+       if (client->entitydatabase)
+               EntityFrame_FreeDatabase(client->entitydatabase);
        if (client->entitydatabase4)
                EntityFrame4_FreeDatabase(client->entitydatabase4);
-       client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool);
+       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_clients_mempool);
+       if (sv.protocol == PROTOCOL_DARKPLACES4)
+               client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool);
+       if (sv.protocol == PROTOCOL_DARKPLACES5)
+               client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_clients_mempool);
 
        MSG_WriteByte (&client->message, svc_print);
        snprintf (message, sizeof (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, PROTOCOL_DARKPLACES5);
+       MSG_WriteLong (&client->message, sv.protocol);
        MSG_WriteByte (&client->message, svs.maxclients);
 
        if (!coop.integer && deathmatch.integer)
@@ -404,8 +424,8 @@ SV_WriteEntitiesToClient
 
 =============
 */
-#ifdef QUAKEENTITIES
-void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
+/*
+void SV_WriteEntitiesToClient_QUAKE (client_t *client, edict_t *clent, sizebuf_t *msg)
 {
        int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects, lightsize;
        int culled_pvs, culled_trace, visibleentities, totalentities;
@@ -710,12 +730,12 @@ 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_WriteDPCoord(msg, origin[0]);
-               if (bits & U_ANGLE1)    MSG_WriteAngle(msg, angles[0]);
-               if (bits & U_ORIGIN2)   MSG_WriteDPCoord(msg, origin[1]);
-               if (bits & U_ANGLE2)    MSG_WriteAngle(msg, angles[1]);
-               if (bits & U_ORIGIN3)   MSG_WriteDPCoord(msg, origin[2]);
-               if (bits & U_ANGLE3)    MSG_WriteAngle(msg, angles[2]);
+               if (bits & U_ORIGIN1)   MSG_WriteCoord13i(msg, origin[0]);
+               if (bits & U_ANGLE1)    MSG_WriteAngle8i(msg, angles[0]);
+               if (bits & U_ORIGIN2)   MSG_WriteCoord13i(msg, origin[1]);
+               if (bits & U_ANGLE2)    MSG_WriteAngle8i(msg, angles[1]);
+               if (bits & U_ORIGIN3)   MSG_WriteCoord13i(msg, origin[2]);
+               if (bits & U_ANGLE3)    MSG_WriteAngle8i(msg, angles[2]);
 
                // LordHavoc: new stuff
                if (bits & U_ALPHA)             MSG_WriteByte(msg, alpha);
@@ -730,7 +750,8 @@ 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 trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_trace, culled_pvs, culled_trace);
 }
-#else
+*/
+
 static int numsendentities;
 static entity_state_t sendentities[MAX_EDICTS];
 static entity_state_t *sendentitiesindex[MAX_EDICTS];
@@ -750,7 +771,7 @@ void SV_PrepareEntitiesForSending(void)
                if (ent->e->free)
                        continue;
 
-               ClearStateToDefault(&cs);
+               cs = defaultstate;
                cs.active = true;
                cs.number = e;
                VectorCopy(ent->v->origin, cs.origin);
@@ -900,6 +921,7 @@ static client_t *sv_writeentitiestoclient_client;
 
 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
 {
+       int isbmodel;
        vec3_t entmins, entmaxs, lightmins, lightmaxs, testorigin;
        model_t *model;
        trace_t trace;
@@ -925,6 +947,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                // LordHavoc: only send entities with a model or important effects
                if (!s->modelindex && s->specialvisibilityradius == 0)
                        return;
+               isbmodel = (model = sv.models[s->modelindex]) == NULL || model->name[0] != '*';
                if (s->tagentity)
                {
                        // tag attached entities simply check their parent
@@ -935,7 +958,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                                return;
                }
                // always send world submodels, they don't generate much traffic
-               else if ((model = sv.models[s->modelindex]) == NULL || model->name[0] != '*')
+               else if (!isbmodel || sv.protocol == PROTOCOL_QUAKE)
                {
                        Mod_CheckLoaded(model);
                        // entity has survived every check so far, check if visible
@@ -981,7 +1004,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                                return;
                        }
                        // or not seen by random tracelines
-                       if (sv_cullentities_trace.integer)
+                       if (sv_cullentities_trace.integer && !isbmodel)
                        {
                                // LordHavoc: test center first
                                testorigin[0] = (entmins[0] + entmaxs[0]) * 0.5f;
@@ -1028,12 +1051,16 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
        sententities[s->number] = sententitiesmark;
 }
 
-void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
+entity_state_t sendstates[MAX_EDICTS]; 
+
+/*
+// entityframe4 protocol
+void SV_WriteEntitiesToClient_EF4(client_t *client, edict_t *clent, sizebuf_t *msg)
 {
        int i;
        vec3_t testorigin;
        entity_state_t *s;
-       entity_database4_t *d;
+       entityframe4_database_t *d;
        int n, startnumber;
        entity_state_t *e, inactiveentitystate;
        sizebuf_t buf;
@@ -1059,8 +1086,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
        d->currentcommit = d->commit + i;
 
        // this state's number gets played around with later
-       ClearStateToDefault(&inactiveentitystate);
-       //inactiveentitystate = defaultstate;
+       inactiveentitystate = defaultstate;
 
        sv_writeentitiestoclient_client = client;
 
@@ -1095,7 +1121,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
                SV_MarkWriteEntityStateToClient(sendentities + i);
 
        d->currentcommit->numentities = 0;
-       d->currentcommit->framenum = ++client->entityframenumber;
+       d->currentcommit->framenum = ++d->latestframenumber;
        MSG_WriteByte(msg, svc_entities);
        MSG_WriteLong(msg, d->referenceframenum);
        MSG_WriteLong(msg, d->currentcommit->framenum);
@@ -1177,7 +1203,64 @@ 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 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);
 }
-#endif
+*/
+
+void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
+{
+       int i, numsendstates;
+       entity_state_t *s;
+
+       // if there isn't enough space to accomplish anything, skip it
+       if (msg->cursize + 25 > msg->maxsize)
+               return;
+
+       sv_writeentitiestoclient_client = client;
+
+       sv_writeentitiestoclient_culled_pvs = 0;
+       sv_writeentitiestoclient_culled_trace = 0;
+       sv_writeentitiestoclient_visibleentities = 0;
+       sv_writeentitiestoclient_totalentities = 0;
+
+       Mod_CheckLoaded(sv.worldmodel);
+
+// find the client's PVS
+       // the real place being tested from
+       VectorAdd(clent->v->origin, clent->v->view_ofs, sv_writeentitiestoclient_testeye);
+       sv_writeentitiestoclient_pvsbytes = 0;
+       if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
+               sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
+
+       sv_writeentitiestoclient_clentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
+
+       sententitiesmark++;
+
+       for (i = 0;i < numsendentities;i++)
+               SV_MarkWriteEntityStateToClient(sendentities + i);
+
+       numsendstates = 0;
+       for (i = 0;i < numsendentities;i++)
+       {
+               if (sententities[sendentities[i].number] == sententitiesmark)
+               {
+                       s = &sendstates[numsendstates++];
+                       *s = sendentities[i];
+                       if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
+                               s->flags |= RENDER_EXTERIORMODEL;
+               }
+       }
+
+       if (sv_cullentities_stats.integer)
+               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);
+       else if (client->entitydatabase4)
+               EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
+       else if (client->entitydatabase)
+               EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
+       else
+               EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
+}
 
 /*
 =============
@@ -1221,7 +1304,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_WriteDPCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]));
+                       MSG_WriteCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]), sv.protocol);
 
                ent->v->dmg_take = 0;
                ent->v->dmg_save = 0;
@@ -1237,7 +1320,12 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
        {
                MSG_WriteByte (msg, svc_setangle);
                for (i=0 ; i < 3 ; i++)
-                       MSG_WriteAngle (msg, ent->v->angles[i] );
+               {
+                       if (sv.protocol == PROTOCOL_DARKPLACES5)
+                               MSG_WriteAngle16i (msg, ent->v->angles[i] );
+                       else
+                               MSG_WriteAngle8i (msg, ent->v->angles[i] );
+               }
                ent->v->fixangle = 0;
        }
 
@@ -1278,19 +1366,22 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
                if (i == 0)
                        i = 255;
                else
-                       i = bound(0, i, 255);
+                       i = bound(0, i, 65535);
        }
        viewzoom = i;
 
-       if (viewzoom != 255)
-               bits |= SU_VIEWZOOM;
+       // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
+       if (sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+               if (viewzoom != 255)
+                       bits |= SU_VIEWZOOM;
 
        for (i=0 ; i<3 ; i++)
        {
                if (ent->v->punchangle[i])
                        bits |= (SU_PUNCH1<<i);
-               if (punchvector[i]) // PROTOCOL_DARKPLACES
-                       bits |= (SU_PUNCHVEC1<<i); // PROTOCOL_DARKPLACES
+               if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+                       if (punchvector[i])
+                               bits |= (SU_PUNCHVEC1<<i);
                if (ent->v->velocity[i])
                        bits |= (SU_VELOCITY1<<i);
        }
@@ -1326,48 +1417,114 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
        for (i=0 ; i<3 ; i++)
        {
                if (bits & (SU_PUNCH1<<i))
-                       MSG_WritePreciseAngle(msg, ent->v->punchangle[i]); // PROTOCOL_DARKPLACES
-               if (bits & (SU_PUNCHVEC1<<i)) // PROTOCOL_DARKPLACES
-                       MSG_WriteFloat(msg, punchvector[i]); // PROTOCOL_DARKPLACES
+               {
+                       if (sv.protocol == PROTOCOL_QUAKE)
+                               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)
+                               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)
+               {
+                       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)
+                                       MSG_WriteCoord32f(msg, punchvector[i]);
+                       }
+               }
                if (bits & (SU_VELOCITY1<<i))
-                       MSG_WriteFloat(msg, ent->v->velocity[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)
+                               MSG_WriteCoord32f(msg, ent->v->velocity[i]);
+               }
        }
 
 // [always sent]       if (bits & SU_ITEMS)
        MSG_WriteLong (msg, items);
 
-       if (bits & SU_WEAPONFRAME)
-               MSG_WriteByte (msg, ent->v->weaponframe);
-       if (bits & SU_ARMOR)
-               MSG_WriteByte (msg, ent->v->armorvalue);
-       if (bits & SU_WEAPON)
-               MSG_WriteByte (msg, SV_ModelIndex(PR_GetString(ent->v->weaponmodel)));
-
-       MSG_WriteShort (msg, ent->v->health);
-       MSG_WriteByte (msg, ent->v->currentammo);
-       MSG_WriteByte (msg, ent->v->ammo_shells);
-       MSG_WriteByte (msg, ent->v->ammo_nails);
-       MSG_WriteByte (msg, ent->v->ammo_rockets);
-       MSG_WriteByte (msg, ent->v->ammo_cells);
-
-       if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
+       if (sv.protocol == PROTOCOL_DARKPLACES5)
        {
-               for(i=0;i<32;i++)
+               if (bits & SU_WEAPONFRAME)
+                       MSG_WriteShort (msg, ent->v->weaponframe);
+               if (bits & SU_ARMOR)
+                       MSG_WriteShort (msg, ent->v->armorvalue);
+               if (bits & SU_WEAPON)
                {
-                       if ( ((int)ent->v->weapon) & (1<<i) )
+                       i = SV_ModelIndex(PR_GetString(ent->v->weaponmodel));
+                       if (i < 0)
                        {
-                               MSG_WriteByte (msg, i);
-                               break;
+                               Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel));
+                               i = 0;
                        }
+                       MSG_WriteShort (msg, i);
                }
+
+               MSG_WriteShort (msg, ent->v->health);
+               MSG_WriteShort (msg, ent->v->currentammo);
+               MSG_WriteShort (msg, ent->v->ammo_shells);
+               MSG_WriteShort (msg, ent->v->ammo_nails);
+               MSG_WriteShort (msg, ent->v->ammo_rockets);
+               MSG_WriteShort (msg, ent->v->ammo_cells);
+
+               MSG_WriteShort (msg, ent->v->weapon);
+       
+               if (bits & SU_VIEWZOOM)
+                       MSG_WriteShort (msg, viewzoom);
        }
        else
        {
-               MSG_WriteByte (msg, ent->v->weapon);
-       }
+               if (bits & SU_WEAPONFRAME)
+                       MSG_WriteByte (msg, ent->v->weaponframe);
+               if (bits & SU_ARMOR)
+                       MSG_WriteByte (msg, ent->v->armorvalue);
+               if (bits & SU_WEAPON)
+               {
+                       i = SV_ModelIndex(PR_GetString(ent->v->weaponmodel));
+                       if (i < 0)
+                       {
+                               Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel));
+                               i = 0;
+                       }
+                       MSG_WriteByte (msg, i);
+               }
+
+               MSG_WriteShort (msg, ent->v->health);
+               MSG_WriteByte (msg, ent->v->currentammo);
+               MSG_WriteByte (msg, ent->v->ammo_shells);
+               MSG_WriteByte (msg, ent->v->ammo_nails);
+               MSG_WriteByte (msg, ent->v->ammo_rockets);
+               MSG_WriteByte (msg, ent->v->ammo_cells);
 
-       if (bits & SU_VIEWZOOM)
-               MSG_WriteByte (msg, viewzoom);
+               if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
+               {
+                       for(i=0;i<32;i++)
+                       {
+                               if ( ((int)ent->v->weapon) & (1<<i) )
+                               {
+                                       MSG_WriteByte (msg, i);
+                                       break;
+                               }
+                       }
+               }
+               else
+               {
+                       MSG_WriteByte (msg, ent->v->weapon);
+               }
+       
+               if (bits & SU_VIEWZOOM)
+               {
+                       if (sv.protocol == PROTOCOL_DARKPLACES4)
+                       {
+                               viewzoom = min(viewzoom, 255);
+                               MSG_WriteByte (msg, viewzoom);
+                       }
+                       else if (sv.protocol == PROTOCOL_DARKPLACES5)
+                               MSG_WriteShort (msg, viewzoom);
+               }
+       }
 }
 
 /*
@@ -1378,10 +1535,38 @@ SV_SendClientDatagram
 static qbyte sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
 qboolean SV_SendClientDatagram (client_t *client)
 {
-       sizebuf_t       msg;
+       int rate, maxrate, maxsize, maxsize2;
+       sizebuf_t msg;
+
+       if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
+       {
+               // for good singleplayer, send huge packets
+               maxsize = sizeof(sv_sendclientdatagram_buf);
+               maxsize2 = sizeof(sv_sendclientdatagram_buf);
+       }
+       else if (sv.protocol == PROTOCOL_DARKPLACES5)
+       {
+               // PROTOCOL_DARKPLACES5 supports packet size limiting of updates
+               maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
+               if (sv_maxrate.integer != maxrate)
+                       Cvar_SetValueQuick(&sv_maxrate, maxrate);
+
+               rate = bound(NET_MINRATE, client->netconnection->rate, maxrate);
+               rate = (int)(client->netconnection->rate * sys_ticrate.value);
+               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 = (int)bound(50.0, client->netconnection->rate * host_realframetime, (double)sizeof(sv_sendclientdatagram_buf));
+       msg.maxsize = maxsize;
        msg.cursize = 0;
 
        MSG_WriteByte (&msg, svc_time);
@@ -1392,9 +1577,13 @@ qboolean SV_SendClientDatagram (client_t *client)
 
        SV_WriteEntitiesToClient (client, client->edict, &msg);
 
+       // expand packet size to allow effects to go over the rate limit
+       // (dropping them is FAR too ugly)
+       msg.maxsize = maxsize2;
+
        // copy the server datagram if there is space
        // FIXME: put in delayed queue of effects to send
-       if (msg.cursize + sv.datagram.cursize <= msg.maxsize)
+       if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
                SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
 
 // send the datagram
@@ -1614,11 +1803,13 @@ int SV_ModelIndex (const char *name)
                if (!strcmp(sv.model_precache[i], name))
                        return i;
        if (i==MAX_MODELS || !sv.model_precache[i])
-               Host_Error ("SV_ModelIndex: model %s not precached", name);
+       {
+               Con_DPrintf ("SV_ModelIndex: model %s not precached", name);
+               return -1;
+       }
        return i;
 }
 
-#ifdef SV_QUAKEENTITIES
 /*
 ================
 SV_CreateBaseline
@@ -1637,7 +1828,7 @@ void SV_CreateBaseline (void)
                svent = EDICT_NUM(entnum);
 
                // LordHavoc: always clear state values, whether the entity is in use or not
-               ClearStateToDefault(&svent->e->baseline);
+               svent->e->baseline = defaultstate;
 
                if (svent->e->free)
                        continue;
@@ -1652,7 +1843,10 @@ void SV_CreateBaseline (void)
                if (entnum > 0 && entnum <= svs.maxclients)
                {
                        svent->e->baseline.colormap = entnum;
-                       svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
+                       i = SV_ModelIndex("progs/player.mdl");
+                       if (i < 0)
+                               i = 0;
+                       svent->e->baseline.modelindex = i;
                }
                else
                {
@@ -1685,12 +1879,11 @@ void SV_CreateBaseline (void)
                MSG_WriteByte (&sv.signon, svent->e->baseline.skin);
                for (i=0 ; i<3 ; i++)
                {
-                       MSG_WriteDPCoord(&sv.signon, svent->e->baseline.origin[i]);
-                       MSG_WriteAngle(&sv.signon, svent->e->baseline.angles[i]);
+                       MSG_WriteCoord(&sv.signon, svent->e->baseline.origin[i], sv.protocol);
+                       MSG_WriteAngle8i(&sv.signon, svent->e->baseline.angles[i]);
                }
        }
 }
-#endif
 
 
 /*
@@ -1852,6 +2045,49 @@ void SV_SpawnServer (const char *server)
 
        strlcpy (sv.name, server, sizeof (sv.name));
 
+       // FIXME: cvar
+       if (!strcasecmp(sv_protocolname.string, "QUAKE"))
+       {
+               sv.protocol = PROTOCOL_QUAKE;
+               sv.netquakecompatible = true;
+       }
+       else if (!strcasecmp(sv_protocolname.string, "QUAKEDP"))
+       {
+               sv.protocol = PROTOCOL_QUAKE;
+               sv.netquakecompatible = false;
+       }
+       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES1"))
+       {
+               sv.protocol = PROTOCOL_DARKPLACES1;
+               sv.netquakecompatible = false;
+       }
+       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES2"))
+       {
+               sv.protocol = PROTOCOL_DARKPLACES2;
+               sv.netquakecompatible = false;
+       }
+       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES3"))
+       {
+               sv.protocol = PROTOCOL_DARKPLACES3;
+               sv.netquakecompatible = false;
+       }
+       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES4"))
+       {
+               sv.protocol = PROTOCOL_DARKPLACES4;
+               sv.netquakecompatible = false;
+       }
+       else if (!strcasecmp(sv_protocolname.string, "DARKPLACES5"))
+       {
+               sv.protocol = PROTOCOL_DARKPLACES5;
+               sv.netquakecompatible = false;
+       }
+       else
+       {
+               sv.protocol = PROTOCOL_DARKPLACES5;
+               sv.netquakecompatible = false;
+               Con_Printf("Unknown sv_protocolname \"%s\", valid values are QUAKE, QUAKEDP, DARKPLACES1, DARKPLACES2, DARKPLACES3, DARKPLACES4, DARKPLACES5, falling back to DARKPLACES5 protocol\n", sv_protocolname.string);
+       }
+
 // load progs to get entity field count
        PR_LoadProgs ();
 
@@ -1972,10 +2208,9 @@ void SV_SpawnServer (const char *server)
 
        Mod_PurgeUnused();
 
-#ifdef QUAKEENTITIES
 // create a baseline for more efficient communications
-       SV_CreateBaseline ();
-#endif
+       if (sv.protocol == PROTOCOL_QUAKE)
+               SV_CreateBaseline ();
 
 // send serverinfo to all connected clients
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
index ada7f28..3eb4d0f 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -613,7 +613,9 @@ void SV_ReadClientMove (usercmd_t *move)
        float total;
 
        // read ping time
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = sv.time - MSG_ReadFloat ();
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        host_client->num_pings++;
        for (i=0, total = 0;i < NUM_PING_TIMES;i++)
                total += host_client->ping_times[i];
@@ -623,16 +625,28 @@ void SV_ReadClientMove (usercmd_t *move)
                val->_float = host_client->ping * 1000.0;
 
        // read current angles
-       // PROTOCOL_DARKPLACES4
        for (i = 0;i < 3;i++)
-               angle[i] = MSG_ReadPreciseAngle();
+       {
+               if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+               if (sv.protocol == PROTOCOL_QUAKE)
+                       angle[i] = MSG_ReadAngle8i();
+               else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
+                       angle[i] = MSG_ReadAngle32f();
+               else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+                       angle[i] = MSG_ReadAngle16i();
+               if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       }
 
        VectorCopy (angle, sv_player->v->v_angle);
 
        // read movement
-       move->forwardmove = MSG_ReadShort ();
-       move->sidemove = MSG_ReadShort ();
-       move->upmove = MSG_ReadShort ();
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       move->forwardmove = MSG_ReadCoord16i ();
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       move->sidemove = MSG_ReadCoord16i ();
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       move->upmove = MSG_ReadCoord16i ();
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        if ((val = GETEDICTFIELDVALUE(sv_player, eval_movement)))
        {
                val->vector[0] = move->forwardmove;
@@ -642,6 +656,7 @@ void SV_ReadClientMove (usercmd_t *move)
 
        // read buttons
        bits = MSG_ReadByte ();
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        sv_player->v->button0 = bits & 1;
        sv_player->v->button2 = (bits & 2)>>1;
        // LordHavoc: added 6 new buttons
@@ -653,6 +668,7 @@ void SV_ReadClientMove (usercmd_t *move)
        if ((val = GETEDICTFIELDVALUE(sv_player, eval_button8))) val->_float = ((bits >> 7) & 1);
 
        i = MSG_ReadByte ();
+       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        if (i)
                sv_player->v->impulse = i;
 }
@@ -665,7 +681,7 @@ SV_ReadClientMessage
 extern void SV_SendServerinfo(client_t *client);
 void SV_ReadClientMessage(void)
 {
-       int cmd;
+       int cmd, num;
        char *s;
 
        //MSG_BeginReading ();
@@ -744,10 +760,17 @@ void SV_ReadClientMessage(void)
                        break;
 
                case clc_ackentities:
-                       host_client->entitydatabase4->ackframenum = MSG_ReadLong();
+                       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+                       num = MSG_ReadLong();
+                       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
                        if (developer_networkentities.integer >= 1)
-                               Con_Printf("recv clc_ackentities %i\n", host_client->entitydatabase4->ackframenum);
-                       EntityFrame4_AckFrame(host_client->entitydatabase4, host_client->entitydatabase4->ackframenum);
+                               Con_Printf("recv clc_ackentities %i\n", num);
+                       if (host_client->entitydatabase)
+                               EntityFrame_AckFrame(host_client->entitydatabase, num);
+                       else if (host_client->entitydatabase4)
+                               EntityFrame4_AckFrame(host_client->entitydatabase4, host_client->entitydatabase4->ackframenum);
+                       else if (host_client->entitydatabase5)
+                               EntityFrame5_AckFrame(host_client->entitydatabase5, num, host_client - svs.clients + 1);
                        break;
                }
        }
diff --git a/view.c b/view.c
index 78ac5d3..060464a 100644 (file)
--- a/view.c
+++ b/view.c
@@ -214,7 +214,7 @@ void V_ParseDamage (void)
 
        armor = MSG_ReadByte ();
        blood = MSG_ReadByte ();
-       MSG_ReadVector(from);
+       MSG_ReadVector(from, cl.protocol);
 
        count = blood*0.5 + armor*0.5;
        if (count < 10)