diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 4fa8150df838211612d955286ac7bd126b3b4e5d..4daff6e22b239d7e04f9ed1a4d729fb7ddfc54c4 100755
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -5078,9 +5078,6 @@ void TryRunTics(tic_t realtics, tic_t entertic)
 	double frame = ((double)SDL_GetPerformanceCounter() / tic_frequency);
 	netUpdateFudge = (((double)SDL_GetPerformanceCounter() / tic_frequency) - frame); // record the timefudge where the net update typically occurs
 
-	//TODO SPLITSCREEN PLAYER
-	// ticcmd_t latestLocalCmd = localcmds;
-
 	NetUpdate();
 
 	if (demoplayback)
@@ -5164,6 +5161,8 @@ void TryRunTics(tic_t realtics, tic_t entertic)
 		//localcmds are being calculated in NetUpdate()->Local_Maketic() function
 		localTicBuffer[(liveTic - i) % MAXSIMULATIONS] = localcmds;
 	}
+	//TODO SPLITSCREEN PLAYER
+	ticcmd_t latestLocalCmd = localcmds;
 
 
 	// Run the real game after dealing with enough simulations or if we don't have any.
@@ -5219,8 +5218,6 @@ void TryRunTics(tic_t realtics, tic_t entertic)
 
 					targetsimtic = gametic + 1;
 
-					DEBFILE(va("============ Running REAL tic %d (local %d)\n", gametic, localgametic));
-
 					G_Ticker((gametic % NEWTICRATERATIO) == 0);
 					ExtraDataTicker();
 					gametic++;
@@ -5270,18 +5267,24 @@ void TryRunTics(tic_t realtics, tic_t entertic)
 		{
 			// collect net condition data based on encoded tics, it's needed for calculating correct netcmds
 			DetermineNetConditions();
+			ticcmd_t temp;
 			for (int j = 0; j < MAXPLAYERS; j++)
 			{
-				if (playeringame[j] && j != consoleplayer)
+				if (playeringame[j] && j != consoleplayer && j != secondarydisplayplayer)
 					netcmds[gametic % BACKUPTICS][j] = gameTicBuffer[(min(simtic + 1, gametic) + MAXSIMULATIONS) % MAXSIMULATIONS][j];
+				else
+				{
+					temp = netcmds[gametic % BACKUPTICS][consoleplayer];
+					netcmds[gametic % BACKUPTICS][consoleplayer] = localcmds;
+				}
 			}
-			// localcmds = latestLocalCmd;
+			DEBFILE(va("============ Running SIMMISS tic %d (local %d)\n", gametic, localgametic));
 			issimulation = true;
 			con_muted = true;
 			G_Ticker(true); //tic one tic further as usual
+			netcmds[gametic % BACKUPTICS][consoleplayer] = temp;
 			issimulation = false;
 			con_muted = false;
-			// latestLocalCmd = localcmds;
 			// we're gonna need more debugs...
 			MakeNetDebugString();
 		}
@@ -5492,7 +5495,8 @@ static void RunSimulations()
 		}
 		else
 			netcmds[gametic % BACKUPTICS][consoleplayer] = localcmds; //NO
-
+		
+		DEBFILE(va("============ Running SIM tic %d (local %d) (sim %d)\n", gametic, localgametic, simtic));
 		G_Ticker(true); // tic a bunch of times lol see what happens lolol
 		simtic++;
 
@@ -5725,6 +5729,11 @@ void DetermineNetConditions()
 void MakeNetDebugString()
 {
 	netDebugText[0] = 0;
+	Net_GetNetStat();
+	sprintf(&netDebugText[strlen(netDebugText)], "RX: %d b/s\n", getbps);
+	sprintf(&netDebugText[strlen(netDebugText)], "TX: %d b/s\n", sendbps);
+	sprintf(&netDebugText[strlen(netDebugText)], "RX_ACK_Miss %.2f%%\n", gamelostpercent);
+	sprintf(&netDebugText[strlen(netDebugText)], "TX_ACK_Miss %.2f%%\n", lostpercent);
 
 	for (int i = min(maxRTT + 4, 16); i >= 0; i--)
 	{
diff --git a/src/p_savenetrb.c b/src/p_savenetrb.c
index 8706ea1d54136e4cee021b17b9c3f85cc9900ccb..05ed3be77d3fe988bf926d1853537b7951ad8eaa 100755
--- a/src/p_savenetrb.c
+++ b/src/p_savenetrb.c
@@ -4675,13 +4675,18 @@ static void P_NetUnArchiveThinkers(void)
 			if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
 				P_RemoveSavegameMobj((mobj_t *)currentthinker, false); // item isn't saved, don't remove it
 			else
+			{
+				// remove it manually, bye!
+				currentthinker->prev->next = currentthinker->next;
+				currentthinker->next->prev = currentthinker->prev;
 				Z_Free(currentthinker);
+			}
 		}
 	}
 
 	// we don't want the removed mobjs to come back
 	iquetail = iquehead = 0;
-	P_InitThinkers();
+	// P_InitThinkers();
 
 	// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
 	for (i = 0; i < numsectors; i++)
@@ -4936,7 +4941,7 @@ static inline void P_UnArchivePolyObj(polyobj_t *po)
 
 	id = READINT32(save_p);
 
-	po->angle = 0; //angle isn't in the original state because we store the absolute number 
+	po->angle = 0; //angle isn't in the original state because we store the absolute number
 
 	angle = READANGLE(save_p);
 
@@ -5684,7 +5689,7 @@ static inline boolean P_UnArchiveLuabanksAndConsistency(void)
 // 	// assign mobj nums for pointer relinking
 // 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 // 	{
-// 		if ((th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) || (th->function.acp1 == (actionf_p1)P_NullPrecipThinker)) 
+// 		if ((th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) || (th->function.acp1 == (actionf_p1)P_NullPrecipThinker))
 // 			continue;
 
 // 		mobj = (mobj_t *)th;
@@ -5857,7 +5862,8 @@ boolean P_LoadGameState(const savestate_t* savestate)
 	loadStateBenchmark = I_GetPreciseTime();
 	if (savestate->buffer == NULL)
 	{
-		CONS_Alert(CONS_ERROR, "Hell, we are going to load the invalid savestate!!!");
+		loadStateBenchmark = I_GetPreciseTime() - loadStateBenchmark;
+		return false;
 	}
 
 	save_p = ((unsigned char*)savestate->buffer);
@@ -5868,6 +5874,7 @@ boolean P_LoadGameState(const savestate_t* savestate)
 	{
 		// savestates do not work cross-level
 		// save_p = NULL; //invalidate it //FUCK
+		loadStateBenchmark = I_GetPreciseTime() - loadStateBenchmark;
 		return false;
 	}
 
@@ -6014,7 +6021,7 @@ boolean P_LoadGameState(const savestate_t* savestate)
 // 	// LUA_LocalUnArchive();
 // 	// This is stupid and hacky _squared_, but it's in the net load code and it says it might work, so I guess it might work!
 // 	P_SetRandSeed(P_GetInitSeed());
-	
+
 // 	P_UnArchiveLuabanksAndConsistency();
 // 	loadStateBenchmark = I_GetTimeUs() - time;