Index: /Daodan/MSVC/Flatline.c
===================================================================
--- /Daodan/MSVC/Flatline.c	(revision 579)
+++ /Daodan/MSVC/Flatline.c	(revision 580)
@@ -9,4 +9,7 @@
 player_info Players[MAX_PLAYERS] = {{0}, {0}, {0}, {0}};
 player_info * PlayerList[MAX_CONNECTIONS] = {0};
+
+unsigned int lastPingTime;
+
 const char * Rejection_Messages[][255] = {
 	{"Server is full"},
@@ -24,7 +27,7 @@
 
 	if (Player > max_connections || !PlayerList[ Player ] ) return;
-	
-			
-//	DDrConsole_PrintF( "Sending sync data for player %i, new index %u", Player, PlayerList[ Player ]->rare_sync_index);
+
+
+	//	DDrConsole_PrintF( "Sending sync data for player %i, new index %u", Player, PlayerList[ Player ]->rare_sync_index);
 	sender->sin_addr.S_un.S_addr = htonl(sender->sin_addr.S_un.S_addr);
 	sync.id = RARE_SYNC_DATA;
@@ -51,17 +54,17 @@
 	sender.sin_port = htons(27777);
 	sender.sin_addr = *((struct in_addr*)(int*)&from);
-	
+
 
 	//packet->data[datalen] = '\0';
-	
+
 	//DDrConsole_PrintF("Packet \r%d recieved from %i",  ++recieved, from);
 
-	
-	
+
+
 	//if data[0] != CONNECT_SEND, search in playerlist for ip address
-	
-
-
-	
+
+
+
+
 	switch(packet->id) {
 		flatline_packet connect_recv;
@@ -70,140 +73,158 @@
 		//rewrite this before we get TCP support*
 		//the way of seeing if there is room for players sucks.
-		case CONNECT_SEND:
-			;
-			
-			connect_recv.id = CONNECT_REPLY;
-		
-			//if(Players[i].ip == sender.sin_addr.S_un.S_addr) break; //needs to send an error message
+	case CONNECT_SEND:
+		;
+
+		connect_recv.id = CONNECT_REPLY;
+
+		//if(Players[i].ip == sender.sin_addr.S_un.S_addr) break; //needs to send an error message
+		sender.sin_addr.S_un.S_addr = htonl(sender.sin_addr.S_un.S_addr);
+		playah = FLrServer_AddPlayer(from,packet->connect_send.name, 0, 0);
+		DDrConsole_PrintF("%s connected from %s", packet->connect_send.name, inet_ntoa(sender.sin_addr ) );
+		if(!((int)playah > -5 && (int)playah <= 0)) {
+			flatline_packet new_char = {0};
+			CharacterObject* Char;
+			connect_recv.connect_reply.goodtogo = 1;
+			connect_recv.connect_reply.player_slot = playah->list_slot;
+			DDrConsole_PrintF("Slot: %i", playah->list_slot);
+
+			//sending this several times to make sure it gets through. Really need to make up some form of packet tracking.
+			NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
+			NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
+			NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
+			NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
+			NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
+			Sleep(100);
+
+			new_char.id = NEW_PLAYER;
+			Char = &new_char.new_player.Character;
+			memset(Char, 0, sizeof(CharacterObject));
+			Char->Header.Type = 'CHAR';
+			Char->OSD.Options = chr_dontaim;
+			for(j = 0; j < max_connections; j++) {
+				if(PlayerList[j] != 0) {
+					new_char.new_player.Playernumber = j;
+					sprintf(Char->OSD.Name,"%s",PlayerList[j]->name);
+
+					sprintf(Char->OSD.Class, "%s", TMrInstance_GetInstanceName(PlayerList[j]->Chr->ONCC));
+					DDrConsole_PrintF("Class %s", Char->OSD.Class );
+
+					sprintf(Char->OSD.Class, "konoko_generic");
+					NetTCPServer_Send((sockaddr *) &sender, (char*)&new_char, sizeof(new_player) + FLATLINE_HEADER );
+				}
+
+			}
+		}
+		else {
+			//fix the error messages...
+			DDrConsole_PrintF("Server is full. :(");
+			connect_recv.connect_reply.goodtogo = 0;
 			sender.sin_addr.S_un.S_addr = htonl(sender.sin_addr.S_un.S_addr);
-			playah = FLrServer_AddPlayer(from,packet->connect_send.name, 0, 0);
-			DDrConsole_PrintF("%s connected from %s", packet->connect_send.name, inet_ntoa(sender.sin_addr ) );
-			if(!((int)playah > -5 && (int)playah <= 0)) {
-				flatline_packet new_char = {0};
-				CharacterObject* Char;
-				connect_recv.connect_reply.goodtogo = 1;
-				connect_recv.connect_reply.player_slot = playah->list_slot;
-				DDrConsole_PrintF("Slot: %i", playah->list_slot);
-
-				//sending this several times to make sure it gets through. Really need to make up some form of packet tracking.
-				NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
-				NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
-				NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
-				NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
-				NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER);
-				Sleep(100);
-
-				new_char.id = NEW_PLAYER;
-				Char = &new_char.new_player.Character;
-				memset(Char, 0, sizeof(CharacterObject));
-				Char->Header.Type = 'CHAR';
-				Char->OSD.Options = chr_dontaim;
-				for(j = 0; j < max_connections; j++) {
-					if(PlayerList[j] != 0) {
-						new_char.new_player.Playernumber = j;
-						sprintf(Char->OSD.Name,"%s",PlayerList[j]->name);
-
-						sprintf(Char->OSD.Class, "%s", TMrInstance_GetInstanceName(PlayerList[j]->Chr->ONCC));
-						DDrConsole_PrintF("Class %s", Char->OSD.Class );
-
-						sprintf(Char->OSD.Class, "konoko_generic");
-						NetTCPServer_Send((sockaddr *) &sender, (char*)&new_char, sizeof(new_player) + FLATLINE_HEADER );
-					}
-
-				}
-			}
-			else {
-				//fix the error messages...
-				DDrConsole_PrintF("Server is full. :(");
-				connect_recv.connect_reply.goodtogo = 0;
-				sender.sin_addr.S_un.S_addr = htonl(sender.sin_addr.S_un.S_addr);
-				memcpy(&connect_recv.connect_reply.message,"Server is full.", sizeof("Server is full."));
-				NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(bool)*2 + FLATLINE_HEADER + sizeof("Server is full."));	
-
-			} 
-
-
+			memcpy(&connect_recv.connect_reply.message,"Server is full.", sizeof("Server is full."));
+			NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(bool)*2 + FLATLINE_HEADER + sizeof("Server is full."));	
+
+		} 
+
+
+		break;
+	case CONNECT_REPLY:
+		break;	//do nothing...a server shouldn't recieve this type of packet.
+	case MESSAGE:
+		for(i = 0; i < MAX_PLAYERS; i++) {
+			//DDrConsole_PrintF("%i : %i | %s : %s", from, Players[i].ip, inet_ntoa(*(struct in_addr*)&from), inet_ntoa(*(struct in_addr*)&(Players[i].ip)));
+			if(Players[i].ip == sender.sin_addr.S_un.S_addr) {
+				found_player = 1;
+				break;
+			}	
+		}
+		if(found_player == 0) return true;
+		else {
+			char message_buffer[512] = {0};
+			flatline_packet message;
+			int message_size;
+			data[datalen] = 0;
+
+			DDrConsole_PrintF("%s: %s", Players[i].name, packet->data);
+			sprintf(message_buffer, "%s: %s", Players[i].name, packet->data);
+
+			message.id = MESSAGE;
+			message_size = sprintf(message.data, "%s", message_buffer);
+			COrMessage_Print(message_buffer, "chat", 0);
+			UDPServer_SendToAll(&message, message_size + 1 + FLATLINE_HEADER);
 			break;
-		case CONNECT_REPLY:
-			break;	//do nothing...a server shouldn't recieve this type of packet.
-		case MESSAGE:
-			for(i = 0; i < MAX_PLAYERS; i++) {
-				//DDrConsole_PrintF("%i : %i | %s : %s", from, Players[i].ip, inet_ntoa(*(struct in_addr*)&from), inet_ntoa(*(struct in_addr*)&(Players[i].ip)));
-				if(Players[i].ip == sender.sin_addr.S_un.S_addr) {
-					found_player = 1;
+		}
+	case CHANGE_NAME:
+		; //wtf, needed or i get an error.
+		DDrConsole_PrintF("Changing Name to: %s", packet->data);
+		for(i = 0; i < MAX_PLAYERS; i++) {
+			if(Players[i].ip == sender.sin_addr.S_un.S_addr) {
+				found_player = 1;
+				break;
+			}	
+		}
+		if(found_player == 0) return true;
+		else {
+			bool name_exists = 0;
+			for(j = 0; j < MAX_PLAYERS; j++) {
+				if(!strcmp(packet->data, Players[j].name)) {
+					name_exists = 1;
 					break;
-				}	
-			}
-			if(found_player == 0) return true;
-			else {
-				char message_buffer[512] = {0};
-				flatline_packet message;
-				int message_size;
-				data[datalen] = 0;
-
-				DDrConsole_PrintF("%s: %s", Players[i].name, packet->data);
-				sprintf(message_buffer, "%s: %s", Players[i].name, packet->data);
-				
-				message.id = MESSAGE;
-				message_size = sprintf(message.data, "%s", message_buffer);
-				COrMessage_Print(message_buffer, "chat", 0);
-				UDPServer_SendToAll(&message, message_size + 1 + FLATLINE_HEADER);
+				}
+			}
+			if(!name_exists) {
+				char message_buffer[1024];
+				sprintf(message_buffer,"%s changed their name to %s", Players[i].name, packet->data);
+				COrMessage_Print(message_buffer, "name_change", 0);
+				memcpy(Players[i].name, packet->data, 256);
+
+			}
+			break;
+		}
+	case PLAYER_INPUT:
+
+		for(i = 0; i < max_connections; i++) {
+			if(PlayerList[i] != 0 && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) {
+				found_player = 1;
 				break;
-			}
-		case CHANGE_NAME:
-			; //wtf, needed or i get an error.
-			DDrConsole_PrintF("Changing Name to: %s", packet->data);
-			for(i = 0; i < MAX_PLAYERS; i++) {
-				if(Players[i].ip == sender.sin_addr.S_un.S_addr) {
-					found_player = 1;
-					break;
-				}	
-			}
-			if(found_player == 0) return true;
-			else {
-				bool name_exists = 0;
-				for(j = 0; j < MAX_PLAYERS; j++) {
-					if(!strcmp(packet->data, Players[j].name)) {
-						name_exists = 1;
-						break;
-					}
-				}
-				if(!name_exists) {
-					char message_buffer[1024];
-					sprintf(message_buffer,"%s changed their name to %s", Players[i].name, packet->data);
-					COrMessage_Print(message_buffer, "name_change", 0);
-					memcpy(Players[i].name, packet->data, 256);
-
-				}
+			}	
+		}
+
+		if(found_player == 0) return true;
+		else {
+			input_struct * packet_input = &packet->input_struct;
+
+
+			PlayerList[i]->Actions1 = packet_input->Actions1;
+			PlayerList[i]->Actions2 = packet_input->Actions2;
+			PlayerList[i]->MouseDeltaX = packet_input->MouseDeltaX;
+			PlayerList[i]->MouseDeltaY = packet_input->MouseDeltaY;
+			PlayerList[i]->LastInputTime = packet_input->Time;
+
+			break;
+		}
+	case RARE_SYNC_DATA_REQUEST:
+		DoRareSync( packet->sync_request , &sender);
+		break;
+	case PK_PONG:
+				for(i = 0; i < max_connections; i++) {
+			if(PlayerList[i] != 0 && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) {
+				found_player = 1;
 				break;
-			}
-		case PLAYER_INPUT:
-			
-			for(i = 0; i < max_connections; i++) {
-				if(PlayerList[i] != 0 && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) {
-					found_player = 1;
-					break;
-				}	
-			}
-			
-			if(found_player == 0) return true;
-			else {
-				input_struct * packet_input = &packet->input_struct;
-
-
-				PlayerList[i]->Actions1 = packet_input->Actions1;
-				PlayerList[i]->Actions2 = packet_input->Actions2;
-				PlayerList[i]->MouseDeltaX = packet_input->MouseDeltaX;
-				PlayerList[i]->MouseDeltaY = packet_input->MouseDeltaY;
-				PlayerList[i]->LastInputTime = packet_input->Time;
-
-				break;
-			}
-		case RARE_SYNC_DATA_REQUEST:
-			DoRareSync( packet->sync_request , &sender);
-			break;
-		default:
-			DDrConsole_PrintF("Warning, recieved badly formed packet!");
-			break;
+			}	
+		}
+
+		if(found_player == 0) return true;
+		if(packet->ping != lastPingTime)
+		{
+			PlayerList[i]->Ping = 999;
+		}
+		else
+		{
+			PlayerList[i]->Ping = (ONgGameState->GameTime - packet->ping) * 1000 / 60; 
+		}
+		break;
+	default:
+		DDrConsole_PrintF("Warning, recieved badly formed packet!");
+		break;
 	}
 	return true;
