diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp
index 25c4e0a44..88346adfc 100644
--- a/source/core/gamecontrol.cpp
+++ b/source/core/gamecontrol.cpp
@@ -1524,9 +1524,9 @@ bool SyncInput()
 	return gamesetinput || cl_syncinput || cl_capfps;
 }
 
-void setForcedSyncInput()
+void setForcedSyncInput(const int playeridx)
 {
-	gamesetinput = true;
+	if (playeridx == myconnectindex) gamesetinput = true;
 }
 
 void resetForcedSyncInput()
@@ -1536,7 +1536,9 @@ void resetForcedSyncInput()
 
 DEFINE_ACTION_FUNCTION_NATIVE(_Raze, forceSyncInput, setForcedSyncInput)
 {
-	setForcedSyncInput();
+	PARAM_PROLOGUE;
+	PARAM_INT(playeridx);
+	setForcedSyncInput(playeridx);
 	return 0;
 }
 
diff --git a/source/core/gamecontrol.h b/source/core/gamecontrol.h
index c8ec5da29..be605e2a8 100644
--- a/source/core/gamecontrol.h
+++ b/source/core/gamecontrol.h
@@ -48,7 +48,7 @@ void CompleteLevel(MapRecord* map);
 bool CheckCheatmode(bool printmsg = true, bool sponly = false);
 void setVideoMode();
 bool SyncInput();
-void setForcedSyncInput();
+void setForcedSyncInput(const int playeridx);
 void resetForcedSyncInput();
 
 void TITLE_InformName(const char* newname);
diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp
index 32c303d3e..f43f2f93e 100644
--- a/source/games/blood/src/nnexts.cpp
+++ b/source/games/blood/src/nnexts.cpp
@@ -2188,7 +2188,7 @@ void trPlayerCtrlSetLookAngle(int value, PLAYER* pPlayer)
 
 	if (const double adjustment = clamp(value * 0.125 * (value > 0 ? lookStepUp : lookStepDown), downAngle, upAngle))
 	{
-		setForcedSyncInput();
+		setForcedSyncInput(pPlayer->nPlayer);
 		pPlayer->actor->spr.Angles.Pitch = maphoriz(-100. * tan(adjustment * pi::pi() * (1. / 1024.)));
 	}
 }
@@ -6060,12 +6060,12 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event)
 			if (actor->xspr.data4 != 0) break;
 			else if (actor->spr.flags & kModernTypeFlag1)
 			{
-				setForcedSyncInput();
+				setForcedSyncInput(pPlayer->nPlayer);
 				pPlayer->actor->spr.Angles.Yaw = actor->spr.Angles.Yaw;
 			}
 			else if (valueIsBetween(actor->xspr.data2, -kAng360, kAng360))
 			{
-				setForcedSyncInput();
+				setForcedSyncInput(pPlayer->nPlayer);
 				pPlayer->actor->spr.Angles.Yaw = mapangle(actor->xspr.data2);
 			}
 			break;
