]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_user.c
protocol/dp8: Implement parting messages
[xonotic/darkplaces.git] / sv_user.c
index 67dbdcc5a943902b8668e0cb5ea664f1bb5045b8..6a621bac6d293c9ec2a573187e7ee821f1f805c9 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -23,8 +23,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "sv_demo.h"
 #define DEBUGMOVES 0
 
-static usercmd_t cmd;
+static usercmd_t usercmd;
 extern cvar_t sv_autodemo_perclient;
+extern cvar_t sv_rollangle;
+extern cvar_t sv_rollspeed;
 
 /*
 ==================
@@ -111,8 +113,7 @@ void SV_Spawn_f(cmd_state_t *cmd)
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
                prog->ExecuteProgram(prog, PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing");
 
-               if (cls.state == ca_dedicated)
-                       Con_Printf("%s connected\n", host_client->name);
+               Con_Printf("%s connected\n", host_client->name);
 
                PRVM_serverglobalfloat(time) = sv.time;
                prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
@@ -304,7 +305,7 @@ void SV_SetIdealPitch (void)
 static vec3_t wishdir, forward, right, up;
 static float wishspeed;
 
-static qboolean onground;
+static qbool onground;
 
 /*
 ==================
@@ -443,12 +444,12 @@ static void SV_WaterMove (void)
        AngleVectors(v_angle, forward, right, up);
 
        for (i=0 ; i<3 ; i++)
-               wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
+               wishvel[i] = forward[i]*usercmd.forwardmove + right[i]*usercmd.sidemove;
 
-       if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)
+       if (!usercmd.forwardmove && !usercmd.sidemove && !usercmd.upmove)
                wishvel[2] -= 60;               // drift towards bottom
        else
-               wishvel[2] += cmd.upmove;
+               wishvel[2] += usercmd.upmove;
 
        fwishspeed = VectorLength(wishvel);
        if (fwishspeed > sv_maxspeed.value)
@@ -520,8 +521,8 @@ static void SV_AirMove (void)
        wishvel[1] = PRVM_serveredictvector(host_client->edict, angles)[1];
        AngleVectors (wishvel, forward, right, up);
 
-       fmove = cmd.forwardmove;
-       smove = cmd.sidemove;
+       fmove = usercmd.forwardmove;
+       smove = usercmd.sidemove;
 
 // hack to not let you back into teleporter
        if (sv.time < PRVM_serveredictfloat(host_client->edict, teleport_time) && fmove < 0)
@@ -531,7 +532,7 @@ static void SV_AirMove (void)
                wishvel[i] = forward[i]*fmove + right[i]*smove;
 
        if ((int)PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_WALK)
-               wishvel[2] += cmd.upmove;
+               wishvel[2] += usercmd.upmove;
 
        VectorCopy (wishvel, wishdir);
        wishspeed = VectorNormalizeLength(wishdir);
@@ -561,13 +562,13 @@ static void SV_AirMove (void)
 
 /*
 ===================
-SV_ClientThink
+SV_PlayerPhysics
 
 the move fields specify an intended velocity in pix/sec
 the angle fields specify an exact angular motion in degrees
 ===================
 */