@@ -214,5 +235,5 @@
 	// Get the local hostname
 	char szHostName[255];
-		struct hostent *host_entry;
+	struct hostent *host_entry;
 	gethostname(szHostName, 255);
 
@@ -228,5 +249,5 @@
 
 void ONrCharacter_SetAnimationInternal(Character* Char, ActiveCharacter* AChar,
-									   short inFromState, short inNextAnimType, const void *TRAM)
+	short inFromState, short inNextAnimType, const void *TRAM)
 {
 	ONCC		*ONCC	= Char->ONCC;
@@ -236,12 +257,12 @@
 
 	if (TRAM == 0) return;
-	
+
 	animType = TRrAnimation_GetType(TRAM);
-	
+
 	AChar->Animation = TRAM;
 	AChar->Frame = 0;
 	AChar->AnimationFromState = inFromState;
 	AChar->AnimationType = animType;
-	
+
 	AChar->NextAnimationType= inNextAnimType;
 	AChar->AnimationToState = TRrAnimation_GetTo(TRAM);
@@ -251,8 +272,8 @@
 
 
-	RGBA green = {0, 0xFF, 0, 0};
-	RGBA red = {0, 0, 0xFF, 0};
-	RGBA grey = {0x80,0x80,0x80,0x80};
-	
+RGBA green = {0, 0xFF, 0, 0};
+RGBA red = {0, 0, 0xFF, 0};
+RGBA grey = {0x80,0x80,0x80,0x80};
+
 //FLrClient_Run
 //Looping function that waits for packets from the server.
@@ -267,5 +288,5 @@
 	int sent_bytes;
 	client_connected = 0;
-	
+
 
 	//starts the connection
@@ -289,8 +310,8 @@
 
 					DDrConsole_PrintColored("Connection successful!",0,green, grey);
-					
+
 					//disable local input.
 					DDrPatch_NOOP(0x004FA929, 5 + 6 + 5);
-					
+
 					//DDrConsole_PrintF("Slot %i",  ((connect_reply*)packet)->player_slot);
 					break;
@@ -316,5 +337,5 @@
 		ActiveCharacter * Active;
 		flatline_packet packet;
-//#define SPAM_INPUT
+		//#define SPAM_INPUT
 #ifdef SPAM_INPUT
 		struct timeval lasttime;
@@ -325,5 +346,5 @@
 #ifdef SPAM_INPUT
 			gettimeofday(&thistime, 0);
-			
+
 			//DDrConsole_PrintF("%i.%i | %i.%i | %i.%i",lasttime.tv_sec, lasttime.tv_usec, thistime.tv_sec, thistime.tv_usec,
 			//	thistime.tv_sec - lasttime.tv_sec, thistime.tv_usec - lasttime.tv_usec);
@@ -332,22 +353,22 @@
 				((thistime.tv_sec > lasttime.tv_sec) && ((thistime.tv_usec + 1000000 - lasttime.tv_usec ) > update_rate * 1000) )
 				|| ((thistime.tv_sec == lasttime.tv_sec) && ((thistime.tv_usec - lasttime.tv_usec ) > update_rate * 1000))
-			) {
-				
-				flatline_packet input_packet;
-				lasttime.tv_usec = ++thistime.tv_usec; //in case recieving packets takes less than 1 ms.
-
-				input_packet.id = PLAYER_INPUT;
-				
-				if( ((GameState*)(ONgGameState))->Input.Current.Actions1 != last1 || ((GameState*)(ONgGameState))->Input.Current.Actions2 != last2) {
-					last1 =((GameState*)(ONgGameState))->Input.Current.Actions1;
-					last2 =((GameState*)(ONgGameState))->Input.Current.Actions2;
-				}
-
-				((input_struct*)(void*)(input_packet.data))->Actions1 = ((GameState*)(ONgGameState))->Input.Current.Actions1;
-				((input_struct*)(void*)(input_packet.data))->Actions2 = ((GameState*)(ONgGameState))->Input.Current.Actions2;
-				((input_struct*)(void*)(input_packet.data))->MouseDeltaX = ((GameState*)(ONgGameState))->Input.MouseDeltaX;
-				((input_struct*)(void*)(input_packet.data))->MouseDeltaY = ((GameState*)(ONgGameState))->Input.MouseDeltaY;
-				sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&input_packet, sizeof(input_struct) + FLATLINE_HEADER);			
-				//if(sent_bytes == SOCKET_ERROR)	NetCatchError();
+				) {
+
+					flatline_packet input_packet;
+					lasttime.tv_usec = ++thistime.tv_usec; //in case recieving packets takes less than 1 ms.
+
+					input_packet.id = PLAYER_INPUT;
+
+					if( ((GameState*)(ONgGameState))->Input.Current.Actions1 != last1 || ((GameState*)(ONgGameState))->Input.Current.Actions2 != last2) {
+						last1 =((GameState*)(ONgGameState))->Input.Current.Actions1;
+						last2 =((GameState*)(ONgGameState))->Input.Current.Actions2;
+					}
+
+					((input_struct*)(void*)(input_packet.data))->Actions1 = ((GameState*)(ONgGameState))->Input.Current.Actions1;
+					((input_struct*)(void*)(input_packet.data))->Actions2 = ((GameState*)(ONgGameState))->Input.Current.Actions2;
+					((input_struct*)(void*)(input_packet.data))->MouseDeltaX = ((GameState*)(ONgGameState))->Input.MouseDeltaX;
+					((input_struct*)(void*)(input_packet.data))->MouseDeltaY = ((GameState*)(ONgGameState))->Input.MouseDeltaY;
+					sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&input_packet, sizeof(input_struct) + FLATLINE_HEADER);			
+					//if(sent_bytes == SOCKET_ERROR)	NetCatchError();
 			}
 #endif
