From 4fce9e090d0d39fcb37d1310d91214473a392d18 Mon Sep 17 00:00:00 2001
From: Spoike <acceptthis@users.sourceforge.net>
Date: Thu, 28 Jul 2022 02:16:54 +0000
Subject: [PATCH] Fix up vrinputs frame times.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6289 fc73d0e0-1445-4013-8a0c-d673dee63da5
---
 engine/client/cl_input.c | 11 +++++++++++
 engine/common/common.c   | 19 +++++++++++++++++--
 engine/server/sv_user.c  | 34 +++++++++++++++++++++++-----------
 3 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c
index f79a592ab..b2808f5d9 100644
--- a/engine/client/cl_input.c
+++ b/engine/client/cl_input.c
@@ -1620,6 +1620,7 @@ static void CL_AccumlateInput(int plnum, float frametime/*extra contribution*/,
 
 	float nscale = framemsecs?framemsecs / (framemsecs+cmd->msec):0;
 	float oscale = 1 - nscale;
+	unsigned int st;
 
 	CL_BaseMove (newmoves, plnum);
 
@@ -1651,6 +1652,16 @@ static void CL_AccumlateInput(int plnum, float frametime/*extra contribution*/,
 	}
 	cmd->msec = framemsecs;
 
+	if (cl.movesequence >= 1)
+	{	//fix up the servertime value to make sure our msecs are actually correct.
+		st = cl.outframes[(cl.movesequence-1)&UPDATE_MASK].cmd[plnum].servertime + (cmd->msec);	//round it.
+		if (abs((int)st-(int)cmd->servertime) < 50)
+		{
+			cmd->servertime = st;
+			cmd->fservertime = (double)st/1000.0;
+		}
+	}
+
 	// if we are spectator, try autocam
 //	if (cl.spectator)
 	Cam_Track(&cl.playerview[plnum], &cl_pendingcmd[plnum]);
diff --git a/engine/common/common.c b/engine/common/common.c
index e4e4f63ac..58b4ed858 100644
--- a/engine/common/common.c
+++ b/engine/common/common.c
@@ -1500,6 +1500,7 @@ void MSGQ2_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const userc
 #define	UC_RIGHT		(1<<4)
 #define	UC_BUTTONS		(1<<5)
 #define	UC_IMPULSE		(1<<6)
+
 #define	UC_UP			(1<<7)	//split from forward/right because its rare, and this avoids sending an extra byte.
 #define UC_ABSANG		(1<<8)	//angle values are shorts
 #define UC_BIGMOVES		(1<<9)	//fwd/left/up are shorts, rather than a fith.
@@ -1507,13 +1508,15 @@ void MSGQ2_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const userc
 #define	UC_CURSORFLDS	(1<<11)	//lots of data in one.
 #define	UC_LIGHTLEV		(1<<12)
 #define	UC_VR_HEAD		(1<<13)
+
 #define	UC_VR_RIGHT		(1<<14)
 #define	UC_VR_LEFT		(1<<15)
 //#define	UC_UNUSED		(1<<16)
 //#define	UC_UNUSED		(1<<17)
-//#define	UC_UNUSED		(1<<18)
+#define	UC_MSEC_DEBUG		(1<<18)	//FIXME: temporary
 //#define	UC_UNUSED		(1<<19)
 //#define	UC_UNUSED		(1<<20)
+
 //#define	UC_UNUSED		(1<<21)
 //#define	UC_UNUSED		(1<<22)
 //#define	UC_UNUSED		(1<<23)
@@ -1521,11 +1524,12 @@ void MSGQ2_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const userc
 //#define	UC_UNUSED		(1<<25)
 //#define	UC_UNUSED		(1<<26)
 //#define	UC_UNUSED		(1<<27)
+
 //#define	UC_UNUSED		(1<<28)
 //#define	UC_UNUSED		(1<<29)
 //#define	UC_UNUSED		(1<<30)
 //#define	UC_UNUSED		(1<<31)
-#define UC_UNSUPPORTED (~(UC_ANGLE1 | UC_ANGLE2 | UC_ANGLE3 | UC_FORWARD | UC_RIGHT | UC_BUTTONS | UC_IMPULSE | UC_UP | UC_ABSANG | UC_BIGMOVES | UC_WEAPON | UC_CURSORFLDS | UC_LIGHTLEV | UC_VR_HEAD | UC_VR_RIGHT | UC_VR_LEFT))
+#define UC_UNSUPPORTED (~(UC_ANGLE1 | UC_ANGLE2 | UC_ANGLE3 | UC_FORWARD | UC_RIGHT | UC_BUTTONS | UC_IMPULSE | UC_UP | UC_ABSANG | UC_BIGMOVES | UC_WEAPON | UC_CURSORFLDS | UC_LIGHTLEV | UC_VR_HEAD | UC_VR_RIGHT | UC_VR_LEFT | UC_MSEC_DEBUG))
 
 #define UC_VR_STATUS		(1<<0)
 #define UC_VR_ANG			(1<<1)
@@ -1651,10 +1655,17 @@ void MSGFTE_WriteDeltaUsercmd (sizebuf_t *buf, const short baseangles[3], const
 	if (MSG_CompareVR(VRDEV_LEFT, from, cmd))
 		bits |= UC_VR_LEFT;
 
+#ifdef _DEBUG
+	if (developer.ival)
+		bits |= UC_MSEC_DEBUG;
+#endif
+
 	//NOTE: WriteUInt64 actually uses some length coding, so its not quite as bloated as it looks.
 	MSG_WriteUInt64(buf, bits);
 
 	MSG_WriteUInt64(buf, cmd->servertime-from->servertime);
+	if (bits & UC_MSEC_DEBUG)
+		MSG_WriteUInt64(buf, cmd->msec);
 	for (i = 0; i < 3; i++)
 	{
 		if (bits & (UC_ANGLE1<<i))
@@ -1768,6 +1779,10 @@ void MSGFTE_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *cmd)
 	*cmd = *from;
 	cmd->servertime = from->servertime+MSG_ReadUInt64();
 	cmd->fservertime = cmd->servertime/1000.0;
+	if (bits & UC_MSEC_DEBUG)
+		cmd->msec = MSG_ReadUInt64();	//for debugging only. only sent when developer 1, for now.
+	else
+		cmd->msec = 0;	//no info...
 	for (i = 0; i < 3; i++)
 	{
 		if (bits & (UC_ANGLE1<<i))
diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c
index 7ec772979..d7a9c1019 100644
--- a/engine/server/sv_user.c
+++ b/engine/server/sv_user.c
@@ -7986,10 +7986,11 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
 	unsigned int loss = (flags & VRM_LOSS)?MSG_ReadByte():0;
 	double delay = (flags & VRM_DELAY)?MSG_ReadByte()/10000.0:0;	//networked as 10ths of a millisecond.
 	unsigned int numacks = (flags & VRM_ACKS)?MSG_ReadUInt64():0;
-	usercmd_t old;
+	usercmd_t oldcmd, newcmd;
 
 	unsigned int seat, frame, a;
 	qboolean ran;
+	unsigned int dropsequence;	//sequence<=this will be ignored as stale
 
 #define VRM_UNSUPPORTED (~(VRM_LOSS|VRM_DELAY|VRM_SEATS|VRM_FRAMES|VRM_ACKS))
 	if (flags & VRM_UNSUPPORTED)
@@ -8021,7 +8022,7 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
 		if (!split)
 		{	//err, they sent too many seats... assume we kicked one. swallow the extra data.
 			for (frame = 0; frame < frames; frame++)
-				MSGFTE_ReadDeltaUsercmd(&nullcmd, &old);
+				MSGFTE_ReadDeltaUsercmd(&nullcmd, &newcmd);
 			continue;
 		}
 
@@ -8035,12 +8036,24 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
 		split->isindependant = !(sv_nqplayerphysics.ival || split->state < cs_spawned || SV_PlayerPhysicsQC || sv.paused || !sv.world.worldmodel || sv.world.worldmodel->loadstate != MLS_LOADED);
 
 		ran = false;
-		old = nullcmd;
+		oldcmd = nullcmd;
+		dropsequence = split->lastcmd.sequence;
 		for (frame = 0; frame < frames; frame++)
 		{
-			MSGFTE_ReadDeltaUsercmd(&old, &split->lastcmd);
-			split->lastcmd.sequence = controller->netchan.outgoing_sequence - (frames-frame-1);
-			old = split->lastcmd;
+			MSGFTE_ReadDeltaUsercmd(&oldcmd, &newcmd);
+			newcmd.sequence = controller->netchan.outgoing_sequence - (frames-frame-1);
+			oldcmd = newcmd;
+
+			if (newcmd.sequence <= dropsequence)
+				continue;	//this one is a dupe.
+
+			newcmd.msec = newcmd.servertime - split->lastcmd.servertime;
+
+			if (oldcmd.msec && newcmd.msec != oldcmd.msec)
+				if (sv_showpredloss.ival)
+					Con_Printf("%s: %g -> %g\n", split->name, newcmd.msec, oldcmd.msec);
+
+			split->lastcmd = newcmd;
 			split->lastcmd.angles[0] += split->baseangles[0];
 			split->lastcmd.angles[1] += split->baseangles[1];
 			split->lastcmd.angles[2] += split->baseangles[2];
@@ -8054,10 +8067,6 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
 
 			if (split->state == cs_spawned)
 			{
-				//handle impulse here, doing it later might mean it got skipped entirely (nq physics often skips frames).
-				if (split->lastcmd.impulse)
-					split->edict->v->impulse = split->lastcmd.impulse;
-
 				if (split->isindependant)
 				{	//this protocol uses bigger timestamps instead of msecs
 					unsigned int curtime = sv.time*1000;
@@ -8082,13 +8091,16 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
 							ran=true;
 						}
 
-						split->lastcmd.msec = split->lastcmd.servertime - split->lastruncmd;
 						SV_RunCmd (&split->lastcmd, false);
 						split->lastruncmd = split->lastcmd.servertime;
 					}
 				}
 				else
 				{
+					//handle impulse here, doing it later might mean it got skipped entirely (nq physics often skips frames).
+					if (split->lastcmd.impulse)
+						split->edict->v->impulse = split->lastcmd.impulse;
+
 					SV_SetEntityButtons(split->edict, split->lastcmd.buttons);
 					split->lastcmd.buttons = 0;
 				}