]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
significant cleanup of input networking code (reorganized and now uses
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 1 May 2007 06:11:48 +0000 (06:11 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 1 May 2007 06:11:48 +0000 (06:11 +0000)
frametimes rather than timestamps for queued moves) and some refinements
to prediction code
tried to reimplement the anti-pogostick code and it's partially working
but not completely (mispredicts for one frame each time)

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

cl_input.c
client.h
csprogs.c
netconn.c

index 10837bd89fa80f20370948176365f08c09a7d6df..ad392f688dd974cd6fcf579e69b552036cc6c19f 100644 (file)
@@ -568,49 +568,10 @@ void CL_UpdatePrydonCursor(void)
        cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl.entities[cl.playerentity].render : NULL);
 }
 
-void CL_ClientMovement_InputQW(void)
+void CL_ClientMovement_ExpireOldMoves(void)
 {
        int i;
        int n;
-       // if time has not advanced, do nothing
-       if (cl.movecmd[0].time <= cl.movecmd[1].time)
-               return;
-       // 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];
-               else if (i == 0)
-                       cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken
-       }
-       // add to input queue if there is room
-       if (cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])))
-       {
-               // add to input queue
-               cl.movement_queue[cl.movement_numqueue].sequence = cls.netcon->qw.outgoing_sequence;
-               cl.movement_queue[cl.movement_numqueue].time = cl.movecmd[0].time;
-               cl.movement_queue[cl.movement_numqueue].frametime = cl.cmd.msec / 1000.0;
-               VectorCopy(cl.cmd.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
-               cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
-               cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
-               cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
-               cl.movement_queue[cl.movement_numqueue].jump = (cl.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;
-       int n;
-       // if time has not advanced, do nothing
-       if (cl.movecmd[0].time <= cl.movecmd[1].time)
-               return;
        // remove stale queue items
        n = cl.movement_numqueue;
        cl.movement_numqueue = 0;
@@ -620,21 +581,28 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
                {
                        if (cl.movement_queue[i].sequence > cls.servermovesequence)
                                cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
-                       else if (i == 0)
-                               cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken
+                       else
+                               cl.movement_replay_canjump = cl.movement_queue[i].canjump;
                }
        }
+}
+
+void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
+{
+       // if time has not advanced, do nothing
+       if (cl.movecmd[0].msec <= 0)
+               return;
        // add to input queue if there is room
        if (cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])))
        {
                // add to input queue
-               cl.movement_queue[cl.movement_numqueue].sequence = cls.movesequence;
+               cl.movement_queue[cl.movement_numqueue].sequence = cl.movecmd[0].sequence;
                cl.movement_queue[cl.movement_numqueue].time = cl.movecmd[0].time;
-               cl.movement_queue[cl.movement_numqueue].frametime = bound(0, cl.movecmd[0].time - cl.movecmd[1].time, 0.1);
-               VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
-               cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
-               cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
-               cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
+               cl.movement_queue[cl.movement_numqueue].frametime = cl.movecmd[0].msec * 0.001;
+               VectorCopy(cl.movecmd[0].viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
+               cl.movement_queue[cl.movement_numqueue].move[0] = cl.movecmd[0].forwardmove;
+               cl.movement_queue[cl.movement_numqueue].move[1] = cl.movecmd[0].sidemove;
+               cl.movement_queue[cl.movement_numqueue].move[2] = cl.movecmd[0].upmove;
                cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
                cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
                cl.movement_numqueue++;
@@ -664,8 +632,6 @@ typedef struct cl_clientmovement_state_s
        qboolean onground;
        // currently crouching
        qboolean crouched;
-       // whether jump button has been released since last jump
-       qboolean canjump;
        // what kind of water (SUPERCONTENTS_LAVA for instance)
        int watertype;
        // how deep
@@ -892,7 +858,7 @@ void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
                                s->velocity[2] = 310;
                                s->waterjumptime = 2;
                                s->onground = false;
-                               s->canjump = false;
+                               s->q.canjump = false;
                        }
                }
        }