@@ -356,112 +377,117 @@
 				//DDrConsole_PrintF("Data recieved, length %i, type %i", len, ((flatline_packet*)data)->id);
 				switch(packet.id) {
-		case MESSAGE:
-			COrMessage_Print(packet.data, "chat", 0);
-			break;
-		case CONNECT_SEND:
-			;if(1) {
-				flatline_packet connect_recv;
-				memcpy(&connect_recv.connect_reply.message,"This isn't a server!", sizeof("This isn't a server!"));
-				NetUDPSocket_Send(client_sock, (sockaddr *) &address, (char*)&connect_recv, sizeof(bool) + FLATLINE_HEADER + sizeof("This isn't a server!"));			
-			}
-		case CONNECT_REPLY:
-			break; //extra packet or something.
-		case NEW_PLAYER:
-			;if(1) { //haxhaxhax
-			CharacterObject* Char = &(packet.new_player.Character);
-			uint32_t chr_index = 0;
-			Character* PC;
-			DDrConsole_PrintF("%i |  %i", packet.new_player.Playernumber ,client_slot);
-			//Char->OSD.Options = 0;
-			if(packet.new_player.Playernumber == client_slot) {
-				PlayerList[packet.new_player.Playernumber] = &Players[0];
-				PC = (ONgGameState->PlayerCharacter);
-				Players[0].Chr = PC;
-
-			}
-			else {
-				ONrGameState_NewCharacter(Char, NULL, NULL, &chr_index);
-				ONgGameState->CharacterStorage[chr_index].charType = 0;
-				PlayerList[packet.new_player.Playernumber] = &Players[chr_index];
-				Players[chr_index].Chr = &(ONgGameState->CharacterStorage[chr_index]);
-				Players[chr_index].Chr->Flags &= 0xFFBFFFFF;
-				Players[chr_index].spawnnumber = chr_index;
-				DDrConsole_PrintF("Spawning player %s, class %s, slot  %i", ((new_player*)(packet.data))->Character.OSD.Name, ((new_player*)(packet.data))->Character.OSD.Class,chr_index) ;
-			}
-			//Players[((new_player*)(packet.data))->Playernumber].spawnnumber = ONrGameState_NewCharacter(&(((new_player*)(packet.data))->Character), NULL, NULL, 0);
-			break;
-				}
-		case PLAYER_DATA:
-			if(1) { //haxhaxhax
-			player_data* pd = &packet.player_data;
-			uint16_t i = pd->PlayerNum;
-			GameInput * Active_Input;
-			pd = (void*)packet.data;
-			
-			//DDrConsole_PrintF("Got data for Player %i, %x", i, PlayerList[i]);
-			if (i > max_connections) break;
-			if( !PlayerList[i] ) break;
-			//PlayerList[i]->Chr = ((GameState *)ONgGameState)->CharacterStorage;
-
-			PlayerList[i]->Actions1 = pd->Inputs.Actions1;
-			PlayerList[i]->Actions2 = pd->Inputs.Actions2;
-			PlayerList[i]->MouseDeltaX = pd->Inputs.MouseDeltaX;
-			PlayerList[i]->MouseDeltaY = pd->Inputs.MouseDeltaY;
-			memcpy( &(PlayerList[i]->player_data), pd, sizeof(player_data) );
-
-			if( !server_started && pd->rare_sync_index > PlayerList[i]->rare_sync_index )
-			{
-					int sent_bytes;
-					flatline_packet sync_request = {0};
-					sync_request.id = RARE_SYNC_DATA_REQUEST;
-					sync_request.sync_request = i;
-					DDrConsole_PrintF( "Requesting sync data for player %i, old index %u", i, PlayerList[i]->rare_sync_index);
-					sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&sync_request, FLATLINE_HEADER + sizeof(int) );
-			}
-
-
-
-	
-			break;
-			}
-		case RARE_SYNC_DATA:
-			if(1) {
-			sl_arg hax[2];
-			int dontuse;
-			uint16_t i = packet.rare_sync_data.PlayerNum;
-						
-			if (i > max_connections) break;
-			if( !PlayerList[i] ) break;
-
-			//WEAPONS ARE DISABLED. Why? Pain in the arse to sync.
-			packet.rare_sync_data.Inventory.Weapons[0] = NULL;
-			packet.rare_sync_data.Inventory.Weapons[1] = NULL;
-			packet.rare_sync_data.Inventory.Weapons[2] = NULL;
-//			TMrInstance_GetDataPtr( 'ONCC', packet.rare_sync_data.Class, PlayerList[ i ]->Chr->ONCC );
-			
-			//add the target character
-			hax[0].type = sl_int32;
-			hax[0].value_int32 = PlayerList[ packet.rare_sync_data.PlayerNum ]->spawnnumber;
-
-			//add the new class
-			//fix this later so we cant buffer overflow :O
-			hax[1].type = sl_str32;
-			hax[1].value_str32 = packet.rare_sync_data.Class;
-			
-			//we are directly calling a bsl function instead of using the normal method for two reasons
-			//1. it has all the checking built in
-			iSetCharacterClass( 0, 2, hax, &dontuse, &dontuse, hax );
-			//DDrConsole_PrintF( "Recieved sync data for player %i, class %s, old index %u, new index %u", i, packet.rare_sync_data.Class, PlayerList[i]->rare_sync_index, packet.rare_sync_data.index);
-			memcpy( &(PlayerList[ i ]->Chr->Inventory), &(packet.rare_sync_data.Inventory), sizeof(Inventory ));
-
-			PlayerList[i]->rare_sync_index = packet.rare_sync_data.index;
-			}
-			break;
-		case FLATLINE_EVENT:
-			FLcEventHandler( packet.flatline_event.event_index, packet.flatline_event.intArray );
-			break;
-		default:
-			DDrConsole_PrintF("Warning, recieved badly formed packet!");
-			break;
+				case MESSAGE:
+					COrMessage_Print(packet.data, "chat", 0);
+					break;
+				case CONNECT_SEND:
+					;if(1) {
+						flatline_packet connect_recv;
+						memcpy(&connect_recv.connect_reply.message,"This isn't a server!", sizeof("This isn't a server!"));
+						NetUDPSocket_Send(client_sock, (sockaddr *) &address, (char*)&connect_recv, sizeof(bool) + FLATLINE_HEADER + sizeof("This isn't a server!"));			
+					}
+				case CONNECT_REPLY:
+					break; //extra packet or something.
+				case NEW_PLAYER:
+					;if(1) { //haxhaxhax
+						CharacterObject* Char = &(packet.new_player.Character);
+						uint32_t chr_index = 0;
+						Character* PC;
+						DDrConsole_PrintF("%i |  %i", packet.new_player.Playernumber ,client_slot);
+						//Char->OSD.Options = 0;
+						if(packet.new_player.Playernumber == client_slot) {
+							PlayerList[packet.new_player.Playernumber] = &Players[0];
+							PC = (ONgGameState->PlayerCharacter);
+							Players[0].Chr = PC;
+
+						}
+						else {
+							ONrGameState_NewCharacter(Char, NULL, NULL, &chr_index);
+							ONgGameState->CharacterStorage[chr_index].charType = 0;
+							PlayerList[packet.new_player.Playernumber] = &Players[chr_index];
+							Players[chr_index].Chr = &(ONgGameState->CharacterStorage[chr_index]);
+							Players[chr_index].Chr->Flags &= 0xFFBFFFFF;
+							Players[chr_index].spawnnumber = chr_index;
+							DDrConsole_PrintF("Spawning player %s, class %s, slot  %i", ((new_player*)(packet.data))->Character.OSD.Name, ((new_player*)(packet.data))->Character.OSD.Class,chr_index) ;
+						}
+						//Players[((new_player*)(packet.data))->Playernumber].spawnnumber = ONrGameState_NewCharacter(&(((new_player*)(packet.data))->Character), NULL, NULL, 0);
+						break;
+					}
+				case PLAYER_DATA:
+					if(1) { //haxhaxhax
+						player_data* pd = &packet.player_data;
+						uint16_t i = pd->PlayerNum;
+						GameInput * Active_Input;
+						pd = (void*)packet.data;
+
+						//DDrConsole_PrintF("Got data for Player %i, %x", i, PlayerList[i]);
+						if (i > max_connections) break;
+						if( !PlayerList[i] ) break;
+						//PlayerList[i]->Chr = ((GameState *)ONgGameState)->CharacterStorage;
+
+						PlayerList[i]->Actions1 = pd->Inputs.Actions1;
+						PlayerList[i]->Actions2 = pd->Inputs.Actions2;
+						PlayerList[i]->MouseDeltaX = pd->Inputs.MouseDeltaX;
+						PlayerList[i]->MouseDeltaY = pd->Inputs.MouseDeltaY;
+						memcpy( &(PlayerList[i]->player_data), pd, sizeof(player_data) );
+
+						if( !server_started && pd->rare_sync_index > PlayerList[i]->rare_sync_index )
+						{
+							int sent_bytes;
+							flatline_packet sync_request = {0};
+							sync_request.id = RARE_SYNC_DATA_REQUEST;
+							sync_request.sync_request = i;
+							DDrConsole_PrintF( "Requesting sync data for player %i, old index %u", i, PlayerList[i]->rare_sync_index);
+							sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&sync_request, FLATLINE_HEADER + sizeof(int) );
+						}
+
+						PlayerList[i]->DataApplied = 0;
+
+
+						break;
+					}
+				case RARE_SYNC_DATA:
+					if(1) {
+						sl_arg hax[2];
+						int dontuse;
+						uint16_t i = packet.rare_sync_data.PlayerNum;
+
+						if (i > max_connections) break;
+						if( !PlayerList[i] ) break;
+
+						//WEAPONS ARE DISABLED. Why? Pain in the arse to sync.
+						packet.rare_sync_data.Inventory.Weapons[0] = NULL;
+						packet.rare_sync_data.Inventory.Weapons[1] = NULL;
+						packet.rare_sync_data.Inventory.Weapons[2] = NULL;
+						//			TMrInstance_GetDataPtr( 'ONCC', packet.rare_sync_data.Class, PlayerList[ i ]->Chr->ONCC );
+
+						//add the target character
+						hax[0].type = sl_int32;
+						hax[0].value_int32 = PlayerList[ packet.rare_sync_data.PlayerNum ]->spawnnumber;
+
+						//add the new class
+						//fix this later so we cant buffer overflow :O
+						hax[1].type = sl_str32;
+						hax[1].value_str32 = packet.rare_sync_data.Class;
+
+						//we are directly calling a bsl function instead of using the normal method for two reasons
+						//1. it has all the checking built in
+						iSetCharacterClass( 0, 2, hax, &dontuse, &dontuse, hax );
+						//DDrConsole_PrintF( "Recieved sync data for player %i, class %s, old index %u, new index %u", i, packet.rare_sync_data.Class, PlayerList[i]->rare_sync_index, packet.rare_sync_data.index);
+						memcpy( &(PlayerList[ i ]->Chr->Inventory), &(packet.rare_sync_data.Inventory), sizeof(Inventory ));
+
+						PlayerList[i]->rare_sync_index = packet.rare_sync_data.index;
+					}
+					break;
+				case FLATLINE_EVENT:
+					FLcEventHandler( packet.flatline_event.event_index, packet.flatline_event.intArray );
+					break;
+				case PK_PING:
+					packet.id = PK_PONG;
+
+					NetUDPSocket_Send(client_sock, (sockaddr *) &address, (char*)&packet, FLATLINE_HEADER + 4);		
+					break;
+				default:
+					DDrConsole_PrintF("Warning, recieved badly formed packet!");
+					break;
 				}
 			}
