Cube  serverutil.mm at [fa4b03aaca]

File src/serverutil.mm artifact e5f6cbf888 part of check-in fa4b03aaca


// misc useful functions used by the server

#include "cube.h"

// all network traffic is in 32bit ints, which are then compressed using the
// following simple scheme (assumes that most values are small).

void
putint(uchar *&p, int n)
{
	if (n < 128 && n > -127) {
		*p++ = n;
	} else if (n < 0x8000 && n >= -0x8000) {
		*p++ = 0x80;
		*p++ = n;
		*p++ = n >> 8;
	} else {
		*p++ = 0x81;
		*p++ = n;
		*p++ = n >> 8;
		*p++ = n >> 16;
		*p++ = n >> 24;
	};
};

int
getint(uchar *&p)
{
	int c = *((char *)p);
	p++;
	if (c == -128) {
		int n = *p++;
		n |= *((char *)p) << 8;
		p++;
		return n;
	} else if (c == -127) {
		int n = *p++;
		n |= *p++ << 8;
		n |= *p++ << 16;
		return n | (*p++ << 24);
	} else
		return c;
}

void
sendstring(OFString *t_, uchar *&p)
{
	@autoreleasepool {
		const char *t = t_.UTF8String;
		while (*t)
			putint(p, *t++);
		putint(p, 0);
	}
}

static const OFString *modenames[] = {
    @"SP",
    @"DMSP",
    @"ffa/default",
    @"coopedit",
    @"ffa/duel",
    @"teamplay",
    @"instagib",
    @"instagib team",
    @"efficiency",
    @"efficiency team",
    @"insta arena",
    @"insta clan arena",
    @"tactics arena",
    @"tactics clan arena",
};

OFString *
modestr(int n)
{
	return (n >= -2 && n < 12) ? modenames[n + 2] : @"unknown";
}

char msgsizesl[] = // size inclusive message token, 0 for variable or
                   // not-checked sizes
    {SV_INITS2C, 4, SV_INITC2S, 0, SV_POS, 12, SV_TEXT, 0, SV_SOUND, 2, SV_CDIS,
        2, SV_EDITH, 7, SV_EDITT, 7, SV_EDITS, 6, SV_EDITD, 6, SV_EDITE, 6,
        SV_DIED, 2, SV_DAMAGE, 4, SV_SHOT, 8, SV_FRAGS, 2, SV_MAPCHANGE, 0,
        SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 3, SV_DENIED, 2, SV_PING, 2, SV_PONG, 2,
        SV_CLIENTPING, 2, SV_GAMEMODE, 2, SV_TIMEUP, 2, SV_EDITENT, 10,
        SV_MAPRELOAD, 2, SV_ITEMACC, 2, SV_SENDMAP, 0, SV_RECVMAP, 1,
        SV_SERVMSG, 0, SV_ITEMLIST, 0, SV_EXT, 0, -1};

char
msgsizelookup(int msg)
{
	for (char *p = msgsizesl; *p >= 0; p += 2)
		if (*p == msg)
			return p[1];
	return -1;
};

// sending of maps between clients

static OFString *copyname;
int copysize;
uchar *copydata = NULL;

void
sendmaps(int n, OFString *mapname, int mapsize, uchar *mapdata)
{
	if (mapsize <= 0 || mapsize > 256 * 256)
		return;
	copyname = mapname;
	copysize = mapsize;
	if (copydata)
		free(copydata);
	copydata = (uchar *)alloc(mapsize);
	memcpy(copydata, mapdata, mapsize);
}

ENetPacket *
recvmap(int n)
{
	if (!copydata)
		return NULL;
	ENetPacket *packet = enet_packet_create(
	    NULL, MAXTRANS + copysize, ENET_PACKET_FLAG_RELIABLE);
	uchar *start = packet->data;
	uchar *p = start + 2;
	putint(p, SV_RECVMAP);
	sendstring(copyname, p);
	putint(p, copysize);
	memcpy(p, copydata, copysize);
	p += copysize;
	*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
	enet_packet_resize(packet, p - start);
	return packet;
}

#ifdef STANDALONE

void
localservertoclient(uchar *buf, int len)
{
}

void
fatal(OFString *s, OFString *o)
{
	cleanupserver();
	[OFStdOut writeFormat:@"servererror: %@\n", s];
	exit(1);
}

void *
alloc(int s)
{
	void *b = calloc(1, s);
	if (!b)
		fatal(@"no memory!");
	return b;
}

int
main(int argc, char *argv[])
{
	int uprate = 0, maxcl = 4;
	char *sdesc = "", *ip = "", *master = NULL, *passwd = "";

	for (int i = 1; i < argc; i++) {
		char *a = &argv[i][2];
		if (argv[i][0] == '-')
			switch (argv[i][1]) {
			case 'u':
				uprate = atoi(a);
				break;
			case 'n':
				sdesc = a;
				break;
			case 'i':
				ip = a;
				break;
			case 'm':
				master = a;
				break;
			case 'p':
				passwd = a;
				break;
			case 'c':
				maxcl = atoi(a);
				break;
			default:
				printf("WARNING: unknown commandline option\n");
			};
	};

	if (enet_initialize() < 0)
		fatal(@"Unable to initialise network module");
	initserver(true, uprate, @(sdesc), @(ip), @(master), @(passwd), maxcl);
	return 0;
}
#endif