project_files/frontlib/ipcconn.c
changeset 7162 fe76d24a25d7
parent 7160 c42949cfdd92
child 7171 906e72caea7b
--- a/project_files/frontlib/ipcconn.c	Thu May 31 18:54:40 2012 +0200
+++ b/project_files/frontlib/ipcconn.c	Sat Jun 02 14:26:52 2012 +0200
@@ -4,23 +4,32 @@
 
 #include <SDL_net.h>
 #include <time.h>
+#include <string.h>
+#include <stdbool.h>
+
 static TCPsocket ipcListenSocket;
 static NonBlockSocket ipcConnSocket;
 
 static uint8_t ipcReadBuffer[256];
 static int ipcReadBufferSize;
 
+static flib_vector demoBuffer;
+static char localPlayerName[255];
+
 void flib_ipcconn_init() {
 	ipcListenSocket = NULL;
 	ipcConnSocket = NULL;
 	ipcReadBufferSize = 0;
+	demoBuffer=NULL;
+	strncpy(localPlayerName, "Local Player", 255);
 }
 
 void flib_ipcconn_quit() {
+	flib_vector_destroy(&demoBuffer);
 	flib_ipcconn_close();
 }
 
-int flib_ipcconn_listen() {
+int flib_ipcconn_start(bool recordDemo) {
 	if(ipcListenSocket || ipcConnSocket) {
 		flib_log_e("flib_ipcconn_listen: Already listening or connected.");
 		return -1;
@@ -42,6 +51,10 @@
 			flib_log_w("Failed to start an IPC listening socket on port %i: %s", ipcPort, SDLNet_GetError());
 		} else {
 			flib_log_i("Listening for IPC connections on port %i.", ipcPort);
+			if(recordDemo) {
+				flib_vector_destroy(&demoBuffer);
+				demoBuffer = flib_vector_create();
+			}
 			return ipcPort;
 		}
 	}
@@ -68,6 +81,44 @@
 	}
 }
 
+static void demo_record(const void *data, size_t len) {
+	if(demoBuffer) {
+		if(flib_vector_append(demoBuffer, data, len) < len) {
+			// Out of memory, fail demo recording
+			flib_vector_destroy(&demoBuffer);
+		}
+	}
+}
+
+static void demo_record_from_engine(const uint8_t *message) {
+	if(!demoBuffer || message[0]==0) {
+		return;
+	}
+	if(strchr("?CEiQqHb", message[1])) {
+		// Those message types are not recorded in a demo.
+		return;
+	}
+
+	if(message[1] == 's') {
+		if(message[0] >= 3) {
+			// Chat messages get a special once-over to make them look as if they were received, not sent.
+			// Get the actual chat message as c string
+			char chatMsg[256];
+			memcpy(chatMsg, message+2, message[0]-3);
+			chatMsg[message[0]-3] = 0;
+
+			char converted[257];
+			bool memessage = message[0] >= 7 && !memcmp(message+2, "/me ", 4);
+			const char *template = memessage ? "s\x02* %s %s  " : "s\x01%s: %s  ";
+			int size = snprintf(converted+1, 256, template, localPlayerName, chatMsg);
+			converted[0] = size>255 ? 255 : size;
+			demo_record(converted, converted[0]+1);
+		}
+	} else {
+		demo_record(message, message[0]+1);
+	}
+}
+
 /**
  * Receive a single message and copy it into the data buffer.
  * Returns the length of the received message, -1 when nothing is received.
@@ -86,6 +137,7 @@
 
 	int msgsize = ipcReadBuffer[0];
 	if(ipcReadBufferSize > msgsize) {
+		demo_record_from_engine(ipcReadBuffer);
 		memcpy(data, ipcReadBuffer+1, msgsize);
 		memmove(ipcReadBuffer, ipcReadBuffer+msgsize+1, ipcReadBufferSize-(msgsize+1));
 		ipcReadBufferSize -= (msgsize+1);
@@ -114,15 +166,20 @@
 	uint8_t sendbuf[256];
 	sendbuf[0] = len;
 	memcpy(sendbuf+1, data, len);
-	if(flib_nbsocket_blocksend(ipcConnSocket, sendbuf, len+1) < len+1) {
+	if(flib_nbsocket_blocksend(ipcConnSocket, sendbuf, len+1) == len+1) {
+		demo_record(sendbuf, len+1);
+		return 0;
+	} else {
 		flib_log_w("Failed or incomplete ICP write: engine connection lost.");
 		flib_nbsocket_close(&ipcConnSocket);
 		return -1;
-	} else {
-		return 0;
 	}
 }
 
+int flib_ipcconn_send_messagestr(char *data) {
+	return flib_ipcconn_send_message(data, strlen(data));
+}
+
 void flib_ipcconn_tick() {
 	if(!ipcConnSocket && ipcListenSocket) {
 		ipcConnSocket = flib_nbsocket_accept(ipcListenSocket, true);
@@ -132,3 +189,32 @@
 		}
 	}
 }
+
+static void replace_gamemode(flib_buffer buf, char gamemode) {
+	size_t msgStart = 0;
+	char *data = (char*)buf.data;
+	while(msgStart+2 < buf.size) {
+		if(!memcmp(data+msgStart, "\x02T", 2)) {
+			data[msgStart+2] = gamemode;
+		}
+		msgStart += (uint8_t)data[msgStart]+1;
+	}
+}
+
+flib_constbuffer flib_ipcconn_getdemo() {
+	if(!demoBuffer) {
+		flib_constbuffer result = {NULL, 0};
+		return result;
+	}
+	replace_gamemode(flib_vector_as_buffer(demoBuffer), 'D');
+	return flib_vector_as_constbuffer(demoBuffer);
+}
+
+flib_constbuffer flib_ipcconn_getsave() {
+	if(!demoBuffer) {
+		flib_constbuffer result = {NULL, 0};
+		return result;
+	}
+	replace_gamemode(flib_vector_as_buffer(demoBuffer), 'S');
+	return flib_vector_as_constbuffer(demoBuffer);
+}