@@ -495,10 +521,10 @@
 	return -1;
 }
-	typedef struct
-	{
-		uint16_t x;
-		uint16_t y;
-		
-	} IMtPoint2D;
+typedef struct
+{
+	uint16_t x;
+	uint16_t y;
+
+} IMtPoint2D;
 static flatline_packet cache_input = {0};
 extern void* TSrTest;
@@ -522,7 +548,7 @@
 		input_packet.input_struct.MouseDeltaX = ((GameState*)(ONgGameState))->Input.MouseDeltaX;
 		input_packet.input_struct.MouseDeltaY = ((GameState*)(ONgGameState))->Input.MouseDeltaY;
-		
+
 		sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&input_packet, sizeof(input_struct) + FLATLINE_HEADER);
-		
+
 		//return ONgGameState;
 	}
@@ -530,4 +556,9 @@
 
 	if(!(server_started || client_connected)) return ONgGameState;
+
+	if(server_started && ONgGameState->GameTime % 120 == 0)
+	{
+		FLsPingAll();
+	}
 
 	for(i = 0; i < max_connections; i++) {
@@ -536,6 +567,6 @@
 		GameInput * Active_Input;
 		if(PlayerList[i] == 0) continue;
-		
-		
+
+
 		Player = PlayerList[i]->Chr;
 		if( Player->Health == 0) 
@@ -575,10 +606,10 @@
 			}
 			continue;
