]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_input.c
fix a const warning
[xonotic/darkplaces.git] / cl_input.c
index 8bc8ef1644c6ef44336ff1eb6a6f9047de0fd8b3..557f04b30ae3f9413981956e14d330edf189bff8 100644 (file)
@@ -288,6 +288,8 @@ cvar_t m_filter = {CVAR_SAVE, "m_filter","0", "smoothes mouse movement, less res
 
 cvar_t cl_netinputpacketspersecond = {CVAR_SAVE, "cl_netinputpacketspersecond","50", "how many input packets to send to server each second"};
 
+cvar_t cl_nodelta = {0, "cl_nodelta", "0", "disables delta compression of non-player entities in QW network protocol"};
+
 
 /*
 ================
@@ -513,6 +515,34 @@ void CL_UpdatePrydonCursor(void)
        //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
 }
 
+void CL_ClientMovement_InputQW(qw_usercmd_t *cmd)
+{
+       int i;
+       int n;
+       // remove stale queue items
+       n = cl.movement_numqueue;
+       cl.movement_numqueue = 0;
+       for (i = 0;i < n;i++)
+               if (cl.movement_queue[i].sequence > cls.netcon->qw.incoming_sequence)
+                       cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       // add to input queue if there is room
+       if (cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])) && cl.mtime[0] > cl.mtime[1])
+       {
+               // add to input queue
+               cl.movement_queue[cl.movement_numqueue].sequence = cls.netcon->qw.outgoing_sequence;
+               cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value / 1000.0;
+               cl.movement_queue[cl.movement_numqueue].frametime = cmd->msec * 0.001;
+               VectorCopy(cmd->angles, cl.movement_queue[cl.movement_numqueue].viewangles);
+               cl.movement_queue[cl.movement_numqueue].move[0] = cmd->forwardmove;
+               cl.movement_queue[cl.movement_numqueue].move[1] = cmd->sidemove;
+               cl.movement_queue[cl.movement_numqueue].move[2] = cmd->upmove;
+               cl.movement_queue[cl.movement_numqueue].jump = (cmd->buttons & 2) != 0;
+               cl.movement_queue[cl.movement_numqueue].crouch = false;
+               cl.movement_numqueue++;
+       }
+       cl.movement_replay = true;
+}
+
 void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
 {
        int i;
@@ -558,6 +588,20 @@ void CL_ClientMovement_Replay(void)
        int contents;
        int crouch;
        int onground;
+       float movevars_gravity;
+       float movevars_stopspeed;
+       float movevars_maxspeed;
+       float movevars_spectatormaxspeed;
+       float movevars_accelerate;
+       float movevars_airaccelerate;
+       float movevars_wateraccelerate;
+       float movevars_friction;
+       float movevars_waterfriction;
+       float movevars_entgravity;
+       float movevars_jumpvelocity;
+       float movevars_edgefriction;
+       float movevars_maxairspeed;
+       float movevars_stepheight;
        double edgefriction;
        double frametime;
        double t;
@@ -582,10 +626,46 @@ void CL_ClientMovement_Replay(void)
        trace_t trace2;
        trace_t trace3;
 
+
        if (!cl.movement_replay)
                return;
        cl.movement_replay = false;
 
+       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       {
+               movevars_gravity = cl.qw_movevars_gravity;
+               movevars_stopspeed = cl.qw_movevars_stopspeed;
+               movevars_maxspeed = cl.qw_movevars_maxspeed;
+               movevars_spectatormaxspeed = cl.qw_movevars_spectatormaxspeed;
+               movevars_accelerate = cl.qw_movevars_accelerate;
+               movevars_airaccelerate = cl.qw_movevars_airaccelerate;
+               movevars_wateraccelerate = cl.qw_movevars_wateraccelerate;
+               movevars_friction = cl.qw_movevars_friction;
+               movevars_waterfriction = cl.qw_movevars_waterfriction;
+               movevars_entgravity = cl.qw_movevars_entgravity;
+               movevars_jumpvelocity = cl_movement_jumpvelocity.value;
+               movevars_edgefriction = cl_movement_edgefriction.value;
+               movevars_maxairspeed = cl_movement_maxairspeed.value;
+               movevars_stepheight = cl_movement_stepheight.value;
+       }
+       else
+       {
+               movevars_gravity = sv_gravity.value;
+               movevars_stopspeed = cl_movement_stopspeed.value;
+               movevars_maxspeed = cl_movement_maxspeed.value;
+               movevars_spectatormaxspeed = cl_movement_maxspeed.value;
+               movevars_accelerate = cl_movement_accelerate.value;
+               movevars_airaccelerate = cl_movement_accelerate.value;
+               movevars_wateraccelerate = cl_movement_accelerate.value;
+               movevars_friction = cl_movement_friction.value;
+               movevars_waterfriction = cl_movement_friction.value;
+               movevars_entgravity = 1;
+               movevars_jumpvelocity = cl_movement_jumpvelocity.value;
+               movevars_edgefriction = cl_movement_edgefriction.value;
+               movevars_maxairspeed = cl_movement_maxairspeed.value;
+               movevars_stepheight = cl_movement_stepheight.value;
+       }
+
        // fetch current starting values
        VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
        VectorCopy(cl.mvelocity[0], currentvelocity);
@@ -652,15 +732,14 @@ void CL_ClientMovement_Replay(void)
                                        VectorScale(wishvel, 1 / wishspeed, wishdir);
                                else
                                        VectorSet( wishdir, 0.0, 0.0, 0.0 );
-                               wishspeed = min(wishspeed, cl_movement_maxspeed.value);
+                               wishspeed = min(wishspeed, movevars_maxspeed) * 0.6;
                                if (crouch)
                                        wishspeed *= 0.5;
-                               wishspeed *= 0.6;
-                               VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity);
+                               VectorScale(currentvelocity, (1 - frametime * movevars_waterfriction), currentvelocity);
                                f = wishspeed - DotProduct(currentvelocity, wishdir);
                                if (f > 0)
                                {
-                                       f = min(f, cl_movement_accelerate.value * frametime * wishspeed);
+                                       f = min(f, movevars_wateraccelerate * frametime * wishspeed);
                                        VectorMA(currentvelocity, f, wishdir, currentvelocity);
                                }
                                if (q->jump)
@@ -683,7 +762,7 @@ void CL_ClientMovement_Replay(void)
                                // walk
                                if (onground && q->jump)
                                {
-                                       currentvelocity[2] += cl_movement_jumpvelocity.value;
+                                       currentvelocity[2] += movevars_jumpvelocity;
                                        onground = false;
                                }
                                VectorSet(yawangles, 0, q->viewangles[1], 0);
@@ -694,7 +773,7 @@ void CL_ClientMovement_Replay(void)
                                        VectorScale(wishvel, 1 / wishspeed, wishdir);
                                else
                                        VectorSet( wishdir, 0.0, 0.0, 0.0 );
-                               wishspeed = min(wishspeed, cl_movement_maxspeed.value);
+                               wishspeed = min(wishspeed, movevars_maxspeed);
                                if (crouch)
                                        wishspeed *= 0.5;
                                // check if onground
@@ -709,17 +788,17 @@ void CL_ClientMovement_Replay(void)
                                                VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
                                                trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
                                                if (trace.fraction == 1)
-                                                       edgefriction = cl_movement_edgefriction.value;
+                                                       edgefriction = movevars_edgefriction;
                                        }
                                        // apply friction
-                                       f = 1 - frametime * edgefriction * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value;
+                                       f = 1 - frametime * edgefriction * ((f < movevars_stopspeed) ? (movevars_stopspeed / f) : 1) * movevars_friction;
                                        f = max(f, 0);
                                        VectorScale(currentvelocity, f, currentvelocity);
                                }
                                else
                                {
                                        // apply air speed limit
-                                       wishspeed = min(wishspeed, cl_movement_maxairspeed.value);
+                                       wishspeed = min(wishspeed, movevars_maxairspeed);
                                }
                                if (gamemode == GAME_NEXUIZ)
                                        addspeed = wishspeed;
@@ -727,7 +806,7 @@ void CL_ClientMovement_Replay(void)
                                        addspeed = wishspeed - DotProduct(currentvelocity, wishdir);
                                if (addspeed > 0)
                                {
-                                       accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed);
+                                       accelspeed = min(movevars_accelerate * frametime * wishspeed, addspeed);
                                        VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity);
                                }
                                currentvelocity[2] -= cl_gravity.value * frametime;
@@ -754,8 +833,8 @@ void CL_ClientMovement_Replay(void)
                                {
                                        // may be a step or wall, try stepping up
                                        // first move forward at a higher level
-                                       VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
-                                       VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
+                                       VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + movevars_stepheight);
+                                       VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + movevars_stepheight);
                                        trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
                                        // then move down from there
                                        VectorCopy(trace2.endpos, currentorigin2);
@@ -792,6 +871,48 @@ void CL_ClientMovement_Replay(void)
        //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
 }
 
+void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, qw_usercmd_t *from, qw_usercmd_t *to)
+{
+       int bits;
+
+       bits = 0;
+       if (to->angles[0] != from->angles[0])
+               bits |= QW_CM_ANGLE1;
+       if (to->angles[1] != from->angles[1])
+               bits |= QW_CM_ANGLE2;
+       if (to->angles[2] != from->angles[2])
+               bits |= QW_CM_ANGLE3;
+       if (to->forwardmove != from->forwardmove)
+               bits |= QW_CM_FORWARD;
+       if (to->sidemove != from->sidemove)
+               bits |= QW_CM_SIDE;
+       if (to->upmove != from->upmove)
+               bits |= QW_CM_UP;
+       if (to->buttons != from->buttons)
+               bits |= QW_CM_BUTTONS;
+       if (to->impulse != from->impulse)
+               bits |= QW_CM_IMPULSE;
+
+       MSG_WriteByte(buf, bits);
+       if (bits & QW_CM_ANGLE1)
+               MSG_WriteAngle16i(buf, to->angles[0]);
+       if (bits & QW_CM_ANGLE2)
+               MSG_WriteAngle16i(buf, to->angles[1]);
+       if (bits & QW_CM_ANGLE3)
+               MSG_WriteAngle16i(buf, to->angles[2]);
+       if (bits & QW_CM_FORWARD)
+               MSG_WriteShort(buf, to->forwardmove);
+       if (bits & QW_CM_SIDE)
+               MSG_WriteShort(buf, to->sidemove);
+       if (bits & QW_CM_UP)
+               MSG_WriteShort(buf, to->upmove);
+       if (bits & QW_CM_BUTTONS)
+               MSG_WriteByte(buf, to->buttons);
+       if (bits & QW_CM_IMPULSE)
+               MSG_WriteByte(buf, to->impulse);
+       MSG_WriteByte(buf, to->msec);
+}
+
 /*
 ==============
 CL_SendMove
@@ -824,7 +945,7 @@ void CL_SendMove(void)
        accumtotal++;
 #endif
 
-       if (cl_movement.integer && cls.signon == SIGNONS)
+       if (cl_movement.integer && cls.signon == SIGNONS && cls.protocol != PROTOCOL_QUAKEWORLD)
        {
                if (!cl.movement_needupdate)
                        return;
@@ -914,7 +1035,71 @@ void CL_SendMove(void)
                        // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
                        // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
                        // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total
-                       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
+                       // PROTOCOL_QUAKEWORLD   clc_move = 34 bytes total (typically, but can reach 43 bytes, or even 49 bytes with roll)
+                       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+                       {
+                               int checksumindex;
+                               double msectime;
+                               static double oldmsectime;
+                               qw_usercmd_t *cmd, *oldcmd;
+                               qw_usercmd_t nullcmd;
+
+                               //Con_Printf("code qw_clc_move\n");
+
+                               i = cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK;
+                               cmd = &cl.qw_moves[i];
+                               memset(&nullcmd, 0, sizeof(nullcmd));
+                               memset(cmd, 0, sizeof(*cmd));
+                               cmd->buttons = bits;
+                               cmd->impulse = impulse;
+                               cmd->forwardmove = (short)bound(-32768, forwardmove, 32767);
+                               cmd->sidemove = (short)bound(-32768, sidemove, 32767);
+                               cmd->upmove = (short)bound(-32768, upmove, 32767);
+                               VectorCopy(cl.viewangles, cmd->angles);
+                               msectime = realtime * 1000;
+                               cmd->msec = (unsigned char)bound(0, msectime - oldmsectime, 255);
+                               // ridiculous value rejection (matches qw)
+                               if (cmd->msec > 250)
+                                       cmd->msec = 100;
+                               oldmsectime = msectime;
+
+                               CL_ClientMovement_InputQW(cmd);
+
+                               MSG_WriteByte(&buf, qw_clc_move);
+                               // save the position for a checksum byte
+                               checksumindex = buf.cursize;
+                               MSG_WriteByte(&buf, 0);
+                               // packet loss percentage
+                               // FIXME: netgraph stuff
+                               MSG_WriteByte(&buf, 0);
+                               // write most recent 3 moves
+                               i = (cls.netcon->qw.outgoing_sequence-2) & QW_UPDATE_MASK;
+                               cmd = &cl.qw_moves[i];
+                               QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, cmd);
+                               oldcmd = cmd;
+                               i = (cls.netcon->qw.outgoing_sequence-1) & QW_UPDATE_MASK;
+                               cmd = &cl.qw_moves[i];
+                               QW_MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
+                               oldcmd = cmd;
+                               i = cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK;
+                               cmd = &cl.qw_moves[i];
+                               QW_MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
+                               // calculate the checksum
+                               buf.data[checksumindex] = COM_BlockSequenceCRCByteQW(buf.data + checksumindex + 1, buf.cursize - checksumindex - 1, cls.netcon->qw.outgoing_sequence);
+                               // if delta compression history overflows, request no delta
+                               if (cls.netcon->qw.outgoing_sequence - cl.qw_validsequence >= QW_UPDATE_BACKUP-1)
+                                       cl.qw_validsequence = 0;
+                               // request delta compression if appropriate
+                               if (cl.qw_validsequence && !cl_nodelta.integer && cls.state == ca_connected && !cls.demorecording)
+                               {
+                                       cl.qw_deltasequence[cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK] = cl.qw_validsequence;
+                                       MSG_WriteByte(&buf, qw_clc_delta);
+                                       MSG_WriteByte(&buf, cl.qw_validsequence & 255);
+                               }
+                               else
+                                       cl.qw_deltasequence[cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK] = -1;
+                       }
+                       else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE)
                        {
                                // 5 bytes
                                MSG_WriteByte (&buf, clc_move);
@@ -929,8 +1114,10 @@ void CL_SendMove(void)
                                // 2 bytes
                                MSG_WriteByte (&buf, bits);
                                MSG_WriteByte (&buf, impulse);
+
+                               CL_ClientMovement_Input((bits & 2) != 0, false);
                        }
-                       else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
+                       else if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
                        {
                                // 5 bytes
                                MSG_WriteByte (&buf, clc_move);
@@ -945,8 +1132,10 @@ void CL_SendMove(void)
                                // 2 bytes
                                MSG_WriteByte (&buf, bits);
                                MSG_WriteByte (&buf, impulse);
+
+                               CL_ClientMovement_Input((bits & 2) != 0, false);
                        }
-                       else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
+                       else if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
                        {
                                // 5 bytes
                                MSG_WriteByte (&buf, clc_move);
@@ -961,12 +1150,14 @@ void CL_SendMove(void)
                                // 2 bytes
                                MSG_WriteByte (&buf, bits);
                                MSG_WriteByte (&buf, impulse);
+
+                               CL_ClientMovement_Input((bits & 2) != 0, false);
                        }
                        else
                        {
                                // 5 bytes
                                MSG_WriteByte (&buf, clc_move);
-                               if (cl.protocol != PROTOCOL_DARKPLACES6)
+                               if (cls.protocol != PROTOCOL_DARKPLACES6)
                                {
                                        if (cl_movement.integer)
                                        {
@@ -998,23 +1189,26 @@ void CL_SendMove(void)
                                MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
                                MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
                                MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
-                       }
 
-                       // FIXME: bits & 16 is +button5, Nexuiz specific
-                       CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
+                               // FIXME: bits & 16 is +button5, Nexuiz specific
+                               CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
+                       }
                }
 
-               // ack the last few frame numbers
-               // (redundent to improve handling of client->server packet loss)
-               // for LATESTFRAMENUMS == 3 case this is 15 bytes
-               for (i = 0;i < LATESTFRAMENUMS;i++)
+               if (cls.protocol != PROTOCOL_QUAKEWORLD)
                {
-                       if (cl.latestframenums[i] > 0)
+                       // ack the last few frame numbers
+                       // (redundent to improve handling of client->server packet loss)
+                       // for LATESTFRAMENUMS == 3 case this is 15 bytes
+                       for (i = 0;i < LATESTFRAMENUMS;i++)
                        {
-                               if (developer_networkentities.integer >= 1)
-                                       Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
-                               MSG_WriteByte(&buf, clc_ackframe);
-                               MSG_WriteLong(&buf, cl.latestframenums[i]);
+                               if (cl.latestframenums[i] > 0)
+                               {
+                                       if (developer_networkentities.integer >= 1)
+                                               Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
+                                       MSG_WriteByte(&buf, clc_ackframe);
+                                       MSG_WriteLong(&buf, cl.latestframenums[i]);
+                               }
                        }
                }
 
@@ -1023,7 +1217,7 @@ void CL_SendMove(void)
        }
 
        // send the reliable message (forwarded commands) if there is one
-       NetConn_SendUnreliableMessage(cls.netcon, &buf);
+       NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol);
 
        if (cls.netcon->message.overflowed)
        {
@@ -1126,5 +1320,7 @@ void CL_InitInput (void)
        Cvar_RegisterVariable(&m_filter);
 
        Cvar_RegisterVariable(&cl_netinputpacketspersecond);
+
+       Cvar_RegisterVariable(&cl_nodelta);
 }