about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2007-09-27 23:55:59 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2007-09-27 23:55:59 +0000
commitfa05b5e2de089ecd85148f3f79bafc7781142b15 (patch)
treebe3d252a8cebf175e0632dfb36dffecd88517586
parentd33bdd1dbbf1f7ffe60fd781cde4580b5951da56 (diff)
downloadzcatch-fa05b5e2de089ecd85148f3f79bafc7781142b15.tar.gz
zcatch-fa05b5e2de089ecd85148f3f79bafc7781142b15.zip
begun the work for the new server browse backend
-rw-r--r--src/engine/client/client.c272
-rw-r--r--src/engine/interface.h17
-rw-r--r--src/engine/memheap.c101
-rw-r--r--src/engine/memheap.h5
-rw-r--r--src/engine/server/server.c2
-rw-r--r--src/game/client/menu.cpp11
-rw-r--r--src/tools/fake_server.c217
7 files changed, 547 insertions, 78 deletions
diff --git a/src/engine/client/client.c b/src/engine/client/client.c
index a518fe39..47175ca6 100644
--- a/src/engine/client/client.c
+++ b/src/engine/client/client.c
@@ -15,6 +15,7 @@
 #include <engine/network.h>
 #include <engine/config.h>
 #include <engine/packer.h>
+#include <engine/memheap.h>
 
 #include <mastersrv/mastersrv.h>
 
@@ -31,8 +32,6 @@ const int prediction_margin = 5;
 	Prediction Latency
 		Upstream latency
 */
-static int info_request_begin;
-static int info_request_end;
 static int snapshot_part;
 static int64 local_start_time;
 
@@ -346,29 +345,119 @@ int *client_get_input(int tick)
 }
 
 // ------ server browse ----
-static struct 
+typedef struct SERVERENTRY_t SERVERENTRY;
+struct SERVERENTRY_t
 {
-	SERVER_INFO infos[MAX_SERVERS];
-	int64 request_times[MAX_SERVERS];
-	NETADDR4 addresses[MAX_SERVERS];
-	int num;
-} servers;
+	NETADDR4 addr;
+	int64 request_time;
+	SERVER_INFO info;
+	
+	SERVERENTRY *next_ip; // ip hashed list
+	
+	SERVERENTRY *prev_req; // request list
+	SERVERENTRY *next_req;
+};
+
+HEAP *serverlist_heap = 0;
+SERVERENTRY **serverlist = 0;
+
+SERVERENTRY *serverlist_ip[256] = {0}; // ip hash list
+
+SERVERENTRY *first_req_server = 0; // request list
+SERVERENTRY *last_req_server = 0;
+
+int num_servers = 0;
+int num_server_capasity = 0;
 
 static int serverlist_lan = 1;
 
-int client_serverbrowse_getlist(SERVER_INFO **serverlist)
+SERVER_INFO *client_serverbrowse_get(int index)
 {
-	*serverlist = servers.infos;
-	return servers.num;
+	if(index < 0 || index >= num_servers)
+		return 0;
+	return &serverlist[index]->info;
+}
+
+int client_serverbrowse_num()
+{
+	return num_servers;
 }
 
 static void client_serverbrowse_init()
 {
-	servers.num = 0;
+}
+
+static void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info)
+{
+	int hash = addr->ip[0];
+	SERVERENTRY *entry = serverlist_ip[hash];
+	while(entry)
+	{
+		if(net_addr4_cmp(&entry->addr, addr) == 0)
+		{
+			/* update the server that we already have */
+			entry->info = *info;
+			if(!request)
+				entry->info.latency = (time_get()-entry->request_time)*1000/time_freq();
+			return;
+		}
+		entry = entry->next_ip;
+	}
+
+	/* create new entry */	
+	entry = (SERVERENTRY *)memheap_allocate(serverlist_heap, sizeof(SERVERENTRY));
+	mem_zero(entry, sizeof(SERVERENTRY));
+	
+	/* set the info */
+	entry->addr = *addr;
+	entry->info = *info;
+
+	/* add to the hash list */	
+	entry->next_ip = serverlist_ip[hash];
+	serverlist_ip[hash] = entry;
+	
+	if(num_servers == num_server_capasity)
+	{
+		num_server_capasity += 100;
+		SERVERENTRY **newlist = mem_alloc(num_server_capasity*sizeof(SERVERENTRY*), 1);
+		memcpy(newlist, serverlist, num_servers*sizeof(SERVERENTRY*));
+		mem_free(serverlist);
+		serverlist = newlist;
+	}
+	
+	/* add to list */
+	serverlist[num_servers] = entry;
+	num_servers++;
+	
+	/* */
+	entry->prev_req = 0;
+	entry->next_req = 0;
+	
+	if(request)
+	{
+		/* add it to the list of servers that we should request info from */
+		entry->prev_req = last_req_server;
+		if(last_req_server)
+			last_req_server->next_req = entry;
+		else
+			first_req_server = entry;
+		last_req_server = entry;
+	}
 }
 
 void client_serverbrowse_refresh(int lan)
 {
+	/* clear out everything */
+	if(serverlist_heap)
+		memheap_destroy(serverlist_heap);
+	serverlist_heap = memheap_create();
+	num_servers = 0;
+	num_server_capasity = 0;
+	mem_zero(serverlist_ip, sizeof(serverlist_ip));
+	first_req_server = 0;
+	last_req_server = 0;
+	
+	/* */
 	serverlist_lan = lan;
 	
 	if(serverlist_lan)
@@ -389,7 +478,7 @@ void client_serverbrowse_refresh(int lan)
 		netclient_send(net, &packet);	
 		
 		// reset the list
-		servers.num = 0;		
+		//servers.num = 0;
 	}
 	else
 	{
@@ -405,27 +494,28 @@ void client_serverbrowse_refresh(int lan)
 		netclient_send(net, &packet);	
 		
 		// reset the list
-		servers.num = 0;
+		//servers.num = 0;
 	}
 }
 
 
