diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 7e9dcf8efae6d150a74f35949ea59e0195b5982a..124845563aa0288e5ad5a76efb2b2387eb8e9165 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -868,12 +868,13 @@ static inline void resynch_write_others(resynchend_pak *rst)
 {
 	UINT8 i;
 
-	rst->ingame = rst->ctfteam = 0;
+	rst->ingame = 0;
 
 	for (i = 0; i < MAXPLAYERS; ++i)
 	{
 		if (!playeringame[i])
 		{
+			rst->ctfteam[i] = 0;
 			rst->score[i] = 0;
 			rst->numboxes[i] = 0;
 			rst->totalring[i] = 0;
@@ -883,11 +884,8 @@ static inline void resynch_write_others(resynchend_pak *rst)
 		}
 
 		if (!players[i].spectator)
-		{
 			rst->ingame |= (1<<i);
-			if (players[i].ctfteam > 1)
-				rst->ctfteam |= (1<<i);
-		}
+		rst->ctfteam[i] = (INT32)LONG(players[i].ctfteam);
 		rst->score[i] = (UINT32)LONG(players[i].score);
 		rst->numboxes[i] = SHORT(players[i].numboxes);
 		rst->totalring[i] = SHORT(players[i].totalring);
@@ -897,28 +895,18 @@ static inline void resynch_write_others(resynchend_pak *rst)
 
 	// endian safeness
 	rst->ingame = (UINT32)LONG(rst->ingame);
-	rst->ctfteam = (UINT32)LONG(rst->ctfteam);
 }
 
 static inline void resynch_read_others(resynchend_pak *p)
 {
 	UINT8 i;
 	UINT32 loc_ingame = (UINT32)LONG(p->ingame);
-	UINT32 loc_ctfteam = (UINT32)LONG(p->ctfteam);
 
 	for (i = 0; i < MAXPLAYERS; ++i)
 	{
 		// We don't care if they're in the game or not, just write all the data.
-		if (loc_ingame & (1<<i))
-		{
-			players[i].spectator = false;
-			players[i].ctfteam = (loc_ctfteam & (1<<i)) ? 2 : 1;
-		}
-		else
-		{
-			players[i].spectator = true;
-			players[i].ctfteam = 0;
-		}
+		players[i].spectator = !(loc_ingame & i<<i);
+		players[i].ctfteam = (INT32)LONG(p->ctfteam[i]); // no, 0 does not mean spectator, at least not in Match
 		players[i].score = (UINT32)LONG(p->score[i]);
 		players[i].numboxes = SHORT(p->numboxes[i]);
 		players[i].totalring = SHORT(p->totalring[i]);
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index fe80be1be5b8193ab6ad2f39c279ba795253b201..02a03738758e6654184ab1a03866ca90690f0c0c 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -133,7 +133,7 @@ typedef struct
 	fixed_t flagz[2];
 
 	UINT32 ingame;  // Spectator bit for each player
-	UINT32 ctfteam; // If not spectator, then which team?
+	INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
 
 	// Resynch game scores and the like all at once
 	UINT32 score[MAXPLAYERS]; // Everyone's score
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 9eb9405cfdd73285701b0d1ffe178bb9f3eae4ab..75f7b3e514e53cb250b40f1969f7b02a3b4d5126 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -460,6 +460,7 @@ static void P_NetUnArchivePlayers(void)
 #define SD_TAG       0x10
 #define SD_FLOORANG  0x20
 #define SD_CEILANG   0x40
+#define SD_TAGLIST   0x80
 
 #define LD_FLAG     0x01
 #define LD_SPECIAL  0x02
@@ -534,6 +535,8 @@ static void P_NetArchiveWorld(void)
 
 		if (ss->tag != SHORT(ms->tag))
 			diff2 |= SD_TAG;
+		if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
+			diff2 |= SD_TAGLIST;
 
 		// Check if any of the sector's FOFs differ from how they spawned
 		if (ss->ffloors)
@@ -581,16 +584,17 @@ static void P_NetArchiveWorld(void)
 				WRITEFIXED(put, ss->ceiling_xoffs);
 			if (diff2 & SD_CYOFFS)
 				WRITEFIXED(put, ss->ceiling_yoffs);
-			if (diff2 & SD_TAG)
-			{
+			if (diff2 & SD_TAG) // save only the tag
 				WRITEINT16(put, ss->tag);
-				WRITEINT32(put, ss->firsttag);
-				WRITEINT32(put, ss->nexttag);
-			}
 			if (diff2 & SD_FLOORANG)
 				WRITEANGLE(put, ss->floorpic_angle);
 			if (diff2 & SD_CEILANG)
 				WRITEANGLE(put, ss->ceilingpic_angle);
+			if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
+			{ // either of these could be changed even if tag isn't
+				WRITEINT32(put, ss->firsttag);
+				WRITEINT32(put, ss->nexttag);
+			}
 
 			// Special case: save the stats of all modified ffloors along with their ffloor "number"s
 			// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
@@ -773,12 +777,11 @@ static void P_NetUnArchiveWorld(void)
 		if (diff2 & SD_CYOFFS)
 			sectors[i].ceiling_yoffs = READFIXED(get);
 		if (diff2 & SD_TAG)
+			sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
+		if (diff2 & SD_TAGLIST)
 		{
-			INT16 tag;
-			tag = READINT16(get);
 			sectors[i].firsttag = READINT32(get);
 			sectors[i].nexttag = READINT32(get);
-			P_ChangeSectorTag(i, tag);
 		}
 		if (diff2 & SD_FLOORANG)
 			sectors[i].floorpic_angle  = READANGLE(get);
@@ -2606,6 +2609,7 @@ static void P_NetUnArchiveThinkers(void)
 	thinker_t *next;
 	UINT8 tclass;
 	UINT8 restoreNum = false;
+	UINT32 i;
 
 	if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
 		I_Error("Bad $$$.sav at archive block Thinkers");
@@ -2626,6 +2630,12 @@ static void P_NetUnArchiveThinkers(void)
 	iquetail = iquehead = 0;
 	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++)
+	{
+		sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL;
+	}
+
 	// read in saved thinkers
 	for (;;)
 	{
diff --git a/src/p_setup.c b/src/p_setup.c
index ae6aa153c2b16e27ee4225ad41e351ac7f9c2ed7..8e746457be9216e8fec73e43bc2dbc24a0d5ea6e 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -677,6 +677,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
 		ss->special = SHORT(ms->special);
 		ss->tag = SHORT(ms->tag);
 		ss->nexttag = ss->firsttag = -1;
+		ss->spawn_nexttag = ss->spawn_firsttag = -1;
 
 		memset(&ss->soundorg, 0, sizeof(ss->soundorg));
 		ss->validcount = 0;
diff --git a/src/p_spec.c b/src/p_spec.c
index 6fcef330cf9e8adfbad25626ee77657bc51cd61d..3d83561a98bc9f66c46917d169f6cde1c6953274 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1519,6 +1519,8 @@ static inline void P_InitTagLists(void)
 		size_t j = (unsigned)sectors[i].tag % numsectors;
 		sectors[i].nexttag = sectors[j].firsttag;
 		sectors[j].firsttag = (INT32)i;
+		sectors[i].spawn_nexttag = sectors[i].nexttag;
+		sectors[j].spawn_firsttag = sectors[j].firsttag;
 	}
 
 	for (i = numlines - 1; i != (size_t)-1; i--)
diff --git a/src/r_defs.h b/src/r_defs.h
index b802acaffc42b301161e44e584625dbd58acb946..b8c21764ec1ffde78d66138201320a434a47cb1b 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -384,6 +384,7 @@ typedef struct sector_s
 #endif
 
 	// these are saved for netgames, so do not let Lua touch these!
+	INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
 
 	// offsets sector spawned with (via linedef type 7)
 	fixed_t spawn_flr_xoffs, spawn_flr_yoffs;