-				
-			
+
+
 		}
 
 		Active_Player = ONrGetActiveCharacter( PlayerList[i]->Chr);
-		
+
 		if(Active_Player == 0) continue;
 		Active_Input = &(Active_Player->Input);
@@ -587,5 +618,6 @@
 			flatline_packet data_out = {0};
 
-			
+			if(!strcmp(PlayerList[i]->player_data.Animation, TMrInstance_GetInstanceName(Active_Player->Animation)))
+				continue;
 
 			data_out.id = PLAYER_DATA;
@@ -600,5 +632,5 @@
 			memcpy(data->Animation, TMrInstance_GetInstanceName(Active_Player->Animation), 31);
 			data->Frame = Active_Player->Frame;
-			
+
 			if(Active_Player->targetThrow)
 			{
@@ -607,6 +639,6 @@
 				data->throw_data.throwFrame = ONrGetActiveCharacter(Active_Player->targetThrow)->Frame;
 			}
-			
-			
+
+
 			if( PlayerList[i]->OldClass != PlayerList[i]->Chr->ONCC || memcmp( &(PlayerList[i]->Inventory), &(PlayerList[i]->Chr->Inventory), sizeof(Inventory) ) )
 			{
@@ -616,7 +648,7 @@
 
 			}
-			
+
 			data->rare_sync_index = PlayerList[i]->rare_sync_index;
