about summary refs log tree commit diff
path: root/src/engine
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2009-05-31 09:44:20 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2009-05-31 09:44:20 +0000
commit4bb1df318905f491740f4298c69cda317fb53fcb (patch)
tree486c4edf2d6af2089ffab60a7422d5e7abefa891 /src/engine
parentb28ede2da2c42643c5aa710a8076f0249d48c9e4 (diff)
downloadzcatch-4bb1df318905f491740f4298c69cda317fb53fcb.tar.gz
zcatch-4bb1df318905f491740f4298c69cda317fb53fcb.zip
moved 0.5 branch to trunk
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/client/ec_client.c2
-rw-r--r--src/engine/client/ec_gfx.c21
-rw-r--r--src/engine/client/ec_inp.c16
-rw-r--r--src/engine/client/ec_srvbrowse.c17
-rw-r--r--src/engine/e_config_variables.h10
-rw-r--r--src/engine/e_network.c6
-rw-r--r--src/engine/server/es_server.c354
7 files changed, 252 insertions, 174 deletions
diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c
index 0a785df7..ad52d077 100644
--- a/src/engine/client/ec_client.c
+++ b/src/engine/client/ec_client.c
@@ -1362,6 +1362,7 @@ static void client_pump_network()
 		if(client_state() != CLIENTSTATE_OFFLINE && netclient_state(net) == NETSTATE_OFFLINE)
 		{
 			client_set_state(CLIENTSTATE_OFFLINE);
+			client_disconnect();
 			dbg_msg("client", "offline error='%s'", netclient_error_string(net));
 		}
 
@@ -1972,6 +1973,7 @@ static void con_serverdummy(void *result, void *user_data)
 static void client_register_commands()
 {
 	MACRO_REGISTER_COMMAND("quit", "", CFGFLAG_CLIENT, con_quit, 0x0, "Quit Teeworlds");
+	MACRO_REGISTER_COMMAND("exit", "", CFGFLAG_CLIENT, con_quit, 0x0, "Quit Teeworlds");
 	MACRO_REGISTER_COMMAND("connect", "s", CFGFLAG_CLIENT, con_connect, 0x0, "Connect to the specified host/ip");
 	MACRO_REGISTER_COMMAND("disconnect", "", CFGFLAG_CLIENT, con_disconnect, 0x0, "Disconnect from the server");
 	MACRO_REGISTER_COMMAND("ping", "", CFGFLAG_CLIENT, con_ping, 0x0, "Ping the current server");
diff --git a/src/engine/client/ec_gfx.c b/src/engine/client/ec_gfx.c
index 64840b2b..97dced87 100644
--- a/src/engine/client/ec_gfx.c
+++ b/src/engine/client/ec_gfx.c
@@ -252,11 +252,24 @@ int gfx_init()
 	if(config.dbg_stress)
 		no_gfx = 1;
 
-	if(SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0)
 	{
-        dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError());
-        return -1;
-    }
+		int systems = 0;
+		
+		if(!no_gfx)
+			systems |= SDL_INIT_VIDEO;
+			
+		if(config.snd_enable)
+			systems |= SDL_INIT_AUDIO;
+
+		if(config.cl_eventthread)
+			systems |= SDL_INIT_EVENTTHREAD;
+		
+		if(SDL_Init(systems) < 0)
+		{
+			dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError());
+			return -1;
+		}
+	}
 	
     atexit(SDL_Quit);
 
diff --git a/src/engine/client/ec_inp.c b/src/engine/client/ec_inp.c
index 6aae34fc..4aea840a 100644
--- a/src/engine/client/ec_inp.c
+++ b/src/engine/client/ec_inp.c
@@ -16,26 +16,16 @@ static unsigned char input_state[2][1024] = {{0}, {0}};
 
 static int input_current = 0;
 static int input_grabbed = 0;
-static int input_use_grab = 0;
 
 static unsigned int last_release = 0;
 static unsigned int release_delta = -1;
 
 void inp_mouse_relative(int *x, int *y)
 {
-	static int last_x = 0, last_y = 0;
-	static int last_sens = 100.0f;
 	int nx = 0, ny = 0;
 	float sens = config.inp_mousesens/100.0f;
 	
-	if(last_sens != config.inp_mousesens)
-	{
-		last_x = (last_x/(float)last_sens)*(float)config.inp_mousesens;
-		last_y = (last_y/(float)last_sens)*(float)config.inp_mousesens;
-		last_sens = config.inp_mousesens;
-	}
-	
-	if(input_use_grab)
+	if(config.inp_grab)
 		SDL_GetRelativeMouseState(&nx, &ny);
 	else
 	{
@@ -101,7 +91,7 @@ void inp_mouse_mode_absolute()
 {
 	SDL_ShowCursor(1);
 	input_grabbed = 0;
-	if(input_use_grab)
+	if(config.inp_grab)
 		SDL_WM_GrabInput(SDL_GRAB_OFF);
 }
 
@@ -109,7 +99,7 @@ void inp_mouse_mode_relative()
 {
 	SDL_ShowCursor(0);
 	input_grabbed = 1;
-	if(input_use_grab)
+	if(config.inp_grab)
 		SDL_WM_GrabInput(SDL_GRAB_ON);
 }
 
diff --git a/src/engine/client/ec_srvbrowse.c b/src/engine/client/ec_srvbrowse.c
index 81712cb4..4a85e778 100644
--- a/src/engine/client/ec_srvbrowse.c
+++ b/src/engine/client/ec_srvbrowse.c
@@ -166,6 +166,22 @@ static void client_serverbrowse_filter()
 			filtered = 1;
 		else if(config.b_filter_pure && (strcmp(serverlist[i]->info.gametype, "DM") != 0 && strcmp(serverlist[i]->info.gametype, "TDM") != 0 && strcmp(serverlist[i]->info.gametype, "CTF") != 0))
 			filtered = 1;
+		else if(config.b_filter_pure_map &&
+			!(strcmp(serverlist[i]->info.map, "dm1") == 0 ||
+			strcmp(serverlist[i]->info.map, "dm2") == 0 ||
+			strcmp(serverlist[i]->info.map, "dm6") == 0 ||
+			strcmp(serverlist[i]->info.map, "dm7") == 0 ||
+			strcmp(serverlist[i]->info.map, "dm8") == 0 ||
+			strcmp(serverlist[i]->info.map, "dm9") == 0 ||
+			strcmp(serverlist[i]->info.map, "ctf1") == 0 ||
+			strcmp(serverlist[i]->info.map, "ctf2") == 0 ||
+			strcmp(serverlist[i]->info.map, "ctf3") == 0 ||
+			strcmp(serverlist[i]->info.map, "ctf4") == 0 ||
+			strcmp(serverlist[i]->info.map, "ctf5") == 0)
+		)
+		{
+			filtered = 1;
+		}
 		else if(config.b_filter_ping < serverlist[i]->info.latency)
 			filtered = 1;
 		else if(config.b_filter_compatversion && strncmp(serverlist[i]->info.version, modc_net_version(), 3) != 0)
@@ -229,6 +245,7 @@ static int client_serverbrowse_sorthash()
 	i |= config.b_sort_order<<7;
 	i |= config.b_filter_compatversion<<8;
 	i |= config.b_filter_pure<<9;
+	i |= config.b_filter_pure_map<<10;
 	i |= config.b_filter_ping<<16;
 	return i;
 }
diff --git a/src/engine/e_config_variables.h b/src/engine/e_config_variables.h
index 01989542..aa3da3f6 100644
--- a/src/engine/e_config_variables.h
+++ b/src/engine/e_config_variables.h
@@ -12,6 +12,10 @@ MACRO_CONFIG_STR(logfile, 128, "", CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filename to log
 MACRO_CONFIG_INT(cl_cpu_throttle, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
 MACRO_CONFIG_INT(cl_editor, 0, 0, 1, CFGFLAG_CLIENT, "")
 
+MACRO_CONFIG_INT(cl_eventthread, 0, 0, 1, CFGFLAG_CLIENT, "Enables the usage of a thread to pump the events")
+
+MACRO_CONFIG_INT(inp_grab, 0, 0, 1, CFGFLAG_CLIENT, "Use forceful input grabbing method")
+
 MACRO_CONFIG_STR(b_filter_string, 64, "", CFGFLAG_SAVE|CFGFLAG_CLIENT, "Server browser filtering string")
 
 MACRO_CONFIG_INT(b_filter_full, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out full server in browser")
@@ -19,7 +23,8 @@ MACRO_CONFIG_INT(b_filter_empty, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter o
 MACRO_CONFIG_INT(b_filter_pw, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out password protected servers in browser")
 MACRO_CONFIG_INT(b_filter_ping, 999, 0, 999, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Ping to filter by in the server browser")
 MACRO_CONFIG_STR(b_filter_gametype, 128, "", CFGFLAG_SAVE|CFGFLAG_CLIENT, "Game types to filter")
-MACRO_CONFIG_INT(b_filter_pure, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out non-pure servers in browser")
+MACRO_CONFIG_INT(b_filter_pure, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out non-standard servers in browser")
+MACRO_CONFIG_INT(b_filter_pure_map, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out non-standard maps in browser")
 MACRO_CONFIG_INT(b_filter_compatversion, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out non-compatible servers in browser")
 
 MACRO_CONFIG_INT(b_sort, 0, 0, 256, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
@@ -60,6 +65,7 @@ MACRO_CONFIG_INT(sv_max_clients, 8, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum num
 MACRO_CONFIG_INT(sv_high_bandwidth, 0, 0, 1, CFGFLAG_SERVER, "Use high bandwidth mode. Doubles the bandwidth required for the server. LAN use only")
 MACRO_CONFIG_INT(sv_register, 1, 0, 1, CFGFLAG_SERVER, "Register server with master server for public listing")
 MACRO_CONFIG_STR(sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password")
+MACRO_CONFIG_INT(sv_map_reload, 0, 0, 1, CFGFLAG_SERVER, "Reload the current map")
 
 MACRO_CONFIG_INT(debug, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Debug mode")
 MACRO_CONFIG_INT(dbg_stress, 0, 0, 0, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Stress systems")
@@ -69,5 +75,3 @@ MACRO_CONFIG_INT(dbg_graphs, 0, 0, 1, CFGFLAG_CLIENT, "Performance graphs")
 MACRO_CONFIG_INT(dbg_hitch, 0, 0, 0, CFGFLAG_SERVER, "Hitch warnings")
 MACRO_CONFIG_STR(dbg_stress_server, 32, "localhost", CFGFLAG_CLIENT, "Server to stress")
 MACRO_CONFIG_INT(dbg_resizable, 0, 0, 0, CFGFLAG_CLIENT, "Enables window resizing")
-
-MACRO_CONFIG_INT(sv_map_reload, 0, 0, 1, CFGFLAG_SERVER, "Reload the current map")
diff --git a/src/engine/e_network.c b/src/engine/e_network.c
index c7aabc99..3c32de1d 100644
--- a/src/engine/e_network.c
+++ b/src/engine/e_network.c
@@ -224,6 +224,12 @@ int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *packet)
 
 	if(packet->flags&NET_PACKETFLAG_CONNLESS)
 	{
+		if(size < 6)
+		{
+			dbg_msg("", "connection less packet too small, %d", size);
+			return -1;
+		}
+			
 		packet->flags = NET_PACKETFLAG_CONNLESS;
 		packet->ack = 0;
 		packet->num_chunks = 0;
diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c
index 3d9f56f5..0072f123 100644
--- a/src/engine/server/es_server.c
+++ b/src/engine/server/es_server.c
@@ -70,6 +70,7 @@ static int snap_id_inited = 0;
 enum
 {
 	SRVCLIENT_STATE_EMPTY = 0,
+	SRVCLIENT_STATE_AUTH,
 	SRVCLIENT_STATE_CONNECTING,
 	SRVCLIENT_STATE_READY,
 	SRVCLIENT_STATE_INGAME,
@@ -211,9 +212,42 @@ const char *server_clientname(int client_id)
 	return clients[client_id].name;
 }
 
+static const char *str_ltrim(const char *str)
+{
+	while(*str && *str <= 32)
+		str++;
+	return str;
+}
+
+static void str_rtrim(char *str)
+{
+	int i = str_length(str);
+	while(i >= 0)
+	{
+		if(str[i] > 32)
+			break;
+		str[i] = 0;
+		i--;
+	}
+}
+
 static int server_try_setclientname(int client_id, const char *name)
 {
 	int i;
+	char trimmed_name[64];
+
+	/* trim the name */
+	str_copy(trimmed_name, str_ltrim(name), sizeof(trimmed_name));
+	str_rtrim(trimmed_name);
+	dbg_msg("", "'%s' -> '%s'", name, trimmed_name);
+	name = trimmed_name;
+	
+	
+	/* check for empty names */
+	if(!name[0])
+		return -1;
+	
+	/* make sure that two clients doesn't have the same name */
 	for(i = 0; i < MAX_CLIENTS; i++)
 		if(i != client_id && clients[i].state >= SRVCLIENT_STATE_READY)
 		{
@@ -221,6 +255,7 @@ static int server_try_setclientname(int client_id, const char *name)
 				return -1;
 		}
 
+	/* set the client name */
 	str_copy(clients[client_id].name, name, MAX_NAME_LENGTH);
 	return 0;
 }
@@ -544,7 +579,7 @@ static void reset_client(int cid)
 
 static int new_client_callback(int cid, void *user)
 {
-	clients[cid].state = SRVCLIENT_STATE_CONNECTING;
+	clients[cid].state = SRVCLIENT_STATE_AUTH;
 	clients[cid].name[0] = 0;
 	clients[cid].clan[0] = 0;
 	clients[cid].authed = 0;
@@ -608,10 +643,9 @@ static void server_process_client_packet(NETCHUNK *packet)
 	int sys;
 	int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
 	
-	if(sys)
+	if(clients[cid].state == SRVCLIENT_STATE_AUTH)
 	{
-		/* system message */
-		if(msg == NETMSG_INFO)
+		if(sys && msg == NETMSG_INFO)
 		{
 			char version[64];
 			const char *password;
@@ -636,185 +670,197 @@ static void server_process_client_packet(NETCHUNK *packet)
 				return;
 			}
 			
+			clients[cid].state = SRVCLIENT_STATE_CONNECTING;
 			server_send_map(cid);
 		}
-		else if(msg == NETMSG_REQUEST_MAP_DATA)
+	}
+	else
+	{
+		if(sys)
 		{
-			int chunk = msg_unpack_int();
-			int chunk_size = 1024-128;
-			int offset = chunk * chunk_size;
-			int last = 0;
-			
-			if(offset+chunk_size >= current_map_size)
+			/* system message */
+			if(msg == NETMSG_REQUEST_MAP_DATA)
+			{
+				int chunk = msg_unpack_int();
+				int chunk_size = 1024-128;
+				int offset = chunk * chunk_size;
+				int last = 0;
+				
+				/* drop faulty map data requests */
+				if(chunk < 0 || offset > current_map_size)
+					return;
+				
+				if(offset+chunk_size >= current_map_size)
+				{
+					chunk_size = current_map_size-offset;
+					if(chunk_size < 0)
+						chunk_size = 0;
+					last = 1;
+				}
+				
+				msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL|MSGFLAG_FLUSH);
+				msg_pack_int(last);
+				msg_pack_int(current_map_size);
+				msg_pack_int(chunk_size);
+				msg_pack_raw(&current_map_data[offset], chunk_size);
+				msg_pack_end();
+				server_send_msg(cid);
+				
+				if(config.debug)
+					dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size);
+			}
+			else if(msg == NETMSG_READY)
 			{
-				chunk_size = current_map_size-offset;
-				if(chunk_size < 0)
-					chunk_size = 0;
-				last = 1;
+				if(clients[cid].state == SRVCLIENT_STATE_CONNECTING)
+				{
+					netserver_client_addr(net, cid, &addr);
+					
+					dbg_msg("server", "player is ready. cid=%x ip=%d.%d.%d.%d",
+						cid,
+						addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
+						);
+					clients[cid].state = SRVCLIENT_STATE_READY;
+					mods_connected(cid);
+				}
 			}
-			
-			msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL|MSGFLAG_FLUSH);
-			msg_pack_int(last);
-			msg_pack_int(current_map_size);
-			msg_pack_int(chunk_size);
-			msg_pack_raw(&current_map_data[offset], chunk_size);
-			msg_pack_end();
-			server_send_msg(cid);
-			
-			if(config.debug)
-				dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size);
-		}
-		else if(msg == NETMSG_READY)
-		{
-			if(clients[cid].state == SRVCLIENT_STATE_CONNECTING)
+			else if(msg == NETMSG_ENTERGAME)
 			{
-				netserver_client_addr(net, cid, &addr);
-				
-				dbg_msg("server", "player is ready. cid=%x ip=%d.%d.%d.%d",
-					cid,
-					addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
-					);
-				clients[cid].state = SRVCLIENT_STATE_READY;
-				mods_connected(cid);
+				if(clients[cid].state == SRVCLIENT_STATE_READY)
+				{
+					netserver_client_addr(net, cid, &addr);
+					
+					dbg_msg("server", "player has entered the game. cid=%x ip=%d.%d.%d.%d",
+						cid,
+						addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
+						);
+					clients[cid].state = SRVCLIENT_STATE_INGAME;
+					mods_client_enter(cid);
+				}
 			}
-		}
-		else if(msg == NETMSG_ENTERGAME)
-		{
-			if(clients[cid].state == SRVCLIENT_STATE_READY)
+			else if(msg == NETMSG_INPUT)
 			{
-				netserver_client_addr(net, cid, &addr);
+				int tick, size, i;
+				CLIENT_INPUT *input;
+				int64 tagtime;
 				
-				dbg_msg("server", "player has entered the game. cid=%x ip=%d.%d.%d.%d",
-					cid,
-					addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
-					);
-				clients[cid].state = SRVCLIENT_STATE_INGAME;
-				mods_client_enter(cid);
-			}
-		}
-		else if(msg == NETMSG_INPUT)
-		{
-			int tick, size, i;
-			CLIENT_INPUT *input;
-			int64 tagtime;
-			
-			clients[cid].last_acked_snapshot = msg_unpack_int();
-			tick = msg_unpack_int();
-			size = msg_unpack_int();
-			
-			/* check for errors */
-			if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE)
-				return;
-
-			if(clients[cid].last_acked_snapshot > 0)
-				clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL;
+				clients[cid].last_acked_snapshot = msg_unpack_int();
+				tick = msg_unpack_int();
+				size = msg_unpack_int();
 				
-			if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0)
-				clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq());
+				/* check for errors */
+				if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE)
+					return;
 
-			/* add message to report the input timing */
-			/* skip packets that are old */
-			if(tick > clients[cid].last_input_tick)
-			{
-				int time_left = ((server_tick_start_time(tick)-time_get())*1000) / time_freq();
-				msg_pack_start_system(NETMSG_INPUTTIMING, 0);
-				msg_pack_int(tick);
-				msg_pack_int(time_left);
-				msg_pack_end();
-				server_send_msg(cid);
-			}
+				if(clients[cid].last_acked_snapshot > 0)
+					clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL;
+					
+				if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0)
+					clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq());
 
-			clients[cid].last_input_tick = tick;
+				/* add message to report the input timing */
+				/* skip packets that are old */
+				if(tick > clients[cid].last_input_tick)
+				{
+					int time_left = ((server_tick_start_time(tick)-time_get())*1000) / time_freq();
+					msg_pack_start_system(NETMSG_INPUTTIMING, 0);
+					msg_pack_int(tick);
+					msg_pack_int(time_left);
+					msg_pack_end();
+					server_send_msg(cid);
+				}
 
-			input = &clients[cid].inputs[clients[cid].current_input];
-			
-			if(tick <= server_tick())
-				tick = server_tick()+1;
+				clients[cid].last_input_tick = tick;
 
-			input->game_tick = tick;
-			
-			for(i = 0; i < size/4; i++)
-				input->data[i] = msg_unpack_int();
-			
-			mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int));
-			
-			clients[cid].current_input++;
-			clients[cid].current_input %= 200;
-		
-			/* call the mod with the fresh input data */
-			if(clients[cid].state == SRVCLIENT_STATE_INGAME)
-				mods_client_direct_input(cid, clients[cid].latestinput.data);
-		}
-		else if(msg == NETMSG_RCON_CMD)
-		{
-			const char *cmd = msg_unpack_string();
+				input = &clients[cid].inputs[clients[cid].current_input];
+				
+				if(tick <= server_tick())
+					tick = server_tick()+1;
+
+				input->game_tick = tick;
+				
+				for(i = 0; i < size/4; i++)
+					input->data[i] = msg_unpack_int();
+				
+				mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int));
+				
+				clients[cid].current_input++;
+				clients[cid].current_input %= 200;
 			
-			if(msg_unpack_error() == 0 && clients[cid].authed)
-			{
-				dbg_msg("server", "cid=%d rcon='%s'", cid, cmd);
-				console_execute_line(cmd);
+				/* call the mod with the fresh input data */
+				if(clients[cid].state == SRVCLIENT_STATE_INGAME)
+					mods_client_direct_input(cid, clients[cid].latestinput.data);
 			}
-		}
-		else if(msg == NETMSG_RCON_AUTH)
-		{
-			const char *pw;
-			msg_unpack_string(); /* login name, not used */
-			pw = msg_unpack_string();
-			
-			if(msg_unpack_error() == 0)
+			else if(msg == NETMSG_RCON_CMD)
 			{
-				if(config.sv_rcon_password[0] == 0)
+				const char *cmd = msg_unpack_string();
+				
+				if(msg_unpack_error() == 0 && clients[cid].authed)
 				{
-					server_send_rcon_line(cid, "No rcon password set on server. Set sv_rcon_password to enable the remote console.");
+					dbg_msg("server", "cid=%d rcon='%s'", cid, cmd);
+					console_execute_line(cmd);
 				}
-				else if(strcmp(pw, config.sv_rcon_password) == 0)
+			}
+			else if(msg == NETMSG_RCON_AUTH)
+			{
+				const char *pw;
+				msg_unpack_string(); /* login name, not used */
+				pw = msg_unpack_string();
+				
+				if(msg_unpack_error() == 0)
 				{
-					msg_pack_start_system(NETMSG_RCON_AUTH_STATUS, MSGFLAG_VITAL);
-					msg_pack_int(1);
-					msg_pack_end();
-					server_send_msg(cid);
-					
-					clients[cid].authed = 1;
-					server_send_rcon_line(cid, "Authentication successful. Remote console access granted.");
-					dbg_msg("server", "cid=%d authed", cid);
+					if(config.sv_rcon_password[0] == 0)
+					{
+						server_send_rcon_line(cid, "No rcon password set on server. Set sv_rcon_password to enable the remote console.");
+					}
+					else if(strcmp(pw, config.sv_rcon_password) == 0)
+					{
+						msg_pack_start_system(NETMSG_RCON_AUTH_STATUS, MSGFLAG_VITAL);
+						msg_pack_int(1);
+						msg_pack_end();
+						server_send_msg(cid);
+						
+						clients[cid].authed = 1;
+						server_send_rcon_line(cid, "Authentication successful. Remote console access granted.");
+						dbg_msg("server", "cid=%d authed", cid);
+					}
+					else
+					{
+						server_send_rcon_line(cid, "Wrong password.");
+					}
 				}
-				else
+			}
+			else if(msg == NETMSG_PING)
+			{
+				msg_pack_start_system(NETMSG_PING_REPLY, 0);
+				msg_pack_end();
+				server_send_msg(cid);
+			}
+			else
+			{
+				char hex[] = "0123456789ABCDEF";
+				char buf[512];
+				int b;
+
+				for(b = 0; b < packet->data_size && b < 32; b++)
 				{
-					server_send_rcon_line(cid, "Wrong password.");
+					buf[b*3] = hex[((const unsigned char *)packet->data)[b]>>4];
+					buf[b*3+1] = hex[((const unsigned char *)packet->data)[b]&0xf];
+					buf[b*3+2] = ' ';
+					buf[b*3+3] = 0;
 				}
+
+				dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size);
+				dbg_msg("server", "%s", buf);
+				
 			}
 		}
-		else if(msg == NETMSG_PING)
-		{
-			msg_pack_start_system(NETMSG_PING_REPLY, 0);
-			msg_pack_end();
-			server_send_msg(cid);
-		}
 		else
 		{
-			char hex[] = "0123456789ABCDEF";
-			char buf[512];
-			int b;
-
-			for(b = 0; b < packet->data_size && b < 32; b++)
-			{
-				buf[b*3] = hex[((const unsigned char *)packet->data)[b]>>4];
-				buf[b*3+1] = hex[((const unsigned char *)packet->data)[b]&0xf];
-				buf[b*3+2] = ' ';
-				buf[b*3+3] = 0;
-			}
-
-			dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size);
-			dbg_msg("server", "%s", buf);
-			
+			/* game message */
+			if(clients[cid].state >= SRVCLIENT_STATE_READY)
+				mods_message(msg, cid);
 		}
 	}
-	else
-	{
-		/* game message */
-		if(clients[cid].state >= SRVCLIENT_STATE_READY)
-			mods_message(msg, cid);
-	}
 }