@@ -977,12 +943,17 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
 
        // jump if on ground with jump button pressed but only if it has been
        // released at least once since the last jump
-       if (s->q.jump && s->onground)// && s->canjump) // FIXME: canjump doesn't work properly
+       if (s->q.jump)
        {
-               s->velocity[2] += s->movevars_jumpvelocity;
-               s->onground = false;
-               s->canjump = false;
+               if (s->onground && s->q.canjump)
+               {
+                       s->velocity[2] += s->movevars_jumpvelocity;
+                       s->onground = false;
+                       s->q.canjump = false;
+               }
        }
+       else
+               s->q.canjump = true;
 
        // calculate movement vector
        VectorSet(yawangles, 0, s->q.viewangles[1], 0);
@@ -1083,7 +1054,7 @@ void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s)
 {
        //Con_Printf(" %f", frametime);
        if (!s->q.jump)
-               s->canjump = true;
+               s->q.canjump = true;
        s->waterjumptime -= s->q.frametime;
        CL_ClientMovement_UpdateStatus(s);
        if (s->waterlevel >= WATERLEVEL_SWIMMING)
@@ -1095,15 +1066,17 @@ void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s)
 void CL_ClientMovement_Replay(void)
 {
        int i;
+       qboolean canjump;
        double totalmovetime;
        cl_clientmovement_state_t s;
 
+       CL_ClientMovement_ExpireOldMoves();
+
        // set up starting state for the series of moves
        memset(&s, 0, sizeof(s));
        VectorCopy(cl.entities[cl.playerentity].state_current.origin, s.origin);
        VectorCopy(cl.mvelocity[0], s.velocity);
        s.crouched = true; // will be updated on first move
-       s.canjump = cl.movement_replay_canjump;
        //Con_Printf("movement replay starting org %f %f %f vel %f %f %f\n", s.origin[0], s.origin[1], s.origin[2], s.velocity[0], s.velocity[1], s.velocity[2]);
 
        // set up movement variables
@@ -1150,16 +1123,19 @@ void CL_ClientMovement_Replay(void)
        for (i = 0;i < cl.movement_numqueue - 1;i++)
                totalmovetime += cl.movement_queue[i].frametime;
        cl.movement_predicted = totalmovetime * 1000.0 >= cl_movement_minping.value && cls.servermovesequence && (cl_movement.integer && !cls.demoplayback && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission);
+       //Con_Printf("%i = %.0f >= %.0f && %i && (%i && %i && %i == %i && %i > 0 && %i\n", cl.movement_predicted, totalmovetime * 1000.0, cl_movement_minping.value, cls.servermovesequence, cl_movement.integer, !cls.demoplayback, cls.signon, SIGNONS, cl.stats[STAT_HEALTH], !cl.intermission);
        if (cl.movement_predicted)
        {
-               //Con_Printf("%f: ", cl.movecmd[0].time);
+               //Con_Printf("%ims\n", cl.movecmd[0].msec);
 
                // replay the input queue to predict current location
                // note: this relies on the fact there's always one queue item at the end
 
+               canjump = cl.movement_replay_canjump;
                for (i = 0;i < cl.movement_numqueue;i++)
                {
                        s.q = cl.movement_queue[i];
+                       s.q.canjump = canjump;
                        // if a move is more than 50ms, do it as two moves (matching qwsv)
                        if (s.q.frametime > 0.05)
                        {
@@ -1167,6 +1143,7 @@ void CL_ClientMovement_Replay(void)
                                CL_ClientMovement_PlayerMove(&s);
                        }
                        CL_ClientMovement_PlayerMove(&s);
+                       canjump = cl.movement_queue[i].canjump = s.q.canjump;
                }
        }
        else
@@ -1180,9 +1157,9 @@ void CL_ClientMovement_Replay(void)
        {
                cl.movement_replay = false;
                // update interpolation timestamps if time has passed
-               if (cl.movecmd[0].time != cl.movecmd[1].time)
+               if (cl.movement_time[0] != cl.movecmd[0].time)
                {
-                       cl.movement_time[1] = cl.movecmd[1].time;
+                       cl.movement_time[1] = cl.movement_time[0];
                        cl.movement_time[0] = cl.movecmd[0].time;
                        cl.movement_time[2] = cl.time;
                        VectorCopy(cl.movement_origin, cl.movement_oldorigin);
@@ -1276,21 +1253,25 @@ CL_SendMove
 usercmd_t nullcmd; // for delta compression of qw moves
 void CL_SendMove(void)
 {
-       int i, j, packetloss, maxusercmds;
+       int i, j, packetloss;
        int bits;
        sizebuf_t buf;
        unsigned char data[1024];
        static double lastsendtime = 0;
        double packettime;
-       double msectime;
-       static double oldmsectime;
+       int msecdelta;
+
+       CL_ClientMovement_ExpireOldMoves();
 
        // if playing a demo, do nothing
        if (!cls.netcon)
                return;
 
        // don't send too often or else network connections can get clogged by a high renderer framerate
-       packettime = 1.0 / bound(10, cl_netinputpacketspersecond.value, 100);
+       if (cl_netinputpacketspersecond.value >= 1)
+               packettime = 1.0 / bound(1, cl_netinputpacketspersecond.value, 1000);
+       else
+               packettime = 0;
        // quakeworld servers take only frametimes
        // predicted dp7 servers take current interpolation time
        // unpredicted servers take an echo of the latest server timestamp
@@ -1299,12 +1280,14 @@ void CL_SendMove(void)
                if (realtime < lastsendtime + packettime)
                        return;
                cl.cmd.time = realtime;
+               cl.cmd.sequence = cls.netcon->qw.outgoing_sequence;
        }
        else if (cl.movement_predicted)
        {
                if (realtime < lastsendtime + packettime)
                        return;
                cl.cmd.time = cl.time;
+               cl.cmd.sequence = cls.movesequence;
        }
        else
        {
@@ -1312,7 +1295,10 @@ void CL_SendMove(void)
                // packet is received, to minimize ping times
                if (!cl.movement_needupdate && realtime < lastsendtime + packettime)
                        return;
+               if (cl.mtime[0] == cl.movecmd[0].time && cl.mtime[1] != cl.mtime[0])
+                       return;
                cl.cmd.time = cl.mtime[0];
+               cl.cmd.sequence = cls.movesequence;
        }
 
        // don't let it fall behind if CL_SendMove hasn't been called recently
@@ -1328,237 +1314,222 @@ void CL_SendMove(void)
        // conditions for sending a move:
        // if the move advances time or if the game is paused (in which case time
        // is not advancing)
-       if ((cl.cmd.time > cl.movecmd[0].time || cl.mtime[0] <= cl.mtime[1]) && cls.signon == SIGNONS)
-       {
-               // don't send a new input packet if the connection is still saturated from
-               // the last one (or chat messages, etc)
-               // note: this behavior comes from QW
-               if (!NetConn_CanSend(cls.netcon))
-                       return;
-
-               // send the movement message
-               // PROTOCOL_QUAKE        clc_move = 16 bytes total
-               // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
-               // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
-               // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
-               // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
-               // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
-               // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total per move (can be up to 16 moves)
-               // PROTOCOL_QUAKEWORLD   clc_move = 34 bytes total (typically, but can reach 43 bytes, or even 49 bytes with roll)
-
-               // set button bits
-               // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
-               bits = 0;
-               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;
-               if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
-               if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
-               if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
-               if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
-               if (key_dest != key_game || key_consoleactive) bits |= 512;
-               if (cl_prydoncursor.integer) bits |= 1024;
-               if (in_button9.state  & 3)  bits |=   2048;in_button9.state  &= ~2;
-               if (in_button10.state  & 3) bits |=   4096;in_button10.state &= ~2;
-               if (in_button11.state  & 3) bits |=   8192;in_button11.state &= ~2;
-               if (in_button12.state  & 3) bits |=  16384;in_button12.state &= ~2;
-               if (in_button13.state  & 3) bits |=  32768;in_button13.state &= ~2;
-               if (in_button14.state  & 3) bits |=  65536;in_button14.state &= ~2;
-               if (in_button15.state  & 3) bits |= 131072;in_button15.state &= ~2;
-               if (in_button16.state  & 3) bits |= 262144;in_button16.state &= ~2;
-               // button bits 19-31 unused currently
-               // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
-               if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
-               if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
-               if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
-               if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
-               cl.cmd.buttons = bits;
-
-               // set impulse
-               cl.cmd.impulse = in_impulse;
-               in_impulse = 0;
-
-               // movement is set by input code (forwardmove/sidemove/upmove)
-
-               // set viewangles
-               VectorCopy(cl.viewangles, cl.cmd.viewangles);
-
-               msectime = floor(cl.cmd.time * 1000);
-               cl.cmd.msec = (unsigned char)bound(0, msectime - oldmsectime, 255);
-               // ridiculous value rejection (matches qw)
-               if (cl.cmd.msec > 250)
-                       cl.cmd.msec = 100;
-               oldmsectime = msectime;
-
-               cls.movesequence++;
-               if (cl_movement.integer)
-                       cl.cmd.sequence = cls.movesequence;
-               else
-                       cl.cmd.sequence = 0;
+       // don't send a new input packet if the connection is still saturated from
+       // the last one (or chat messages, etc)
+       // note: this behavior comes from QW
+       if ((cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon == SIGNONS) && !NetConn_CanSend(cls.netcon))
+               return;
 
-               // set prydon cursor info
-               CL_UpdatePrydonCursor();
+       // increase the move counter since we intend to send a move
+       cls.movesequence++;
+
+       // send the movement message
+       // PROTOCOL_QUAKE        clc_move = 16 bytes total
+       // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
+       // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
+       // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
+       // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
+       // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
+       // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
+       // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
+       // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
+       // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total per move (can be up to 16 moves)
+       // PROTOCOL_QUAKEWORLD   clc_move = 34 bytes total (typically, but can reach 43 bytes, or even 49 bytes with roll)
+
+       // set prydon cursor info
+       CL_UpdatePrydonCursor();
+
+       // set button bits
+       // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
+       bits = 0;
+       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;
+       if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
+       if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
+       if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
+       if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
+       if (key_dest != key_game || key_consoleactive) bits |= 512;
+       if (cl_prydoncursor.integer) bits |= 1024;
+       if (in_button9.state  & 3)  bits |=   2048;in_button9.state  &= ~2;
+       if (in_button10.state  & 3) bits |=   4096;in_button10.state &= ~2;
+       if (in_button11.state  & 3) bits |=   8192;in_button11.state &= ~2;
+       if (in_button12.state  & 3) bits |=  16384;in_button12.state &= ~2;
+       if (in_button13.state  & 3) bits |=  32768;in_button13.state &= ~2;
+       if (in_button14.state  & 3) bits |=  65536;in_button14.state &= ~2;
+       if (in_button15.state  & 3) bits |= 131072;in_button15.state &= ~2;
+       if (in_button16.state  & 3) bits |= 262144;in_button16.state &= ~2;
+       // button bits 19-31 unused currently
+       // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
+       if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
+       if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
+       if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
+       if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
+       cl.cmd.buttons = bits;
+
+       // set impulse
+       cl.cmd.impulse = in_impulse;
+       in_impulse = 0;
+
+       // movement is set by input code (forwardmove/sidemove/upmove)
+
+       // set viewangles
+       VectorCopy(cl.viewangles, cl.cmd.viewangles);
+
+       msecdelta = (int)(floor(cl.cmd.time * 1000) - floor(cl.movecmd[0].time * 1000));
+       cl.cmd.msec = (unsigned char)bound(0, msecdelta, 255);
+       // ridiculous value rejection (matches qw)
+       if (cl.cmd.msec > 250)
+               cl.cmd.msec = 100;
+
+       cl.cmd.predicted = cl_movement.integer;
+
+       // always dump the first two messages, because they may contain leftover inputs from the last level
+       if (cl.cmd.sequence <= 2)
+               cl.cmd.forwardmove = cl.cmd.sidemove = cl.cmd.upmove = cl.cmd.impulse = cl.cmd.buttons = 0;
+
+       // update the cl.movecmd array which holds the most recent moves
+       for (i = CL_MAX_USERCMDS - 1;i >= 1;i--)
+               cl.movecmd[i] = cl.movecmd[i-1];
+       cl.movecmd[0] = cl.cmd;
 
-               // always dump the first two messages, because they may contain leftover inputs from the last level
-               if (cls.movesequence > 2)
+       if (cls.protocol == PROTOCOL_QUAKEWORLD)
+       {
+               int checksumindex;
+
+               CL_ClientMovement_Input((cl.movecmd[0].buttons & 2) != 0, false);
+
+               MSG_WriteByte(&buf, qw_clc_move);
+               // save the position for a checksum byte
+               checksumindex = buf.cursize;
+               MSG_WriteByte(&buf, 0);
+               // packet loss percentage
+               for (j = 0, packetloss = 0;j < NETGRAPH_PACKETS;j++)
+                       if (cls.netcon->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
+                               packetloss++;
+               packetloss = packetloss * 100 / NETGRAPH_PACKETS;
+               MSG_WriteByte(&buf, packetloss);
+               // write most recent 3 moves
+               QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, &cl.movecmd[2]);
+               QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[2], &cl.movecmd[1]);
+               QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[1], &cl.movecmd[0]);
+               // 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)
                {
-                       // update the cl.movecmd array which holds the most recent moves
-                       for (i = CL_MAX_USERCMDS - 1;i >= 1;i--)
-                               cl.movecmd[i] = cl.movecmd[i-1];
-                       cl.movecmd[0] = cl.cmd;
+                       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.signon == SIGNONS)
+       {
+               if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
+                       // 3 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle8i (&buf, cl.movecmd[0].viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove);
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove);
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, cl.movecmd[0].buttons);
+                       MSG_WriteByte (&buf, cl.movecmd[0].impulse);
+               }
+               else if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
+                       // 12 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle32f (&buf, cl.movecmd[0].viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove);
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove);
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, cl.movecmd[0].buttons);
+                       MSG_WriteByte (&buf, cl.movecmd[0].impulse);
+               }
+               else if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
+                       // 6 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle16i (&buf, cl.movecmd[0].viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove);
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove);
+                       MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, cl.movecmd[0].buttons);
+                       MSG_WriteByte (&buf, cl.movecmd[0].impulse);
+               }
+               else if (cls.signon == SIGNONS)
+               {
+                       int maxusercmds;
+                       usercmd_t *cmd;
 
-                       // set the maxusercmds variable to limit how many should be sent
-                       if (cls.protocol == PROTOCOL_QUAKEWORLD)
-                       {
-                               // qw uses exactly 3 moves
-                               maxusercmds = 3;
-                       }
-                       else
-                       {
-                               // configurable number of unacknowledged moves
-                               maxusercmds = bound(1, cl_netinputpacketlosstolerance.integer + 1, CL_MAX_USERCMDS);
-                               // when movement prediction is off, there's not much point in repeating old input as it will just be ignored
-                               if (!cl.cmd.sequence)
-                                       maxusercmds = 1;
-                       }
+                       // FIXME: cl.movecmd[0].buttons & 16 is +button5, Nexuiz specific
+                       CL_ClientMovement_Input((cl.movecmd[0].buttons & 2) != 0, (cl.movecmd[0].buttons & 16) != 0);
 
-                       if (cls.protocol == PROTOCOL_QUAKEWORLD)
-                       {
-                               int checksumindex;
-
-                               CL_ClientMovement_InputQW();
-
-                               MSG_WriteByte(&buf, qw_clc_move);
-                               // save the position for a checksum byte
-                               checksumindex = buf.cursize;
-                               MSG_WriteByte(&buf, 0);
-                               // packet loss percentage
-                               for (j = 0, packetloss = 0;j < NETGRAPH_PACKETS;j++)
-                                       if (cls.netcon->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
-                                               packetloss++;
-                               packetloss = packetloss * 100 / NETGRAPH_PACKETS;
-                               MSG_WriteByte(&buf, packetloss);
-                               // write most recent 3 moves
-                               QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, &cl.movecmd[2]);
-                               QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[2], &cl.movecmd[1]);
-                               QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[1], &cl.movecmd[0]);
-                               // 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)
+                       // set the maxusercmds variable to limit how many should be sent
+                       maxusercmds = bound(1, cl_netinputpacketlosstolerance.integer + 1, CL_MAX_USERCMDS);
+                       // when movement prediction is off, there's not much point in repeating old input as it will just be ignored
+                       if (!cl.cmd.predicted)
+                               maxusercmds = 1;
+
+                       // send the latest moves in order, the old ones will be
+                       // ignored by the server harmlessly, however if the previous
+                       // packets were lost these moves will be used
+                       //
+                       // this reduces packet loss impact on gameplay.
+                       for (j = 0, cmd = &cl.movecmd[maxusercmds-1];j < maxusercmds;j++, cmd--)
                        {
-                               CL_ClientMovement_Input((cl.movecmd[0].buttons & 2) != 0, false);
-
-                               // 5 bytes
+                               // don't repeat any stale moves
+                               if (cmd->sequence && cmd->sequence < cls.servermovesequence)
+                                       continue;
+                               // 5/9 bytes
                                MSG_WriteByte (&buf, clc_move);
-                               MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
-                               // 3 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle8i (&buf, cl.movecmd[0].viewangles[i]);
+                               if (cls.protocol != PROTOCOL_DARKPLACES6)
+                                       MSG_WriteLong (&buf, cmd->predicted ? cmd->sequence : 0);
+                               MSG_WriteFloat (&buf, cmd->time); // last server packet time
                                // 6 bytes
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove);
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove);
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove);
-                               // 2 bytes
-                               MSG_WriteByte (&buf, cl.movecmd[0].buttons);
-                               MSG_WriteByte (&buf, cl.movecmd[0].impulse);
-                       }
-                       else if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
-                       {
-                               CL_ClientMovement_Input((cl.movecmd[0].buttons & 2) != 0, false);
-
-                               // 5 bytes
-                               MSG_WriteByte (&buf, clc_move);
-                               MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
-                               // 12 bytes
                                for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle32f (&buf, cl.movecmd[0].viewangles[i]);
+                                       MSG_WriteAngle16i (&buf, cmd->viewangles[i]);
                                // 6 bytes
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove);
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove);
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove);
-                               // 2 bytes
-                               MSG_WriteByte (&buf, cl.movecmd[0].buttons);
-                               MSG_WriteByte (&buf, cl.movecmd[0].impulse);
-                       }
-                       else if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
-                       {
-                               CL_ClientMovement_Input((cl.movecmd[0].buttons & 2) != 0, false);
-
+                               MSG_WriteCoord16i (&buf, cmd->forwardmove);
+                               MSG_WriteCoord16i (&buf, cmd->sidemove);
+                               MSG_WriteCoord16i (&buf, cmd->upmove);
                                // 5 bytes
-                               MSG_WriteByte (&buf, clc_move);
-                               MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
-                               // 6 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle16i (&buf, cl.movecmd[0].viewangles[i]);
-                               // 6 bytes
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove);
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove);
-                               MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove);
-                               // 2 bytes
-                               MSG_WriteByte (&buf, cl.movecmd[0].buttons);
-                               MSG_WriteByte (&buf, cl.movecmd[0].impulse);
-                       }
-                       else
-                       {
-                               usercmd_t *cmd;
-                               // FIXME: cl.movecmd[0].buttons & 16 is +button5, Nexuiz specific
-                               CL_ClientMovement_Input((cl.movecmd[0].buttons & 2) != 0, (cl.movecmd[0].buttons & 16) != 0);
-
-                               // send the latest moves in order, the old ones will be
-                               // ignored by the server harmlessly, however if the previous
-                               // packets were lost these moves will be used
-                               //
-                               // this reduces packet loss impact on gameplay.
-                               for (j = 0, cmd = &cl.movecmd[maxusercmds-1];j < maxusercmds;j++, cmd--)
-                               {
-                                       // don't repeat any stale moves
-                                       if (cmd->sequence && cmd->sequence < cls.servermovesequence)
-                                               continue;
-                                       // 5/9 bytes
-                                       MSG_WriteByte (&buf, clc_move);
-                                       if (cls.protocol != PROTOCOL_DARKPLACES6)
-                                               MSG_WriteLong (&buf, cmd->sequence);
-                                       MSG_WriteFloat (&buf, cmd->time); // last server packet time
-                                       // 6 bytes
-                                       for (i = 0;i < 3;i++)
-                                               MSG_WriteAngle16i (&buf, cmd->viewangles[i]);
-                                       // 6 bytes
-                                       MSG_WriteCoord16i (&buf, cmd->forwardmove);
-                                       MSG_WriteCoord16i (&buf, cmd->sidemove);
-                                       MSG_WriteCoord16i (&buf, cmd->upmove);
-                                       // 5 bytes
-                                       MSG_WriteLong (&buf, cmd->buttons);
-                                       MSG_WriteByte (&buf, cmd->impulse);
-                                       // PRYDON_CLIENTCURSOR
-                                       // 30 bytes
-                                       MSG_WriteShort (&buf, (short)(cmd->cursor_screen[0] * 32767.0f));
-                                       MSG_WriteShort (&buf, (short)(cmd->cursor_screen[1] * 32767.0f));
-                                       MSG_WriteFloat (&buf, cmd->cursor_start[0]);
-                                       MSG_WriteFloat (&buf, cmd->cursor_start[1]);
-                                       MSG_WriteFloat (&buf, cmd->cursor_start[2]);
-                                       MSG_WriteFloat (&buf, cmd->cursor_impact[0]);
-                                       MSG_WriteFloat (&buf, cmd->cursor_impact[1]);
-                                       MSG_WriteFloat (&buf, cmd->cursor_impact[2]);
-                                       MSG_WriteShort (&buf, cmd->cursor_entitynumber);
-                               }
+                               MSG_WriteLong (&buf, cmd->buttons);
+                               MSG_WriteByte (&buf, cmd->impulse);
+                               // PRYDON_CLIENTCURSOR
+                               // 30 bytes
+                               MSG_WriteShort (&buf, (short)(cmd->cursor_screen[0] * 32767.0f));
+                               MSG_WriteShort (&buf, (short)(cmd->cursor_screen[1] * 32767.0f));
+                               MSG_WriteFloat (&buf, cmd->cursor_start[0]);
+                               MSG_WriteFloat (&buf, cmd->cursor_start[1]);
+                               MSG_WriteFloat (&buf, cmd->cursor_start[2]);
+                               MSG_WriteFloat (&buf, cmd->cursor_impact[0]);
+                               MSG_WriteFloat (&buf, cmd->cursor_impact[1]);
+                               MSG_WriteFloat (&buf, cmd->cursor_impact[2]);
+                               MSG_WriteShort (&buf, cmd->cursor_entitynumber);
                        }
                }
        }
