--- a/project_files/frontlib/hwconsts.h Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/hwconsts.h Thu Jun 21 21:32:12 2012 +0200
@@ -8,7 +8,7 @@
#define HEDGEHOGS_PER_TEAM 8
#define NETGAME_DEFAULT_PORT 46631
-#define PROTOCOL_VERSION 42
+#define PROTOCOL_VERSION 41
#define MIN_SERVER_VERSION 1
#define GAMEMOD_PERHOGAMMO_MASKBIT 22
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/md5/md5.c Thu Jun 21 21:32:12 2012 +0200
@@ -0,0 +1,381 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/md5/md5.h Thu Jun 21 21:32:12 2012 +0200
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/roomlist.c Thu Jun 21 21:32:12 2012 +0200
@@ -0,0 +1,146 @@
+#include "roomlist.h"
+
+#include "../util/util.h"
+#include "../util/list.h"
+#include "../util/logging.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+flib_roomlist *flib_roomlist_create() {
+ return flib_calloc(1, sizeof(flib_roomlist));
+}
+
+static void flib_roomlist_room_destroy(flib_roomlist_room *room) {
+ if(room) {
+ free(room->map);
+ free(room->name);
+ free(room->owner);
+ free(room->scheme);
+ free(room->weapons);
+ free(room);
+ }
+}
+
+void flib_roomlist_destroy(flib_roomlist *list) {
+ if(list) {
+ for(int i=0; i<list->roomCount; i++) {
+ flib_roomlist_room_destroy(list->rooms[i]);
+ }
+ free(list);
+ }
+}
+
+static flib_roomlist_room *fillRoomFromParams(char **params) {
+ flib_roomlist_room *result = NULL;
+ flib_roomlist_room *tmpRoom = flib_calloc(1, sizeof(flib_roomlist_room));
+ if(tmpRoom) {
+ tmpRoom->inProgress = !strcmp(params[0], "True");
+ tmpRoom->name = flib_strdupnull(params[1]);
+ tmpRoom->playerCount = atoi(params[2]);
+ tmpRoom->teamCount = atoi(params[3]);
+ tmpRoom->owner = flib_strdupnull(params[4]);
+ tmpRoom->map = flib_strdupnull(params[5]);
+ tmpRoom->scheme = flib_strdupnull(params[6]);
+ tmpRoom->weapons = flib_strdupnull(params[7]);
+ if(tmpRoom->name && tmpRoom->owner && tmpRoom->map && tmpRoom->scheme && tmpRoom->weapons) {
+ result = tmpRoom;
+ tmpRoom = NULL;
+ }
+ }
+ flib_roomlist_room_destroy(tmpRoom);
+ return result;
+}
+
+int flib_roomlist_add(flib_roomlist *list, char **params) {
+ int result = -1;
+ if(!list || !params) {
+ flib_log_e("null parameter in flib_roomlist_add");
+ } else {
+ flib_roomlist_room *tmpRoom = fillRoomFromParams(params);
+ if(tmpRoom) {
+ flib_roomlist_room **rooms = flib_list_insert(list->rooms, &list->roomCount, sizeof(*list->rooms), &tmpRoom, 0);
+ if(rooms) {
+ list->rooms = rooms;
+ tmpRoom = NULL;
+ result = 0;
+ }
+ }
+ flib_roomlist_room_destroy(tmpRoom);
+ }
+ return result;
+}
+
+static int findRoom(flib_roomlist *list, const char *name) {
+ for(int i=0; i<list->roomCount; i++) {
+ if(!strcmp(name, list->rooms[i]->name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int flib_roomlist_update(flib_roomlist *list, const char *name, char **params) {
+ int result = -1;
+ if(!list || !name || !params) {
+ flib_log_e("null parameter in flib_roomlist_update");
+ } else {
+ flib_roomlist_room *tmpRoom = fillRoomFromParams(params);
+ int roomid = findRoom(list, name);
+ if(tmpRoom && roomid>=0) {
+ flib_roomlist_room_destroy(list->rooms[roomid]);
+ list->rooms[roomid] = tmpRoom;
+ tmpRoom = NULL;
+ result = 0;
+ }
+ flib_roomlist_room_destroy(tmpRoom);
+ }
+ return result;
+}
+
+flib_roomlist_room *flib_roomlist_find(flib_roomlist *list, const char *name) {
+ flib_roomlist_room *result = NULL;
+ if(!list || !name) {
+ flib_log_e("null parameter in flib_roomlist_find");
+ } else {
+ int roomid = findRoom(list, name);
+ if(roomid>=0) {
+ result = list->rooms[roomid];
+ }
+ }
+ return result;
+}
+
+void flib_roomlist_clear(flib_roomlist *list) {
+ if(!list) {
+ flib_log_e("null parameter in flib_roomlist_clear");
+ } else {
+ for(int i=0; i<list->roomCount; i++) {
+ flib_roomlist_room_destroy(list->rooms[i]);
+ }
+ free(list->rooms);
+ list->rooms = NULL;
+ list->roomCount = 0;
+ }
+}
+
+int flib_roomlist_delete(flib_roomlist *list, const char *name) {
+ int result = -1;
+ if(!list || !name) {
+ flib_log_e("null parameter in flib_roomlist_delete");
+ } else {
+ int roomid = findRoom(list, name);
+ if(roomid<0) {
+ flib_log_w("Attempt to delete unknown room %s", name);
+ } else {
+ flib_roomlist_room *room = list->rooms[roomid];
+ flib_roomlist_room **rooms = flib_list_delete(list->rooms, &list->roomCount, sizeof(*list->rooms), roomid);
+ if(rooms || list->roomCount==0) {
+ list->rooms = rooms;
+ flib_roomlist_room_destroy(room);
+ result = 0;
+ }
+ }
+ }
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/roomlist.h Thu Jun 21 21:32:12 2012 +0200
@@ -0,0 +1,61 @@
+/**
+ * Models the list of rooms on a server for netplay.
+ */
+
+#ifndef ROOMLIST_H_
+#define ROOMLIST_H_
+
+#include <stdbool.h>
+
+typedef struct {
+ bool inProgress; // true if the game is running
+ char *name;
+ int playerCount;
+ int teamCount;
+ char *owner;
+ char *map; // This is either a map name, or one of +rnd+, +maze+ or +drawn+.
+ char *scheme;
+ char *weapons;
+} flib_roomlist_room;
+
+typedef struct {
+ int roomCount;
+ flib_roomlist_room **rooms;
+} flib_roomlist;
+
+flib_roomlist *flib_roomlist_create();
+
+void flib_roomlist_destroy(flib_roomlist *list);
+
+/**
+ * Insert a new room at the start of the list. The room is defined by the params-array,
+ * which must consist of 8 non-null strings, as sent by the server in netplay.
+ *
+ * Returns 0 on success.
+ */
+int flib_roomlist_add(flib_roomlist *list, char **params);
+
+/**
+ * Update the room with the name [name] with parameters sent by the server.
+ *
+ * Returns 0 on success.
+ */
+int flib_roomlist_update(flib_roomlist *list, const char *name, char **params);
+
+/**
+ * Returns the room with the name [name] from the list if it exists, NULL otherwise
+ */
+flib_roomlist_room *flib_roomlist_find(flib_roomlist *list, const char *name);
+
+/**
+ * Removes all rooms from the list
+ */
+void flib_roomlist_clear(flib_roomlist *list);
+
+/**
+ * Delete the room with the name [name] from the room list.
+ * Returns 0 on success.
+ */
+int flib_roomlist_delete(flib_roomlist *list, const char *name);
+
+#endif
--- a/project_files/frontlib/model/schemelist.c Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/model/schemelist.c Thu Jun 21 21:32:12 2012 +0200
@@ -4,6 +4,7 @@
#include "../util/logging.h"
#include "../util/util.h"
#include "../util/refcounter.h"
+#include "../util/list.h"
#include <stdio.h>
#include <stdlib.h>
@@ -192,38 +193,28 @@
}
int flib_schemelist_insert(flib_schemelist *list, flib_cfg *cfg, int pos) {
- int result = -1;
- if(!list || !cfg || pos < 0 || pos > list->schemeCount) {
- flib_log_e("Invalid parameter in flib_schemelist_insert");
+ flib_cfg **changedList = flib_list_insert(list->schemes, &list->schemeCount, sizeof(*list->schemes), &cfg, pos);
+ if(changedList) {
+ list->schemes = changedList;
+ flib_cfg_retain(cfg);
+ return 0;
} else {
- flib_cfg **newSchemes = flib_realloc(list->schemes, (list->schemeCount+1)*sizeof(*list->schemes));
- if(newSchemes) {
- list->schemes = newSchemes;
- memmove(list->schemes+pos+1, list->schemes+pos, (list->schemeCount-pos)*sizeof(*list->schemes));
- list->schemes[pos] = flib_cfg_retain(cfg);
- list->schemeCount++;
+ return -1;
+ }
+}
+
+int flib_schemelist_delete(flib_schemelist *list, int pos) {
+ int result = -1;
+ if(!list || pos<0 || pos>=list->schemeCount) {
+ flib_log_e("Invalid parameter in flib_schemelist_delete");
+ } else {
+ flib_cfg *elem = list->schemes[pos];
+ flib_cfg **changedList = flib_list_delete(list->schemes, &list->schemeCount, sizeof(*list->schemes), pos);
+ if(changedList || list->schemeCount==0) {
+ list->schemes = changedList;
+ flib_cfg_release(elem);
result = 0;
}
}
return result;
}
-
-int flib_schemelist_delete(flib_schemelist *list, int pos) {
- int result = -1;
- if(!list || pos < 0 || pos >= list->schemeCount) {
- flib_log_e("Invalid parameter in flib_schemelist_delete");
- } else {
- flib_cfg_release(list->schemes[pos]);
- memmove(list->schemes+pos, list->schemes+pos+1, (list->schemeCount-(pos+1))*sizeof(*list->schemes));
- list->schemes[list->schemeCount-1] = NULL;
- list->schemeCount--;
-
- // If the realloc fails, just keep using the old buffer...
- flib_cfg **newSchemes = flib_realloc(list->schemes, list->schemeCount*sizeof(*list->schemes));
- if(newSchemes || list->schemeCount==1) {
- list->schemes = newSchemes;
- }
- result = 0;
- }
- return result;
-}
--- a/project_files/frontlib/model/team.h Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/model/team.h Thu Jun 21 21:32:12 2012 +0200
@@ -1,19 +1,25 @@
+/**
+ * This file defines a data structure for a hedgewars team.
+ *
+ * Teams are used in several different contexts in Hedgewars, and some of these require
+ * extra information about teams. For example, the weaponset is important
+ * to the engine, but not for ini reading/writing, and with the team statistics it is the
+ * other way around. To keep things simple, the data structure can hold all information
+ * used in any context. On the downside, tat means we can't use static typing to ensure
+ * that team information is "complete" for a particular purpose.
+ */
#ifndef TEAM_H_
#define TEAM_H_
+
#include "weapon.h"
#include "../hwconsts.h"
#include <stdbool.h>
#include <stdint.h>
-#define TEAM_DEFAULT_HOGNAME "Hog"
-#define TEAM_DEFAULT_HAT "NoHat"
-#define TEAM_DEFAULT_DIFFICULTY 0
#define TEAM_DEFAULT_HEALTH 100
-// TODO default bindings?
-
typedef struct {
char *action;
char *binding;
--- a/project_files/frontlib/model/weapon.c Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/model/weapon.c Thu Jun 21 21:32:12 2012 +0200
@@ -4,6 +4,7 @@
#include "../util/logging.h"
#include "../util/util.h"
#include "../util/refcounter.h"
+#include "../util/list.h"
#include <stdlib.h>
#include <ctype.h>
@@ -187,39 +188,29 @@
return flib_weaponsetlist_retain(flib_calloc(1, sizeof(flib_weaponsetlist)));
}
-int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *weaponset, int pos) {
- int result = -1;
- if(!list || !weaponset || pos < 0 || pos > list->weaponsetCount) {
- flib_log_e("Invalid parameter in flib_weaponsetlist_insert");
+int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *set, int pos) {
+ flib_weaponset **changedList = flib_list_insert(list->weaponsets, &list->weaponsetCount, sizeof(*list->weaponsets), &set, pos);
+ if(changedList) {
+ list->weaponsets = changedList;
+ flib_weaponset_retain(set);
+ return 0;
} else {
- flib_weaponset **newSets = flib_realloc(list->weaponsets, (list->weaponsetCount+1)*sizeof(*list->weaponsets));
- if(newSets) {
- list->weaponsets = newSets;
- memmove(list->weaponsets+pos+1, list->weaponsets+pos, (list->weaponsetCount-pos)*sizeof(*list->weaponsets));
- list->weaponsets[pos] = flib_weaponset_retain(weaponset);
- list->weaponsetCount++;
- result = 0;
- }
+ return -1;
}
- return result;
}
int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos) {
int result = -1;
- if(!list || pos < 0 || pos >= list->weaponsetCount) {
+ if(!list || pos<0 || pos>=list->weaponsetCount) {
flib_log_e("Invalid parameter in flib_weaponsetlist_delete");
} else {
- flib_weaponset_release(list->weaponsets[pos]);
- memmove(list->weaponsets+pos, list->weaponsets+pos+1, (list->weaponsetCount-(pos+1))*sizeof(*list->weaponsets));
- list->weaponsets[list->weaponsetCount-1] = NULL;
- list->weaponsetCount--;
-
- // If the realloc fails, just keep using the old buffer...
- flib_weaponset **newSets = flib_realloc(list->weaponsets, list->weaponsetCount*sizeof(*list->weaponsets));
- if(newSets || list->weaponsetCount==1) {
- list->weaponsets = newSets;
+ flib_weaponset *elem = list->weaponsets[pos];
+ flib_weaponset **changedList = flib_list_delete(list->weaponsets, &list->weaponsetCount, sizeof(*list->weaponsets), pos);
+ if(changedList || list->weaponsetCount==0) {
+ list->weaponsets = changedList;
+ flib_weaponset_release(elem);
+ result = 0;
}
- result = 0;
}
return result;
}
--- a/project_files/frontlib/net/netconn.c Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/net/netconn.c Thu Jun 21 21:32:12 2012 +0200
@@ -23,53 +23,178 @@
#include "netprotocol.h"
#include "../util/logging.h"
#include "../util/util.h"
+#include "../model/roomlist.h"
+#include "../md5/md5.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <ctype.h>
struct _flib_netconn {
flib_netbase *netBase;
char *playerName;
+ flib_cfg_meta *metaCfg;
+ flib_roomlist *roomList;
int netconnState; // One of the NETCONN_STATE constants
- void (*onErrorCb)(void* context, int errorCode, const char *errorMsg);
- void *onErrorCtx;
+ bool isAdmin; // Player is server administrator
+ bool isChief; // Player can modify the current room
+
+
+ void (*onMessageCb)(void *context, int msgtype, const char *msg);
+ void *onMessageCtx;
+
+ void (*onConnectedCb)(void *context);
+ void *onConnectedCtx;
+
+ void (*onDisconnectedCb)(void *context, int reason, const char *message);
+ void *onDisconnectedCtx;
+
+ void (*onRoomAddCb)(void *context, const flib_roomlist_room *room);
+ void *onRoomAddCtx;
+
+ void (*onRoomDeleteCb)(void *context, const char *name);
+ void *onRoomDeleteCtx;
+
+ void (*onRoomUpdateCb)(void *context, const char *oldName, const flib_roomlist_room *room);
+ void *onRoomUpdateCtx;
+
+ void (*onChatCb)(void *context, const char *nick, const char *msg);
+ void *onChatCtx;
+
+ void (*onLobbyJoinCb)(void *context, const char *nick);
+ void *onLobbyJoinCtx;
- void (*onConnectedCb)(void *context, const char *serverMessage);
- void *onConnectedCtx;
+ void (*onLobbyLeaveCb)(void *context, const char *nick, const char *partMessage);
+ void *onLobbyLeaveCtx;
+
+ void (*onRoomJoinCb)(void *context, const char *nick);
+ void *onRoomJoinCtx;
+
+ void (*onRoomLeaveCb)(void *context, const char *nick, const char *partMessage);
+ void *onRoomLeaveCtx;
+
+ void (*onNickTakenCb)(void *context, const char *nick);
+ void *onNickTakenCtx;
+
+ void (*onNickAcceptCb)(void *context, const char *nick);
+ void *onNickAcceptCtx;
+
+ void (*onPasswordRequestCb)(void *context, const char *nick);
+ void *onPasswordRequestCtx;
+
+ void (*onRoomChiefStatusCb)(void *context, bool isChief);
+ void *onRoomChiefStatusCtx;
+
+ void (*onReadyStateCb)(void *context, const char *nick, bool ready);
+ void *onReadyStateCtx;
+
+ void (*onEnterRoomCb)(void *context, bool chief);
+ void *onEnterRoomCtx;
+
+ void (*onLeaveRoomCb)(void *context, int reason, const char *message);
+ void *onLeaveRoomCtx;
+
+ void (*onTeamAddCb)(void *context, flib_team *team);
+ void *onTeamAddCtx;
bool running;
bool destroyRequested;
};
-static void defaultCallback_onError(void* context, int errorCode, const char *errormsg) {}
-static void defaultCallback_onConnected(void *context, const char *serverMessage) {}
+static void defaultCallback_onMessage(void *context, int msgtype, const char *msg) {
+ flib_log_i("Net: [%i] %s", msgtype, msg);
+}
+
+static void defaultCallback_void(void *context) {}
+static void defaultCallback_bool(void *context, bool isChief) {}
+static void defaultCallback_str(void *context, const char *str) {}
+static void defaultCallback_int_str(void *context, int i, const char *str) {}
+static void defaultCallback_str_str(void *context, const char *str1, const char *str2) {}
+static void defaultCallback_str_bool(void *context, const char *str, bool b) {}
+
+static void defaultCallback_onRoomAdd(void *context, const flib_roomlist_room *room) {}
+static void defaultCallback_onRoomUpdate(void *context, const char *oldName, const flib_roomlist_room *room) {}
+static void defaultCallback_onChat(void *context, const char *nick, const char *msg) {
+ flib_log_i("%s: %s", nick, msg);
+}
-static void clearCallbacks(flib_netconn *conn) {
- conn->onErrorCb = &defaultCallback_onError;
- conn->onConnectedCb = &defaultCallback_onConnected;
+// Change the name by suffixing it with a number. If it already ends in a number, increase that number by 1.
+static void defaultCallback_onNickTaken(void *context, const char *requestedNick) {
+ flib_netconn *conn = context;
+ size_t namelen = strlen(requestedNick);
+ int digits = 0;
+ while(digits<namelen && isdigit(requestedNick[namelen-1-digits])) {
+ digits++;
+ }
+ long suffix = 0;
+ if(digits>0) {
+ suffix = atol(requestedNick+namelen-digits)+1;
+ }
+ char *newPlayerName = flib_asprintf("%.*s%li", namelen-digits, requestedNick, suffix);
+ if(newPlayerName) {
+ flib_netconn_send_nick(conn, newPlayerName);
+ } else {
+ flib_netconn_send_quit(conn, "Nick already taken.");
+ }
+ free(newPlayerName);
+}
+
+// Default behavior: Quit
+static void defaultCallback_onPasswordRequest(void *context, const char *requestedNick) {
+ flib_netconn_send_quit((flib_netconn*)context, "Authentication failed");
}
+static void defaultCallback_onTeamAdd(void *context, flib_team *team) {}
-flib_netconn *flib_netconn_create(const char *playerName, const char *host, uint16_t port) {
+static void clearCallbacks(flib_netconn *conn) {
+ flib_netconn_onMessage(conn, NULL, NULL);
+ flib_netconn_onConnected(conn, NULL, NULL);
+ flib_netconn_onDisconnected(conn, NULL, NULL);
+ flib_netconn_onRoomAdd(conn, NULL, NULL);
+ flib_netconn_onRoomDelete(conn, NULL, NULL);
+ flib_netconn_onRoomUpdate(conn, NULL, NULL);
+ flib_netconn_onChat(conn, NULL, NULL);
+ flib_netconn_onLobbyJoin(conn, NULL, NULL);
+ flib_netconn_onLobbyLeave(conn, NULL, NULL);
+ flib_netconn_onRoomJoin(conn, NULL, NULL);
+ flib_netconn_onRoomLeave(conn, NULL, NULL);
+ flib_netconn_onNickTaken(conn, NULL, NULL);
+ flib_netconn_onNickAccept(conn, NULL, NULL);
+ flib_netconn_onPasswordRequest(conn, NULL, NULL);
+ flib_netconn_onRoomChiefStatus(conn, NULL, NULL);
+ flib_netconn_onReadyStateCb(conn, NULL, NULL);
+ flib_netconn_onEnterRoomCb(conn, NULL, NULL);
+ flib_netconn_onTeamAddCb(conn, NULL, NULL);
+}
+
+flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *host, uint16_t port) {
flib_netconn *result = NULL;
- flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn));
- if(newConn) {
- newConn->netconnState = NETCONN_STATE_AWAIT_CONNECTED;
- newConn->running = false;
- newConn->destroyRequested = false;
- clearCallbacks(newConn);
- newConn->netBase = flib_netbase_create(host, port);
- newConn->playerName = flib_strdupnull(playerName);
- if(newConn->netBase && newConn->playerName) {
- result = newConn;
- newConn = NULL;
+ if(!playerName || !metacfg || !host) {
+ flib_log_e("null parameter in flib_netconn_create");
+ } else {
+ flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn));
+ if(newConn) {
+ newConn->netconnState = NETCONN_STATE_CONNECTING;
+ newConn->isAdmin = false;
+ newConn->isChief = false;
+ newConn->metaCfg = flib_cfg_meta_retain(metacfg);
+ newConn->roomList = flib_roomlist_create();
+ newConn->running = false;
+ newConn->destroyRequested = false;
+ clearCallbacks(newConn);
+ newConn->netBase = flib_netbase_create(host, port);
+ newConn->playerName = flib_strdupnull(playerName);
+ if(newConn->netBase && newConn->playerName && newConn->roomList) {
+ result = newConn;
+ newConn = NULL;
+ }
}
+ flib_netconn_destroy(newConn);
}
- flib_netconn_destroy(newConn);
return result;
}
@@ -85,27 +210,271 @@
conn->destroyRequested = true;
} else {
flib_netbase_destroy(conn->netBase);
+ flib_cfg_meta_release(conn->metaCfg);
+ flib_roomlist_destroy(conn->roomList);
free(conn->playerName);
free(conn);
}
}
}
-void flib_netconn_onError(flib_netconn *conn, void (*callback)(void *context, int errorCode, const char *errorMsg), void* context) {
+const flib_roomlist *flib_netconn_get_roomlist(flib_netconn *conn) {
+ const flib_roomlist *result = NULL;
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_get_roomlist");
+ } else {
+ result = conn->roomList;
+ }
+ return result;
+}
+
+bool flib_netconn_is_chief(flib_netconn *conn) {
+ bool result = false;
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_is_chief");
+ } else if(conn->netconnState == NETCONN_STATE_ROOM || conn->netconnState == NETCONN_STATE_INGAME) {
+ result = conn->isChief;
+ }
+ return result;
+}
+
+int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg) {
+ int result = -1;
if(!conn) {
- flib_log_e("null parameter in flib_netconn_onError");
+ flib_log_e("null parameter in flib_netconn_send_quit");
+ } else {
+ result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "QUIT", quitmsg ? quitmsg : "User quit");
+ }
+ return result;
+}
+
+int flib_netconn_send_chat(flib_netconn *conn, const char *chat) {
+ int result = -1;
+ if(!conn || !chat) {
+ flib_log_e("null parameter in flib_netconn_send_chat");
+ } else {
+ result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "CHAT", chat);
+ }
+ return result;
+}
+
+int flib_netconn_send_nick(flib_netconn *conn, const char *nick) {
+ int result = -1;
+ if(!conn || !nick) {
+ flib_log_e("null parameter in flib_netconn_send_nick");
+ } else {
+ char *tmpName = flib_strdupnull(nick);
+ if(tmpName) {
+ if(!flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "NICK", nick)) {
+ free(conn->playerName);
+ conn->playerName = tmpName;
+ tmpName = NULL;
+ result = 0;
+ }
+ }
+ free(tmpName);
+ }
+ return result;
+}
+
+int flib_netconn_send_password(flib_netconn *conn, const char *latin1Passwd) {
+ int result = -1;
+ if(!conn || !latin1Passwd) {
+ flib_log_e("null parameter in flib_netconn_send_password");
} else {
- conn->onErrorCb = callback ? callback : &defaultCallback_onError;
- conn->onErrorCtx = context;
+ md5_state_t md5state;
+ uint8_t md5bytes[16];
+ char md5hex[33];
+ md5_init(&md5state);
+ md5_append(&md5state, (unsigned char*)latin1Passwd, strlen(latin1Passwd));
+ md5_finish(&md5state, md5bytes);
+ for(int i=0;i<sizeof(md5bytes); i++) {
+ // Needs to be lowercase - server checks case sensitive
+ snprintf(md5hex+i*2, 3, "%02x", (unsigned)md5bytes[i]);
+ }
+ result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "PASSWORD", md5hex);
+ }
+ return result;
+}
+
+/*
+ * Callback registration functions
+ */
+
+void flib_netconn_onMessage(flib_netconn *conn, void (*callback)(void *context, int msgtype, const char *msg), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onMessage");
+ } else {
+ conn->onMessageCb = callback ? callback : &defaultCallback_onMessage;
+ conn->onMessageCtx = context;
+ }
+}
+
+void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onConnected");
+ } else {
+ conn->onConnectedCb = callback ? callback : &defaultCallback_void;
+ conn->onConnectedCtx = context;
+ }
+}
+
+void flib_netconn_onDisconnected(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onDisconnected");
+ } else {
+ conn->onDisconnectedCb = callback ? callback : &defaultCallback_int_str;
+ conn->onDisconnectedCtx = context;
+ }
+}
+
+void flib_netconn_onRoomAdd(flib_netconn *conn, void (*callback)(void *context, const flib_roomlist_room *room), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onRoomAdd");
+ } else {
+ conn->onRoomAddCb = callback ? callback : &defaultCallback_onRoomAdd;
+ conn->onRoomAddCtx = context;
+ }
+}
+
+void flib_netconn_onRoomDelete(flib_netconn *conn, void (*callback)(void *context, const char *name), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onRoomDelete");
+ } else {
+ conn->onRoomDeleteCb = callback ? callback : &defaultCallback_str;
+ conn->onRoomDeleteCtx = context;
}
}
-void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context, const char *serverMessage), void* context) {
+void flib_netconn_onRoomUpdate(flib_netconn *conn, void (*callback)(void *context, const char *oldName, const flib_roomlist_room *room), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onRoomUpdate");
+ } else {
+ conn->onRoomUpdateCb = callback ? callback : &defaultCallback_onRoomUpdate;
+ conn->onRoomUpdateCtx = context;
+ }
+}
+
+void flib_netconn_onChat(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *msg), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onChat");
+ } else {
+ conn->onChatCb = callback ? callback : &defaultCallback_onChat;
+ conn->onChatCtx = context;
+ }
+}
+
+void flib_netconn_onLobbyJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onLobbyJoin");
+ } else {
+ conn->onLobbyJoinCb = callback ? callback : &defaultCallback_str;
+ conn->onLobbyJoinCtx = context;
+ }
+}
+
+void flib_netconn_onLobbyLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMsg), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onLobbyLeave");
+ } else {
+ conn->onLobbyLeaveCb = callback ? callback : &defaultCallback_str_str;
+ conn->onLobbyLeaveCtx = context;
+ }
+}
+
+void flib_netconn_onRoomJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onRoomJoin");
+ } else {
+ conn->onRoomJoinCb = callback ? callback : &defaultCallback_str;
+ conn->onRoomJoinCtx = context;
+ }
+}
+
+void flib_netconn_onRoomLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMessage), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onRoomLeave");
+ } else {
+ conn->onRoomLeaveCb = callback ? callback : &defaultCallback_str_str;
+ conn->onRoomLeaveCtx = context;
+ }
+}
+
+void flib_netconn_onNickTaken(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) {
if(!conn) {
- flib_log_e("null parameter in flib_netconn_onConnected");
+ flib_log_e("null parameter in flib_netconn_onNickTaken");
+ } else if(!callback) {
+ conn->onNickTakenCb = &defaultCallback_onNickTaken;
+ conn->onNickTakenCtx = conn;
+ } else {
+ conn->onNickTakenCb = callback;
+ conn->onNickTakenCtx = context;
+ }
+}
+
+void flib_netconn_onNickAccept(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onNickAccept");
+ } else {
+ conn->onNickAcceptCb = callback ? callback : &defaultCallback_str;
+ conn->onNickAcceptCtx = context;
+ }
+}
+
+void flib_netconn_onPasswordRequest(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onPasswordRequest");
+ } else if(!callback) {
+ conn->onPasswordRequestCb = &defaultCallback_onPasswordRequest;
+ conn->onPasswordRequestCtx = conn;
+ } else {
+ conn->onPasswordRequestCb = callback;
+ conn->onPasswordRequestCtx = context;
+ }
+}
+
+void flib_netconn_onRoomChiefStatus(flib_netconn *conn, void (*callback)(void *context, bool chief), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onRoomChiefStatus");
} else {
- conn->onConnectedCb = callback ? callback : &defaultCallback_onConnected;
- conn->onConnectedCtx = context;
+ conn->onRoomChiefStatusCb = callback ? callback : &defaultCallback_bool;
+ conn->onRoomChiefStatusCtx = context;
+ }
+}
+
+void flib_netconn_onReadyStateCb(flib_netconn *conn, void (*callback)(void *context, const char *nick, bool ready), void* context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onReadyStateCb");
+ } else {
+ conn->onReadyStateCb = callback ? callback : &defaultCallback_str_bool;
+ conn->onReadyStateCtx = context;
+ }
+}
+
+void flib_netconn_onEnterRoomCb(flib_netconn *conn, void (*callback)(void *context, bool chief), void *context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onEnterRoomCb");
+ } else {
+ conn->onEnterRoomCb = callback ? callback : &defaultCallback_bool;
+ conn->onEnterRoomCtx = context;
+ }
+}
+
+void flib_netconn_onLeaveRoomCb(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void *context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onLeaveRoomCb");
+ } else {
+ conn->onLeaveRoomCb = callback ? callback : &defaultCallback_int_str;
+ conn->onLeaveRoomCtx = context;
+ }
+}
+
+void flib_netconn_onTeamAddCb(flib_netconn *conn, void (*callback)(void *context, flib_team *team), void *context) {
+ if(!conn) {
+ flib_log_e("null parameter in flib_netconn_onTeamAddCb");
+ } else {
+ conn->onTeamAddCb = callback ? callback : &defaultCallback_onTeamAdd;
+ conn->onTeamAddCtx = context;
}
}
@@ -120,43 +489,54 @@
continue;
}
+ if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
+ char *buf = flib_join(netmsg->parts, netmsg->partCount, "|");
+ if(buf) {
+ flib_log_d("[Net In]%s", buf);
+ }
+ free(buf);
+ }
+
const char *cmd = netmsg->parts[0];
if (!strcmp(cmd, "NICK") && netmsg->partCount>=2) {
- free(conn->playerName);
- conn->playerName = flib_strdupnull(netmsg->parts[1]);
- if(!conn->playerName) {
- // TODO handle error
+ if(netmsg->partCount<2) {
+ flib_log_w("Net: Malformed NICK message");
+ } else {
+ free(conn->playerName);
+ conn->playerName = flib_strdupnull(netmsg->parts[1]);
+ if(!conn->playerName) {
+ conn->netconnState = NETCONN_STATE_DISCONNECTED;
+ conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Out of memory");
+ exit = true;
+ } else {
+ conn->onNickAcceptCb(conn->onNickAcceptCtx, conn->playerName);
+ }
}
- // TODO callback?
} else if (!strcmp(cmd, "PROTO")) {
// The server just echoes this back apparently
} else if (!strcmp(cmd, "ERROR")) {
- // TODO: onErrorMessage?
- if (netmsg->partCount == 2) {
- conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, netmsg->parts[1]);
+ if (netmsg->partCount >= 2) {
+ conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_ERROR, netmsg->parts[1]);
} else {
- conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, "Unknown Error");
+ conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_ERROR, "Unknown Error");
}
} else if(!strcmp(cmd, "WARNING")) {
- // TODO: onWarnMessage?
- if (netmsg->partCount == 2) {
- conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, netmsg->parts[1]);
+ if (netmsg->partCount >= 2) {
+ conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_WARNING, netmsg->parts[1]);
} else {
- conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, "Unknown Warning");
+ conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_WARNING, "Unknown Warning");
}
} else if(!strcmp(cmd, "CONNECTED")) {
if(netmsg->partCount<3 || atol(netmsg->parts[2])<MIN_SERVER_VERSION) {
- flib_log_w("Server too old");
+ flib_log_w("Net: Server too old");
flib_netbase_sendf(net, "%s\n%s\n\n", "QUIT", "Server too old");
- // TODO actually disconnect?
conn->netconnState = NETCONN_STATE_DISCONNECTED;
- conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_SERVER_TOO_OLD, "Server too old");
+ conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_SERVER_TOO_OLD, "Server too old");
exit = true;
} else {
flib_netbase_sendf(net, "%s\n%s\n\n", "NICK", conn->playerName);
flib_netbase_sendf(net, "%s\n%i\n\n", "PROTO", (int)PROTOCOL_VERSION);
- conn->netconnState = NETCONN_STATE_LOBBY;
}
} else if(!strcmp(cmd, "PING")) {
if (netmsg->partCount > 1) {
@@ -168,39 +548,39 @@
if(netmsg->partCount % 8 != 1) {
flib_log_w("Net: Malformed ROOMS message");
} else {
- // TODO
- //QStringList tmp = lst;
- //tmp.removeFirst();
- //m_roomsListModel->setRoomsList(tmp);
+ flib_roomlist_clear(conn->roomList);
+ for(int i=1; i<netmsg->partCount; i+=8) {
+ if(flib_roomlist_add(conn->roomList, netmsg->parts+i)) {
+ flib_log_e("Error adding room to list in ROOMS message");
+ }
+ }
+ if(conn->netconnState == NETCONN_STATE_CONNECTING) {
+ // We delay the "connected" callback until now to ensure the room list is avaliable.
+ conn->onConnectedCb(conn->onConnectedCtx);
+ conn->netconnState = NETCONN_STATE_LOBBY;
+ }
}
} else if (!strcmp(cmd, "SERVER_MESSAGE")) {
if(netmsg->partCount < 2) {
flib_log_w("Net: Empty SERVERMESSAGE message");
} else {
- // TODO
- // emit serverMessage(lst[1]);
+ conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_SERVERMESSAGE, netmsg->parts[1]);
}
} else if (!strcmp(cmd, "CHAT")) {
if(netmsg->partCount < 3) {
flib_log_w("Net: Empty CHAT message");
} else {
- // TODO
- // if (netClientState == InLobby)
- // emit chatStringLobby(lst[1], HWProto::formatChatMsgForFrontend(lst[2]));
- // else
- // emit chatStringFromNet(HWProto::formatChatMsg(lst[1], lst[2]));
+ conn->onChatCb(conn->onChatCtx, netmsg->parts[1], netmsg->parts[2]);
}
} else if (!strcmp(cmd, "INFO")) {
if(netmsg->partCount < 5) {
flib_log_w("Net: Malformed INFO message");
} else {
- // TODO
-// QStringList tmp = lst;
-// tmp.removeFirst();
-// if (netClientState == InLobby)
-// emit chatStringLobby(tmp.join("\n").prepend('\x01'));
-// else
-// emit chatStringFromNet(tmp.join("\n").prepend('\x01'));
+ char *joined = flib_join(netmsg->parts+1, netmsg->partCount-1, "\n");
+ if(joined) {
+ conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_PLAYERINFO, joined);
+ }
+ free(joined);
}
} else if(!strcmp(cmd, "SERVER_VARS")) {
// TODO
@@ -227,12 +607,12 @@
case 'r':
for(int j = 2; j < netmsg->partCount; ++j) {
if (!strcmp(conn->playerName, netmsg->parts[i])) {
- // TODO
- // if (isChief && !setFlag) ToggleReady();
- // else emit setMyReadyStatus(setFlag);
+ // TODO what is the reason behind this (copied from QtFrontend)?
+ if (conn->isChief && !setFlag) {
+ flib_netbase_sendf(conn->netBase, "%s\n\n", "TOGGLE_READY");
+ }
}
- // TODO
- // emit setReadyStatus(lst[i], setFlag);
+ conn->onReadyStateCb(conn->onReadyStateCtx, netmsg->parts[i], setFlag);
}
break;
default:
@@ -245,10 +625,14 @@
if(netmsg->partCount != 24) {
flib_log_w("Net: Bad ADD_TEAM message");
} else {
- // TODO
-// QStringList tmp = lst;
-// tmp.removeFirst();
-// emit AddNetTeam(tmp);
+ flib_team *team = flib_team_from_netmsg(netmsg->parts+1);
+ if(!team) {
+ conn->netconnState = NETCONN_STATE_DISCONNECTED;
+ conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Internal error");
+ exit = true;
+ } else {
+ conn->onTeamAddCb(conn->onTeamAddCtx, team);
+ }
}
} else if (!strcmp(cmd, "REMOVE_TEAM")) {
if(netmsg->partCount != 2) {
@@ -259,14 +643,10 @@
}
} else if(!strcmp(cmd, "ROOMABANDONED")) {
conn->netconnState = NETCONN_STATE_LOBBY;
-// TODO
-// askRoomsList();
-// emit LeftRoom(tr("Room destroyed"));
+ conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_ABANDONED, "Room destroyed");
} else if(!strcmp(cmd, "KICKED")) {
conn->netconnState = NETCONN_STATE_LOBBY;
-// TODO
-// askRoomsList();
-// emit LeftRoom(tr("You got kicked"));
+ conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_KICKED, "You got kicked");
} else if(!strcmp(cmd, "JOINED")) {
if(netmsg->partCount < 2) {
flib_log_w("Net: Bad JOINED message");
@@ -276,16 +656,10 @@
bool isMe = !strcmp(conn->playerName, netmsg->parts[i]);
if (isMe) {
conn->netconnState = NETCONN_STATE_ROOM;
-// TODO
-// emit EnteredGame();
-// emit roomMaster(isChief);
-// if (isChief)
-// emit configAsked();
+ conn->onEnterRoomCb(conn->onEnterRoomCtx, conn->isChief);
}
-// TODO
-// emit nickAdded(lst[i], isChief && !isMe));
-// emit chatStringFromNet(tr("%1 *** %2 has joined the room").arg('\x03').arg(lst[i]));
+ conn->onRoomJoinCb(conn->onRoomJoinCtx, netmsg->parts[i]);
}
}
} else if(!strcmp(cmd, "LOBBY:JOINED")) {
@@ -296,47 +670,43 @@
{
bool isMe = !strcmp(conn->playerName, netmsg->parts[i]);
if (isMe) {
- conn->netconnState = NETCONN_STATE_LOBBY;
- // TODO
-// RawSendNet(QString("LIST"));
-// emit connected();
+ if(flib_netbase_sendf(conn->netBase, "%s\n\n", "LIST")) {
+ // If sending this fails, the protocol breaks (we'd be waiting infinitely for the room list)
+ flib_netbase_sendf(net, "%s\n%s\n\n", "QUIT", "Client error");
+ conn->netconnState = NETCONN_STATE_DISCONNECTED;
+ conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Failed to send a critical message.");
+ exit = true;
+ }
}
- // TODO
-// emit nickAddedLobby(lst[i], false);
-// emit chatStringLobby(lst[i], tr("%1 *** %2 has joined").arg('\x03').arg("|nick|"));
+ conn->onLobbyJoinCb(conn->onLobbyJoinCtx, netmsg->parts[i]);
}
}
} else if(!strcmp(cmd, "LEFT")) {
if(netmsg->partCount < 2) {
flib_log_w("Net: Bad LEFT message");
} else {
- // TODO
-// emit nickRemoved(lst[1]);
-// if (netmsg->partCount < 3)
-// emit chatStringFromNet(tr("%1 *** %2 has left").arg('\x03').arg(lst[1]));
-// else
-// emit chatStringFromNet(tr("%1 *** %2 has left (%3)").arg('\x03').arg(lst[1], lst[2]));
+ conn->onRoomLeaveCb(conn->onRoomLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
}
} else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) {
const char *subcmd = netmsg->parts[1];
if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) {
- // TODO
-// QStringList tmp = lst;
-// tmp.removeFirst();
-// tmp.removeFirst();
-//
-// m_roomsListModel->addRoom(tmp);
+ if(flib_roomlist_add(conn->roomList, netmsg->parts+2)) {
+ flib_log_e("Error adding new room to list");
+ } else {
+ conn->onRoomAddCb(conn->onRoomAddCtx, conn->roomList->rooms[0]);
+ }
} else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) {
- // TODO
-// QStringList tmp = lst;
-// tmp.removeFirst();
-// tmp.removeFirst();
-//
-// QString roomName = tmp.takeFirst();
-// m_roomsListModel->updateRoom(roomName, tmp);
+ if(flib_roomlist_update(conn->roomList, netmsg->parts[2], netmsg->parts+3)) {
+ flib_log_e("Error updating room in list");
+ } else {
+ conn->onRoomUpdateCb(conn->onRoomUpdateCtx, netmsg->parts[2], flib_roomlist_find(conn->roomList, netmsg->parts[2]));
+ }
} else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) {
- // TODO
- // m_roomsListModel->removeRoom(lst[2]);
+ if(flib_roomlist_delete(conn->roomList, netmsg->parts[2])) {
+ flib_log_e("Error deleting room from list");
+ } else {
+ conn->onRoomDeleteCb(conn->onRoomDeleteCtx, netmsg->parts[2]);
+ }
} else {
flib_log_w("Net: Unknown or malformed ROOM subcommand: %s", subcmd);
}
@@ -344,20 +714,14 @@
if(netmsg->partCount < 2) {
flib_log_w("Net: Bad LOBBY:LEFT message");
} else {
- // TODO
-// emit nickRemovedLobby(lst[1]);
-// if (netmsg->partCount < 3)
-// emit chatStringLobby(tr("%1 *** %2 has left").arg('\x03').arg(lst[1]));
-// else
-// emit chatStringLobby(lst[1], tr("%1 *** %2 has left (%3)").arg('\x03').arg("|nick|", lst[2]));
+ conn->onLobbyLeaveCb(conn->onLobbyLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
}
} else if (!strcmp(cmd, "RUN_GAME")) {
conn->netconnState = NETCONN_STATE_INGAME;
// TODO
// emit AskForRunGame();
} else if (!strcmp(cmd, "ASKPASSWORD")) {
- // TODO
- // emit AskForPassword(mynick);
+ conn->onPasswordRequestCb(conn->onPasswordRequestCtx, conn->playerName);
} else if (!strcmp(cmd, "NOTICE")) {
if(netmsg->partCount < 2) {
flib_log_w("Net: Bad NOTICE message");
@@ -366,9 +730,10 @@
long n = strtol(netmsg->parts[1], NULL, 10);
if(errno) {
flib_log_w("Net: Bad NOTICE message");
+ } else if(n==0) {
+ conn->onNickTakenCb(conn->onNickTakenCtx, conn->playerName);
} else {
- // TODO
- // handleNotice(n);
+ flib_log_w("Net: Unknown NOTICE message: %l", n);
}
}
} else if (!strcmp(cmd, "TEAM_ACCEPTED")) {
@@ -423,25 +788,23 @@
if (netmsg->partCount < 2) {
flib_log_w("Net: Bad BYE message");
} else {
+ conn->netconnState = NETCONN_STATE_DISCONNECTED;
if (!strcmp(netmsg->parts[1], "Authentication failed")) {
- // TODO
- //emit AuthFailed();
+ conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_AUTH_FAILED, netmsg->parts[1]);
+ } else {
+ conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_NORMAL, netmsg->parts[1]);
}
- // TODO
-// m_game_connected = false;
-// Disconnect();
-// emit disconnected(lst[1]);
+ exit = true;
}
} else if (!strcmp(cmd, "ADMIN_ACCESS")) {
- // TODO
- // emit adminAccess(true);
+ // TODO callback?
+ conn->isAdmin = true;
} else if (!strcmp(cmd, "ROOM_CONTROL_ACCESS")) {
if (netmsg->partCount < 2) {
flib_log_w("Net: Bad ROOM_CONTROL_ACCESS message");
} else {
- // TODO
-// isChief = (lst[1] != "0");
-// emit roomMaster(isChief);
+ conn->isChief = strcmp("0", netmsg->parts[1]);
+ conn->onRoomChiefStatusCb(conn->onRoomChiefStatusCtx, conn->isChief);
}
} else {
flib_log_w("Unknown server command: %s", cmd);
--- a/project_files/frontlib/net/netconn.h Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/net/netconn.h Thu Jun 21 21:32:12 2012 +0200
@@ -2,44 +2,178 @@
#define NETCONN_H_
#include "../model/gamesetup.h"
+#include "../model/cfg.h"
+#include "../model/roomlist.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
-#define NETCONN_STATE_AWAIT_CONNECTED 0
+#define NETCONN_STATE_CONNECTING 0
#define NETCONN_STATE_LOBBY 1
#define NETCONN_STATE_ROOM 2
#define NETCONN_STATE_INGAME 3
#define NETCONN_STATE_DISCONNECTED 10
-#define NETCONN_ERROR_SERVER_TOO_OLD 1
-#define NETCONN_ERROR_FROM_SERVER 2
+#define NETCONN_DISCONNECT_NORMAL 0
+#define NETCONN_DISCONNECT_SERVER_TOO_OLD 1
+#define NETCONN_DISCONNECT_AUTH_FAILED 2
+#define NETCONN_DISCONNECT_INTERNAL_ERROR 100
+
+#define NETCONN_ROOMLEAVE_ABANDONED 0
+#define NETCONN_ROOMLEAVE_KICKED 1
+
+#define NETCONN_MSG_TYPE_PLAYERINFO 0
+#define NETCONN_MSG_TYPE_SERVERMESSAGE 1
+#define NETCONN_MSG_TYPE_WARNING 2
+#define NETCONN_MSG_TYPE_ERROR 3
+
struct _flib_netconn;
typedef struct _flib_netconn flib_netconn;
-flib_netconn *flib_netconn_create(const char *playerName, const char *host, uint16_t port);
+flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *host, uint16_t port);
void flib_netconn_destroy(flib_netconn *conn);
/**
- * This is called when we can't stay connected due to a problem, e.g. because the
- * server version is too old, or we are unexpectedly disconnected.
- *
- * Once this callback has been called, you should destroy the flib_netconn.
- */
-void flib_netconn_onError(flib_netconn *conn, void (*callback)(void *context, int errorCode, const char *errormsg), void* context);
-
-/**
- * This is called when we receive a CONNECTED message from the server, which should be the first
- * message arriving from the server.
- */
-void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context, const char *serverMessage), void* context);
-
-/**
* Perform I/O operations and call callbacks if something interesting happens.
* Should be called regularly.
*/
void flib_netconn_tick(flib_netconn *conn);
+
+/**
+ * Return the current roomlist. Don't free or modify.
+ */
+const flib_roomlist *flib_netconn_get_roomlist(flib_netconn *conn);
+
+/**
+ * Are you currently the owner of this room? The return value only makes sense in
+ * NETCONN_STATE_ROOM and NETCONN_STATE_INGAME states.
+ */
+bool flib_netconn_is_chief(flib_netconn *conn);
+
+/**
+ * quitmsg may be null
+ */
+int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg);
+int flib_netconn_send_chat(flib_netconn *conn, const char *chat);
+
+/**
+ * Note: Most other functions in this lib accept UTF-8, but the password needs to be
+ * sent as latin1
+ */
+int flib_netconn_send_password(flib_netconn *conn, const char *latin1Passwd);
+
+/**
+ * Request a different nickname.
+ * This function only makes sense in reaction to an onNickTaken callback, because the netconn automatically
+ * requests the nickname you provide on creation, and once the server accepts the nickname (onNickAccept)
+ * it can no longer be changed.
+ *
+ * As a response to the nick change request, the server will either reply with a confirmation (onNickAccept)
+ * or a rejection (onNickTaken). Note that the server confirms a nick even if it is password protected, the
+ * password request happens afterwards.
+ */
+int flib_netconn_send_nick(flib_netconn *conn, const char *nick);
+
+/**
+ * Callback for several informational messages that should be displayed to the user
+ * (e.g. in the chat window), but do not require a reaction. If a game is running, you might
+ * want to redirect some of these messages to the engine as well so the user will see them.
+ */
+void flib_netconn_onMessage(flib_netconn *conn, void (*callback)(void *context, int msgtype, const char *msg), void* context);
+
+/**
+ * We received a chat message. Where this message belongs depends on the current state (lobby/room/game). In particular,
+ * if a game is running the message should be passed to the engine.
+ */
+void flib_netconn_onChat(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *msg), void* context);
+
+/**
+ * This is called when we receive a CONNECTED message from the server, which should be the first
+ * message arriving from the server.
+ */
+void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context), void* context);
+
+/**
+ * This is *always* the last callback (unless the netconn is destroyed early), and the netconn should be destroyed when it is received.
+ * The reason is one of the NETCONN_DISCONNECT_ constants. Sometime a message is included as well, but that parameter might
+ * also be NULL.
+ */
+void flib_netconn_onDisconnected(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void* context);
+
+/**
+ * Callbacks for room list updates. The room list is managed automatically and can be queried with
+ * flib_netconn_get_roomlist() as soon as the onConnected callback is fired. These callbacks
+ * provide notification about changes.
+ */
+void flib_netconn_onRoomAdd(flib_netconn *conn, void (*callback)(void *context, const flib_roomlist_room *room), void* context);
+void flib_netconn_onRoomDelete(flib_netconn *conn, void (*callback)(void *context, const char *name), void* context);
+void flib_netconn_onRoomUpdate(flib_netconn *conn, void (*callback)(void *context, const char *oldName, const flib_roomlist_room *room), void* context);
+
+/**
+ * Callbacks for players joining or leaving a room or the lobby. If join is true it's a join, otherwise a leave.
+ * NOTE: partMessage is null if no parting message was given.
+ */
+void flib_netconn_onLobbyJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+void flib_netconn_onLobbyLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMessage), void* context);
+void flib_netconn_onRoomJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+void flib_netconn_onRoomLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMessage), void* context);
+
+/**
+ * onNickTaken is called on connecting to the server, if it turns out that there is already a player with the same nick.
+ * In order to proceed, a new nickname needs to be sent to the server using flib_netconn_send_nick() (or of course you can
+ * bail out and send a QUIT). If you don't set a callback, the netconn will automatically react by generating a new name.
+ * Once the server accepts a name, you will be informed with an onNickAccept callback.
+ */
+void flib_netconn_onNickTaken(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+
+/**
+ * onNickAccept informs that your nickname has been accepted by the server, i.e. there was nobody with that nick already
+ * on the server.
+ * Note that a nick request is sent automatically by the netconn when you join the server, so you should receive this
+ * callback shortly after connecting.
+ */
+void flib_netconn_onNickAccept(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+
+/**
+ * When connecting with a registered nickname, the server will ask for a password before admitting you in.
+ * This callback is called when that happens. As a reaction, you can send the password using
+ * flib_netconn_send_password or choose a different nick. If you don't register a callback,
+ * the default behavior is to just quit in a way that will cause a disconnect with NETCONN_DISCONNECT_AUTH_FAILED.
+ */
+void flib_netconn_onPasswordRequest(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+
+/**
+ * This callback informs about changes to your room chief status, i.e. whether you are allowed to
+ * modify the current room. Generally when you create a room you start out being room chief, and
+ * when you join an existing room you are not. However, in some situations room ownership can change,
+ * and if that happens this callback is called with the new status.
+ *
+ * Note: This callback does not automatically fire when joining a room. You can always query the
+ * current chief status using flib_netconn_is_chief().
+ */
+void flib_netconn_onRoomChiefStatus(flib_netconn *conn, void (*callback)(void *context, bool chief), void* context);
+
+/**
+ * One of the players in the room (possibly you!) changed their ready state.
+ */
+void flib_netconn_onReadyStateCb(flib_netconn *conn, void (*callback)(void *context, const char *nick, bool ready), void* context);
+
+/**
+ * You just left the lobby and entered a room.
+ * If chief is true, you can and should send a full configuration for the room now.
+ */
+void flib_netconn_onEnterRoomCb(flib_netconn *conn, void (*callback)(void *context, bool chief), void *context);
+
+/**
+ * You just left a room and entered the lobby again.
+ * reason is one of the NETCONN_ROOMLEAVE_ constants.
+ * This will not be called when you actively leave a room using PART.
+ */
+void flib_netconn_onLeaveRoomCb(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void *context);
+
+void flib_netconn_onTeamAddCb(flib_netconn *conn, void (*callback)(void *context, flib_team *team), void *context);
+
#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netprotocol.c Thu Jun 21 21:32:12 2012 +0200
@@ -0,0 +1,59 @@
+#include "netprotocol.h"
+
+#include "../util/util.h"
+#include "../util/logging.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static int fillTeamFromMsg(flib_team *team, char **parts) {
+ team->name = flib_strdupnull(parts[0]);
+ team->grave = flib_strdupnull(parts[2]);
+ team->fort = flib_strdupnull(parts[3]);
+ team->voicepack = flib_strdupnull(parts[4]);
+ team->flag = flib_strdupnull(parts[5]);
+ if(!team->name || !team->grave || !team->fort || !team->voicepack || !team->flag) {
+ return -1;
+ }
+
+ long color;
+ if(sscanf(parts[1], "#%lx", &color)) {
+ team->color = color;
+ } else {
+ return -1;
+ }
+
+ errno = 0;
+ long difficulty = strtol(parts[6], NULL, 10);
+ if(errno) {
+ return -1;
+ }
+
+ for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+ flib_hog *hog = &team->hogs[i];
+ hog->difficulty = difficulty;
+ hog->name = flib_strdupnull(parts[7+2*i]);
+ hog->hat = flib_strdupnull(parts[8+2*i]);
+ if(!hog->name || !hog->hat) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+flib_team *flib_team_from_netmsg(char **parts) {
+ flib_team *result = NULL;
+ flib_team *tmpTeam = flib_calloc(1, sizeof(flib_team));
+ if(tmpTeam) {
+ if(!fillTeamFromMsg(tmpTeam, parts)) {
+ result = tmpTeam;
+ tmpTeam = NULL;
+ } else {
+ flib_log_e("Error parsing team from net.");
+ }
+ }
+ flib_team_destroy(tmpTeam);
+ return result;
+}
--- a/project_files/frontlib/net/netprotocol.h Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/net/netprotocol.h Thu Jun 21 21:32:12 2012 +0200
@@ -1,7 +1,12 @@
#ifndef NETPROTOCOL_H_
#define NETPROTOCOL_H_
+#include "../model/team.h"
+/**
+ * Create a new team from this 23-part net message
+ */
+flib_team *flib_team_from_netmsg(char **parts);
#endif /* NETPROTOCOL_H_ */
--- a/project_files/frontlib/test.c Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/test.c Thu Jun 21 21:32:12 2012 +0200
@@ -1,12 +1,13 @@
#include "frontlib.h"
#include "util/logging.h"
#include "util/buffer.h"
+#include "util/util.h"
#include "model/map.h"
#include "model/weapon.h"
#include "model/schemelist.h"
#include "ipc/mapconn.h"
#include "ipc/gameconn.h"
-#include "net/netbase.h"
+#include "net/netconn.h"
#include <stdlib.h>
#include <stdbool.h>
@@ -198,6 +199,65 @@
}
}
+void handleNetDisconnect(void *context, int reason, const char *message) {
+ flib_log_i("Disconnected: %s", message);
+ flib_netconn_destroy(*(flib_netconn**)context);
+ *(flib_netconn**)context = NULL;
+}
+
+void handleNetConnected(void *context) {
+ const flib_roomlist *roomlist = flib_netconn_get_roomlist(*(flib_netconn**)context);
+ flib_log_i("List of rooms:");
+ for(int i=0; i<roomlist->roomCount; i++) {
+ flib_roomlist_room *room = roomlist->rooms[i];
+ flib_log_i("%1s %20s %20s %2i %2i %20s %20s %20s", room->inProgress ? "X" : " ", room->name, room->owner, room->playerCount, room->teamCount, room->map, room->scheme, room->weapons);
+ }
+}
+
+void handleLobbyJoin(void *context, const char *nick) {
+ flib_log_i("%s joined", nick);
+}
+
+void handleChat(void *context, const char *nick, const char *msg) {
+ flib_log_i("%s: %s", nick, msg);
+ if(!memcmp("frontbot ", msg, strlen("frontbot "))) {
+ const char *command = msg+strlen("frontbot ");
+ if(!memcmp("quit", command, strlen("quit"))) {
+ flib_netconn_send_quit(*(flib_netconn**)context, "Yeth Mathter");
+ } else if(!memcmp("describe ", command, strlen("describe "))) {
+ const char *roomname = command+strlen("describe ");
+ const flib_roomlist *roomlist = flib_netconn_get_roomlist(*(flib_netconn**)context);
+ flib_roomlist_room *room = flib_roomlist_find((flib_roomlist*)roomlist, roomname);
+ if(!room) {
+ flib_netconn_send_chat(*(flib_netconn**)context, "Unknown room.");
+ } else {
+ char *text = flib_asprintf(
+ "%s is a room created by %s, where %i players (%i teams) are %s on %s%s, using the %s scheme and %s weaponset.",
+ room->name,
+ room->owner,
+ room->playerCount,
+ room->teamCount,
+ room->inProgress ? "fighting" : "preparing to fight",
+ room->map[0]=='+' ? "" : "the map ",
+ !strcmp("+rnd+", room->map) ? "a random map" :
+ !strcmp("+maze+", room->map) ? "a random maze" :
+ !strcmp("+drawn+", room->map) ? "a hand-drawn map" :
+ room->map,
+ room->scheme,
+ room->weapons);
+ if(text) {
+ flib_netconn_send_chat(*(flib_netconn**)context, text);
+ }
+ free(text);
+ }
+ }
+ }
+}
+
+void handleAskPass(void *context, const char *nick) {
+ flib_netconn_send_password((flib_netconn*)context, "Lorem");
+}
+
int main(int argc, char *argv[]) {
flib_init(0);
flib_log_setLevel(FLIB_LOGLEVEL_ALL);
@@ -207,36 +267,20 @@
//testSave();
//testGame();
- flib_netbase *conn = flib_netbase_create("140.247.62.101", 46631);
+ flib_cfg_meta *meta = flib_cfg_meta_from_ini("metasettings.ini");
+ assert(meta);
+ flib_netconn *conn = flib_netconn_create("Medo42", meta, "140.247.62.101", 46631);
+ assert(conn);
+ flib_cfg_meta_release(meta);
- while(flib_netbase_connected(conn)) {
- flib_netmsg *msg = flib_netbase_recv_message(conn);
- if(msg && msg->partCount>0) {
- flib_log_i("[NET IN] %s", msg->parts[0]);
- for(int i=1; i<msg->partCount; i++) {
- flib_log_i("[NET IN][-] %s", msg->parts[i]);
- }
- if(!strcmp(msg->parts[0], "CONNECTED")) {
- flib_netmsg *nickmsg = flib_netmsg_create();
- flib_netmsg_append_part(nickmsg, "NICK", 4);
- flib_netmsg_append_part(nickmsg, "Medo42_frontlib", 15);
- flib_netmsg *protomsg = flib_netmsg_create();
- flib_netmsg_append_part(protomsg, "PROTO", 5);
- flib_netmsg_append_part(protomsg, "42", 2);
- flib_netbase_send_message(conn, nickmsg);
- flib_netbase_send_message(conn, protomsg);
- flib_netmsg_destroy(nickmsg);
- flib_netmsg_destroy(protomsg);
- }
- if(!strcmp(msg->parts[0], "SERVER_MESSAGE")) {
- flib_netmsg *quitmsg = flib_netmsg_create();
- flib_netmsg_append_part(quitmsg, "QUIT", 4);
- flib_netmsg_append_part(quitmsg, "Just testing", 12);
- flib_netbase_send_message(conn, quitmsg);
- flib_netmsg_destroy(quitmsg);
- }
- }
- flib_netmsg_destroy(msg);
+ flib_netconn_onConnected(conn, handleNetConnected, &conn);
+ flib_netconn_onDisconnected(conn, handleNetDisconnect, &conn);
+ flib_netconn_onLobbyJoin(conn, handleLobbyJoin, &conn);
+ flib_netconn_onChat(conn, handleChat, &conn);
+ flib_netconn_onPasswordRequest(conn, handleAskPass, conn);
+
+ while(conn) {
+ flib_netconn_tick(conn);
}
flib_quit();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/list.c Thu Jun 21 21:32:12 2012 +0200
@@ -0,0 +1,42 @@
+#include "list.h"
+
+#include <string.h>
+#include "util.h"
+#include "logging.h"
+
+void *flib_list_insert(void *list, int *listSizePtr, size_t elementSize, void *elementPtr, int pos) {
+ void *result = NULL;
+ if(!listSizePtr || !elementPtr || pos < 0 || pos > *listSizePtr) {
+ flib_log_e("Invalid parameter in flib_list_insert");
+ } else {
+ unsigned char *newList = flib_realloc(list, ((*listSizePtr)+1)*elementSize);
+ if(newList) {
+ memmove(newList + (pos+1)*elementSize, newList + pos*elementSize, ((*listSizePtr)-pos)*elementSize);
+ memmove(newList + pos*elementSize, elementPtr, elementSize);
+ (*listSizePtr)++;
+ result = newList;
+ }
+ }
+ return result;
+}
+
+void *flib_list_delete(void *list, int *listSizePtr, size_t elementSize, int pos) {
+ void *result = NULL;
+ if(!listSizePtr || pos < 0 || pos >= *listSizePtr) {
+ flib_log_e("Invalid parameter in flib_list_delete");
+ } else {
+ unsigned char *charList = list;
+ memmove(charList + (pos*elementSize), charList + (pos+1)*elementSize, (*listSizePtr-(pos+1))*elementSize);
+ (*listSizePtr)--;
+
+ // If the realloc fails, just keep using the old buffer...
+ size_t newCharSize = (*listSizePtr)*elementSize;
+ void *newList = flib_realloc(list, newCharSize);
+ if(newList || newCharSize==0) {
+ result = newList;
+ } else {
+ result = list;
+ }
+ }
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/list.h Thu Jun 21 21:32:12 2012 +0200
@@ -0,0 +1,24 @@
+/**
+ * Simple dynamic array manipulation functions.
+ */
+
+#ifndef LIST_H_
+#define LIST_H_
+
+#include <stddef.h>
+
+/**
+ * Insert element into the list and increase listSize.
+ * Returns a pointer to the modified list on success, NULL on failure. On success, the old
+ * pointer is no longer valid, and on failure the list remains unchanged (similar to realloc)
+ */
+void *flib_list_insert(void *list, int *listSizePtr, size_t elementSize, void *elementPtr, int pos);
+
+/**
+ * Remove an element from the list and decrease listSize.
+ * Returns a pointer to the modified list on success, NULL on failure. On success, the old
+ * pointer is no longer valid, and on failure the list remains unchanged (similar to realloc)
+ */
+void *flib_list_delete(void *list, int *listSizePtr, size_t elementSize, int pos);
+
+#endif /* LIST_H_ */
--- a/project_files/frontlib/util/util.c Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/util/util.c Thu Jun 21 21:32:12 2012 +0200
@@ -36,6 +36,28 @@
return result;
}
+char *flib_join(char **parts, int partCount, const char *delimiter) {
+ size_t totalSize = 1;
+ size_t delimLen = strlen(delimiter);
+ for(int i=0; i<partCount; i++) {
+ totalSize += strlen(parts[i]) + delimLen;
+ }
+
+ char *result = flib_malloc(totalSize);
+ if(result) {
+ size_t outpos = 0;
+ for(int i=0; i<partCount; i++) {
+ if(i>0) {
+ strcpy(result+outpos, delimiter);
+ outpos += delimLen;
+ }
+ strcpy(result+outpos, parts[i]);
+ outpos += strlen(parts[i]);
+ }
+ }
+ return result;
+}
+
char *flib_strdupnull(const char *str) {
if(!str) {
return NULL;
--- a/project_files/frontlib/util/util.h Tue Jun 19 21:20:08 2012 +0200
+++ b/project_files/frontlib/util/util.h Thu Jun 21 21:32:12 2012 +0200
@@ -19,6 +19,12 @@
char *flib_vasprintf(const char *fmt, va_list args);
/**
+ * Creates a new string (that must be freed) containing all parts
+ * joined together, with the specified delimiter between each.
+ */
+char *flib_join(char **parts, int partCount, const char *delimiter);
+
+/**
* Return a duplicate of the provided string, or NULL if an error
* occurs or if str is already NULL.
*