-			
+
 
 			if(i == 0) {
@@ -632,9 +664,10 @@
 				data->Inputs.MouseDeltaY = PlayerList[i]->MouseDeltaY;
 			}
+			data->Ping = PlayerList[i]->Ping;
 			memcpy( &(PlayerList[i]->player_data), data, sizeof(player_data) );
-			
+
 			UDPServer_SendToAll(&data_out, sizeof(player_data) + FLATLINE_HEADER);
 		}
-		
+
 		if( (server_started && i !=0)  || (!server_started/* && i != client_slot*/) ) 
 		{
@@ -643,5 +676,5 @@
 			Active_Input->Start.Actions1 = ~Active_Input->Current.Actions1 & PlayerList[i]->Actions1;
 			Active_Input->Start.Actions2 = ~Active_Input->Current.Actions2 & PlayerList[i]->Actions2;
-			
+
 			Active_Input->Current.Actions1 = PlayerList[i]->Actions1;
 			Active_Input->Current.Actions2 = PlayerList[i]->Actions2;
@@ -656,4 +689,7 @@
 				void* Animation;
 				player_data* pd = &PlayerList[i]->player_data;
+
+				if(PlayerList[i]->DataApplied) continue;
+
 				Player->Health = PlayerList[i]->player_data.Health;
 				PlayerList[i]->Chr->MaxHealth = PlayerList[i]->player_data.MaxHealth;
@@ -668,15 +704,15 @@
 				Active_Player->PhyContext->Position = PlayerList[i]->player_data.Position;
 				OldAnimation = Active_Player->Animation;
-				
+
 				if (!(Player->Flags & ONcCharacterFlag_BeingThrown) &&
 					(pd->Animation != 0))
 				{
 					// get a pointer to the animation
-					
-						TMrInstance_GetDataPtr(
+
+					TMrInstance_GetDataPtr(
 						'TRAM',
 						pd->Animation,
 						&Animation);
-						if (Animation != OldAnimation)
+					if (Animation != OldAnimation)
 					{
 						short	num_frames;
@@ -684,17 +720,17 @@
 
 						// if the character is dead, make sure this animation is appropriate for death
-				/*
+						/*
 						if (Player->Flags & ONcCharacterFlag_Dead)
 						{
-							short	curToState = TRrAnimation_GetTo(Active_Player->Animation);
-							short	newToState = TRrAnimation_GetTo(animation);
-
-							// if we are currently heading towards fallen and the new animation would not
-							// then this is a better animation to run when we are dead
-							if ((ONrAnimState_IsFallen(curToState)) &&
-								(!ONrAnimState_IsFallen(newToState)))
-							{
-								updateAnimation = false;
-							}
+						short	curToState = TRrAnimation_GetTo(Active_Player->Animation);
+						short	newToState = TRrAnimation_GetTo(animation);
+
+						// if we are currently heading towards fallen and the new animation would not
+						// then this is a better animation to run when we are dead
+						if ((ONrAnimState_IsFallen(curToState)) &&
+						(!ONrAnimState_IsFallen(newToState)))
+						{
+						updateAnimation = false;
+						}
 						}
 						*/
@@ -713,11 +749,11 @@
 						{
 							// set the characters animation
-					/*	ONrCharacter_SetAnimationInternal(Player,
-								Active_Player,
-								Active_Player->AnimationToState,
-								0,
-								Animation);
-						ONrCharacter_NewAnimationHook(Player, Active_Player);*/
-						//Player->Flags |= 0x00000010;
+							/*	ONrCharacter_SetAnimationInternal(Player,
+							Active_Player,
+							Active_Player->AnimationToState,
+							0,
+							Animation);
+							ONrCharacter_NewAnimationHook(Player, Active_Player);*/
+							//Player->Flags |= 0x00000010;
 							ONrCharacter_SetAnimationExternal(Player, TRrAnimation_GetFrom(Animation), Animation, 0);
 						}
@@ -739,6 +775,6 @@
 				if (PlayerList[i]->player_data.throw_data.throwName[0] != 0)
 				{
-					pd->throw_data.throwing = PlayerList[pd->throw_data.throwing]->spawnnumber;
-					if ((pd->throw_data.throwing != Active_Player->throwing) &&
+					short throwTarget = PlayerList[pd->throw_data.throwing]->spawnnumber;
+					if ((throwTarget != Active_Player->throwing) &&
 						(pd->throw_data.throwFrame < 10))
 					{
@@ -754,5 +790,5 @@
 
 						// set the throw target
-						Active_Player->ThrowTargetCharacter = &ONgGameState->CharacterStorage[pd->throw_data.throwing];
+						Active_Player->ThrowTargetCharacter = &ONgGameState->CharacterStorage[throwTarget];
 						Target = ONrGetActiveCharacter(Active_Player->ThrowTargetCharacter);
 						if ((Target->Animation != throw_animation) &&
@@ -762,9 +798,9 @@
 							// set the throw variables
 							Active_Player->targetThrow	= throw_animation;
-							Active_Player->throwing		= pd->throw_data.throwing;
+							Active_Player->throwing		= throwTarget;
 
 							// run the throw
 							ONrCharacter_NewAnimationHook(Player, Active_Player);
-							
+
 							if (Active_Player->ThrowTargetCharacter)
 							{
@@ -775,4 +811,5 @@
 					}
 				}
+				PlayerList[i]->DataApplied = 1;
 
 			}
@@ -791,8 +828,8 @@
 	//Kill off the character in another function, please
 	//ONrCharacter_SetHitPoints(  PlayerList[Player]->Chr, 0);
-	
+
 	memset(PlayerList[Player], 0, sizeof(player_info));
 	PlayerList[Player] = 0;
-	
+
 
 
@@ -832,12 +869,14 @@
 			DrawLocation.x += 150;
 			TSrContext_DrawText(ScoreboardInstance, "Score", 255, 0, &DrawLocation);
+			DrawLocation.x += 50;
+			TSrContext_DrawText(ScoreboardInstance, "Ping", 255, 0, &DrawLocation);
 			for(i = 0; i <MAX_PLAYERS; i++)
 			{
-				if(PlayerList[i] == 0) continue;
+				if(PlayerList[i] == 0 || PlayerList[i]->Chr == 0) continue;
 
 				DrawLocation.x = 20;
 				DrawLocation.y += LineHeight;
-				
-				if(PlayerList[i]->Chr->Health == 0) 
+
+				if(PlayerList[i]->Chr && PlayerList[i]->Chr->Health == 0) 
 				{
 					TSrContext_SetShade(ScoreboardInstance, red);
@@ -852,7 +891,9 @@
 				sprintf(DrawString, "%i", PlayerList[i]->Chr->Damage);
 				TSrContext_DrawText(ScoreboardInstance, DrawString, 255, 0, &DrawLocation);
-
-			}
-		}
-	}
-}
+				DrawLocation.x += 50;
+				sprintf(DrawString, "%i", PlayerList[i]->player_data.Ping);
+				TSrContext_DrawText(ScoreboardInstance, DrawString, 255, 0, &DrawLocation);
+			}
+		}
+	}
+}
Index: /Daodan/MSVC/Flatline.h
===================================================================
--- /Daodan/MSVC/Flatline.h	(revision 579)
+++ /Daodan/MSVC/Flatline.h	(revision 580)
@@ -129,5 +129,5 @@
 	int Damage;
 	int Deaths;