diff --git a/source/games/blood/src/player.cpp b/source/games/blood/src/player.cpp
index 0020256d4..f5fc043df 100644
--- a/source/games/blood/src/player.cpp
+++ b/source/games/blood/src/player.cpp
@@ -1525,7 +1525,7 @@ void ProcessInput(PLAYER* pPlayer)
 	if (actor->xspr.health == 0)
 	{
 		// force synchronised input upon death.
-		setForcedSyncInput();
+		setForcedSyncInput(pPlayer->nPlayer);
 
 		bool bSeqStat = playerSeqPlaying(pPlayer, 16);
 		DBloodActor* fragger = pPlayer->fragger;
diff --git a/source/games/duke/src/gameexec.cpp b/source/games/duke/src/gameexec.cpp
index 094a668fb..236dd83d5 100644
--- a/source/games/duke/src/gameexec.cpp
+++ b/source/games/duke/src/gameexec.cpp
@@ -551,7 +551,7 @@ void DoPlayer(bool bSet, int lVar1, int lLabelID, int lVar2, DDukeActor* sActor,
 		break;
 
 	case PLAYER_NEWOWNER:
-		if (bSet && (ps[iPlayer].newOwner = vValue.safeActor())) setForcedSyncInput();
+		if (bSet && (ps[iPlayer].newOwner = vValue.safeActor())) setForcedSyncInput(iPlayer);
 		else SetGameVarID(lVar2, ps[iPlayer].newOwner, sActor, sPlayer);
 		break;
 
@@ -621,7 +621,7 @@ void DoPlayer(bool bSet, int lVar1, int lLabelID, int lVar2, DDukeActor* sActor,
 		break;
 
 	case PLAYER_ON_CRANE:
-		if (bSet && (ps[iPlayer].on_crane = vValue.safeActor())) setForcedSyncInput();
+		if (bSet && (ps[iPlayer].on_crane = vValue.safeActor())) setForcedSyncInput(iPlayer);
 		else SetGameVarID(lVar2, (ps[iPlayer].on_crane), sActor, sPlayer);
 		break;
 
diff --git a/source/games/duke/src/player.cpp b/source/games/duke/src/player.cpp
index 49e38750b..a67f3f30d 100644
--- a/source/games/duke/src/player.cpp
+++ b/source/games/duke/src/player.cpp
@@ -546,7 +546,7 @@ void playerisdead(int snum, int psectlotag, double floorz, double ceilingz)
 	auto actor = p->GetActor();
 
 	// lock input when dead.
-	setForcedSyncInput();
+	setForcedSyncInput(snum);
 
 	if (p->dead_flag == 0)
 	{
diff --git a/source/games/duke/src/player_d.cpp b/source/games/duke/src/player_d.cpp
index 527b599f4..2c6b56991 100644
--- a/source/games/duke/src/player_d.cpp
+++ b/source/games/duke/src/player_d.cpp
@@ -2714,7 +2714,7 @@ void processinput_d(int snum)
 
 	if (p->newOwner != nullptr)
 	{
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 		p->vel.X = p->vel.Y = 0;
 		pact->vel.X = 0;
 
@@ -2733,12 +2733,12 @@ void processinput_d(int snum)
 	if (p->centeringView())
 	{
 		p->sync.horz = 0;
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 	}
 
 	if (p->on_crane != nullptr)
 	{
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 		goto HORIZONLY;
 	}
 
@@ -2774,7 +2774,7 @@ void processinput_d(int snum)
 		doubvel = 0;
 		p->vel.X = 0;
 		p->vel.Y = 0;
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 	}
 	else if (SyncInput())
 	{
diff --git a/source/games/duke/src/player_r.cpp b/source/games/duke/src/player_r.cpp
index 6d7e3d134..66ca79391 100644
--- a/source/games/duke/src/player_r.cpp
+++ b/source/games/duke/src/player_r.cpp
@@ -3302,7 +3302,7 @@ void processinput_r(int snum)
 
 	if (p->newOwner != nullptr)
 	{
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 		p->vel.X = p->vel.Y = 0;
 		pact->vel.X = 0;
 
@@ -3321,12 +3321,12 @@ void processinput_r(int snum)
 	if (p->centeringView())
 	{
 		p->sync.horz = 0;
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 	}
 
 	if (p->on_crane != nullptr)
 	{
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 		goto HORIZONLY;
 	}
 
@@ -3376,7 +3376,7 @@ void processinput_r(int snum)
 		doubvel = 0;
 		p->vel.X = 0;
 		p->vel.Y = 0;
-		setForcedSyncInput();
+		setForcedSyncInput(snum);
 	}
 	else if (SyncInput())
 	{
diff --git a/source/games/exhumed/src/player.cpp b/source/games/exhumed/src/player.cpp
index 56d30fd2c..9d7c83501 100644
--- a/source/games/exhumed/src/player.cpp
+++ b/source/games/exhumed/src/player.cpp
@@ -1058,7 +1058,7 @@ void AIPlayer::Tick(RunListEvent* ev)
     {
         if (nTotalPlayers <= 1)
         {
-            setForcedSyncInput();
+            setForcedSyncInput(nPlayer);
             pPlayerActor->spr.Angles = DRotator(nullAngle, GetAngleToSprite(pPlayerActor, pSpiritSprite), nullAngle);
             pPlayerActor->backupang();
 
@@ -2491,7 +2491,7 @@ sectdone:
     }
     else // else, player's health is less than 0
     {
-        setForcedSyncInput();
+        setForcedSyncInput(nPlayer);
 
         // loc_1C0E9
         if (actions & SB_OPEN)
diff --git a/source/games/sw/src/player.cpp b/source/games/sw/src/player.cpp
index 53407126a..8d0c5bb5d 100644
--- a/source/games/sw/src/player.cpp
+++ b/source/games/sw/src/player.cpp
@@ -2630,7 +2630,7 @@ void DoPlayerMoveVehicle(PLAYER* pp)
     pp->setcursector(pp->sop->op_main_sector); // for speed
 
     double floordist = abs(zz - pp->sop->floor_loz);
-    setForcedSyncInput();
+    setForcedSyncInput(pp->pnum);
 
     if (RectClip)
     {
@@ -2751,7 +2751,7 @@ void DoPlayerMoveTurret(PLAYER* pp)
             PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
     }
 
-    setForcedSyncInput();
+    setForcedSyncInput(pp->pnum);
     DoPlayerTurnTurret(pp);
 
     if (PLAYER_MOVING(pp) == 0)
@@ -5868,7 +5868,7 @@ void DoPlayerBeginDie(PLAYER* pp)
     pp->Flags |= (PF_DEAD);
     plActor->user.Flags &= ~(SPR_BOUNCE);
     pp->Flags &= ~(PF_HEAD_CONTROL);
-    setForcedSyncInput();
+    setForcedSyncInput(pp->pnum);
 }
 
 //---------------------------------------------------------------------------
diff --git a/wadsrc/static/zscript/games/duke/actors/crane.zs b/wadsrc/static/zscript/games/duke/actors/crane.zs
index 414eeedad..0b88ec768 100644
--- a/wadsrc/static/zscript/games/duke/actors/crane.zs
+++ b/wadsrc/static/zscript/games/duke/actors/crane.zs
@@ -151,7 +151,7 @@ class DukeCrane : DukeActor
 					plr.on_crane = self;
 					plr.actor.PlayActorSound("CRANEGRAB");
 					plr.settargetangle(self.angle + 180);
-					Raze.forceSyncInput();
+					Raze.forceSyncInput(Duke.GetPlayerIndex(plr));
 				}
 				else
 				{
diff --git a/wadsrc/static/zscript/games/duke/actors/viewscreen.zs b/wadsrc/static/zscript/games/duke/actors/viewscreen.zs
index e04c9fd2b..454da018f 100644
--- a/wadsrc/static/zscript/games/duke/actors/viewscreen.zs
+++ b/wadsrc/static/zscript/games/duke/actors/viewscreen.zs
@@ -47,7 +47,7 @@ class DukeViewscreen : DukeActor
 				camsprite = self;
 
 				user.newOwner = acti;
-				Raze.forceSyncInput();
+				Raze.forceSyncInput(Duke.GetPlayerIndex(user));
 				return true;
 			}
 		}
diff --git a/wadsrc/static/zscript/razebase.zs b/wadsrc/static/zscript/razebase.zs
index b4a161713..1161babd7 100644
--- a/wadsrc/static/zscript/razebase.zs
+++ b/wadsrc/static/zscript/razebase.zs
@@ -171,7 +171,7 @@ struct Raze
 	static double bobval(double angle) { return sin(angle * (360. / 2048)); }
 	native static TextureID PickTexture(TextureID texid);
 	native static int GetBuildTime();
-	native static void forceSyncInput();
+	native static void forceSyncInput(int playeridx);
 	native static Font PickBigFont(String cmptext = "");
 	native static Font PickSmallFont(String cmptext = "");
 	native static int SoundEnabled();