-void SV_ClientThink (void)
+void SV_PlayerPhysics (void)
 {
        prvm_prog_t *prog = SVVM_prog;
        vec3_t v_angle, angles, velocity;
@@ -578,7 +579,7 @@ void SV_ClientThink (void)
        // make sure the velocity is sane (not a NaN)
        SV_CheckVelocity(host_client->edict);
 
-       // LadyHavoc: QuakeC replacement for SV_ClientThink (player movement)
+       // LadyHavoc: QuakeC replacement for SV_PlayerPhysics (player movement)
        if (PRVM_serverfunction(SV_PlayerPhysics) && sv_playerphysicsqc.integer)
        {
                PRVM_serverglobalfloat(time) = sv.time;
@@ -599,14 +600,14 @@ void SV_ClientThink (void)
        if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
                return;
 
-       cmd = host_client->cmd;
+       usercmd = host_client->cmd;
 
        // angles
        // show 1/3 the pitch angle and all the roll angle
        VectorAdd (PRVM_serveredictvector(host_client->edict, v_angle), PRVM_serveredictvector(host_client->edict, punchangle), v_angle);
        VectorCopy(PRVM_serveredictvector(host_client->edict, angles), angles);
        VectorCopy(PRVM_serveredictvector(host_client->edict, velocity), velocity);
-       PRVM_serveredictvector(host_client->edict, angles)[ROLL] = V_CalcRoll (angles, velocity)*4;
+       PRVM_serveredictvector(host_client->edict, angles)[ROLL] = Com_CalcRoll (angles, velocity, sv_rollangle.value, sv_rollspeed.value)*4;
        if (!PRVM_serveredictfloat(host_client->edict, fixangle))
        {
                PRVM_serveredictvector(host_client->edict, angles)[PITCH] = -v_angle[PITCH]/3;
@@ -620,16 +621,6 @@ void SV_ClientThink (void)
                return;
        }
 
-       /*
-       // Player is (somehow) outside of the map, or flying, or noclipping
-       if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP && (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict)))
-       //if (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_NOCLIP || PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict))
-       {
-               SV_FreeMove ();
-               return;
-       }
-       */
-
        // walk
        if ((PRVM_serveredictfloat(host_client->edict, waterlevel) >= 2) && (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP))
        {
@@ -663,7 +654,7 @@ static void SV_ReadClientMove (void)
        // read ping time
        if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3 && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5 && sv.protocol != PROTOCOL_DARKPLACES6)
                move->sequence = MSG_ReadLong(&sv_message);
-       move->time = move->clienttime = MSG_ReadFloat(&sv_message);
+       move->time = MSG_ReadFloat(&sv_message);
        if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        move->receivetime = (float)sv.time;
 
@@ -672,7 +663,7 @@ static void SV_ReadClientMove (void)
 #endif
        // limit reported time to current time
        // (incase the client is trying to cheat)
-       move->time = min(move->time, move->receivetime + sv.frametime);
+       move->time = min(move->time, sv.time + sv.frametime);
 
        // read current angles
        for (i = 0;i < 3;i++)
@@ -727,7 +718,7 @@ static void SV_ReadClientMove (void)
                }
                // as requested by FrikaC, cursor_trace_ent is reset to world if the
                // entity is free at time of receipt
-               if (PRVM_EDICT_NUM(move->cursor_entitynumber)->priv.server->free)
+               if (PRVM_EDICT_NUM(move->cursor_entitynumber)->free)
                        move->cursor_entitynumber = 0;
                if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
        }
@@ -747,7 +738,8 @@ static void SV_ReadClientMove (void)
                sv_readmoves[sv_numreadmoves++] = *move;
 
        // movement packet loss tracking
-       if(move->sequence)
+       // bones_was_here: checking begun prevents heavy loss detection right after a map change
+       if(move->sequence && host_client->begun)
        {
                if(move->sequence > host_client->movement_highestsequence_seen)
                {
@@ -784,12 +776,10 @@ static void SV_ExecuteClientMoves(void)
 {
        prvm_prog_t *prog = SVVM_prog;
        int moveindex;
-       float moveframetime;
+       double moveframetime;
        double oldframetime;
        double oldframetime2;
-#ifdef NUM_PING_TIMES
-       double total;
-#endif
+
        if (sv_numreadmoves < 1)
                return;
        // only start accepting input once the player is spawned
@@ -820,7 +810,9 @@ static void SV_ExecuteClientMoves(void)
                                // this is a new move
                                move->time = bound(sv.time - 1, move->time, sv.time); // prevent slowhack/speedhack combos
                                move->time = max(move->time, host_client->cmd.time); // prevent backstepping of time
-                               moveframetime = bound(0, move->time - host_client->cmd.time, min(0.1, sv_clmovement_inputtimeout.value));
+                               // bones_was_here: limit moveframetime to a multiple of sv.frametime to match inputtimeout behaviour
+                               moveframetime = min(move->time - host_client->cmd.time, min(0.1, sys_ticrate.value > 0.0 && sv.frametime > 0.0 ? sv.frametime * ceil(sv_clmovement_inputtimeout.value / sv.frametime) : sv_clmovement_inputtimeout.value));
+
 
                                // discard (treat like lost) moves with too low distance from
                                // the previous one to prevent hacks using float inaccuracy
@@ -849,8 +841,6 @@ static void SV_ExecuteClientMoves(void)
                                //  with this approach, and if they don't send input for a while they
                                //  start moving anyway, so the longest 'lagaport' possible is
                                //  determined by the sv_clmovement_inputtimeout cvar)
-                               if (moveframetime <= 0)
-                                       continue;
                                oldframetime = PRVM_serverglobalfloat(frametime);
                                oldframetime2 = sv.frametime;
                                // update ping time for qc to see while executing this move
@@ -866,7 +856,7 @@ static void SV_ExecuteClientMoves(void)
                                SV_Physics_ClientMove();
                                sv.frametime = oldframetime2;
                                PRVM_serverglobalfloat(frametime) = oldframetime;
-                               host_client->clmovement_inputtimeout = sv_clmovement_inputtimeout.value;
+                               host_client->clmovement_inputtimeout = min(0.1, sv_clmovement_inputtimeout.value);
                        }
                }
        }