-static void client_serverbrowse_request(int id)
+static void client_serverbrowse_request(SERVERENTRY *entry)
 {
 	if(config.debug)
 	{
 		dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
-			servers.addresses[id].ip[0], servers.addresses[id].ip[1], servers.addresses[id].ip[2],
-			servers.addresses[id].ip[3], servers.addresses[id].port);
+			entry->addr.ip[0], entry->addr.ip[1], entry->addr.ip[2],
+			entry->addr.ip[3], entry->addr.port);
 	}
-	NETPACKET packet;
-	packet.client_id = -1;
-	packet.address = servers.addresses[id];
-	packet.flags = PACKETFLAG_CONNLESS;
-	packet.data_size = sizeof(SERVERBROWSE_GETINFO);
-	packet.data = SERVERBROWSE_GETINFO;
-	netclient_send(net, &packet);
-	servers.request_times[id] = time_get();
+	
+	NETPACKET p;
+	p.client_id = -1;
+	p.address = entry->addr;
+	p.flags = PACKETFLAG_CONNLESS;
+	p.data_size = sizeof(SERVERBROWSE_GETINFO);
+	p.data = SERVERBROWSE_GETINFO;
+	netclient_send(net, &p);
+	entry->request_time = time_get();
 }
 
 static void client_serverbrowse_update()
@@ -433,7 +523,55 @@ static void client_serverbrowse_update()
 	int64 timeout = time_freq();
 	int64 now = time_get();
 	int max_requests = 10;
+	int count;
+	
+	SERVERENTRY *entry, *next;
 	
+	/* do timeouts */
+	entry = first_req_server;
+	while(1)
+	{
+		if(!entry) // no more entries
+			break;
+			
+		next = entry->next_req;
+		
+		if(entry->request_time && entry->request_time+timeout < now)
+		{
+			/* timeout */
+			if(entry->prev_req)
+				entry->prev_req->next_req = entry->next_req;
+			else
+				first_req_server = entry->next_req;
+				
+			if(entry->next_req)
+				entry->next_req->prev_req = entry->prev_req;
+			else
+				last_req_server = entry->prev_req;
+		}
+			
+		entry = next;
+	}
+
+	/* do timeouts */
+	entry = first_req_server;
+	count = 0;
+	while(1)
+	{
+		if(!entry) // no more entries
+			break;
+			
+		if(count == max_requests) // no more then 10 concurrent requests
+			break;
+			
+		if(entry->request_time == 0)
+			client_serverbrowse_request(entry);
+		
+		count++;
+		entry = entry->next_req;
+	}
+		
+	/*
 	// timeout old requests
 	while(info_request_begin < servers.num && info_request_begin < info_request_end)
 	{
@@ -448,7 +586,7 @@ static void client_serverbrowse_update()
 	{
 		client_serverbrowse_request(info_request_end);
 		info_request_end++;
-	}
+	}*/
 }
 
 // ------ state handling -----
