about summary refs log tree commit diff
path: root/src/engine
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2008-07-06 11:21:21 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2008-07-06 11:21:21 +0000
commit9d632dd826c8a312095de0f56df66b2580d336cb (patch)
tree3fdde543c94323d6c698d278a58bf18e3c385776 /src/engine
parent3705064b109580103a3d13f44693503da9927281 (diff)
downloadzcatch-9d632dd826c8a312095de0f56df66b2580d336cb.tar.gz
zcatch-9d632dd826c8a312095de0f56df66b2580d336cb.zip
major update. server clean up and much added documentation
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/client/ec_client.c63
-rw-r--r--src/engine/client/ec_srvbrowse.c10
-rw-r--r--src/engine/e_engine.c9
-rw-r--r--src/engine/e_engine.h2
-rw-r--r--src/engine/e_if_client.h5
-rw-r--r--src/engine/e_if_gfx.h4
-rw-r--r--src/engine/e_if_other.h14
-rw-r--r--src/engine/e_if_server.h2
-rw-r--r--src/engine/e_network.c48
-rw-r--r--src/engine/e_network.h16
-rw-r--r--src/engine/e_snapshot.c34
-rw-r--r--src/engine/e_system.c80
-rw-r--r--src/engine/e_system.h589
-rw-r--r--src/engine/server/es_register.c14
-rw-r--r--src/engine/server/es_server.c25
15 files changed, 615 insertions, 300 deletions
diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c
index 8872d5f4..b8439194 100644
--- a/src/engine/client/ec_client.c
+++ b/src/engine/client/ec_client.c
@@ -43,7 +43,7 @@ const int prediction_margin = 7; /* magic network prediction value */
 NETCLIENT *net;
 
 /* TODO: ugly, fix me */
-extern void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info);
+extern void client_serverbrowse_set(NETADDR *addr, int request, SERVER_INFO *info);
 
 static int snapshot_part;
 static int64 local_start_time;
@@ -53,7 +53,7 @@ static float frametime = 0.0001f;
 static float frametime_low = 1.0f;
 static float frametime_high = 0.0f;
 static int frames = 0;
-static NETADDR4 server_address;
+static NETADDR server_address;
 static int window_must_refocus = 0;
 static int snaploss = 0;
 static int snapcrcerrors = 0;
@@ -489,11 +489,13 @@ void client_connect(const char *server_address_str)
 	
 	if(port_str)
 		port = atoi(port_str);
-		
-	if(net_host_lookup(buf, port, &server_address) != 0)
+	
+	/* TODO: IPv6 support */
+	if(net_host_lookup(buf, &server_address, NETTYPE_IPV4) != 0)
 		dbg_msg("client", "could not find the address of %s, connecting to localhost", buf);
 	
 	rcon_authed = 0;
+	server_address.port = port;
 	netclient_connect(net, &server_address);
 	client_set_state(CLIENTSTATE_CONNECTING);
 	
@@ -534,6 +536,8 @@ static int client_load_data()
 extern int snapshot_data_rate[0xffff];
 extern int snapshot_data_updates[0xffff];
 
+const char *modc_getitemname(int type);
+
 static void client_debug_render()
 {
 	static NETSTATS prev, current;
@@ -555,29 +559,50 @@ static void client_debug_render()
 		net_stats(&current);
 	}
 	
+	/*
+		eth = 14
+		ip = 20
+		udp = 8
+		total = 42
+	*/
+	
 	frametime_avg = frametime_avg*0.9f + frametime*0.1f;
-	str_format(buffer, sizeof(buffer), "ticks: %8d %8d send: %5d/%3d recv: %5d/%3d snaploss: %d  mem %dk   gfxmem: %dk  fps: %3d",
+	str_format(buffer, sizeof(buffer), "ticks: %8d %8d snaploss: %d  mem %dk   gfxmem: %dk  fps: %3d",
 		current_tick, current_predtick,
-		(current.sent_bytes-prev.sent_bytes),
-		(current.sent_packets-prev.sent_packets),
-		(current.recv_bytes-prev.recv_bytes),
-		(current.recv_packets-prev.recv_packets),
 		snaploss,
 		mem_allocated()/1024,
 		gfx_memory_usage()/1024,
 		(int)(1.0f/frametime_avg));
 	gfx_quads_text(2, 2, 16, buffer);
 
+	
+	{
+		int send_packets = (current.sent_packets-prev.sent_packets);
+		int send_bytes = (current.sent_bytes-prev.sent_bytes);
+		int send_total = send_bytes + send_packets*42;
+		int recv_packets = (current.recv_packets-prev.recv_packets);
+		int recv_bytes = (current.recv_bytes-prev.recv_bytes);
+		int recv_total = recv_bytes + recv_packets*42;
+		
+		if(!send_packets) send_packets++;
+		if(!recv_packets) recv_packets++;
+		str_format(buffer, sizeof(buffer), "send: %3d %5d+%4d=%5d (%3d kbps) avg: %5d\nrecv: %3d %5d+%4d=%5d (%3d kbps) avg: %5d",
+			send_packets, send_bytes, send_packets*42, send_total, (send_total*8)/1024, send_bytes/send_packets,
+			recv_packets, recv_bytes, recv_packets*42, recv_total, (recv_total*8)/1024, recv_bytes/recv_packets);
+		gfx_quads_text(2, 14, 16, buffer);
+	}
 	/* render rates */
 	{
+		int y = 0;
 		int i;
 		for(i = 0; i < 256; i++)
 		{
 			if(snapshot_data_rate[i])
 			{
-				str_format(buffer, sizeof(buffer), "%4d : %8d %8d %8d", i, snapshot_data_rate[i]/8, snapshot_data_updates[i],
+				str_format(buffer, sizeof(buffer), "%4d %20s: %8d %8d %8d", i, modc_getitemname(i), snapshot_data_rate[i]/8, snapshot_data_updates[i],
 					(snapshot_data_rate[i]/snapshot_data_updates[i])/8);
-				gfx_quads_text(2, 100+i*8, 16, buffer);
+				gfx_quads_text(2, 100+y*12, 16, buffer);
+				y++;
 			}
 		}
 	}
@@ -684,13 +709,13 @@ static void client_process_packet(NETCHUNK *packet)
 			memcmp(packet->data, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0)
 		{
 			int size = packet->data_size-sizeof(SERVERBROWSE_LIST);
-			int num = size/sizeof(NETADDR4);
-			NETADDR4 *addrs = (NETADDR4 *)((char*)packet->data+sizeof(SERVERBROWSE_LIST));
+			int num = size/sizeof(NETADDR);
+			NETADDR *addrs = (NETADDR *)((char*)packet->data+sizeof(SERVERBROWSE_LIST));
 			int i;
 			
 			for(i = 0; i < num; i++)
 			{
-				NETADDR4 addr = addrs[i];
+				NETADDR addr = addrs[i];
 				SERVER_INFO info = {0};
 
 #if defined(CONF_ARCH_ENDIAN_BIG)
@@ -1016,12 +1041,16 @@ static void client_process_packet(NETCHUNK *packet)
 						purgetick = delta_tick;
 						snapsize = snapshot_unpack_delta(deltashot, (SNAPSHOT*)tmpbuffer3, deltadata, deltasize);
 						if(snapsize < 0)
+						{
+							dbg_msg("client", "delta unpack failed!");
 							return;
-							
+						}
+						
 						if(msg != NETMSG_SNAPEMPTY && snapshot_crc((SNAPSHOT*)tmpbuffer3) != crc)
 						{
 							if(config.debug)
-								dbg_msg("client", "snapshot crc error %d", snapcrcerrors);
+								dbg_msg("client", "snapshot crc error #%d - tick=%d wantedcrc=%d gotcrc=%d compressed_size=%d", snapcrcerrors, game_tick, crc, snapshot_crc((SNAPSHOT*)tmpbuffer3), complete_size);
+								
 							snapcrcerrors++;
 							if(snapcrcerrors > 10)
 							{
@@ -1248,7 +1277,7 @@ extern void editor_init();
 
 static void client_run()
 {
-	NETADDR4 bindaddr;
+	NETADDR bindaddr;
 	int64 reporttime = time_get();
 	int64 reportinterval = time_freq()*1;
 
diff --git a/src/engine/client/ec_srvbrowse.c b/src/engine/client/ec_srvbrowse.c
index d6f045f1..41c6a7a0 100644
--- a/src/engine/client/ec_srvbrowse.c
+++ b/src/engine/client/ec_srvbrowse.c
@@ -20,7 +20,7 @@ extern NETCLIENT *net;
 typedef struct SERVERENTRY_t SERVERENTRY;
 struct SERVERENTRY_t
 {
-	NETADDR4 addr;
+	NETADDR addr;
 	int64 request_time;
 	int got_info;
 	SERVER_INFO info;
@@ -264,7 +264,7 @@ static void client_serverbrowse_remove_request(SERVERENTRY *entry)
 	}
 }
 
-void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info)
+void client_serverbrowse_set(NETADDR *addr, int request, SERVER_INFO *info)
 {
 	int hash = addr->ip[0];
 	SERVERENTRY *entry = 0;
@@ -272,7 +272,7 @@ void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info)
 	entry = serverlist_ip[hash];
 	while(entry)
 	{
-		if(net_addr4_cmp(&entry->addr, addr) == 0)
+		if(net_addr_comp(&entry->addr, addr) == 0)
 		{
 			/* update the server that we already have */
 			if(!serverlist_lan)
@@ -377,7 +377,7 @@ void client_serverbrowse_refresh(int lan)
 	}
 	else
 	{
-		NETADDR4 addr;
+		NETADDR addr;
 		NETCHUNK p;
 		int i;
 		
@@ -396,7 +396,7 @@ void client_serverbrowse_refresh(int lan)
 				continue;
 			
 			p.address = addr;
-			netclient_send(net, &p);	
+			netclient_send(net, &p);
 		}
 
 		if(config.debug)
diff --git a/src/engine/e_engine.c b/src/engine/e_engine.c
index 6e1efa95..f71b7b6e 100644
--- a/src/engine/e_engine.c
+++ b/src/engine/e_engine.c
@@ -235,11 +235,11 @@ enum
 typedef struct
 {
 	char hostname[128];
-	NETADDR4 addr;
+	NETADDR addr;
 	
 	/* these are used for lookups */
 	struct {
-		NETADDR4 addr;
+		NETADDR addr;
 		int result;
 		void *thread;
 		volatile int state;
@@ -264,7 +264,7 @@ void lookup_thread(void *user)
 	for(i = 0; i < info->num; i++)
 	{
 		int index = info->start+i;
-		master_servers[index].lookup.result = net_host_lookup(master_servers[index].hostname, 8300, &master_servers[index].lookup.addr);
+		master_servers[index].lookup.result = net_host_lookup(master_servers[index].hostname, &master_servers[index].lookup.addr, NETTYPE_IPV4);
 		master_servers[index].lookup.state = STATE_RESULT;
 	}
 }
@@ -304,6 +304,7 @@ void mastersrv_update()
 			if(master_servers[i].lookup.result == 0)
 			{
 				master_servers[i].addr = master_servers[i].lookup.addr;
+				master_servers[i].addr.port = 8300;
 			}
 			master_servers[i].lookup.state = STATE_PROCESSED;
 		}
@@ -332,7 +333,7 @@ int mastersrv_refreshing()
 	return needs_update;
 }
 
-NETADDR4 mastersrv_get(int index) 
+NETADDR mastersrv_get(int index) 
 {
 	return master_servers[index].addr;
 }
diff --git a/src/engine/e_engine.h b/src/engine/e_engine.h
index 7b5baec9..1c247588 100644
--- a/src/engine/e_engine.h
+++ b/src/engine/e_engine.h
@@ -24,5 +24,5 @@ int mastersrv_refresh_addresses();
 void mastersrv_update();
 int mastersrv_refreshing();
 void mastersrv_dump_servers();
-NETADDR4 mastersrv_get(int index);
+NETADDR mastersrv_get(int index);
 const char *mastersrv_name(int index);
diff --git a/src/engine/e_if_client.h b/src/engine/e_if_client.h
index e06d3e6b..280edf1a 100644
--- a/src/engine/e_if_client.h
+++ b/src/engine/e_if_client.h
@@ -3,6 +3,10 @@
 #define ENGINE_IF_CLIENT_H
 
 /*
+	Title: Client Interface
+*/
+
+/*
 	Section: Constants
 */
 
@@ -21,7 +25,6 @@ enum
 	CLIENTSTATE_ONLINE,
 	CLIENTSTATE_QUITING,
 
-
 	/* Constants: Image Formats
 		IMG_AUTO - Lets the engine choose the format.
 		IMG_RGB - 8-Bit uncompressed RGB
diff --git a/src/engine/e_if_gfx.h b/src/engine/e_if_gfx.h
index 57af6072..b758ed30 100644
--- a/src/engine/e_if_gfx.h
+++ b/src/engine/e_if_gfx.h
@@ -3,6 +3,10 @@
 #define ENGINE_IF_GFX_H
 
 /*
+	Title: Graphics
+*/
+
+/*
 	Section: Structures
 */
 
diff --git a/src/engine/e_if_other.h b/src/engine/e_if_other.h
index e02a7fd1..3d43533d 100644
--- a/src/engine/e_if_other.h
+++ b/src/engine/e_if_other.h
@@ -281,6 +281,20 @@ void snap_invalidate_item(int snapid, int index);
 */
 void snap_input(void *data, int size);
 
+/*
+	Function: snap_set_staticsize
+		Tells the engine how big a specific item always will be. This
+		helps the engine to compress snapshots better.
+	
+	Arguments:
+		type - Item type
+		size - Size of the data.
+		
+	Remarks:
+		Size must be in a multiple of 4.
+*/
+void snap_set_staticsize(int type, int size);
+
 /* message packing */
 enum
 {
diff --git a/src/engine/e_if_server.h b/src/engine/e_if_server.h
index c9775d90..dd5e1403 100644
--- a/src/engine/e_if_server.h
+++ b/src/engine/e_if_server.h
@@ -3,7 +3,7 @@
 #define ENGINE_IF_SERVER_H
 
 /*
-	Section: Server Hooks
+	Section: Server Interface
 */
 
 /* server */
diff --git a/src/engine/e_network.c b/src/engine/e_network.c
index 51fcbd75..2eef9006 100644
--- a/src/engine/e_network.c
+++ b/src/engine/e_network.c
@@ -170,7 +170,7 @@ typedef struct
 	
 	NETPACKETCONSTRUCT construct;
 	
-	NETADDR4 peeraddr;
+	NETADDR peeraddr;
 	NETSOCKET socket;
 	NETSTATS stats;
 } NETCONNECTION;
@@ -182,7 +182,7 @@ typedef struct
 
 typedef struct
 {
-	NETADDR4 addr;
+	NETADDR addr;
 	NETCONNECTION *conn;
 	int current_chunk;
 	int client_id;
@@ -205,7 +205,7 @@ struct NETSERVER_t
 
 struct NETCLIENT_t
 {
-	NETADDR4 server_addr;
+	NETADDR server_addr;
 	NETSOCKET socket;
 	
 	NETRECVINFO recv;
@@ -215,7 +215,7 @@ struct NETCLIENT_t
 static IOHANDLE datalog = 0;
 static HUFFSTATE huffmanstate;
 
-#define COMPRESSION 0
+#define COMPRESSION 1
 
 typedef struct pcap_hdr_s {
         unsigned magic_number;   /* magic number */
@@ -235,7 +235,7 @@ typedef struct pcaprec_hdr_s {
 } pcaprec_hdr_t;
 
 /* packs the data tight and sends it */
-static void send_packet(NETSOCKET socket, NETADDR4 *addr, NETPACKETCONSTRUCT *packet)
+static void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet)
 {
 	unsigned char buffer[NET_MAX_PACKETSIZE];
 	buffer[0] = ((packet->flags<<4)&0xf0)|((packet->ack>>8)&0xf);
@@ -249,13 +249,13 @@ static void send_packet(NETSOCKET socket, NETADDR4 *addr, NETPACKETCONSTRUCT *pa
 	
 	if(COMPRESSION)
 	{
-		int compressed_size = (huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[4], NET_MAX_PACKETSIZE-4)+7)/8;
-		net_udp4_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size);
+		int compressed_size = (huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[3], NET_MAX_PACKETSIZE-4)+7)/8;
+		net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size);
 	}
 	else
 	{
 		mem_copy(&buffer[3], packet->chunk_data, packet->data_size);
-		net_udp4_send(socket, addr, buffer, NET_PACKETHEADERSIZE+packet->data_size);
+		net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+packet->data_size);
 	}
 }
 
@@ -473,7 +473,7 @@ static void conn_resend(NETCONNECTION *conn)
 	dbg_msg("conn", "resent %d packets", resend_count);
 }
 
-static int conn_connect(NETCONNECTION *conn, NETADDR4 *addr)
+static int conn_connect(NETCONNECTION *conn, NETADDR *addr)
 {
 	if(conn->state != NET_CONNSTATE_OFFLINE)
 		return -1;
@@ -504,7 +504,7 @@ static void conn_disconnect(NETCONNECTION *conn, const char *reason)
 	conn_reset(conn);
 }
 
-static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR4 *addr)
+static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *addr)
 {
 	int64 now = time_get();
 	conn->last_recv_time = now;
@@ -685,11 +685,11 @@ static int conn_update(NETCONNECTION *conn)
 	return 0;
 }
 
