From ae5f0d833775c2242cbf305bd7257c9aa87854d2 Mon Sep 17 00:00:00 2001
From: Yukita Mayako <catgirl@goddess.moe>
Date: Wed, 24 Feb 2016 08:15:39 -0500
Subject: [PATCH] Added client --> server movement communications.

---
 src/d_datawrap.c |  27 ++++++----
 src/d_datawrap.h |  12 +++--
 src/d_enet.c     | 134 ++++++++++++++++++++++++++++++++++++++++-------
 src/m_menu.c     |  12 ++++-
 4 files changed, 149 insertions(+), 36 deletions(-)

diff --git a/src/d_datawrap.c b/src/d_datawrap.c
index 34dcdeb9ff..838af499e7 100644
--- a/src/d_datawrap.c
+++ b/src/d_datawrap.c
@@ -13,25 +13,37 @@ static void CheckEOF(DataWrap dw, size_t l)
 	}
 }
 
-static UINT8 ReadUINT8(DataWrap dw)
+UINT8 DW_ReadUINT8(DataWrap dw)
 {
 	CheckEOF(dw, 1);
 	return READUINT8(dw->p);
 }
 
-static UINT16 ReadUINT16(DataWrap dw)
+UINT16 DW_ReadUINT16(DataWrap dw)
 {
 	CheckEOF(dw, 2);
 	return READUINT16(dw->p);
 }
 
-static INT16 ReadINT16(DataWrap dw)
+UINT32 DW_ReadUINT32(DataWrap dw)
+{
+	CheckEOF(dw, 4);
+	return READUINT32(dw->p);
+}
+
+SINT8 DW_ReadSINT8(DataWrap dw)
+{
+	CheckEOF(dw, 1);
+	return READSINT8(dw->p);
+}
+
+INT16 DW_ReadINT16(DataWrap dw)
 {
 	CheckEOF(dw, 2);
 	return READINT16(dw->p);
 }
 
-static char *ReadStringn(DataWrap dw, size_t n)
+char *DW_ReadStringn(DataWrap dw, size_t n)
 {
 	char *string = ZZ_Alloc(n+1);
 	char *p = string;
@@ -53,12 +65,5 @@ DataWrap D_NewDataWrap(const void *data, size_t len, jmp_buf *eofjmp)
 	dw->data = dw->p = data;
 	dw->len = len;
 	dw->eofjmp = eofjmp;
-
-	dw->ReadUINT8 = ReadUINT8;
-	dw->ReadUINT16 = ReadUINT16;
-
-	dw->ReadINT16 = ReadINT16;
-
-	dw->ReadStringn = ReadStringn;
 	return dw;
 }
diff --git a/src/d_datawrap.h b/src/d_datawrap.h
index 4baf08f63f..6bd9c32cd4 100644
--- a/src/d_datawrap.h
+++ b/src/d_datawrap.h
@@ -5,13 +5,15 @@ typedef struct DataWrap_s {
 	const void *data, *p;
 	size_t len;
 	jmp_buf	*eofjmp;
+} *DataWrap;
 
-	UINT8 (*ReadUINT8)(struct DataWrap_s *);
-	UINT16 (*ReadUINT16)(struct DataWrap_s *);
+UINT8 DW_ReadUINT8(struct DataWrap_s *);
+UINT16 DW_ReadUINT16(struct DataWrap_s *);
+UINT32 DW_ReadUINT32(struct DataWrap_s *);
 
-	INT16 (*ReadINT16)(struct DataWrap_s *);
+SINT8 DW_ReadSINT8(struct DataWrap_s *);
+INT16 DW_ReadINT16(struct DataWrap_s *);
 
-	char *(*ReadStringn)(struct DataWrap_s *, size_t n);
-} *DataWrap;
+char *DW_ReadStringn(struct DataWrap_s *, size_t n);
 
 DataWrap D_NewDataWrap(const void *data, size_t len, jmp_buf *eofjmp);
diff --git a/src/d_enet.c b/src/d_enet.c
index c6fda1765b..539be9224b 100644
--- a/src/d_enet.c
+++ b/src/d_enet.c
@@ -7,6 +7,7 @@
 #include "z_zone.h"
 #include "m_menu.h"
 #include "d_datawrap.h"
+#include "g_game.h"
 
 UINT8 net_nodecount, net_playercount;
 UINT8 playernode[MAXPLAYERS];