@@ -597,7 +735,30 @@ static void client_process_packet(NETPACKET *packet)
 		if(packet->data_size >= (int)sizeof(SERVERBROWSE_LIST) &&
 			memcmp(packet->data, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0)
 		{
+			int size = packet->data_size-sizeof(SERVERBROWSE_LIST);
+			//mem_copy(servers.addresses, (char*)packet->data+sizeof(SERVERBROWSE_LIST), size);
+			int num = size/sizeof(NETADDR4);
+			NETADDR4 *addrs = (NETADDR4 *)((char*)packet->data+sizeof(SERVERBROWSE_LIST));
+			
+			int i;
+			for(i = 0; i < num; i++)
+			{
+				NETADDR4 addr = addrs[i];
+				SERVER_INFO info = {0};
+				
+				info.latency = 999;
+				sprintf(info.address, "%d.%d.%d.%d:%d",
+					addr.ip[0], addr.ip[1], addr.ip[2],
+					addr.ip[3], addr.port);
+				sprintf(info.name, "%d.%d.%d.%d:%d",
+					addr.ip[0], addr.ip[1], addr.ip[2],
+					addr.ip[3], addr.port);
+				
+				client_serverbrowse_set(addrs+i, 1, &info);
+			}
+			
 			// server listing
+			/*
 			int size = packet->data_size-sizeof(SERVERBROWSE_LIST);
 			mem_copy(servers.addresses, (char*)packet->data+sizeof(SERVERBROWSE_LIST), size);
 			servers.num = size/sizeof(NETADDR4);
@@ -621,7 +782,7 @@ static void client_process_packet(NETPACKET *packet)
 				sprintf(servers.infos[i].name, "%d.%d.%d.%d:%d",
 					servers.addresses[i].ip[0], servers.addresses[i].ip[1], servers.addresses[i].ip[2],
 					servers.addresses[i].ip[3], servers.addresses[i].port);
-			}
+			}*/
 		}
 
 		if(packet->data_size >= (int)sizeof(SERVERBROWSE_INFO) &&
@@ -630,46 +791,27 @@ static void client_process_packet(NETPACKET *packet)
 			// we got ze info
 			UNPACKER up;
 			unpacker_reset(&up, (unsigned char*)packet->data+sizeof(SERVERBROWSE_INFO), packet->data_size-sizeof(SERVERBROWSE_INFO));
+			SERVER_INFO info = {0};
+
+			strncpy(info.version, unpacker_get_string(&up), 32);
+			strncpy(info.name, unpacker_get_string(&up), 64);
+			strncpy(info.map, unpacker_get_string(&up), 32);
+			info.game_type = atol(unpacker_get_string(&up));
+			info.flags = atol(unpacker_get_string(&up));
+			info.progression = atol(unpacker_get_string(&up));
+			info.num_players = atol(unpacker_get_string(&up));
+			info.max_players = atol(unpacker_get_string(&up));
 			
-			if(serverlist_lan)
-			{
-				if(servers.num != MAX_SERVERS)
-				{
-					int i = servers.num;
-					strncpy(servers.infos[i].name, unpacker_get_string(&up), 128);
-					strncpy(servers.infos[i].map, unpacker_get_string(&up), 128);
-					servers.infos[i].max_players = unpacker_get_int(&up);
-					servers.infos[i].num_players = unpacker_get_int(&up);
-					servers.infos[i].latency = 0;
-					
-					sprintf(servers.infos[i].address, "%d.%d.%d.%d:%d",
-						packet->address.ip[0], packet->address.ip[1], packet->address.ip[2],
-						packet->address.ip[3], packet->address.port);
-
-					if(config.debug)
-						dbg_msg("client", "got server info");
-					servers.num++;
-					
-				}
-			}
-			else
+			int i;
+			for(i = 0; i < info.num_players; i++)
 			{
-				int i;
-				for(i = 0; i < servers.num; i++)
-				{
-					if(net_addr4_cmp(&servers.addresses[i], &packet->address) == 0)
-					{
-						strncpy(servers.infos[i].name, unpacker_get_string(&up), 128);
-						strncpy(servers.infos[i].map, unpacker_get_string(&up), 128);
-						servers.infos[i].max_players = unpacker_get_int(&up);
-						servers.infos[i].num_players = unpacker_get_int(&up);
-						servers.infos[i].latency = ((time_get() - servers.request_times[i])*1000)/time_freq();
-						if(config.debug)
-							dbg_msg("client", "got server info");
-						break;
-					}
-				}
+				strncpy(info.player_names[i], unpacker_get_string(&up), 48);
+				info.player_scores[i] = atol(unpacker_get_string(&up));
 			}
+			
+			/* TODO: unpack players aswell */
+			client_serverbrowse_set(&packet->address, 0, &info);
+
 		}
 	}
 	else