@@ -1583,17 +1554,14 @@ void CL_SendMove(void)
        // PROTOCOL_DARKPLACES6 = 67 bytes per packet
        // PROTOCOL_DARKPLACES7 = 71 bytes per packet
 
-       if (cls.protocol != PROTOCOL_QUAKEWORLD)
+       // acknowledge any recently received data blocks
+       for (i = 0;i < CL_MAX_DOWNLOADACKS && (cls.dp_downloadack[i].start || cls.dp_downloadack[i].size);i++)
        {
-               // acknowledge any recently received data blocks
-               for (i = 0;i < CL_MAX_DOWNLOADACKS && (cls.dp_downloadack[i].start || cls.dp_downloadack[i].size);i++)
-               {
-                       MSG_WriteByte(&buf, clc_ackdownloaddata);
-                       MSG_WriteLong(&buf, cls.dp_downloadack[i].start);
-                       MSG_WriteShort(&buf, cls.dp_downloadack[i].size);
-                       cls.dp_downloadack[i].start = 0;
-                       cls.dp_downloadack[i].size = 0;
-               }
+               MSG_WriteByte(&buf, clc_ackdownloaddata);
+               MSG_WriteLong(&buf, cls.dp_downloadack[i].start);
+               MSG_WriteShort(&buf, cls.dp_downloadack[i].size);
+               cls.dp_downloadack[i].start = 0;
+               cls.dp_downloadack[i].size = 0;
        }
 
        // send the reliable message (forwarded commands) if there is one
