project_files/frontlib/ipc/gameconn.c
changeset 7316 f7b49b2c5d84
parent 7314 6171f0bad318
child 7320 e704706008d4
equal deleted inserted replaced
7314:6171f0bad318 7316:f7b49b2c5d84
    82 	conn->onEngineMessageCb = &defaultCallback_onEngineMessage;
    82 	conn->onEngineMessageCb = &defaultCallback_onEngineMessage;
    83 }
    83 }
    84 
    84 
    85 static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) {
    85 static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) {
    86 	flib_gameconn *result = NULL;
    86 	flib_gameconn *result = NULL;
    87 	if(!log_badparams_if(!playerName)) {
    87 	flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn));
    88 		flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn));
    88 	if(tempConn) {
    89 		if(tempConn) {
    89 		tempConn->ipcBase = flib_ipcbase_create();
    90 			tempConn->ipcBase = flib_ipcbase_create();
    90 		tempConn->configBuffer = flib_vector_create();
    91 			tempConn->configBuffer = flib_vector_create();
    91 		tempConn->playerName = flib_strdupnull(playerName);
    92 			tempConn->playerName = flib_strdupnull(playerName);
    92 		if(tempConn->ipcBase && tempConn->configBuffer && tempConn->playerName) {
    93 			if(tempConn->ipcBase && tempConn->configBuffer && tempConn->playerName) {
    93 			if(record) {
    94 				if(record) {
    94 				tempConn->demoBuffer = flib_vector_create();
    95 					tempConn->demoBuffer = flib_vector_create();
       
    96 				}
       
    97 				tempConn->state = AWAIT_CONNECTION;
       
    98 				tempConn->netgame = netGame;
       
    99 				clearCallbacks(tempConn);
       
   100 				result = tempConn;
       
   101 				tempConn = NULL;
       
   102 			}
    95 			}
   103 		}
    96 			tempConn->state = AWAIT_CONNECTION;
   104 		flib_gameconn_destroy(tempConn);
    97 			tempConn->netgame = netGame;
   105 	}
    98 			clearCallbacks(tempConn);
       
    99 			result = tempConn;
       
   100 			tempConn = NULL;
       
   101 		}
       
   102 	}
       
   103 	flib_gameconn_destroy(tempConn);
   106 	return result;
   104 	return result;
   107 }
   105 }
   108 
   106 
   109 flib_gameconn *flib_gameconn_create(const char *playerName, const flib_gamesetup *setup, bool netgame) {
   107 flib_gameconn *flib_gameconn_create(const char *playerName, const flib_gamesetup *setup, bool netgame) {
       
   108 	if(log_badargs_if2(playerName==NULL, setup==NULL)) {
       
   109 		return NULL;
       
   110 	}
   110 	flib_gameconn *result = NULL;
   111 	flib_gameconn *result = NULL;
   111 	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, netgame);
   112 	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, netgame);
   112 	if(tempConn) {
   113 	if(tempConn) {
   113 		if(flib_ipc_append_fullconfig(tempConn->configBuffer, setup, netgame)) {
   114 		if(flib_ipc_append_fullconfig(tempConn->configBuffer, setup, netgame)) {
   114 			flib_log_e("Error generating full game configuration for the engine.");
   115 			flib_log_e("Error generating full game configuration for the engine.");
   119 	}
   120 	}
   120 	flib_gameconn_destroy(tempConn);
   121 	flib_gameconn_destroy(tempConn);
   121 	return result;
   122 	return result;
   122 }
   123 }
   123 
   124 
   124 flib_gameconn *flib_gameconn_create_playdemo(const uint8_t *demo, int size) {
   125 flib_gameconn *flib_gameconn_create_playdemo(const uint8_t *demo, size_t size) {
       
   126 	if(log_badargs_if(demo==NULL && size>0)) {
       
   127 		return NULL;
       
   128 	}
   125 	flib_gameconn *result = NULL;
   129 	flib_gameconn *result = NULL;
   126 	flib_gameconn *tempConn = flib_gameconn_create_partial(false, "Player", false);
   130 	flib_gameconn *tempConn = flib_gameconn_create_partial(false, "Player", false);
   127 	if(tempConn) {
   131 	if(tempConn) {
   128 		if(!flib_vector_append(tempConn->configBuffer, demo, size)) {
   132 		if(!flib_vector_append(tempConn->configBuffer, demo, size)) {
   129 			result = tempConn;
   133 			result = tempConn;
   132 	}
   136 	}
   133 	flib_gameconn_destroy(tempConn);
   137 	flib_gameconn_destroy(tempConn);
   134 	return result;
   138 	return result;
   135 }
   139 }
   136 
   140 
   137 flib_gameconn *flib_gameconn_create_loadgame(const char *playerName, const uint8_t *save, int size) {
   141 flib_gameconn *flib_gameconn_create_loadgame(const char *playerName, const uint8_t *save, size_t size) {
       
   142 	if(log_badargs_if(save==NULL && size>0)) {
       
   143 		return NULL;
       
   144 	}
   138 	flib_gameconn *result = NULL;
   145 	flib_gameconn *result = NULL;
   139 	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, false);
   146 	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, false);
   140 	if(tempConn) {
   147 	if(tempConn) {
   141 		if(!flib_vector_append(tempConn->configBuffer, save, size)) {
   148 		if(!flib_vector_append(tempConn->configBuffer, save, size)) {
   142 			result = tempConn;
   149 			result = tempConn;
   146 	flib_gameconn_destroy(tempConn);
   153 	flib_gameconn_destroy(tempConn);
   147 	return result;
   154 	return result;
   148 }
   155 }
   149 
   156 
   150 flib_gameconn *flib_gameconn_create_campaign(const char *playerName, const char *seed, const char *script) {
   157 flib_gameconn *flib_gameconn_create_campaign(const char *playerName, const char *seed, const char *script) {
       
   158 	if(log_badargs_if3(playerName==NULL, seed==NULL, script==NULL)) {
       
   159 		return NULL;
       
   160 	}
   151 	flib_gameconn *result = NULL;
   161 	flib_gameconn *result = NULL;
   152 	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, false);
   162 	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, false);
   153 	if(tempConn) {
   163 	if(tempConn) {
   154 		if(!flib_ipc_append_message(tempConn->configBuffer, "TL")
   164 		if(!flib_ipc_append_message(tempConn->configBuffer, "TL")
   155 				&& !flib_ipc_append_seed(tempConn->configBuffer, seed)
   165 				&& !flib_ipc_append_seed(tempConn->configBuffer, seed)
   182 		}
   192 		}
   183 	}
   193 	}
   184 }
   194 }
   185 
   195 
   186 int flib_gameconn_getport(flib_gameconn *conn) {
   196 int flib_gameconn_getport(flib_gameconn *conn) {
   187 	if(!log_badparams_if(!conn)) {
   197 	if(log_badargs_if(conn==NULL)) {
   188 		return flib_ipcbase_port(conn->ipcBase);
   198 		return 0;
   189 	}
   199 	}
   190 	return 0;
   200 	return flib_ipcbase_port(conn->ipcBase);
   191 }
   201 }
   192 
   202 
   193 static void demo_append(flib_gameconn *conn, const void *data, size_t len) {
   203 static void demo_append(flib_gameconn *conn, const void *data, size_t len) {
   194 	if(conn->demoBuffer) {
   204 	if(conn->demoBuffer) {
   195 		if(flib_vector_append(conn->demoBuffer, data, len)) {
   205 		if(flib_vector_append(conn->demoBuffer, data, len)) {
   205 
   215 
   206 	// If the message starts with /me, it will be displayed differently.
   216 	// If the message starts with /me, it will be displayed differently.
   207 	bool meMessage = msglen >= 4 && !memcmp(message, "/me ", 4);
   217 	bool meMessage = msglen >= 4 && !memcmp(message, "/me ", 4);
   208 	const char *template = meMessage ? "s\x02* %s %s  " : "s\x01%s: %s  ";
   218 	const char *template = meMessage ? "s\x02* %s %s  " : "s\x01%s: %s  ";
   209 	int size = snprintf((char*)buffer+1, 256, template, playerName, meMessage ? message+4 : message);
   219 	int size = snprintf((char*)buffer+1, 256, template, playerName, meMessage ? message+4 : message);
   210 	if(size>0) {
   220 	if(log_e_if(size<=0, "printf error")) {
       
   221 		return -1;
       
   222 	} else {
   211 		buffer[0] = size>255 ? 255 : size;
   223 		buffer[0] = size>255 ? 255 : size;
   212 		return 0;
   224 		return 0;
   213 	} else {
       
   214 		return -1;
       
   215 	}
   225 	}
   216 }
   226 }
   217 
   227 
   218 static void demo_append_chatmessage(flib_gameconn *conn, const char *message) {
   228 static void demo_append_chatmessage(flib_gameconn *conn, const char *message) {
   219 	// Chat messages are reformatted to make them look as if they were received, not sent.
   229 	// Chat messages are reformatted to make them look as if they were received, not sent.
   233 		msgStart += (uint8_t)data[msgStart]+1;
   243 		msgStart += (uint8_t)data[msgStart]+1;
   234 	}
   244 	}
   235 }
   245 }
   236 
   246 
   237 int flib_gameconn_send_enginemsg(flib_gameconn *conn, const uint8_t *data, size_t len) {
   247 int flib_gameconn_send_enginemsg(flib_gameconn *conn, const uint8_t *data, size_t len) {
   238 	int result = -1;
   248 	if(log_badargs_if2(conn==NULL, data==NULL && len>0)) {
   239 	if(!log_badparams_if(!conn || (!data && len>0))
   249 		return -1;
   240 			&& !flib_ipcbase_send_raw(conn->ipcBase, data, len)) {
   250 	}
       
   251 	int result = flib_ipcbase_send_raw(conn->ipcBase, data, len);
       
   252 	if(!result) {
   241 		demo_append(conn, data, len);
   253 		demo_append(conn, data, len);
   242 		result = 0;
       
   243 	}
   254 	}
   244 	return result;
   255 	return result;
   245 }
   256 }
   246 
   257 
   247 int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg) {
   258 int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg) {
   248 	int result = -1;
   259 	if(log_badargs_if2(conn==NULL, msg==NULL)) {
   249 	if(!conn || !msg) {
   260 		return -1;
   250 		flib_log_e("null parameter in flib_gameconn_send_textmsg");
   261 	}
   251 	} else {
       
   252 		uint8_t converted[257];
       
   253 		int size = snprintf((char*)converted+1, 256, "s%c%s", (char)msgtype, msg);
       
   254 		if(size>0) {
       
   255 			converted[0] = size>255 ? 255 : size;
       
   256 			if(!flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
       
   257 				demo_append(conn, converted, converted[0]+1);
       
   258 				result = 0;
       
   259 			}
       
   260 		}
       
   261 	}
       
   262 	return result;
       
   263 }
       
   264 
       
   265 int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg) {
       
   266 	int result = -1;
   262 	int result = -1;
   267 	uint8_t converted[257];
   263 	uint8_t converted[257];
   268 	if(!conn || !playername || !msg) {
   264 	int size = snprintf((char*)converted+1, 256, "s%c%s", (char)msgtype, msg);
   269 		flib_log_e("null parameter in flib_gameconn_send_chatmsg");
   265 	if(size>0) {
   270 	} else if(format_chatmessage(converted, playername, msg)) {
   266 		converted[0] = size>255 ? 255 : size;
   271 		flib_log_e("Error formatting message in flib_gameconn_send_chatmsg");
   267 		if(!flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
   272 	} else if(!flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
   268 			demo_append(conn, converted, converted[0]+1);
       
   269 			result = 0;
       
   270 		}
       
   271 	}
       
   272 	return result;
       
   273 }
       
   274 
       
   275 int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg) {
       
   276 	if(log_badargs_if3(conn==NULL, playername==NULL, msg==NULL)) {
       
   277 		return -1;
       
   278 	}
       
   279 	uint8_t converted[257];
       
   280 	if(!format_chatmessage(converted, playername, msg)
       
   281 			&& !flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
   273 		demo_append(conn, converted, converted[0]+1);
   282 		demo_append(conn, converted, converted[0]+1);
   274 		result = 0;
   283 		return 0;
   275 	}
   284 	}
   276 	return result;
   285 	return -1;
   277 }
   286 }
   278 
   287 
   279 void flib_gameconn_onConnect(flib_gameconn *conn, void (*callback)(void* context), void* context) {
   288 /**
   280 	if(!conn) {
   289  * This macro generates a callback setter function. It uses the name of the callback to
   281 		flib_log_e("null parameter in flib_gameconn_onConnect");
   290  * automatically generate the function name and the fields to set, so a consistent naming
   282 	} else {
   291  * convention needs to be enforced (not that that is a bad thing). If null is passed as
   283 		conn->onConnectCb = callback ? callback : &defaultCallback_onConnect;
   292  * callback to the generated function, the defaultCb will be set instead (with conn
   284 		conn->onConnectCtx = context;
   293  * as the context).
   285 	}
   294  */
   286 }
   295 #define GENERATE_CB_SETTER(cbName, cbParameterTypes, defaultCb) \
   287 
   296 	void flib_gameconn_##cbName(flib_gameconn *conn, void (*callback)cbParameterTypes, void *context) { \
   288 void flib_gameconn_onDisconnect(flib_gameconn *conn, void (*callback)(void* context, int reason), void* context) {
   297 		if(!log_badargs_if(conn==NULL)) { \
   289 	if(!conn) {
   298 			conn->cbName##Cb = callback ? callback : &defaultCb; \
   290 		flib_log_e("null parameter in flib_gameconn_onDisconnect");
   299 			conn->cbName##Ctx = callback ? context : conn; \
   291 	} else {
   300 		} \
   292 		conn->onDisconnectCb = callback ? callback : &defaultCallback_onDisconnect;
   301 	}
   293 		conn->onDisconnectCtx = context;
   302 
   294 	}
   303 /**
   295 }
   304  * Generate a callback setter function like GENERATE_CB_SETTER, and automatically generate a
   296 
   305  * no-op callback function as well that is used as default.
   297 void flib_gameconn_onErrorMessage(flib_gameconn *conn, void (*callback)(void* context, const char *msg), void* context) {
   306  */
   298 	if(!conn) {
   307 #define GENERATE_CB_SETTER_AND_DEFAULT(cbName, cbParameterTypes) \
   299 		flib_log_e("null parameter in flib_gameconn_onErrorMessage");
   308 	static void _noop_callback_##cbName cbParameterTypes {} \
   300 	} else {
   309 	GENERATE_CB_SETTER(cbName, cbParameterTypes, _noop_callback_##cbName)
   301 		conn->onErrorMessageCb = callback ? callback : &defaultCallback_onErrorMessage;
   310 
   302 		conn->onErrorMessageCtx = context;
   311 GENERATE_CB_SETTER_AND_DEFAULT(onConnect, (void *context));
   303 	}
   312 GENERATE_CB_SETTER_AND_DEFAULT(onDisconnect, (void* context, int reason));
   304 }
   313 GENERATE_CB_SETTER(onErrorMessage, (void* context, const char *msg), defaultCallback_onErrorMessage);
   305 
   314 GENERATE_CB_SETTER_AND_DEFAULT(onChat, (void* context, const char *msg, bool teamchat));
   306 void flib_gameconn_onChat(flib_gameconn *conn, void (*callback)(void* context, const char *msg, bool teamchat), void* context) {
   315 GENERATE_CB_SETTER_AND_DEFAULT(onGameRecorded, (void *context, const uint8_t *record, int size, bool isSavegame));
   307 	if(!conn) {
   316 GENERATE_CB_SETTER_AND_DEFAULT(onEngineMessage, (void *context, const uint8_t *em, size_t size));
   308 		flib_log_e("null parameter in flib_gameconn_onChat");
   317 
   309 	} else {
   318 #undef GENERATE_CB_SETTER_AND_DEFAULT
   310 		conn->onChatCb = callback ? callback : &defaultCallback_onChat;
   319 #undef GENERATE_CB_SETTER
   311 		conn->onChatCtx = context;
       
   312 	}
       
   313 }
       
   314 
       
   315 void flib_gameconn_onGameRecorded(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *record, int size, bool isSavegame), void* context) {
       
   316 	if(!conn) {
       
   317 		flib_log_e("null parameter in flib_gameconn_onGameRecorded");
       
   318 	} else {
       
   319 		conn->onGameRecordedCb = callback ? callback : &defaultCallback_onGameRecorded;
       
   320 		conn->onGameRecordedCtx = context;
       
   321 	}
       
   322 }
       
   323 
       
   324 void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, size_t size), void* context) {
       
   325 	if(!conn) {
       
   326 		flib_log_e("null parameter in flib_gameconn_onEngineMessage");
       
   327 	} else {
       
   328 		conn->onEngineMessageCb = callback ? callback : &defaultCallback_onEngineMessage;
       
   329 		conn->onEngineMessageCtx = context;
       
   330 	}
       
   331 }
       
   332 
   320 
   333 static void flib_gameconn_wrappedtick(flib_gameconn *conn) {
   321 static void flib_gameconn_wrappedtick(flib_gameconn *conn) {
   334 	if(conn->state == AWAIT_CONNECTION) {
   322 	if(conn->state == AWAIT_CONNECTION) {
   335 		flib_ipcbase_accept(conn->ipcBase);
   323 		flib_ipcbase_accept(conn->ipcBase);
   336 		switch(flib_ipcbase_state(conn->ipcBase)) {
   324 		switch(flib_ipcbase_state(conn->ipcBase)) {
   430 		conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR);
   418 		conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR);
   431 	}
   419 	}
   432 }
   420 }
   433 
   421 
   434 void flib_gameconn_tick(flib_gameconn *conn) {
   422 void flib_gameconn_tick(flib_gameconn *conn) {
   435 	if(!conn) {
   423 	if(!log_badargs_if(conn == NULL)
   436 		flib_log_e("null parameter in flib_gameconn_tick");
   424 			&& !log_w_if(conn->running, "Call to flib_gameconn_tick from a callback")
   437 	} else if(conn->running) {
   425 			&& !log_w_if(conn->state == FINISHED, "We are already done.")) {
   438 		flib_log_w("Call to flib_gameconn_tick from a callback");
       
   439 	} else if(conn->state == FINISHED) {
       
   440 		flib_log_w("Call to flib_gameconn_tick, but we are already done.");
       
   441 	} else {
       
   442 		conn->running = true;
   426 		conn->running = true;
   443 		flib_gameconn_wrappedtick(conn);
   427 		flib_gameconn_wrappedtick(conn);
   444 		conn->running = false;
   428 		conn->running = false;
   445 
   429 
   446 		if(conn->destroyRequested) {
   430 		if(conn->destroyRequested) {