@@ -898,8 +1040,6 @@ static void client_run(const char *direct_connect_server)
 {
 	local_start_time = time_get();
 	snapshot_part = 0;
-	info_request_begin = 0;
-	info_request_end = 0;
 	
 	client_serverbrowse_init();
 	
diff --git a/src/engine/interface.h b/src/engine/interface.h
index fb2ebe6c..118b858f 100644
--- a/src/engine/interface.h
+++ b/src/engine/interface.h
@@ -13,7 +13,7 @@ extern "C" {
 
 enum 
 {
-	MAX_CLIENTS=8,
+	MAX_CLIENTS=16,
 	SERVER_TICK_SPEED=50, /* TODO: this should be removed */
 	SNAP_CURRENT=0,
 	SNAP_PREV=1,
@@ -55,12 +55,18 @@ typedef struct
 
 typedef struct
 {
+	int progression;
+	int game_type;
 	int max_players;
 	int num_players;
+	int flags;
 	int latency; /* in ms */
-	char name[128];
-	char map[128];
-	char address[128];
+	char name[64];
+	char map[32];
+	char version[32];
+	char address[24];
+	char player_names[16][48];
+	int player_scores[16];
 } SERVER_INFO;
 
 /* image loaders */
@@ -785,7 +791,8 @@ void client_quit();
 void client_rcon(const char *cmd);
 
 void client_serverbrowse_refresh(int lan);
-int client_serverbrowse_getlist(SERVER_INFO **servers);
+SERVER_INFO *client_serverbrowse_get(int index);
+int client_serverbrowse_num();
 
 /* undocumented graphics stuff */
 void gfx_pretty_text(float x, float y, float size, const char *text, int max_width);
diff --git a/src/engine/memheap.c b/src/engine/memheap.c
new file mode 100644
index 00000000..5fe30295
--- /dev/null
+++ b/src/engine/memheap.c
@@ -0,0 +1,101 @@
+#include "system.h"
+
+typedef struct CHUNK_t
+{
+	char *memory;
+	char *current;
+	char *end;
+	struct CHUNK_t *next;
+} CHUNK;
+
+typedef struct 
+{
+	CHUNK *current;
+} HEAP;
+
+/* how large each chunk should be */
+static const int chunksize = 1024*64;
+
+/* allocates a new chunk to be used */
+static CHUNK *memheap_newchunk()
+{
+	CHUNK *chunk;
+	char *mem;
+	
+	/* allocate memory */
+	mem = mem_alloc(sizeof(CHUNK)+chunksize, 1);
+	if(!mem)
+		return 0x0;
+
+	/* the chunk structure is located in the begining of the chunk */
+	/* init it and return the chunk */
+	chunk = (CHUNK*)mem;
+	chunk->memory = (char*)(chunk+1);
+	chunk->current = chunk->memory;
+	chunk->end = chunk->memory + chunksize;
+	chunk->next = (CHUNK *)0x0;
+	return chunk;
+}
+
+/******************/
+static void *memheap_allocate_from_chunk(CHUNK *chunk, int size)
+{
+	char *mem;
+	
+	/* check if we need can fit the allocation */
+	if(chunk->current + size >= chunk->end)
+		return (void*)0x0;
+
+	/* get memory and move the pointer forward */
+	mem = chunk->current;
+	chunk->current += size;
+	return mem;
+}
+
+/* creates a heap */
+HEAP *memheap_create()
+{
+	CHUNK *chunk;
+	HEAP *heap;
+	
+	/* allocate a chunk and allocate the heap structure on that chunk */
+	chunk = memheap_newchunk();
+	heap = (HEAP *)memheap_allocate_from_chunk(chunk, sizeof(HEAP));
+	heap->current = chunk;
+	return heap;
+}
+
+/* destroys the heap */
+void memheap_destroy(HEAP *heap)
+{
+	CHUNK *chunk = heap->current;
+	CHUNK *next;
+	
+	while(chunk)
+	{
+		next = chunk->next;
+		mem_free(chunk);
+		chunk = next;
+	}
+}
+
+/* */
+void *memheap_allocate(HEAP *heap, int size)
+{
+	char *mem;
+
+	/* try to allocate from current chunk */
+	mem = (char *)memheap_allocate_from_chunk(heap->current, size);
+	if(!mem)
+	{
+		/* allocate new chunk and add it to the heap */
+		CHUNK *chunk = memheap_newchunk();
+		chunk->next = heap->current;
+		heap->current = chunk;
+		
+		/* try to allocate again */
+		mem = (char *)memheap_allocate_from_chunk(heap->current, size);
+	}
+	
+	return mem;
+}
diff --git a/src/engine/memheap.h b/src/engine/memheap.h
new file mode 100644
index 00000000..414db5e8
--- /dev/null
+++ b/src/engine/memheap.h
@@ -0,0 +1,5 @@
+
+typedef struct HEAP_t HEAP;
+HEAP *memheap_create();
+void memheap_destroy(HEAP *heap);
+void *memheap_allocate(HEAP *heap, int size);
diff --git a/src/engine/server/server.c b/src/engine/server/server.c
index db911819..3bcb79dd 100644
--- a/src/engine/server/server.c
+++ b/src/engine/server/server.c
@@ -494,7 +494,7 @@ static void server_send_serverinfo(NETADDR4 *addr)
 	packer_reset(&p);
 	packer_add_raw(&p, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO));
 	packer_add_string(&p, config.sv_name, 128);
-	packer_add_string(&p, config.sv_map, 128);
+	packer_add_string(&p, config.sv_map, 32);
 	packer_add_int(&p, netserver_max_clients(net)); /* max_players */
 	int c = 0;
 	int i;
diff --git a/src/game/client/menu.cpp b/src/game/client/menu.cpp
index 43b11142..a5d6d5b6 100644
--- a/src/game/client/menu.cpp
+++ b/src/game/client/menu.cpp
@@ -631,8 +631,7 @@ static int do_server_list(float x, float y, int *scroll_index, int *selected_ind
 	const float real_width = item_width + 20;
 	const float real_height = item_height * visible_items + spacing * (visible_items - 1);
 
-	SERVER_INFO *servers;
-	int num_servers = client_serverbrowse_getlist(&servers);
+	int num_servers = client_serverbrowse_num();
 
 	int r = -1;
 
@@ -644,7 +643,7 @@ static int do_server_list(float x, float y, int *scroll_index, int *selected_ind
 			//ui_do_image(empty_item_texture, x, y + i * item_height + i * spacing, item_width, item_height);
 		else
 		{
-			SERVER_INFO *item = &servers[item_index];
+			SERVER_INFO *item = client_serverbrowse_get(item_index);
 
 			bool clicked = false;
 			clicked = ui_do_button(item, item->name, 0, x, y + i * item_height + i * spacing, item_width, item_height,
@@ -718,10 +717,10 @@ static int main_render()
 
 	if (last_selected_index != selected_index && selected_index != -1)
 	{
-		SERVER_INFO *servers;
-		client_serverbrowse_getlist(&servers);
+		SERVER_INFO *server;
+		server = client_serverbrowse_get(selected_index);
 
-		strcpy(address, servers[selected_index].address);
+		strcpy(address, server->address);
 	}
 
 	static int refresh_button, join_button, quit_button;
diff --git a/src/tools/fake_server.c b/src/tools/fake_server.c
new file mode 100644
index 00000000..01ba57b0
--- /dev/null
+++ b/src/tools/fake_server.c
@@ -0,0 +1,217 @@
+#include <engine/config.h>
+#include <engine/system.h>
+#include <engine/network.h>
+#include <mastersrv/mastersrv.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ 32 version
+ 64 servername
+ 32 mapname
+  2 gametype
+  2 flags
+  4 progression
+  3 num players
+  3 max players
+  {
+  	48 name
+     6 score
+  } * players
+
+         111111111122222222223333333333444444444
+123456789012345678901234567890123456789012345678
+0.3 2d82e361de24cb25
+my own private little server
+magnus.auvinen@teewars.somehost-strage-host.com
+*/
+
+NETSERVER *net;
+
+int progression = 50;
+int game_type = 0;
+int flags = 0;
+
+const char *version = "0.3.0 2d82e361de24cb25";
+const char *map = "somemap";
+const char *server_name = "unnamed server";
+NETADDR4 master_servers[16] = {{{0},0}};
+int num_masters = 0;
+
+const char *player_names[16] = {0};
+int player_scores[16] = {0};
+int num_players = 0;
+int max_players = 0;
+
+static void send_heartbeats()
+{
+	int i = 0;
+
+	NETPACKET p;
+	p.client_id = -1;
+	p.flags = PACKETFLAG_CONNLESS;
+	p.data_size = sizeof(SERVERBROWSE_HEARTBEAT);
+	p.data = SERVERBROWSE_HEARTBEAT;
+
+	for(i = 0; i < num_masters; i++)
+	{
+		p.address = master_servers[i];
+		netserver_send(net, &p);
+	}
+}
+
+char infomsg[1024];
+int infomsg_size;
+
+static void writestr(const char *str)
+{
+	int l = strlen(str)+1;
+	memcpy(&infomsg[infomsg_size], str, l);
+	infomsg_size += l;
+}
+
+static void writeint(int i)
+{
+	char buf[64];
+	sprintf(buf, "%d", i);
+	writestr(buf);
+}
+
+static void build_infomessage()
+{
+	int i;
+	infomsg_size = sizeof(SERVERBROWSE_INFO);
+	memcpy(infomsg, SERVERBROWSE_INFO, infomsg_size);
+	
+	writestr(version);
+	writestr(server_name);
+	writestr(map);
+	writeint(game_type);
+	writeint(flags);
+	writeint(progression);
+	writeint(num_players);
+	writeint(max_players);
+	for(i = 0; i < num_players; i++)
+	{
+		writestr(player_names[i]);
+		writeint(player_scores[i]);
+	}
+}
+
+static void send_serverinfo(NETADDR4 *addr)
+{
+	NETPACKET p;
+	p.client_id = -1;
+	p.address = *addr;
+	p.flags = PACKETFLAG_CONNLESS;
+	p.data_size = infomsg_size;
+	p.data = infomsg;
+	netserver_send(net, &p);
+}
+
+static void send_fwcheckresponse(NETADDR4 *addr)
+{
+	NETPACKET p;
+	p.client_id = -1;
+	p.address = *addr;
+	p.flags = PACKETFLAG_CONNLESS;
+	p.data_size = sizeof(SERVERBROWSE_FWRESPONSE);
+	p.data = SERVERBROWSE_FWRESPONSE;
+	netserver_send(net, &p);
+}
+
+static int run()
+{
+	int64 next_heartbeat = 0;
+	NETADDR4 bindaddr = {{0},0};
+	net = netserver_open(bindaddr, 0, 0);
+	if(!net)
+		return -1;
+	
+	while(1)
+	{
+		NETPACKET p;
+		netserver_update(net);
+		while(netserver_recv(net, &p))
+		{
+			if(p.client_id == -1)
+			{
+				if(p.data_size == sizeof(SERVERBROWSE_GETINFO) &&
+					memcmp(p.data, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0)
+				{
+					send_serverinfo(&p.address);
+				}
+				else if(p.data_size == sizeof(SERVERBROWSE_FWCHECK) &&
+					memcmp(p.data, SERVERBROWSE_FWCHECK, sizeof(SERVERBROWSE_FWCHECK)) == 0)
+				{
+					send_fwcheckresponse(&p.address);
+				}
+			}
+		}
+		
+		/* send heartbeats if needed */
+		if(next_heartbeat < time_get())
+		{
+			next_heartbeat = time_get()+time_freq()*30;
+			send_heartbeats();
+		}
+		
+		thread_sleep(10);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	net_init();
+	
+	while(argc)
+	{
+		if(strcmp(*argv, "-m") == 0)
+		{
+			argc--; argv++;
+			net_host_lookup(*argv, 0, &master_servers[num_masters]);
+			argc--; argv++;
+			master_servers[num_masters].port = atoi(*argv);
+			num_masters++;
+		}
+		else if(strcmp(*argv, "-p") == 0)
+		{
+			argc--; argv++;
+			player_names[num_players++] = *argv;
+			argc--; argv++;
+			player_scores[num_players] = atoi(*argv);
+		}
+		else if(strcmp(*argv, "-x") == 0)
+		{
+			argc--; argv++;
+			max_players = atoi(*argv);
+		}
+		else if(strcmp(*argv, "-t") == 0)
+		{
+			argc--; argv++;
+			game_type = atoi(*argv);
+		}
+		else if(strcmp(*argv, "-p") == 0)
+		{
+			argc--; argv++;
+			progression = atoi(*argv);
+		}
+		else if(strcmp(*argv, "-f") == 0)
+		{
+			argc--; argv++;
+			flags = atoi(*argv);
+		}
+		else if(strcmp(*argv, "-n") == 0)
+		{
+			argc--; argv++;
+			server_name = *argv;
+		}
+		
+		argc--; argv++;
+	}
+	
+	build_infomessage();
+	return run();
+}
+