@@ -15,10 +16,14 @@ SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (spl
 UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
 boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
 
-#define NETCHANNELS 4
 #define MAX_SERVER_MESSAGE 320
 
 enum {
+	CHANNEL_GENERAL = 0,
+	CHANNEL_CHAT,
+	CHANNEL_MOVE,
+	NET_CHANNELS,
+
 	DISCONNECT_UNKNOWN = 0,
 	DISCONNECT_SHUTDOWN,
 	DISCONNECT_FULL,
@@ -27,6 +32,8 @@ enum {
 	CLIENT_ASKMSINFO = 0,
 	CLIENT_JOIN,
 	CLIENT_CHAT,
+	CLIENT_CHARACTER,
+	CLIENT_MOVE,
 
 	SERVER_MSINFO = 0,
 	SERVER_MAPINFO,
@@ -37,10 +44,20 @@ static ENetHost *ServerHost = NULL,
 	*ClientHost = NULL;
 static ENetPeer *nodetopeer[MAXNETNODES];
 
+typedef struct {
+	ticcmd_t cmd;
+	fixed_t x,y,z,
+		vx,vy,vz,
+		ax,ay,az;
+	angle_t angle, aiming;
+	enum state state;
+} GhostData;
+
 typedef struct PeerData_s {
 	UINT8 node;
 	UINT8 flags;
 	char name[MAXPLAYERNAME+1];
+	GhostData ghost;
 } PeerData;
 
 enum {
@@ -48,6 +65,7 @@ enum {
 };
 
 static void ServerSendMapInfo(UINT8 node);
+static void Net_SendMove(void);
 
 boolean Net_GetNetStat(void)
 {
@@ -68,12 +86,12 @@ static void ServerHandlePacket(UINT8 node, DataWrap data)
 {
 	PeerData *pdata = nodetopeer[node]->data;
 
-	switch(data->ReadUINT8(data))
+	switch(DW_ReadUINT8(data))
 	{
 	case CLIENT_JOIN:
 	{
-		UINT16 version = data->ReadUINT16(data);
-		UINT16 subversion = data->ReadUINT16(data);
+		UINT16 version = DW_ReadUINT16(data);
+		UINT16 subversion = DW_ReadUINT16(data);
 
 		if (version != VERSION || subversion != SUBVERSION)
 		{
@@ -82,7 +100,7 @@ static void ServerHandlePacket(UINT8 node, DataWrap data)
 			break;
 		}
 
-		char *name = data->ReadStringn(data, MAXPLAYERNAME);
+		char *name = DW_ReadStringn(data, MAXPLAYERNAME);
 		strcpy(pdata->name, name);
 		Z_Free(name);
 
@@ -100,7 +118,7 @@ static void ServerHandlePacket(UINT8 node, DataWrap data)
 		UINT8 *buf = ndata;
 
 		WRITEUINT8(buf, SERVER_MESSAGE);
-		sprintf(buf, "\3<%s> %s", pdata->name, data->ReadStringn(data, 256));
+		sprintf(buf, "\3<%s> %s", pdata->name, DW_ReadStringn(data, 256));
 		buf += strlen(buf)+1;
 		CONS_Printf("%s\n", ndata+1);
 
@@ -109,6 +127,45 @@ static void ServerHandlePacket(UINT8 node, DataWrap data)
 		break;
 	}
 
+	case CLIENT_CHARACTER:
+	{
+		UINT8 pnum;
+		// this message might be sent when the player first spawns
+		if (nodetoplayer[node] == -1)
+		{
+			for (pnum = 0; pnum < MAXPLAYERS; pnum++)
+				if (!playeringame[pnum])
+					break;
+			I_Assert(pnum != MAXPLAYERS);
+			CL_ClearPlayer(pnum);
+			playeringame[pnum] = true;
+			G_AddPlayer(pnum);
+			playernode[pnum] = node;
+			nodetoplayer[node] = pnum;
+		}
+		pnum = nodetoplayer[node];
+		SetPlayerSkin(pnum, DW_ReadStringn(data, SKINNAMESIZE));
+		players[pnum].skincolor = DW_ReadUINT8(data) % MAXSKINCOLORS;
+		break;
+	}
+
+	case CLIENT_MOVE:
+	{
+		player_t *player;
+		if (nodetoplayer[node] == -1)
+			break;
+		player = &players[nodetoplayer[node]];
+		player->cmd.forwardmove = DW_ReadSINT8(data);
+		player->cmd.sidemove = DW_ReadSINT8(data);
+		player->cmd.angleturn = DW_ReadINT16(data);
+		player->cmd.aiming = DW_ReadINT16(data);
+		player->cmd.buttons = DW_ReadUINT16(data);
+		player->mo->x = DW_ReadINT16(data) << 16;
+		player->mo->y = DW_ReadINT16(data) << 16;
+		player->mo->z = DW_ReadINT16(data) << 16;
+		break;
+	}
+
 	default:
 		CONS_Printf("NETWORK: Unknown message type recieved from node %u!\n", node);
 		break;
@@ -119,13 +176,13 @@ void CL_ConnectionSuccessful(void);
 
 static void ClientHandlePacket(UINT8 node, DataWrap data)
 {
-	switch(data->ReadUINT8(data))
+	switch(DW_ReadUINT8(data))
 	{
 	case SERVER_MAPINFO:
 	{
 		CL_ConnectionSuccessful();
-		gamemap = data->ReadINT16(data);
-		gametype = data->ReadINT16(data);
+		gamemap = DW_ReadINT16(data);
+		gametype = DW_ReadINT16(data);
 		CONS_Printf("NETWORK: Heading to map %u\n", gamemap);
 		G_InitNew(false, G_BuildMapName(gamemap), true, true);
 		M_StartControlPanel();
@@ -135,7 +192,7 @@ static void ClientHandlePacket(UINT8 node, DataWrap data)
 
 	case SERVER_MESSAGE:
 	{
-		char *msg = data->ReadStringn(data, MAX_SERVER_MESSAGE);
+		char *msg = DW_ReadStringn(data, MAX_SERVER_MESSAGE);
 		CONS_Printf("%s\n", msg);
 		Z_Free(msg);
 		break;
@@ -154,6 +211,9 @@ void Net_AckTicker(void)
 	PeerData *pdata;
 	jmp_buf safety;
 
+	if(addedtogame && ClientHost)
+		Net_SendMove();
+
 	while (ClientHost && enet_host_service(ClientHost, &e, 0) > 0)
 		switch (e.type)
 		{
@@ -221,6 +281,8 @@ void Net_AckTicker(void)
 			pdata = ZZ_Alloc(sizeof(*pdata));
 			pdata->node = i;
 			pdata->flags = 0;
+			strcpy(pdata->name, "New Player");
+			memset(&pdata->ghost, 0, sizeof(GhostData));
 
 			e.peer->data = pdata;
 
@@ -260,7 +322,7 @@ void Net_AckTicker(void)
 void D_NetOpen(void)
 {
 	ENetAddress address = { ENET_HOST_ANY, 5029 };
-	ServerHost = enet_host_create(&address, MAXNETNODES, NETCHANNELS, 0, 0);
+	ServerHost = enet_host_create(&address, MAXNETNODES, NET_CHANNELS-1, 0, 0);
 	if (!ServerHost)
 		I_Error("ENet failed to open server host. (Check if the port is in use?)");
 
@@ -275,7 +337,7 @@ boolean D_NetConnect(const char *hostname, const char *port)
 	ENetAddress address;
 	ENetEvent e;
 
-	ClientHost = enet_host_create(NULL, 1, NETCHANNELS, 0, 0);
+	ClientHost = enet_host_create(NULL, 1, NET_CHANNELS-1, 0, 0);
 	if (!ClientHost)
 		I_Error("ENet failed to initialize client host.\n");
 
@@ -287,7 +349,7 @@ boolean D_NetConnect(const char *hostname, const char *port)
 	if (port != NULL)
 		address.port = atoi(port) || address.port;
 
-	nodetopeer[servernode] = enet_host_connect(ClientHost, &address, NETCHANNELS, 0);
+	nodetopeer[servernode] = enet_host_connect(ClientHost, &address, NET_CHANNELS-1, 0);
 	if (!nodetopeer[servernode])
 		I_Error("Failed to allocate ENet peer for connecting ???\n");
 	nodeingame[servernode] = true;
@@ -422,8 +484,7 @@ void Net_SendJoin(void)
 	WRITESTRINGN(buf, cv_playername.string, MAXPLAYERNAME);
 
 	packet = enet_packet_create(data, buf-data, ENET_PACKET_FLAG_RELIABLE);
-	enet_peer_send(nodetopeer[servernode], 0, packet);
-	CONS_Printf("NETWORK: Join request sent. Now...\n");
+	enet_peer_send(nodetopeer[servernode], CHANNEL_GENERAL, packet);
 }
 
 static void ServerSendMapInfo(UINT8 node)
@@ -437,7 +498,7 @@ static void ServerSendMapInfo(UINT8 node)
 	WRITEINT16(buf, gametype);
 
 	packet = enet_packet_create(data, buf-data, ENET_PACKET_FLAG_RELIABLE);
-	enet_peer_send(nodetopeer[node], 0, packet);
+	enet_peer_send(nodetopeer[node], CHANNEL_GENERAL, packet);
 }
 
 void Net_SendChat(char *line)
@@ -461,7 +522,44 @@ void Net_SendChat(char *line)
 
 	packet = enet_packet_create(data, buf-data, ENET_PACKET_FLAG_RELIABLE);
 	if (server)
-		enet_host_broadcast(ServerHost, 0, packet);
+		enet_host_broadcast(ServerHost, CHANNEL_CHAT, packet);
 	else
-		enet_peer_send(nodetopeer[servernode], 0, packet);
+		enet_peer_send(nodetopeer[servernode], CHANNEL_CHAT, packet);
+}
+
+void Net_SendCharacter(void)
+{
+	ENetPacket *packet;
+	UINT8 data[1+SKINNAMESIZE+1];
+	UINT8 *buf = data;
+
+	WRITEUINT8(buf, CLIENT_CHARACTER);
+	WRITESTRINGN(buf, cv_skin.string, SKINNAMESIZE);
+	WRITEUINT8(buf, cv_playercolor.value);
+
+	packet = enet_packet_create(data, buf-data, ENET_PACKET_FLAG_RELIABLE);
+	enet_peer_send(nodetopeer[servernode], CHANNEL_GENERAL, packet);
+}
+
+static void Net_SendMove(void)
+{
+	ENetPacket *packet;
+	UINT8 data[256];
+	UINT8 *buf = data;
+
+	if (!addedtogame)
+		return;
+
+	WRITEUINT8(buf, CLIENT_MOVE);
+	WRITESINT8(buf, players[consoleplayer].cmd.forwardmove);
+	WRITESINT8(buf, players[consoleplayer].cmd.sidemove);
+	WRITEINT16(buf, players[consoleplayer].cmd.angleturn);
+	WRITEINT16(buf, players[consoleplayer].cmd.aiming);
+	WRITEUINT16(buf, players[consoleplayer].cmd.buttons);
+	WRITEINT16(buf, players[consoleplayer].mo->x >> 16);
+	WRITEINT16(buf, players[consoleplayer].mo->y >> 16);
+	WRITEINT16(buf, players[consoleplayer].mo->z >> 16);
+
+	packet = enet_packet_create(data, buf-data, 0);
+	enet_peer_send(nodetopeer[servernode], CHANNEL_MOVE, packet);
 }
diff --git a/src/m_menu.c b/src/m_menu.c
index a9db1e6409..1633d80f85 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -5167,10 +5167,11 @@ static void M_DrawSetupNetgameChoosePlayerMenu(void)
 
 static void M_NetgameChoosePlayer(INT32 choice)
 {
+	char *skinname;
 	INT32 foundskin;
 
 	// skip this if forcecharacter
-	if (mapheaderinfo[startmap-1] && mapheaderinfo[startmap-1]->forcecharacter[0] == '\0')
+	if (!mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->forcecharacter[0] == '\0')
 	{
 		// M_SetupChoosePlayer didn't call us directly, that means we've been properly set up.
 		char_scroll = itemOn*128*FRACUNIT; // finish scrolling the menu
@@ -5189,7 +5190,12 @@ static void M_NetgameChoosePlayer(INT32 choice)
 	playernode[consoleplayer] = 0;
 	addedtogame = true;
 
-	if ((foundskin = R_SkinAvailable(MP_Description[choice].skinname)) != -1)
+	if (!mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->forcecharacter[0] == '\0')
+		skinname = MP_Description[choice].skinname;
+	else
+		skinname = mapheaderinfo[gamemap-1]->forcecharacter;
+
+	if ((foundskin = R_SkinAvailable(skinname)) != -1)
 	{
 		cv_skin.value = foundskin;
 		CV_StealthSet(&cv_skin, skins[foundskin].name);
@@ -5209,6 +5215,8 @@ static void M_NetgameChoosePlayer(INT32 choice)
 		players[consoleplayer].pflags |= PF_FLIPCAM;
 	if (cv_analog.value)
 		players[consoleplayer].pflags |= PF_ANALOGMODE;
+
+	Net_SendCharacter();
 }
 
 // ===============
-- 
GitLab