-
+	uint16_t Ping;
 } player_data;
 
@@ -162,4 +162,5 @@
 		uint16_t		sync_request;
 		flatline_event	flatline_event;
+		uint32_t		ping;
 	};
 } flatline_packet;
@@ -187,4 +188,6 @@
 	RARE_SYNC_DATA_REQUEST,
 	FLATLINE_EVENT,
+	PK_PING,
+	PK_PONG,
 };
 
@@ -228,4 +231,6 @@
 	int flags;
 	int DeathTime;
+	uint32_t Ping;
+	bool DataApplied;
 } player_info;
 
@@ -235,5 +240,5 @@
 
 void NetCatchError();
-#define MAX_PLAYERS 128
+#define MAX_PLAYERS 32
 #define CONNECTION_TIMEOUT 15
 #define MAX_CONNECTIONS 32
@@ -246,11 +251,16 @@
 extern player_info Players[];
 extern player_info * PlayerList[];
+
 int UDPServer_SendToAll(void* packet, int size);
+
 extern bool client_connected;
 extern bool server_started;
 extern char player_name[];
+
 void FLrRun_Scores();
 void FLrPlayerDisconnect( int Player );
 void FLrPlayerRespawn( int Player );
 int FLrEvent_GetNumArgs( int eventIndex );