@@ -895,17 +885,9 @@ static void SV_ExecuteClientMoves(void)
                host_client->movesequence = 0;
                // make sure that normal physics takes over immediately
                host_client->clmovement_inputtimeout = 0;
+               // update ping time
+               host_client->ping = host_client->cmd.receivetime - sv_readmoves[sv_numreadmoves-1].time;
        }
-
-       // calculate average ping time
-       host_client->ping = host_client->cmd.receivetime - host_client->cmd.clienttime;
-#ifdef NUM_PING_TIMES
-       host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = host_client->cmd.receivetime - host_client->cmd.clienttime;
-       host_client->num_pings++;
-       for (i=0, total = 0;i < NUM_PING_TIMES;i++)
-               total += host_client->ping_times[i];
-       host_client->ping = total / NUM_PING_TIMES;
-#endif
 }
 
 void SV_ApplyClientMove (void)
@@ -971,7 +953,7 @@ void SV_ApplyClientMove (void)
        PRVM_serveredictfloat(host_client->edict, ping_movementloss) = movementloss / (float) NETGRAPH_PACKETS;
 }
 
-static qboolean SV_FrameLost(int framenum)
+static qbool SV_FrameLost(int framenum)
 {
        if (host_client->entitydatabase5)
        {
@@ -1017,14 +999,14 @@ void SV_ReadClientMessage(void)
                if (!host_client->active)
                {
                        // a command caused an error
-                       SV_DropClient (false);
+                       SV_DropClient (false, "Connection closing");
                        return;
                }
 
                if (sv_message.badread)
                {
                        Con_Print("SV_ReadClientMessage: badread\n");
-                       SV_DropClient (false);
+                       SV_DropClient (false, "An internal server error occurred");
                        return;
                }
 
@@ -1043,7 +1025,7 @@ void SV_ReadClientMessage(void)
                        Con_Printf("SV_ReadClientMessage: unknown command char %i (at offset 0x%x)\n", netcmd, sv_message.readcount);
                        if (developer_networking.integer)
                                Com_HexDumpToConsole(sv_message.data, sv_message.cursize);
-                       SV_DropClient (false);
+                       SV_DropClient (false, "Unknown message sent to the server");
                        return;
 
                case clc_nop:
@@ -1072,7 +1054,7 @@ void SV_ReadClientMessage(void)
                        if (strncasecmp(s, "spawn", 5) == 0
                         || strncasecmp(s, "begin", 5) == 0
                         || strncasecmp(s, "prespawn", 8) == 0)
-                               Cmd_ExecuteString (&cmd_serverfromclient, s, src_client, true);
+                               Cmd_ExecuteString (cmd_serverfromclient, s, src_client, true);
                        else if (PRVM_serverfunction(SV_ParseClientCommand))
                        {
                                int restorevm_tempstringsbuf_cursize;
@@ -1084,7 +1066,7 @@ void SV_ReadClientMessage(void)
                                prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
                        }
                        else
-                               Cmd_ExecuteString (&cmd_serverfromclient, s, src_client, true);
+                               Cmd_ExecuteString (cmd_serverfromclient, s, src_client, true);
                        break;
 
 clc_stringcmd_invalid:
@@ -1094,7 +1076,9 @@ clc_stringcmd_invalid:
                        break;
 
                case clc_disconnect:
-                       SV_DropClient (false); // client wants to disconnect
+                       SV_DropClient (true, sv.protocol == PROTOCOL_DARKPLACES8
+                                      ? MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring))
+                                      : "Disconnect by user"); // client wants to disconnect
                        return;
 
                case clc_move: