about summary refs log tree commit diff
path: root/src/engine/client/client.cpp
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2007-07-21 18:07:27 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2007-07-21 18:07:27 +0000
commit9e4aea97bdb5a903150df57f8d546733ce4b4db2 (patch)
tree7e18776bd7ace981895bca01ac753c9c289a71a5 /src/engine/client/client.cpp
parentf0e8502050ce27b9cef72fa385619d13faa35c27 (diff)
downloadzcatch-9e4aea97bdb5a903150df57f8d546733ce4b4db2.tar.gz
zcatch-9e4aea97bdb5a903150df57f8d546733ce4b4db2.zip
lots of cool new features :D new master server
Diffstat (limited to 'src/engine/client/client.cpp')
-rw-r--r--src/engine/client/client.cpp481
1 files changed, 301 insertions, 180 deletions
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index 57b3bd57..816a30e7 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -20,6 +20,8 @@
 #include <engine/config.h>
 #include <engine/network.h>
 
+#include <mastersrv/mastersrv.h>
+
 using namespace baselib;
 
 // --- input wrappers ---
@@ -156,15 +158,92 @@ int client_send_msg()
 	return 0;
 }
 
+static struct 
+{
+	server_info infos[MAX_SERVERS];
+	int64 request_times[MAX_SERVERS];
+	netaddr4 addresses[MAX_SERVERS];
+	int num;
+} servers;
+
+static netaddr4 master_server;
+
+int client_serverbrowse_getlist(server_info **serverlist)
+{
+	*serverlist = servers.infos;
+	return servers.num;
+}
+
+void client_serverbrowse_refresh()
+{
+	dbg_msg("client", "requesting server list");
+	NETPACKET packet;
+	packet.client_id = -1;
+	packet.address = master_server;
+	packet.flags = PACKETFLAG_CONNLESS;
+	packet.data_size = sizeof(SERVERBROWSE_GETLIST);
+	packet.data = SERVERBROWSE_GETLIST;
+	net.send(&packet);	
+	
+	// reset the list
+	servers.num = 0;
+}
+
+enum
+{
+	STATE_OFFLINE,
+	STATE_CONNECTING,
+	STATE_LOADING,
+	STATE_ONLINE,
+	STATE_BROKEN,
+	STATE_QUIT,
+};
+
+static netaddr4 server_address;
+
+static int state;
+static int get_state() { return state; }
+static void set_state(int s)
+{
+	dbg_msg("game", "state change. last=%d current=%d", state, s);
+	state = s;
+}
+
+
+void client_connect(const char *server_address_str)
+{
+	char buf[512];
+	strncpy(buf, server_address_str, 512);
+	
+	const char *port_str = 0;
+	for(int k = 0; buf[k]; k++)
+	{
+		if(buf[k] == ':')
+		{
+			port_str = &(buf[k+1]);
+			buf[k] = 0;
+			break;
+		}
+	}
+	
+	int port = 8303;
+	if(port_str)
+		port = atoi(port_str);
+		
+	if(net_host_lookup(buf, port, &server_address) != 0)
+		dbg_msg("client", "could not find the address of %s, connecting to localhost", buf);
+	
+	net.connect(&server_address);
+	set_state(STATE_CONNECTING);	
+}
+
 // --- client ---
 // TODO: remove this class
 class client
 {
 public:
-	
-	//socket_udp4 socket;
-	//connection conn;
-	int64 reconnect_timer;
+	int info_request_begin;
+	int info_request_end;
 	
 	int snapshot_part;
 
@@ -173,24 +252,6 @@ public:
 	// data to hold three snapshots
 	// previous, 
 
-	enum
-	{
-		STATE_OFFLINE,
-		STATE_CONNECTING,
-		STATE_LOADING,
-		STATE_ONLINE,
-		STATE_BROKEN,
-		STATE_QUIT,
-	};
-	
-	int state;
-	int get_state() { return state; }
-	void set_state(int s)
-	{
-		dbg_msg("game", "state change. last=%d current=%d", state, s);
-		state = s;
-	}
-
 	void send_info()
 	{
 		recived_snapshots = 0;
@@ -242,12 +303,6 @@ public:
 		map_unload();
 	}
 	
-	void connect(netaddr4 *server_address)
-	{
-		net.connect(server_address);
-		set_state(STATE_CONNECTING);
-	}
-	
 	bool load_data()
 	{
 		debug_font = gfx_load_texture("data/debug_font.png");
@@ -293,13 +348,11 @@ public:
 		}
 		else if (get_state() != STATE_CONNECTING && get_state() != STATE_LOADING)
 		{
-			netaddr4 server_address;
-			int status = modmenu_render(&server_address);
+			//netaddr4 server_address;
+			int status = modmenu_render();
 
 			if (status == -1)
 				set_state(STATE_QUIT);
-			else if (status)
-				connect(&server_address);
 		}
 		else if (get_state() == STATE_CONNECTING || get_state() == STATE_LOADING)
 		{
@@ -332,7 +385,7 @@ public:
 		}
 	}
 	
-	void run(netaddr4 *server_address)
+	void run(const char *direct_connect_server)
 	{
 		local_start_time = time_get();
 		snapshot_part = 0;
@@ -356,20 +409,16 @@ public:
 		// init menu
 		modmenu_init();
 		
-		net.open(0);
-		
 		// open socket
-		/*
-		if(!socket.open(0))
-		{
-			dbg_msg("network/client", "failed to open socket");
-			return;
-		}*/
+		net.open(0, 0);
+		
+		//
+		net_host_lookup(MASTERSERVER_ADDRESS, MASTERSERVER_PORT, &master_server);
 
 		// connect to the server if wanted
-		if(server_address)
-			connect(server_address);
-		
+		if(direct_connect_server)
+			client_connect(direct_connect_server);
+			
 		//int64 inputs_per_second = 50;
 		//int64 time_per_input = time_freq()/inputs_per_second;
 		int64 game_starttime = time_get();
@@ -413,6 +462,9 @@ public:
 			// pump the network
 			pump_network();
 			
+			// update the server browser
+			serverbrowse_update();
+			
 			// render
 			render();
 			
@@ -457,146 +509,235 @@ public:
 		send_error(msg);
 		set_state(STATE_BROKEN);
 	}
+	
+	void serverbrowse_request(int id)
+	{
+		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);
+		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;
+		net.send(&packet);
+		servers.request_times[id] = time_get();
+	}
+	
+	void serverbrowse_update()
+	{
+		int64 timeout = time_freq();
+		int64 now = time_get();
+		int max_requests = 10;
+		
+		// timeout old requests
+		while(info_request_begin < servers.num && info_request_begin < info_request_end)
+		{
+			if(now > servers.request_times[info_request_begin]+timeout)
+				info_request_begin++;
+			else
+				break;
+		}
+		
+		// send new requests
+		while(info_request_end < servers.num && info_request_end-info_request_begin < max_requests)
+		{
+			serverbrowse_request(info_request_end);
+			info_request_end++;
+		}
+	}
 
 	void process_packet(NETPACKET *packet)
 	{
-		int sys;
-		int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
-		if(sys)
+		if(packet->client_id == -1)
 		{
-			// system message
-			if(msg == NETMSG_MAP)
+			// connectionlesss
+			if(packet->data_size >= (int)sizeof(SERVERBROWSE_LIST) &&
+				memcmp(packet->data, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0)
 			{
-				const char *map = msg_unpack_string();
-				dbg_msg("client/network", "connection accepted, map=%s", map);
-				set_state(STATE_LOADING);
-				
-				if(map_load(map))
+				// 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);
+
+				info_request_begin = 0;
+				info_request_end = 0;
+
+				for(int i = 0; i < servers.num; i++)
 				{
-					modc_entergame();
-					send_entergame();
-					dbg_msg("client/network", "loading done");
-					// now we will wait for two snapshots
-					// to finish the connection
+					servers.infos[i].num_players = 0;
+					servers.infos[i].max_players = 0;
+					servers.infos[i].latency = 999;
+					sprintf(servers.infos[i].address, "%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);
 				}
-				else
+			}
+
+			if(packet->data_size >= (int)sizeof(SERVERBROWSE_INFO) &&
+				memcmp(packet->data, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
+			{
+				// we got ze info
+				data_unpacker unpacker;
+				unpacker.reset((unsigned char*)packet->data+sizeof(SERVERBROWSE_INFO), packet->data_size-sizeof(SERVERBROWSE_INFO));
+				
+				for(int i = 0; i < servers.num; i++)
 				{
-					error("failure to load map");
+					if(net_addr4_cmp(&servers.addresses[i], &packet->address) == 0)
+					{
+						strncpy(servers.infos[i].name, unpacker.get_string(), 128);
+						strncpy(servers.infos[i].map, unpacker.get_string(), 128);
+						servers.infos[i].max_players = unpacker.get_int();
+						servers.infos[i].num_players = unpacker.get_int();
+						servers.infos[i].latency = ((time_get() - servers.request_times[i])*1000)/time_freq();
+						dbg_msg("client", "got server info");
+						break;
+					}
 				}
 			}
-			else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY)
+		}
+		else
+		{
+			
+			int sys;
+			int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
+			if(sys)
 			{
-				//dbg_msg("client/network", "got snapshot");
-				int game_tick = msg_unpack_int();
-				int delta_tick = game_tick-msg_unpack_int();
-				int num_parts = 1;
-				int part = 0;
-				int part_size = 0;
-				
-				if(msg == NETMSG_SNAP)
+				// system message
+				if(msg == NETMSG_MAP)
 				{
-					num_parts = msg_unpack_int();
-					part = msg_unpack_int();
+					const char *map = msg_unpack_string();
+					dbg_msg("client/network", "connection accepted, map=%s", map);
+					set_state(STATE_LOADING);
+					
+					if(map_load(map))
+					{
+						modc_entergame();
+						send_entergame();
+						dbg_msg("client/network", "loading done");
+						// now we will wait for two snapshots
+						// to finish the connection
+					}
+					else
+					{
+						error("failure to load map");
+					}
 				}
-				
-				if(msg != NETMSG_SNAPEMPTY)
-					part_size = msg_unpack_int();
-				
-				if(snapshot_part == part)
+				else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY)
 				{
-					// TODO: clean this up abit
-					const char *d = (const char *)msg_unpack_raw(part_size);
-					mem_copy((char*)snapshots[SNAP_INCOMMING] + part*MAX_SNAPSHOT_PACKSIZE, d, part_size);
-					snapshot_part++;
-				
-					if(snapshot_part == num_parts)
+					//dbg_msg("client/network", "got snapshot");
+					int game_tick = msg_unpack_int();
+					int delta_tick = game_tick-msg_unpack_int();
+					int num_parts = 1;
+					int part = 0;
+					int part_size = 0;
+					
+					if(msg == NETMSG_SNAP)
 					{
-						snapshot *tmp = snapshots[SNAP_PREV];
-						snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
-						snapshots[SNAP_CURRENT] = tmp;
-						current_tick = game_tick;
-
-						// decompress snapshot
-						void *deltadata = snapshot_empty_delta();
-						int deltasize = sizeof(int)*3;
-
-						unsigned char tmpbuffer[MAX_SNAPSHOT_SIZE];
-						unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
-						if(part_size)
+						num_parts = msg_unpack_int();
+						part = msg_unpack_int();
+					}
+					
+					if(msg != NETMSG_SNAPEMPTY)
+						part_size = msg_unpack_int();
+					
+					if(snapshot_part == part)
+					{
+						// TODO: clean this up abit
+						const char *d = (const char *)msg_unpack_raw(part_size);
+						mem_copy((char*)snapshots[SNAP_INCOMMING] + part*MAX_SNAPSHOT_PACKSIZE, d, part_size);
+						snapshot_part++;
+					
+						if(snapshot_part == num_parts)
 						{
-							int compsize = zerobit_decompress(snapshots[SNAP_INCOMMING], part_size, tmpbuffer);
-							int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2);
-							deltadata = tmpbuffer2;
-							deltasize = intsize;
-						}
+							snapshot *tmp = snapshots[SNAP_PREV];
+							snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
+							snapshots[SNAP_CURRENT] = tmp;
+							current_tick = game_tick;
+
+							// decompress snapshot
+							void *deltadata = snapshot_empty_delta();
+							int deltasize = sizeof(int)*3;
+
+							unsigned char tmpbuffer[MAX_SNAPSHOT_SIZE];
+							unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
+							if(part_size)
+							{
+								int compsize = zerobit_decompress(snapshots[SNAP_INCOMMING], part_size, tmpbuffer);
+								int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2);
+								deltadata = tmpbuffer2;
+								deltasize = intsize;
+							}
 
-						// find snapshot that we should use as delta 
-						static snapshot emptysnap;
-						emptysnap.data_size = 0;
-						emptysnap.num_items = 0;
-						
-						snapshot *deltashot = &emptysnap;
-						int deltashot_size;
+							// find snapshot that we should use as delta 
+							static snapshot emptysnap;
+							emptysnap.data_size = 0;
+							emptysnap.num_items = 0;
+							
+							snapshot *deltashot = &emptysnap;
+							int deltashot_size;
 
-						if(delta_tick >= 0)
-						{
-							void *delta_data;
-							deltashot_size = snapshots_new.get(delta_tick, &delta_data);
-							if(deltashot_size >= 0)
+							if(delta_tick >= 0)
 							{
-								deltashot = (snapshot *)delta_data;
+								void *delta_data;
+								deltashot_size = snapshots_new.get(delta_tick, &delta_data);
+								if(deltashot_size >= 0)
+								{
+									deltashot = (snapshot *)delta_data;
+								}
+								else
+								{
+									// TODO: handle this
+									dbg_msg("client", "error, couldn't find the delta snapshot");
+								}
 							}
-							else
+
+							int snapsize = snapshot_unpack_delta(deltashot, (snapshot*)snapshots[SNAP_CURRENT], deltadata, deltasize);
+							//snapshot *shot = (snapshot *)snapshots[SNAP_CURRENT];
+
+							// purge old snapshots					
+							snapshots_new.purge_until(delta_tick);
+							snapshots_new.purge_until(game_tick-50); // TODO: change this to server tickrate
+							
+							// add new
+							snapshots_new.add(game_tick, snapsize, snapshots[SNAP_CURRENT]);
+							
+							// apply snapshot, cycle pointers
+							recived_snapshots++;
+							snapshot_start_time = time_get();
+							
+							// we got two snapshots until we see us self as connected
+							if(recived_snapshots == 2)
 							{
-								// TODO: handle this
-								dbg_msg("client", "error, couldn't find the delta snapshot");
+								local_start_time = time_get();
+								set_state(STATE_ONLINE);
 							}
+							
+							if(recived_snapshots > 2)
+								modc_newsnapshot();
+							
+							snapshot_part = 0;
+							
+							// ack snapshot
+							msg_pack_start_system(NETMSG_SNAPACK, 0);
+							msg_pack_int(game_tick);
+							msg_pack_end();
+							client_send_msg();
 						}
-
-						int snapsize = snapshot_unpack_delta(deltashot, (snapshot*)snapshots[SNAP_CURRENT], deltadata, deltasize);
-						//snapshot *shot = (snapshot *)snapshots[SNAP_CURRENT];
-
-						// purge old snapshots					
-						snapshots_new.purge_until(delta_tick);
-						snapshots_new.purge_until(game_tick-50); // TODO: change this to server tickrate
-						
-						// add new
-						snapshots_new.add(game_tick, snapsize, snapshots[SNAP_CURRENT]);
-						
-						// apply snapshot, cycle pointers
-						recived_snapshots++;
-						snapshot_start_time = time_get();
-						
-						// we got two snapshots until we see us self as connected
-						if(recived_snapshots == 2)
-						{
-							local_start_time = time_get();
-							set_state(STATE_ONLINE);
-						}
-						
-						if(recived_snapshots > 2)
-							modc_newsnapshot();
-						
+					}
+					else
+					{
+						dbg_msg("client", "snapshot reset!");
 						snapshot_part = 0;
-						
-						// ack snapshot
-						msg_pack_start_system(NETMSG_SNAPACK, 0);
-						msg_pack_int(game_tick);
-						msg_pack_end();
-						client_send_msg();
 					}
 				}
-				else
-				{
-					dbg_msg("client", "snapshot reset!");
-					snapshot_part = 0;
-				}
 			}
-		}
-		else
-		{
-			// game message
-			modc_message(msg);
+			else
+			{
+				// game message
+				modc_message(msg);
+			}
 		}
 	}
 	
@@ -636,11 +777,8 @@ int main(int argc, char **argv)
 	config_reset();
 	config_load("teewars.cfg");
 
+	const char *direct_connect_server = 0x0;
 	snd_set_master_volume(config.volume / 255.0f);
-
-	netaddr4 server_address(127, 0, 0, 1, 8303);
-	//const char *name = "nameless jerk";
-	bool connect_at_once = false;
 	bool editor = false;
 
 	// init network, need to be done first so we can do lookups
@@ -653,24 +791,7 @@ int main(int argc, char **argv)
 		{
 			// -c SERVER:PORT
 			i++;
-			const char *port_str = 0;
-			for(int k = 0; argv[i][k]; k++)
-			{
-				if(argv[i][k] == ':')
-				{
-					port_str = &(argv[i][k+1]);
-					argv[i][k] = 0;
-					break;
-				}
-			}
-			int port = 8303;
-			if(port_str)
-				port = atoi(port_str);
-				
-			if(net_host_lookup(argv[i], port, &server_address) != 0)
-				dbg_msg("main", "could not find the address of %s, connecting to localhost", argv[i]);
-			else
-				connect_at_once = true;
+			direct_connect_server = argv[i];
 		}
 		else if(argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0 && argc - i > 1)
 		{
@@ -695,7 +816,7 @@ int main(int argc, char **argv)
 	{
 		// start the client
 		client c;
-		c.run(connect_at_once ? &server_address : 0x0);
+		c.run(direct_connect_server);
 	}
 	return 0;
 }