+
+extern unsigned int lastPingTime;
 #endif
Index: /Daodan/MSVC/Flatline_BSL.c
===================================================================
--- /Daodan/MSVC/Flatline_BSL.c	(revision 579)
+++ /Daodan/MSVC/Flatline_BSL.c	(revision 580)
@@ -32,5 +32,5 @@
 uint16_t ONICALL change_name(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
 {
-	
+
 	//should also return your name...
 	sprintf(player_name, "%.31s", args[0].value_str32);
@@ -73,14 +73,14 @@
 {
 	if(	NetPlatform_Initalize()) {
-	static flatline_packet packet;
-	sock = NetUDPSocket_Create(27777);
-	address.sin_family = AF_INET; address.sin_port = htons(27777); address.sin_addr.S_un.S_addr = inet_addr(args[0].value_str32 );	
-	//address.sin_family = AF_INET; address.sin_port = htons(27777); address.sin_addr.S_un.S_addr = inet_addr("192.168.0.1");	
-
-	packet.id = CONNECT_SEND;
-	memcpy(((connect_send*)(packet.data))->country ,  player_country, 2);
-	memcpy(((connect_send*)(packet.data))->name, player_name, 256);
-	DDrConsole_PrintF("%s", ((connect_send*)(packet.data))->name);
-	CreateThread(NULL, 0, StartClient, &packet, 0, 0);
+		static flatline_packet packet;
+		sock = NetUDPSocket_Create(27777);
+		address.sin_family = AF_INET; address.sin_port = htons(27777); address.sin_addr.S_un.S_addr = inet_addr(args[0].value_str32 );	
+		//address.sin_family = AF_INET; address.sin_port = htons(27777); address.sin_addr.S_un.S_addr = inet_addr("192.168.0.1");	
+
+		packet.id = CONNECT_SEND;
+		memcpy(((connect_send*)(packet.data))->country ,  player_country, 2);
+		memcpy(((connect_send*)(packet.data))->name, player_name, 256);
+		DDrConsole_PrintF("%s", ((connect_send*)(packet.data))->name);
+		CreateThread(NULL, 0, StartClient, &packet, 0, 0);
 
 	}
@@ -111,5 +111,5 @@
 					PlayerList[j]->name,
 					PlayerList[j]->Chr
-			);
+					);
 			}
 		}
@@ -130,4 +130,13 @@
 	FLrPlayerDisconnect(args[0].value_int32 - 1);
 	FLsPublic_Event(EV_DISCONNECT, &args[0].value_int32);
+	return 0;
+}
+
+uint16_t ONICALL ping(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
+{
+	if(server_started)
+	{
+		FLsPingAll();
+	}
 	return 0;
 }
@@ -160,5 +169,5 @@
 			new_char.id = NEW_PLAYER;
 			OBJrObjectType_EnumerateObjects('CHAR',BINACHARCallback, (int)args[0].value_str32);
-		//	while(!spawnObject);
+			//	while(!spawnObject);
 			if(spawnObject)
 			{
@@ -179,6 +188,6 @@
 		}
 	}
-	
-		return 0;
+
+	return 0;
 }
 
@@ -193,5 +202,5 @@
 		}
 	}
-return 0;
+	return 0;
 }
 uint16_t ONICALL con(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
@@ -201,7 +210,8 @@
 }
 
-		
-void SLrFlatline_Initialize() {
-	
+
+void SLrFlatline_Initialize() 
+{
+
 	DDrPatch_MakeCall(0x004FA88B, FLrInput_Update_Keys);
 	FLrInput_Update_Keys();
@@ -217,3 +227,4 @@
 	SLrScript_Command_Register_Void("con", "Activates a console", "con:int", con);
 	//SLrScript_Command_Register_ReturnType("ai2_spawn","creates and starts an AI from a character object","ai_name:string [force_spawn:string{\"force\"} | ]", sl_void, spawnAI);
-}
+	SLrScript_Command_Register_Void("ping", "pong!", "", ping);
+}
Index: /Daodan/MSVC/Flatline_Server.c
===================================================================
--- /Daodan/MSVC/Flatline_Server.c	(revision 579)
+++ /Daodan/MSVC/Flatline_Server.c	(revision 580)
@@ -126,8 +126,8 @@
 //FLsPublic_Event
 //Sends an event (door opening, player disconnecting, etc) to all players
-//Always make sure you send a pointer to this, even if it is just one arg. ;)
-//Returns 0 because mixing C and assembly is stupid.
+//Always make sure you send a pointer to this, even if it is just one arg. ;).
 //If it is void the double door in State crashes. Probably stack corruption,
 //I'm not sure exactly why.
+//So we return 0 to stop that.
 int FLsPublic_Event( const unsigned int eventIndex, const int * args )
 {
@@ -142,2 +142,9 @@
 }
 
+void FLsPingAll()
+{
+	flatline_packet ping;
+	ping.id = PK_PING;
+	lastPingTime = ping.ping = ONgGameState->GameTime;
+	UDPServer_SendToAll(&ping, FLATLINE_HEADER + 4);
+}
Index: /Daodan/MSVC/Flatline_Server.h
===================================================================
--- /Daodan/MSVC/Flatline_Server.h	(revision 579)
+++ /Daodan/MSVC/Flatline_Server.h	(revision 580)
@@ -12,3 +12,4 @@
 
 void FLrServer_Initialize();
+void FLsPingAll();
 #endif