-NETSERVER *netserver_open(NETADDR4 bindaddr, int max_clients, int flags)
+NETSERVER *netserver_open(NETADDR bindaddr, int max_clients, int flags)
 {
 	int i;
 	NETSERVER *server;
-	NETSOCKET socket = net_udp4_create(bindaddr);
+	NETSOCKET socket = net_udp_create(bindaddr);
 	if(socket == NETSOCKET_INVALID)
 		return 0;
 	
@@ -756,7 +756,7 @@ static void recvinfo_clear(NETRECVINFO *info)
 	info->valid = 0;
 }
 
-static void recvinfo_start(NETRECVINFO *info, NETADDR4 *addr, NETCONNECTION *conn, int cid)
+static void recvinfo_start(NETRECVINFO *info, NETADDR *addr, NETCONNECTION *conn, int cid)
 {
 	info->addr = *addr;
 	info->conn = conn;
@@ -823,7 +823,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
 {
 	while(1)
 	{
-		NETADDR4 addr;
+		NETADDR addr;
 		int i, bytes, found;
 			
 		/* check for a chunk */
@@ -831,7 +831,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
 			return 1;
 		
 		/* TODO: empty the recvinfo */
-		bytes = net_udp4_recv(s->socket, &addr, s->recv.buffer, NET_MAX_PACKETSIZE);
+		bytes = net_udp_recv(s->socket, &addr, s->recv.buffer, NET_MAX_PACKETSIZE);
 
 		/* no more packets for now */
 		if(bytes <= 0)
@@ -849,7 +849,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
 				for(i = 0; i < s->max_clients; i++)
 				{
 					if(s->slots[i].conn.state != NET_CONNSTATE_OFFLINE &&
-						net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
+						net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
 					{
 						found = 1; /* silent ignore.. we got this client already */
 						break;
@@ -884,7 +884,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
 				/* normal packet, find matching slot */
 				for(i = 0; i < s->max_clients; i++)
 				{
-					if(net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
+					if(net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
 					{
 						if(conn_feed(&s->slots[i].conn, &s->recv.data, &addr))
 						{
@@ -952,17 +952,17 @@ NETSOCKET netserver_socket(NETSERVER *s)
 	return s->socket;
 }
 
-int netserver_client_addr(NETSERVER *s, int client_id, NETADDR4 *addr)
+int netserver_client_addr(NETSERVER *s, int client_id, NETADDR *addr)
 {
 	*addr = s->slots[client_id].conn.peeraddr;
 	return 1;
 }
 
-NETCLIENT *netclient_open(NETADDR4 bindaddr, int flags)
+NETCLIENT *netclient_open(NETADDR bindaddr, int flags)
 {
 	NETCLIENT *client = (NETCLIENT *)mem_alloc(sizeof(NETCLIENT), 1);
 	mem_zero(client, sizeof(NETCLIENT));
-	client->socket = net_udp4_create(bindaddr);
+	client->socket = net_udp_create(bindaddr);
 	conn_init(&client->conn, client->socket);
 	return client;
 }
@@ -988,7 +988,7 @@ int netclient_disconnect(NETCLIENT *c, const char *reason)
 	return 0;
 }
 
-int netclient_connect(NETCLIENT *c, NETADDR4 *addr)
+int netclient_connect(NETCLIENT *c, NETADDR *addr)
 {
 	conn_connect(&c->conn, addr);
 	return 0;
@@ -998,7 +998,7 @@ int netclient_recv(NETCLIENT *c, NETCHUNK *chunk)
 {
 	while(1)
 	{
-		NETADDR4 addr;
+		NETADDR addr;
 		int bytes;
 			
 		/* check for a chunk */
@@ -1006,7 +1006,7 @@ int netclient_recv(NETCLIENT *c, NETCHUNK *chunk)
 			return 1;
 		
 		/* TODO: empty the recvinfo */
-		bytes = net_udp4_recv(c->socket, &addr, c->recv.buffer, NET_MAX_PACKETSIZE);
+		bytes = net_udp_recv(c->socket, &addr, c->recv.buffer, NET_MAX_PACKETSIZE);
 
 		/* no more packets for now */
 		if(bytes <= 0)
@@ -1089,7 +1089,7 @@ void netcommon_openlog(const char *filename)
 
 
 static const int freq_table[256+1] = {
-31230,4545,2657,431,1950,919,444,482,2244,617,838,542,715,1814,304,240,754,212,647,186,
+1<<30,4545,2657,431,1950,919,444,482,2244,617,838,542,715,1814,304,240,754,212,647,186,
 283,131,146,166,543,164,167,136,179,859,363,113,157,154,204,108,137,180,202,176,
 872,404,168,134,151,111,113,109,120,126,129,100,41,20,16,22,18,18,17,19,
 16,37,13,21,362,166,99,78,95,88,81,70,83,284,91,187,77,68,52,68,
diff --git a/src/engine/e_network.h b/src/engine/e_network.h
index 746230a7..eaa9df39 100644
--- a/src/engine/e_network.h
+++ b/src/engine/e_network.h
@@ -5,7 +5,7 @@ typedef struct
 	/* -1 means that it's a stateless packet */
 	/* 0 on the client means the server */
 	int client_id;
-	NETADDR4 address; /* only used when client_id == -1 */
+	NETADDR address; /* only used when client_id == -1 */
 	int flags;
 	int data_size;
 	const void *data;
@@ -45,7 +45,7 @@ void netcommon_openlog(const char *filename);
 void netcommon_init();
 
 /* server side */
-NETSERVER *netserver_open(NETADDR4 bindaddr, int max_clients, int flags);
+NETSERVER *netserver_open(NETADDR bindaddr, int max_clients, int flags);
 int netserver_set_callbacks(NETSERVER *s, NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user);
 int netserver_recv(NETSERVER *s, NETCHUNK *chunk);
 int netserver_send(NETSERVER *s, NETCHUNK *chunk);
@@ -53,14 +53,14 @@ int netserver_close(NETSERVER *s);
 int netserver_update(NETSERVER *s);
 NETSOCKET netserver_socket(NETSERVER *s);
 int netserver_drop(NETSERVER *s, int client_id, const char *reason);
-int netserver_client_addr(NETSERVER *s, int client_id, NETADDR4 *addr);
+int netserver_client_addr(NETSERVER *s, int client_id, NETADDR *addr);
 int netserver_max_clients(NETSERVER *s);
 /*void netserver_stats(NETSERVER *s, NETSTATS *stats);*/
 
 /* client side */
-NETCLIENT *netclient_open(NETADDR4 bindaddr, int flags);
+NETCLIENT *netclient_open(NETADDR bindaddr, int flags);
 int netclient_disconnect(NETCLIENT *c, const char *reason);
-int netclient_connect(NETCLIENT *c, NETADDR4 *addr);
+int netclient_connect(NETCLIENT *c, NETADDR *addr);
 int netclient_recv(NETCLIENT *c, NETCHUNK *chunk);
 int netclient_send(NETCLIENT *c, NETCHUNK *chunk);
 int netclient_close(NETCLIENT *c);
@@ -79,7 +79,7 @@ public:
 	net_server() : ptr(0) {}
 	~net_server() { close(); }
 	
-	int open(NETADDR4 bindaddr, int max, int flags) { ptr = netserver_open(bindaddr, max, flags); return ptr != 0; }
+	int open(NETADDR bindaddr, int max, int flags) { ptr = netserver_open(bindaddr, max, flags); return ptr != 0; }
 	int close() { int r = netserver_close(ptr); ptr = 0; return r; }
 	
 	int set_callbacks(NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user)
@@ -103,10 +103,10 @@ public:
 	net_client() : ptr(0) {}
 	~net_client() { close(); }
 	
-	int open(NETADDR4 bindaddr, int flags) { ptr = netclient_open(bindaddr, flags); return ptr != 0; }
+	int open(NETADDR bindaddr, int flags) { ptr = netclient_open(bindaddr, flags); return ptr != 0; }
 	int close() { int r = netclient_close(ptr); ptr = 0; return r; }
 	
-	int connect(NETADDR4 *addr) { return netclient_connect(ptr, addr); }
+	int connect(NETADDR *addr) { return netclient_connect(ptr, addr); }
 	int disconnect(const char *reason) { return netclient_disconnect(ptr, reason); }
 	
 	int recv(NETCHUNK *chunk) { return netclient_recv(ptr, chunk); }
diff --git a/src/engine/e_snapshot.c b/src/engine/e_snapshot.c
index 9d06f59d..88949b65 100644
--- a/src/engine/e_snapshot.c
+++ b/src/engine/e_snapshot.c
@@ -6,6 +6,15 @@
 #include "e_common_interface.h"
 
 
+/* TODO: strange arbitrary number */
+static short item_sizes[64] = {0};
+
+void snap_set_staticsize(int itemtype, int size)
+{
+	dbg_msg("","%d = %d", itemtype, size);
+	item_sizes[itemtype] = size;
+}
+
 int *snapitem_data(SNAPSHOT_ITEM *item) { return (int *)(item+1); }
 int snapitem_type(SNAPSHOT_ITEM *item) { return item->type_and_id>>16; }
 int snapitem_id(SNAPSHOT_ITEM *item) { return item->type_and_id&0xffff; }
@@ -253,14 +262,21 @@ int snapshot_create_delta(SNAPSHOT *from, SNAPSHOT *to, void *dstdata)
 			if(pastindex != -1)
 			{
 				static PERFORMACE_INFO scope = {"diff", 0};
+				int *item_data_dst = data+3;
 				perf_start(&scope);
 		
 				pastitem = snapshot_get_item(from, pastindex);
-				if(diff_item((int*)snapitem_data(pastitem), (int*)snapitem_data(curitem), data+3, itemsize/4))
+				
+				if(item_sizes[snapitem_type(curitem)])
+					item_data_dst = data+2;
+				
+				if(diff_item((int*)snapitem_data(pastitem), (int*)snapitem_data(curitem), item_data_dst, itemsize/4))
 				{
-					*data++ = itemsize;
+					
 					*data++ = snapitem_type(curitem);
 					*data++ = snapitem_id(curitem);
+					if(!item_sizes[snapitem_type(curitem)])
+						*data++ = itemsize/4;
 					data += itemsize/4;
 					delta->num_update_items++;
 				}
@@ -271,9 +287,10 @@ int snapshot_create_delta(SNAPSHOT *from, SNAPSHOT *to, void *dstdata)
 				static PERFORMACE_INFO scope = {"copy", 0};
 				perf_start(&scope);
 				
-				*data++ = itemsize;
 				*data++ = snapitem_type(curitem);
 				*data++ = snapitem_id(curitem);
+				if(!item_sizes[snapitem_type(curitem)])
+					*data++ = itemsize/4;
 				
 				mem_copy(data, snapitem_data(curitem), itemsize);
 				size_count += itemsize;
@@ -370,12 +387,19 @@ int snapshot_unpack_delta(SNAPSHOT *from, SNAPSHOT *to, void *srcdata, int data_
 	/* unpack updated stuff */
 	for(i = 0; i < delta->num_update_items; i++)
 	{
-		if(data+3 > end)
+		if(data+2 > end)
 			return -1;
 		
-		itemsize = *data++;
 		type = *data++;
 		id = *data++;
+		if(item_sizes[type])
+			itemsize = item_sizes[type];
+		else
+		{
+			if(data+1 > end)
+				return -1;
+			itemsize = (*data++) * 4;
+		}
 		snapshot_current = type;
 		
 		if(range_check(end, data, itemsize) || itemsize < 0) return -1;
diff --git a/src/engine/e_system.c b/src/engine/e_system.c
index c0d3595c..f8fca864 100644
--- a/src/engine/e_system.c
+++ b/src/engine/e_system.c
@@ -465,8 +465,9 @@ int64 time_freq()
 }
 
 /* -----  network ----- */
-static void netaddr4_to_sockaddr(const NETADDR4 *src, struct sockaddr *dest)
+static void netaddr_to_sockaddr(const NETADDR *src, struct sockaddr *dest)
 {
+	/* TODO: IPv6 support */
 	struct sockaddr_in *p = (struct sockaddr_in *)dest;
 	mem_zero(p, sizeof(struct sockaddr_in));
 	p->sin_family = AF_INET;
@@ -474,9 +475,11 @@ static void netaddr4_to_sockaddr(const NETADDR4 *src, struct sockaddr *dest)
 	p->sin_addr.s_addr = htonl(src->ip[0]<<24|src->ip[1]<<16|src->ip[2]<<8|src->ip[3]);
 }
 
-static void sockaddr_to_netaddr4(const struct sockaddr *src, NETADDR4 *dst)
+static void sockaddr_to_netaddr(const struct sockaddr *src, NETADDR *dst)
 {
+	/* TODO: IPv6 support */
 	unsigned int ip = htonl(((struct sockaddr_in*)src)->sin_addr.s_addr);
+	dst->type = NETTYPE_IPV4;
 	dst->port = htons(((struct sockaddr_in*)src)->sin_port);
 	dst->ip[0] = (unsigned char)((ip>>24)&0xFF);
 	dst->ip[1] = (unsigned char)((ip>>16)&0xFF);
@@ -484,21 +487,15 @@ static void sockaddr_to_netaddr4(const struct sockaddr *src, NETADDR4 *dst)
 	dst->ip[3] = (unsigned char)(ip&0xFF);
 }
 
-int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b)
+int net_addr_comp(const NETADDR *a, const NETADDR *b)
 {
-	if(	a->ip[0] != b->ip[0] ||
-		a->ip[1] != b->ip[1] ||
-		a->ip[2] != b->ip[2] ||
-		a->ip[3] != b->ip[3] ||
-		a->port != b->port
-	)
-		return 1;
-	return 0;
+	return mem_comp(a, b, sizeof(NETADDR));
 }
 
 
-int net_host_lookup(const char *hostname, unsigned short port, NETADDR4 *addr)
+int net_host_lookup(const char *hostname, NETADDR *addr, int types)
 {
+	/* TODO: IPv6 support */
 	struct addrinfo hints;
 	struct addrinfo *result;
 	int e;
@@ -510,14 +507,15 @@ int net_host_lookup(const char *hostname, unsigned short port, NETADDR4 *addr)
 	if(e != 0 || !result)
 		return -1;
 
-	sockaddr_to_netaddr4(result->ai_addr, addr);
+	sockaddr_to_netaddr(result->ai_addr, addr);
 	freeaddrinfo(result);
-	addr->port = port;
+	addr->port = 0;
 	return 0;
 }
 
-NETSOCKET net_udp4_create(NETADDR4 bindaddr)
+NETSOCKET net_udp_create(NETADDR bindaddr)
 {
+	/* TODO: IPv6 support */
 	struct sockaddr addr;
 	unsigned int mode = 1;
 	int broadcast = 1;
@@ -528,10 +526,10 @@ NETSOCKET net_udp4_create(NETADDR4 bindaddr)
 		return NETSOCKET_INVALID;
 	
 	/* bind, we should check for error */
-	netaddr4_to_sockaddr(&bindaddr, &addr);
+	netaddr_to_sockaddr(&bindaddr, &addr);
 	if(bind(sock, &addr, sizeof(addr)) != 0)
 	{
-		net_udp4_close(sock);
+		net_udp_close(sock);
 		return NETSOCKET_INVALID;
 	}
 	
@@ -549,12 +547,12 @@ NETSOCKET net_udp4_create(NETADDR4 bindaddr)
 	return sock;
 }
 
-int net_udp4_send(NETSOCKET sock, const NETADDR4 *addr, const void *data, int size)
+int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size)
 {
 	struct sockaddr sa;
 	int d;
 	mem_zero(&sa, sizeof(sa));
-	netaddr4_to_sockaddr(addr, &sa);
+	netaddr_to_sockaddr(addr, &sa);
 	d = sendto((int)sock, (const char*)data, size, 0, &sa, sizeof(sa));
 	if(d < 0)
 		dbg_msg("net", "sendto error %d %x", d, d);
@@ -563,7 +561,7 @@ int net_udp4_send(NETSOCKET sock, const NETADDR4 *addr, const void *data, int si
 	return d;
 }
 
-int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize)
+int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize)
 {
 	struct sockaddr from;
 	int bytes;
@@ -571,7 +569,7 @@ int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize)
 	bytes = recvfrom(sock, (char*)data, maxsize, 0, &from, &fromlen);
 	if(bytes > 0)
 	{
-		sockaddr_to_netaddr4(&from, addr);
+		sockaddr_to_netaddr(&from, addr);
 		network_stats.recv_bytes += bytes;
 		network_stats.recv_packets++;
 		return bytes;
@@ -581,7 +579,7 @@ int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize)
 	return -1; /* error */
 }
 
-int net_udp4_close(NETSOCKET sock)
+int net_udp_close(NETSOCKET sock)
 {
 #if defined(CONF_FAMILY_WINDOWS)
 	closesocket(sock);
@@ -591,8 +589,9 @@ int net_udp4_close(NETSOCKET sock)
 	return 0;
 }
 
-NETSOCKET net_tcp4_create(const NETADDR4 *a)
+NETSOCKET net_tcp_create(const NETADDR *a)
 {
+	/* TODO: IPv6 support */
     struct sockaddr addr;
 
     /* create socket */
@@ -601,14 +600,14 @@ NETSOCKET net_tcp4_create(const NETADDR4 *a)
         return NETSOCKET_INVALID;
 
     /* bind, we should check for error */
-    netaddr4_to_sockaddr(a, &addr);
+    netaddr_to_sockaddr(a, &addr);
     bind(sock, &addr, sizeof(addr));
 
     /* return */
     return sock;
 }
 
-int net_tcp4_set_non_blocking(NETSOCKET sock)
+int net_tcp_set_non_blocking(NETSOCKET sock)
 {
 	unsigned int mode = 1;
 #if defined(CONF_FAMILY_WINDOWS)
@@ -618,7 +617,7 @@ int net_tcp4_set_non_blocking(NETSOCKET sock)
 #endif
 }
 
-int net_tcp4_set_blocking(NETSOCKET sock)
+int net_tcp_set_blocking(NETSOCKET sock)
 {
 	unsigned int mode = 0;
 #if defined(CONF_FAMILY_WINDOWS)
@@ -628,12 +627,12 @@ int net_tcp4_set_blocking(NETSOCKET sock)
 #endif
 }
 
-int net_tcp4_listen(NETSOCKET sock, int backlog)
+int net_tcp_listen(NETSOCKET sock, int backlog)
 {
 	return listen(sock, backlog);
 }
 
-int net_tcp4_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR4 *a)
+int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a)
 {
 	int s;
 	socklen_t sockaddr_len;
@@ -645,48 +644,48 @@ int net_tcp4_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR4 *a)
 
 	if (s != -1)
 	{
-		sockaddr_to_netaddr4(&addr, a);
+		sockaddr_to_netaddr(&addr, a);
 		*new_sock = s;
 	}
 	return s;
 }
 
-int net_tcp4_connect(NETSOCKET sock, const NETADDR4 *a)
+int net_tcp_connect(NETSOCKET sock, const NETADDR *a)
 {
   struct sockaddr addr;
 
-  netaddr4_to_sockaddr(a, &addr);
+  netaddr_to_sockaddr(a, &addr);
   return connect(sock, &addr, sizeof(addr)); 
 }
 
-int net_tcp4_connect_non_blocking(NETSOCKET sock, const NETADDR4 *a)
+int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a)
 {
 	struct sockaddr addr;
 	int res;
 
-	netaddr4_to_sockaddr(a, &addr);
-	net_tcp4_set_non_blocking(sock);
+	netaddr_to_sockaddr(a, &addr);
+	net_tcp_set_non_blocking(sock);
   	res = connect(sock, &addr, sizeof(addr));
-	net_tcp4_set_blocking(sock);
+	net_tcp_set_blocking(sock);
 
 	return res;
 }
 
-int net_tcp4_send(NETSOCKET sock, const void *data, int size)
+int net_tcp_send(NETSOCKET sock, const void *data, int size)
 {
   int d;
   d = send((int)sock, (const char*)data, size, 0);
   return d;
 }
 
-int net_tcp4_recv(NETSOCKET sock, void *data, int maxsize)
+int net_tcp_recv(NETSOCKET sock, void *data, int maxsize)
 {
   int bytes;
   bytes = recv((int)sock, (char*)data, maxsize, 0);
   return bytes;
 }
 
-int net_tcp4_close(NETSOCKET sock)
+int net_tcp_close(NETSOCKET sock)
 {
 #if defined(CONF_FAMILY_WINDOWS)
 	closesocket(sock);
@@ -958,6 +957,11 @@ void str_hex(char *dst, int dst_size, const void *data, int data_size)
 	}
 }
 
+int mem_comp(const void *a, const void *b, int size)
+{
+	return memcmp(a,b,size);
+}
+
 void net_stats(NETSTATS *stats_inout)
 {
 	*stats_inout = network_stats;
diff --git a/src/engine/e_system.h b/src/engine/e_system.h
index 38c2b076..0b1cbaab 100644
--- a/src/engine/e_system.h
+++ b/src/engine/e_system.h
@@ -1,4 +1,9 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+/*
+	Title: OS Abstraction
+*/
+
 #ifndef BASE_SYSTEM_H
 #define BASE_SYSTEM_H
 
@@ -9,10 +14,9 @@ extern "C" {
 #endif
 
 /* Group: Debug */
-/**********
+/*
 	Function: dbg_assert
-	
-	Breaks into the debugger based on a test.
+		Breaks into the debugger based on a test.
 	
 	Parameters:
 		test - Result of the test.
@@ -23,25 +27,24 @@ extern "C" {
 	
 	See Also:
 		<dbg_break>
-**********/
+*/
 void dbg_assert(int test, const char *msg);
 #define dbg_assert(test,msg) dbg_assert_imp(__FILE__, __LINE__, test,  msg)
 void dbg_assert_imp(const char *filename, int line, int test, const char *msg);
 
-/**********
+/*
 	Function: dbg_break
-	
-	Breaks into the debugger.
+		Breaks into the debugger.
 	
 	Remarks:
 		Does nothing in release version of the library.
 	
 	See Also:
 		<dbg_assert>
-**********/
+*/
 void dbg_break();
 
-/**********
+/*
 	Function: dbg_msg
 	
 	Prints a debug message.
@@ -55,15 +58,14 @@ void dbg_break();
 		
 	See Also:
 		<dbg_assert>
-**********/
+*/
 void dbg_msg(const char *sys, const char *fmt, ...);
 
 /* Group: Memory */
 
-/**********
+/*
 	Function: mem_alloc
-	
-	Allocates memory.
+		Allocates memory.
 	
 	Parameters:
 		size - Size of the needed block.
@@ -79,14 +81,13 @@ void dbg_msg(const char *sys, const char *fmt, ...);
 
 	See Also:
 		<mem_free>
-**********/
+*/
 void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment);
 #define mem_alloc(s,a) mem_alloc_debug(__FILE__, __LINE__, (s), (a))
 
-/**********
+/*
 	Function: mem_free
-	
-	Frees a block allocated through <mem_alloc>.
+		Frees a block allocated through <mem_alloc>.
 	
 	Remarks:
 		- In the debug version of the library the function will assert if
@@ -95,10 +96,10 @@ void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned al
 	
 	See Also:
 		<mem_alloc>
-**********/
+*/
 void mem_free(void *block);
 
-/**********
+/*
 	Function: mem_copy
 		Copies a a memory block.
 	
@@ -113,37 +114,54 @@ void mem_free(void *block);
 	
 	See Also:
 		<mem_move>
-**********/
+*/
 void mem_copy(void *dest, const void *source, unsigned size);
 
-/**********
+/*
 	Function: mem_move
-		Copies a a memory block.
+		Copies a a memory block
 	
 	Parameters:
-		dest - Destination.
-		source - Source to copy.
-		size - Size of the block to copy.
+		dest - Destination
+		source - Source to copy
+		size - Size of the block to copy
 	
 	Remarks:
-		- This functions handles cases where source and destination is overlapping.
+		- This functions handles cases where source and destination
+		is overlapping
 	
 	See Also:
 		<mem_copy>
-**********/
+*/
 void mem_move(void *dest, const void *source, unsigned size);
 
-/**********
+/*
 	Function: mem_zero
-		Sets a complete memory block to 0.
+		Sets a complete memory block to 0
 	
 	Parameters:
-		block - Pointer to the block to zero out.
-		size - Size of the block.
-**********/
+		block - Pointer to the block to zero out
+		size - Size of the block
+*/
 void mem_zero(void *block, unsigned size);
 
-/* ------- io ------- */
+/*
+	Function: mem_comp
+		Compares two blocks of memory
+	
+	Parameters:
+		a - First block of data
+		b - Second block of data
+		size - Size of the data to compare
+		
+	Returns:
+		<0 - Block a is lesser then block b
+		0 - Block a is equal to block b
+		>0 - Block a is greater then block b
+*/
+int mem_comp(const void *a, const void *b, int size);
+
+/* Group: File IO */
 enum {
 	IOFLAG_READ = 1,
 	IOFLAG_WRITE = 2,
@@ -156,9 +174,7 @@ enum {
 
 typedef struct IOINTERNAL *IOHANDLE;
 
-/**** Group: File IO ****/
-
-/****
+/*
 	Function: io_open
 		Opens a file.
 
@@ -169,10 +185,10 @@ typedef struct IOINTERNAL *IOHANDLE;
 	Returns:
 		Returns a handle to the file on success and 0 on failure.
 
-****/
+*/
 IOHANDLE io_open(const char *filename, int flags);
 
-/****
+/*
 	Function: io_read
 		Reads data into a buffer from a file.
 
@@ -184,10 +200,10 @@ IOHANDLE io_open(const char *filename, int flags);
 	Returns:
 		Number of bytes read.
 
-****/
+*/
 unsigned io_read(IOHANDLE io, void *buffer, unsigned size);
 
-/*****
+/*
 	Function: io_skip
 		Skips data in a file.
 	
@@ -197,13 +213,12 @@ unsigned io_read(IOHANDLE io, void *buffer, unsigned size);
 		
 	Returns:
 		Number of bytes skipped.
-****/
+*/
 unsigned io_skip(IOHANDLE io, unsigned size);
 
-/*****
+/*
 	Function: io_write
-	
-	Writes data from a buffer to file.
+		Writes data from a buffer to file.
 	
 	Parameters:
 		io - Handle to the file.
@@ -212,10 +227,10 @@ unsigned io_skip(IOHANDLE io, unsigned size);
 		
 	Returns:
 		Number of bytes written.
-*****/
+*/
 unsigned io_write(IOHANDLE io, const void *buffer, unsigned size);
 
-/*****
+/*
 	Function: io_seek
 		Seeks to a specified offset in the file.
 	
@@ -226,10 +241,10 @@ unsigned io_write(IOHANDLE io, const void *buffer, unsigned size);
 		
 	Returns:
 		Returns 0 on success.
-*****/
+*/
 int io_seek(IOHANDLE io, int offset, int origin);
 
-/*****
+/*
 	Function: io_tell
 		Gets the current position in the file.
 	
@@ -238,10 +253,10 @@ int io_seek(IOHANDLE io, int offset, int origin);
 		
 	Returns:
 		Returns the current position. -1L if an error occured.
-*****/
+*/
 long int io_tell(IOHANDLE io);
 
-/*****
+/*
 	Function: io_length
 		Gets the total length of the file. Resetting cursor to the beginning
 	
@@ -250,10 +265,10 @@ long int io_tell(IOHANDLE io);
 		
 	Returns:
 		Returns the total size. -1L if an error occured.
-*****/
+*/
 long int io_length(IOHANDLE io);
 
-/*****
+/*
 	Function: io_close
 		Closes a file.
 	
@@ -262,10 +277,10 @@ long int io_length(IOHANDLE io);
 		
 	Returns:
 		Returns 0 on success.
-*****/
+*/
 int io_close(IOHANDLE io);
 
-/*****
+/*
 	Function: io_flush
 		Empties all buffers and writes all pending data.
 	
@@ -274,22 +289,77 @@ int io_close(IOHANDLE io);
 		
 	Returns:
 		Returns 0 on success.
-*****/
+*/
 int io_flush(IOHANDLE io);
 
-/**** Group: Threads ****/
 
-/*****
+/*
+	Function: io_stdin
+		Returns an <IOHANDLE> to the standard input.
+*/
+IOHANDLE io_stdin();
+
+/*
+	Function: io_stdout
+		Returns an <IOHANDLE> to the standard output.
+*/
+IOHANDLE io_stdout();
+
+/*
+	Function: io_stderr
+		Returns an <IOHANDLE> to the standard error.
+*/
+IOHANDLE io_stderr();
+
+
+/* Group: Threads */
+
+/*
 	Function: thread_sleep
-	
-	Suspends the current thread for a given period.
+		Suspends the current thread for a given period.
 	
 	Parameters:
 		milliseconds - Number of milliseconds to sleep.
-*****/
+*/
 void thread_sleep(int milliseconds);
 
-/**** Group: Locks ****/
+/*
+	Function: thread_create
+		Creates a new thread.
+	
+	Parameters:
+		threadfunc - Entry point for the new thread.
+		user - Pointer to pass to the thread.
+		
+*/
+void *thread_create(void (*threadfunc)(void *), void *user);
+
+/*
+	Function: thread_wait
+		Waits for a thread to be done or destroyed.
+	
+	Parameters:
+		thread - Thread to wait for.
+*/
+void thread_wait(void *thread);
+
+/*
+	Function: thread_destoy
+		Destroys a thread.
+	
+	Parameters:
+		thread - Thread to destroy.
+*/
+void thread_destroy(void *thread);
+
+/*
+	Function: thread_yeild
+		Yeild the current threads execution slice.
+*/
+void thread_yield();
+
+
+/* Group: Locks */
 typedef void* LOCK;
 
 LOCK lock_create();
@@ -299,7 +369,7 @@ int lock_try(LOCK lock);
 void lock_wait(LOCK lock);
 void lock_release(LOCK lock);
 
-/**** Group: Timer ****/
+/* Group: Timer */
 #ifdef __GNUC__
 /* if compiled with -pedantic-errors it will complain about long
 	not being a C90 thing.
@@ -308,71 +378,88 @@ __extension__ typedef long long int64;
 #else
 typedef long long int64;
 #endif
-/*****
+/*
 	Function: time_get
-	
-	Fetches a sample from a high resolution timer.
+		Fetches a sample from a high resolution timer.
 	
 	Returns:
 		Current value of the timer.
 
 	Remarks:
 		To know how fast the timer is ticking, see <time_freq>.
-*****/
+*/
 int64 time_get();
 
-/*****
+/*
 	Function: time_freq
-	
-	Returns the frequency of the high resolution timer.
+		Returns the frequency of the high resolution timer.
 	
 	Returns:
 		Returns the frequency of the high resolution timer.
-*****/
+*/
 int64 time_freq();
 
-/**** Group: Network General ipv4 ****/
+/*
+	Function: time_timestamp
+		Retrives the current time as a UNIX timestamp
+	
+	Returns:
+		The time as a UNIX timestamp
+*/
+unsigned time_timestamp();
+
+/* Group: Network General ipv4 */
 typedef int NETSOCKET;
 enum
 {
-	NETSOCKET_INVALID = -1
+	NETSOCKET_INVALID = -1,
+	
+	NETTYPE_INVALID = 0,
+	NETTYPE_IPV4 = 1,
+	NETTYPE_IPV6 = 2,
+	NETTYPE_ALL = ~0
 };
 
-typedef struct 
+/*
+typedef struct
 {
 	unsigned char ip[4];
 	unsigned short port;
-} NETADDR4;
+} NETADDR4;*/
 
-/*****
+typedef struct
+{
+	unsigned int type;
+	unsigned char ip[16];
+	unsigned short port;
+} NETADDR;
+
+/*
 	Function: net_host_lookup
-	
-	Does a hostname lookup by name and fills out the passed NETADDE4 struct with the recieved details.
+		Does a hostname lookup by name and fills out the passed NETADDR struct with the recieved details.
 
 	Returns:
 		0 on success.
-*****/
-int net_host_lookup(const char *hostname, unsigned short port, NETADDR4 *addr);
+*/
+int net_host_lookup(const char *hostname, NETADDR *addr, int types);
 
-/**** Group: Network UDP4 ****/
+/* Group: Network UDP */
 
-/*****
-	Function: net_udp4_create
-	
-	Creates a UDP4 socket and binds it to a port.
+/*
+	Function: net_udp_create
+		Creates a UDP socket and binds it to a port.
 
 	Parameters:
 		port - Port to bind the socket to.
 	
 	Returns:
 		On success it returns an handle to the socket. On failure it returns NETSOCKET_INVALID.
-*****/
-NETSOCKET net_udp4_create(NETADDR4 bindaddr);
+*/
+NETSOCKET net_udp_create(NETADDR bindaddr);
 
-/*****
-	Function: net_udp4_send
-	
-	Sends a packet over an UDP4 socket.
+/*
+	Function: net_udp_send
+		Sends a packet over an UDP socket.
 
 	Parameters:
 		sock - Socket to use.
@@ -382,177 +469,322 @@ NETSOCKET net_udp4_create(NETADDR4 bindaddr);
 	
 	Returns:
 		On success it returns the number of bytes sent. Returns -1 on error.
-*****/
-int net_udp4_send(NETSOCKET sock, const NETADDR4 *addr, const void *data, int size);
+*/
+int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size);
 
-/*****
-	Function: net_udp4_recv
-	
-	Recives a packet over an UDP4 socket.
+/*
+	Function: net_udp_recv
+		Recives a packet over an UDP socket.
 
 	Parameters:
 		sock - Socket to use.
-		addr - Pointer to an NETADDR4 that will recive the address.
+		addr - Pointer to an NETADDR that will recive the address.
 		data - Pointer to a buffer that will recive the data.
 		maxsize - Maximum size to recive.
 	
 	Returns:
 		On success it returns the number of bytes recived. Returns -1 on error.
-*****/
-int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize);
+*/
+int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize);
 
-/*****
-	Function: net_udp4_close
-	
-	Closes an UDP4 socket.
+/*
+	Function: net_udp_close
+		Closes an UDP socket.
 
 	Parameters:
 		sock - Socket to close.
 	
 	Returns:
 		Returns 0 on success. -1 on error.
-*****/
-int net_udp4_close(NETSOCKET sock);
+*/
+int net_udp_close(NETSOCKET sock);
 
 
-/**** Group: Network TCP4 ****/
+/* Group: Network TCP */
 
-/*****
-	Function: net_tcp4_create
+/*
+	Function: net_tcp_create
 	
 	DOCTODO: serp
-*****/
-NETSOCKET net_tcp4_create(const NETADDR4 *a);
+*/
+NETSOCKET net_tcp_create(const NETADDR *a);
 
-/*****
-	Function: net_tcp4_set_non_blocking
+/*
+	Function: net_tcp_set_non_blocking
 
 	DOCTODO: serp
-*****/
-int net_tcp4_set_non_blocking(NETSOCKET sock);
+*/
+int net_tcp_set_non_blocking(NETSOCKET sock);
 
-/*****
-	Function: net_tcp4_set_non_blocking
+/*
+	Function: net_tcp_set_non_blocking
 
 	DOCTODO: serp
-*****/
-int net_tcp4_set_blocking(NETSOCKET sock);
+*/
+int net_tcp_set_blocking(NETSOCKET sock);
 
-/*****
-	Function: net_tcp4_listen
+/*
+	Function: net_tcp_listen
 
 	DOCTODO: serp 
-*****/
-int net_tcp4_listen(NETSOCKET sock, int backlog);
+*/
+int net_tcp_listen(NETSOCKET sock, int backlog);
 
-/*****
-	Function: net_tcp4_accept
+/*
+	Function: net_tcp_accept
 	
 	DOCTODO: serp
-*****/
-int net_tcp4_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR4 *a);
+*/
+int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a);
 
-/*****
-	Function: net_tcp4_connect
+/*
+	Function: net_tcp_connect
 	
 	DOCTODO: serp
-*****/
-int net_tcp4_connect(NETSOCKET sock, const NETADDR4 *a);
+*/
+int net_tcp_connect(NETSOCKET sock, const NETADDR *a);
 
-/*****
-	Function: net_tcp4_connect_non_blocking
+/*
+	Function: net_tcp_connect_non_blocking
 	
 	DOCTODO: serp
-*****/
-int net_tcp4_connect_non_blocking(NETSOCKET sock, const NETADDR4 *a);
+*/
+int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a);
 
-/*****
-	Function: net_tcp4_send
+/*
+	Function: net_tcp_send
 	
 	DOCTODO: serp
-*****/
-int net_tcp4_send(NETSOCKET sock, const void *data, int size);
+*/
+int net_tcp_send(NETSOCKET sock, const void *data, int size);
 
-/*****
-	Function: net_tcp4_recv
+/*
+	Function: net_tcp_recv
 	
 	DOCTODO: serp
-*****/
-int net_tcp4_recv(NETSOCKET sock, void *data, int maxsize);
+*/
+int net_tcp_recv(NETSOCKET sock, void *data, int maxsize);
 
-/*****
-	Function: net_tcp4_close
+/*
+	Function: net_tcp_close
 	
 	DOCTODO: serp
-*****/
-int net_tcp4_close(NETSOCKET sock);
+*/
+int net_tcp_close(NETSOCKET sock);
 
-/*****
+/*
 	Function: net_errno
 
 	DOCTODO: serp
-*****/
+*/
 int net_errno();
 
-/*****
+/*
 	Function: net_would_block
 
 	DOCTODO: serp
-*****/
+*/
 int net_would_block();
 
-/*****
+/*
 	Function: net_init
 
 	DOCTODO: serp
-*****/
+*/
 int net_init();
 
+/* Group: Strings */
 
+/*
+	Function: str_append
+		Appends a string to another.
+	
+	Parameters:
+		dst - Pointer to a buffer that contains a string.
+		src - String to append.
+		dst_size - Size of the buffer of the dst string.
+		
+	Remarks:
+		- The strings are treated as zero-termineted strings.
+		- Garantees that dst string will contain zero-termination.
+*/
+void str_append(char *dst, const char *src, int dst_size);
 
-/* NOT DOCUMENTED */
-typedef void (*fs_listdir_callback)(const char *name, int is_dir, void *user);
-int fs_listdir(const char *dir, fs_listdir_callback cb, void *user);
-int fs_storage_path(const char *appname, char *path, int max);
-int fs_makedir(const char *path);
-int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b);
-int net_socket_read_wait(NETSOCKET sock, int time);
-
-void mem_debug_dump();
-int mem_allocated();
+/*
+	Function: str_copy
+		Copies a string to another.
+		
+	Parameters:
+		dst - Pointer to a buffer that shall recive the string.
+		src - String to be copied.
+		dst_size - Size of the buffer dst.
 
-void *thread_create(void (*threadfunc)(void *), void *user);
-void thread_wait(void *thread);
-void thread_destroy(void *thread);
-void thread_yield();
-unsigned time_timestamp();
+	Remarks:
+		- The strings are treated as zero-termineted strings.
+		- Garantees that dst string will contain zero-termination.
+*/
+void str_copy(char *dst, const char *src, int dst_size);
 
-void swap_endian(void *data, unsigned elem_size, unsigned num);
+/*
+	Function: str_format
+		Performs printf formating into a buffer.
+		
+	Parameters:
+		buffer - Pointer to the buffer to recive the formated string.
+		buffer_size - Size of the buffer.
+		format - printf formating string.
+		... - Parameters for the formating.
 
-/* #define cache_prefetch(addr) __builtin_prefetch(addr) */
+	Remarks:
+		- See the C manual for syntax for the printf formating string.
+		- The strings are treated as zero-termineted strings.
+		- Garantees that dst string will contain zero-termination.
+*/
+void str_format(char *buffer, int buffer_size, const char *format, ...);
 
-/*typedef unsigned char [256] pstr;
-void pstr_format(pstr *str, )*/
+/*
+	Function: str_sanitize_strong
+		Replaces all characters below 32 and above 127 with whitespace.
+	
+	Parameters:
+		str - String to sanitize.
 
-void str_append(char *dst, const char *src, int dst_size);
-void str_copy(char *dst, const char *src, int dst_size);
-void str_format(char *buffer, int buffer_size, const char *format, ...);
+	Remarks:
+		- The strings are treated as zero-termineted strings.
+*/
 void str_sanitize_strong(char *str);
+
+/*
+	Function: str_sanitize
+		Replaces all characters below 32 and above 127 with whitespace with
+		exception to \r, \n and \r.
+	
+	Parameters:
+		str - String to sanitize.
+
+	Remarks:
+		- The strings are treated as zero-termineted strings.
+*/
 void str_sanitize(char *str);
+
+/*
+	Function: str_comp_nocase
+		Compares to strings case insensitive.
+	
+	Parameters:
+		a - String to compare.
+		b - String to compare.
+	
+	Returns:	
+		<0 - String g a is lesser then string b
+		0 - String a is equal to string b
+		>0 - String a is greater then string b
+
+	Remarks:
+		- Only garanted to work with a-z/A-Z.
+		- The strings are treated as zero-termineted strings.
+*/
 int str_comp_nocase(const char *a, const char *b);
+
+/*
+	Function: str_find_nocase
+		Finds a string inside another string case insensitive.
+
+	Parameters:
+		haystack - String to search in
+		needle - String to search for
+		
+	Returns:
+		A pointer into haystack where the needle was found.
+		Returns NULL of needle could not be found.
+
+	Remarks:
+		- Only garanted to work with a-z/A-Z.
+		- The strings are treated as zero-termineted strings.
+*/
 const char *str_find_nocase(const char *haystack, const char *needle);
+
+
+/*
+	Function: str_hex
+		Takes a datablock and generates a hexstring of it.
+
+	Parameters:
+		dst - Buffer to fill with hex data
+		dst_size - size of the buffer
+		data - Data to turn into hex
+		data - Size of the data
+
+	Remarks:
+		- The desination buffer will be zero-terminated
+*/
 void str_hex(char *dst, int dst_size, const void *data, int data_size);
 
+
+/*
+	Function: fs_listdir
+		Lists the files in a directory
+		
+	Parameters:
+		dir - Directory to list
+		cb - Callback function to call for each entry
+		user - Pointer to give to the callback
+	
+	Returns:
+		DOCTODO
+*/
+typedef void (*fs_listdir_callback)(const char *name, int is_dir, void *user);
+int fs_listdir(const char *dir, fs_listdir_callback cb, void *user);
+
+/*
+	Function: fs_makedir
+		Creates a directory
+	
+	Parameters:
+		path - Directory to create
+	
+	Returns:
+		DOCTODO
+	
+	Remarks:
+		Does not create several directories if needed. "a/b/c" will result
+		in a failure if b or a does not exist.
+*/
+int fs_makedir(const char *path);
+
+/*
+	Function: fs_storage_path
+		Fetches per user configuration directory.
+	
+	Returns:
+		DOCTODO
+	
+	Remarks:
+		- Returns ~/.appname on UNIX based systems
+		- Returns %APPDATA%/Appname on Windows based systems
+*/
+int fs_storage_path(const char *appname, char *path, int max);
+
+
+/*
+	Group: Undocumented
+*/
+
+int net_addr_comp(const NETADDR *a, const NETADDR *b);
+int net_addr_str(const NETADDR *addr, char *string, int max_length);
+int net_socket_read_wait(NETSOCKET sock, int time);
+
+void mem_debug_dump();
+int mem_allocated();
+
+void swap_endian(void *data, unsigned elem_size, unsigned num);
+
 typedef void (*DBG_LOGGER)(const char *line);
 void dbg_logger(DBG_LOGGER logger);
 void dbg_logger_stdout();
 void dbg_logger_debugger();
 void dbg_logger_file(const char *filename);
 
-IOHANDLE io_stdin();
-IOHANDLE io_stdout();
-IOHANDLE io_stderr();
-
 typedef struct
 {
 	int sent_packets;
@@ -561,6 +793,7 @@ typedef struct
 	int recv_bytes;
 } NETSTATS;
 
+
 void net_stats(NETSTATS *stats);
 
 #ifdef __cplusplus
diff --git a/src/engine/server/es_register.c b/src/engine/server/es_register.c
index cec0fa19..a85900aa 100644
--- a/src/engine/server/es_register.c
+++ b/src/engine/server/es_register.c
@@ -29,7 +29,7 @@ static void register_new_state(int state)
 	register_state_start = time_get();
 }
 
-static void register_send_fwcheckresponse(NETADDR4 *addr)
+static void register_send_fwcheckresponse(NETADDR *addr)
 {
 	NETCHUNK packet;
 	packet.client_id = -1;
@@ -40,7 +40,7 @@ static void register_send_fwcheckresponse(NETADDR4 *addr)
 	netserver_send(net, &packet);
 }
 	
-static void register_send_heartbeat(NETADDR4 addr)
+static void register_send_heartbeat(NETADDR addr)
 {
 	static unsigned char data[sizeof(SERVERBROWSE_HEARTBEAT) + 2];
 	unsigned short port = config.sv_port;
@@ -62,7 +62,7 @@ static void register_send_heartbeat(NETADDR4 addr)
 	netserver_send(net, &packet);
 }
 
-static void register_send_count_request(NETADDR4 addr)
+static void register_send_count_request(NETADDR addr)
 {
 	NETCHUNK packet;
 	packet.client_id = -1;
@@ -75,13 +75,13 @@ static void register_send_count_request(NETADDR4 addr)
 
 typedef struct
 {
-	NETADDR4 addr;
+	NETADDR addr;
 	int count;
 	int valid;
 	int64 last_send;
 } MASTERSERVER_INFO;
 
-static MASTERSERVER_INFO masterserver_info[MAX_MASTERSERVERS] = {{{{0}}}};
+static MASTERSERVER_INFO masterserver_info[MAX_MASTERSERVERS] = {{{0}}};
 static int register_registered_server = -1;
 
 void register_update()
@@ -111,7 +111,7 @@ void register_update()
 			int i;
 			for(i = 0; i < MAX_MASTERSERVERS; i++)
 			{
-				NETADDR4 addr = mastersrv_get(i);
+				NETADDR addr = mastersrv_get(i);
 				masterserver_info[i].addr = addr;
 				masterserver_info[i].count = 0;
 				
@@ -229,7 +229,7 @@ static void register_got_count(NETCHUNK *p)
 
 	for(i = 0; i < MAX_MASTERSERVERS; i++)
 	{
-		if(net_addr4_cmp(&masterserver_info[i].addr, &p->address) == 0)
+		if(net_addr_comp(&masterserver_info[i].addr, &p->address) == 0)
 		{
 			masterserver_info[i].count = count;
 			break;
diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c
index ac1a79a1..72da4f5d 100644
--- a/src/engine/server/es_server.c
+++ b/src/engine/server/es_server.c
@@ -147,8 +147,8 @@ int snap_new_id()
 {
 	int id;
 	int64 now = time_get();
-	dbg_assert(snap_id_inited == 1, "requesting id too soon");
-	
+	if(!snap_id_inited)
+		snap_init_id();
 	
 	/* process timed ids */
 	while(snap_first_timed_id != -1 && snap_ids[snap_first_timed_id].timeout < now)
@@ -433,7 +433,7 @@ static void server_do_snap()
 					break;
 				}
 			}
-			
+	
 			/* create delta */
 			{
 				static PERFORMACE_INFO scope = {"delta", 0};
@@ -453,16 +453,18 @@ static void server_do_snap()
 
 				{				
 					static PERFORMACE_INFO scope = {"compress", 0};
+					/*char buffer[512];*/
 					perf_start(&scope);
 					snapshot_size = intpack_compress(deltadata, deltasize, compdata);
+					
+					/*str_hex(buffer, sizeof(buffer), compdata, snapshot_size);
+					dbg_msg("", "deltasize=%d -> %d : %s", deltasize, snapshot_size, buffer);*/
+					
 					perf_end();
 				}
-				
 
 				numpackets = (snapshot_size+max_size-1)/max_size;
 				
-				
-				
 				for(n = 0, left = snapshot_size; left; n++)
 				{
 					int chunk = left < max_size ? left : max_size;
@@ -776,7 +778,7 @@ static void server_process_client_packet(NETCHUNK *packet)
 	}
 }
 
-static void server_send_serverinfo(NETADDR4 *addr, int lan)
+static void server_send_serverinfo(NETADDR *addr, int lan)
 {
 	NETCHUNK packet;
 	PACKER p;
@@ -904,10 +906,9 @@ static int server_load_map(const char *mapname)
 
 static int server_run()
 {
-	NETADDR4 bindaddr;
+	NETADDR bindaddr;
 
 	net_init();
-	snap_init_id();
 	
 	/* */
 	console_register_print_callback(server_send_rcon_line_authed);
@@ -920,9 +921,11 @@ static int server_run()
 	}
 	
 	/* start server */
-	if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, config.sv_port, &bindaddr) == 0)
+	/* TODO: IPv6 support */
+	if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, &bindaddr, NETTYPE_IPV4) == 0)
 	{
 		/* sweet! */
+		bindaddr.port = config.sv_port;
 	}
 	else
 	{
@@ -1108,7 +1111,7 @@ static void con_kick(void *result, void *user_data)
 static void con_status(void *result, void *user_data)
 {
 	int i;
-	NETADDR4 addr;
+	NETADDR addr;
 	for(i = 0; i < MAX_CLIENTS; i++)
 	{
 		if(clients[i].state == SRVCLIENT_STATE_INGAME)