From 0060caaf1afd561b30a31b9c539d74ff6810f090 Mon Sep 17 00:00:00 2001
From: toasterbabe <rollerorbital@gmail.com>
Date: Fri, 17 Mar 2017 23:11:32 +0000
Subject: [PATCH] Fixed synchronisation of skin changes and forceskin.

There's an outstanding issue - you can set forceskin to whatever you want to as the host. This needs to be fixed, but I'm commiting my successes first.
---
 src/command.c  | 6 +++++-
 src/d_clisrv.c | 7 ++++++-
 src/d_clisrv.h | 1 +
 src/d_netcmd.c | 7 -------
 src/r_things.c | 3 ++-
 5 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/src/command.c b/src/command.c
index 00749ed8d..ad576b54c 100644
--- a/src/command.c
+++ b/src/command.c
@@ -1407,8 +1407,12 @@ static void CV_SetValueMaybeStealth(consvar_t *var, INT32 value, boolean stealth
 
 	if (var == &cv_forceskin) // Special handling.
 	{
-		if ((value < 0) || (value >= numskins))
+		if ((server || adminplayer == consoleplayer) && ((value < 0) || (value >= numskins) || !(R_SkinUnlock(-1, cv_forceskin.value))))
+		{
+			CONS_Printf("Please provide a valid skin name (\"None\" disables).\n");
 			sprintf(val, "None");
+			value = -1;
+		}
 		else
 			sprintf(val, "%s", skins[value].name);
 	}
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 000816450..8d5b91b38 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -1366,6 +1366,8 @@ static boolean SV_SendServerConfig(INT32 node)
 	// which is nice and easy for us to detect
 	memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins));
 	memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor));
+	// ...except for availabilities, where 00 is nonexistent
+	memset(netbuffer->u.servercfg.playeravailabilities, 0x00, sizeof(netbuffer->u.servercfg.playeravailabilities));
 
 	for (i = 0; i < MAXPLAYERS; i++)
 	{
@@ -1373,6 +1375,7 @@ static boolean SV_SendServerConfig(INT32 node)
 			continue;
 		netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin;
 		netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor;
+		netbuffer->u.servercfg.playeravailabilities[i] = (UINT32)players[i].availabilities;
 	}
 
 	memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
@@ -3494,10 +3497,12 @@ static void HandlePacketFromAwayNode(SINT8 node)
 			for (j = 0; j < MAXPLAYERS; j++)
 			{
 				if (netbuffer->u.servercfg.playerskins[j] == 0xFF
-				 && netbuffer->u.servercfg.playercolor[j] == 0xFF)
+				 && netbuffer->u.servercfg.playercolor[j] == 0xFF
+				 && netbuffer->u.servercfg.playeravailabilities[j] == 0x00)
 					continue; // not in game
 
 				playeringame[j] = true;
+				players[j].availabilities = netbuffer->u.servercfg.playeravailabilities[j];
 				SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]);
 				players[j].skincolor = netbuffer->u.servercfg.playercolor[j];
 			}
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index 8f0aedbf3..c2ec1ad58 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -285,6 +285,7 @@ typedef struct
 	// 0xFF == not in game; else player skin num
 	UINT8 playerskins[MAXPLAYERS];
 	UINT8 playercolor[MAXPLAYERS];
+	UINT32 playeravailabilities[MAXPLAYERS];
 
 	UINT8 gametype;
 	UINT8 modifiedgame;
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 7fcbac092..1220b77af 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -4048,13 +4048,6 @@ static void Command_Archivetest_f(void)
   */
 static void ForceSkin_OnChange(void)
 {
-	if ((server || adminplayer == consoleplayer) && ((cv_forceskin.value == -1 && stricmp(cv_forceskin.string, "None")) || !(R_SkinUnlock(-1, cv_forceskin.value))))
-	{
-		CONS_Printf("Please provide a valid skin name (\"None\" disables).\n");
-		CV_SetValue(&cv_forceskin, -1);
-		return;
-	}
-
 	// NOT in SP, silly!
 	if (!(netgame || multiplayer))
 		return;
diff --git a/src/r_things.c b/src/r_things.c
index 03125f921..520dae30e 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -2576,7 +2576,7 @@ boolean R_SkinUnlock(INT32 playernum, INT32 skinnum)
 		|| ((playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked))
 		|| (modeattacking) // If you have someone else's run you might as well take a look
 		|| (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1.
-		|| (netgame && !(server || adminplayer == consoleplayer) && (cv_forceskin.value == skinnum)) // Force 2.
+		|| (netgame && (cv_forceskin.value == skinnum)) // Force 2.
 		);
 }
 
@@ -2622,6 +2622,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
 	player_t *player = &players[playernum];
 	skin_t *skin = &skins[skinnum];
 	UINT8 newcolor = 0;
+	CONS_Printf("%d - %d\n", playernum, player->availabilities);
 
 	if (skinnum >= 0 && skinnum < numskins && R_SkinUnlock(playernum, skinnum)) // Make sure it exists!
 	{