index 9d98fa701e3e558e014faf03b4ac22d76de05514..6b469af0c43eb5e592fba4ba0b5704efd4b18f47 100644 (file)
--- a/client.h
+++ b/client.h
@@ -359,6 +359,7 @@ typedef struct usercmd_s
        int impulse;
        int sequence;
        qboolean applied; // if false we're still accumulating a move
+       qboolean predicted; // if true the sequence should be sent as 0
 } usercmd_t;
 
 typedef struct lightstyle_s
@@ -582,6 +583,7 @@ typedef struct client_movementqueue_s
        float move[3];
        qboolean jump;
        qboolean crouch;
+       qboolean canjump;
 }
 client_movementqueue_t;
 
index 5a241863c8710636429f47a018ad38118e9887f6..8ba21cb727357a359f6d5146a7fc22db01a9a676 100644 (file)
--- a/csprogs.c
+++ b/csprogs.c
@@ -67,11 +67,11 @@ static void CSQC_SetGlobals (void)
                prog->globals.client->frametime = cl.time - csqc_frametime;
                csqc_frametime = cl.time;
                prog->globals.client->servercommandframe = cls.servermovesequence;
-               prog->globals.client->clientcommandframe = cls.movesequence;
+               prog->globals.client->clientcommandframe = cl.movecmd[0].sequence;
                VectorCopy(cl.viewangles, prog->globals.client->input_angles);
                VectorCopy(cl.viewangles, csqc_angles);
-               prog->globals.client->input_buttons = cl.cmd.buttons;
-               VectorSet(prog->globals.client->input_movevalues, cl.cmd.forwardmove, cl.cmd.sidemove, cl.cmd.upmove);
+               prog->globals.client->input_buttons = cl.movecmd[0].buttons;
+               VectorSet(prog->globals.client->input_movevalues, cl.movecmd[0].forwardmove, cl.movecmd[0].sidemove, cl.movecmd[0].upmove);
                //VectorCopy(cl.movement_origin, csqc_origin);
                Matrix4x4_OriginFromMatrix(&cl.entities[cl.viewentity].render.matrix, csqc_origin);
                VectorCopy(csqc_origin, prog->globals.client->pmove_org);
index cc560f2f885038866e872d1d3d056706020966cd..916dc6885ea85bd2e9834db53823bc06692b4a35 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -1165,7 +1165,7 @@ void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peer
        cls.signon = 0;                         // need all the signon messages before playing
        cls.protocol = initialprotocol;
        // reset move sequence numbering on this new connection
-       cls.movesequence = 0;
+       cls.movesequence = 1;
        cls.servermovesequence = 0;
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
                Cmd_ForwardStringToServer("new");