Index: /Daodan/MSVC/Flatline.c
===================================================================
--- /Daodan/MSVC/Flatline.c	(revision 583)
+++ /Daodan/MSVC/Flatline.c	(revision 584)
@@ -25,34 +25,4 @@
 #define BETTER_SYNC
 
-void DoRareSync( short Player, sockaddr_in * sender )
-{
-	flatline_packet sync = {0};	
-
-	if (Player > max_connections || !PlayerList[ Player ] ) return;
-
-
-	//	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;
-	sprintf( sync.rare_sync_data.Class, TMrInstance_GetInstanceName( PlayerList[ Player ]->Chr->ONCC ) );
-	//using ->Inventory instead of ->Chr->Inventory to keep the index and Inventory in sync, just in case.
-	memcpy( &(sync.rare_sync_data.Inventory), &(PlayerList[ Player ]->Inventory), sizeof(Inventory) );
-	//WEAPONS ARE DISABLED. Why? Pain in the arse to sync.
-	sync.rare_sync_data.Inventory.Weapons[0] = NULL;
-	sync.rare_sync_data.Inventory.Weapons[1] = NULL;
-	sync.rare_sync_data.Inventory.Weapons[2] = NULL;
-	sync.rare_sync_data.PlayerNum = Player;
-	sync.rare_sync_data.index = PlayerList[ Player ]->rare_sync_index;
-	NetTCPServer_Send( sender, (char*)&sync, sizeof(rare_sync_data) + FLATLINE_HEADER );
-}
-
-enum
-{
-	JustSpawned,
-	FirstPass,
-	SecondPass,
-	NoPass,
-};
-
 bool FLrServer_PacketCallback(char* data, int datalen, int from)
 {
@@ -102,10 +72,10 @@
 			//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);
 			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;
@@ -202,15 +172,12 @@
 
 
-			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]->InputFromClient.Actions1 = packet_input->Actions1;
+			PlayerList[i]->InputFromClient.Actions2 = packet_input->Actions2;
+			PlayerList[i]->InputFromClient.MouseDeltaX = packet_input->MouseDeltaX;
+			PlayerList[i]->InputFromClient.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++) {
@@ -279,246 +246,7 @@
 
 
-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.
-int client_slot = 0;
-
-void FLrClient_GetPackets()
-{
-	flatline_packet packet;
-	uint16_t len;
-	//#define SPAM_INPUT
-#ifdef SPAM_INPUT
-	struct timeval lasttime;
-	struct timeval thistime;
-	gettimeofday(&lasttime, 0);
-#endif
-	
-
-		while(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, &packet, &len)) {
-			//packet = (flatline_packet*)data;
-			//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 CHANGE_NAME:
-				if(PlayerList[(char)packet.data[0]])
-				{
-					char message_buffer[1024];
-					sprintf(message_buffer,"%s changed their name to %s", PlayerList[(char)packet.data[0]]->name, packet.data + 1);
-					COrMessage_Print(message_buffer, "name_change", 0);
-
-					sprintf_s(PlayerList[packet.data[0]]->name, 32, "%s", packet.data + 1);
-
-				}
-				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) ;
-						sprintf_s(Players[chr_index].name, 32, "%s", ((new_player*)(packet.data))->Character.OSD.Name);
-					}
-					//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;
-
-					pd = (void*)packet.data;
-
-
-					if (i > max_connections) break;
-					if( !PlayerList[i] ) break;
-
-					memcpy( &(PlayerList[i]->player_data), pd, sizeof(player_data) );
-					if(PlayerList[i]->player_data.Health == 0)
-					{
-						short breakfast = 1;
-					}
-					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 = NoPass;
-
-
-					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;
-			case PK_ALL_INPUT:
-				if(1)
-				{
-					int Player, i;
-					for(i = 0; packet.all_input[i].PlayerNum != -1; i++)
-					{
-						Player = packet.all_input[i].PlayerNum;
-						if(PlayerList[Player])
-						{
-							PlayerList[Player]->Actions1 = packet.all_input[Player].Actions1;
-							PlayerList[Player]->Actions2 = packet.all_input[Player].Actions2;
-							PlayerList[Player]->MouseDeltaX = packet.all_input[Player].MouseDeltaX;
-							PlayerList[Player]->MouseDeltaY = packet.all_input[Player].MouseDeltaY;
-							PlayerList[Player]->Facing = packet.all_input[Player].Facing;
-							PlayerList[Player]->DesiredFacing = packet.all_input[Player].DesiredFacing;
-							PlayerList[Player]->Position = packet.all_input[Player].Position;
-							PlayerList[Player]->NeedToSetFP = 1;
-						}
-					}
-				}
-				break;
-			default:
-				DDrConsole_PrintF("Warning, recieved badly formed packet!");
-				break;
-			}
-	}
-}
-
-
-bool FLrClient_Run(flatline_packet* packet)
-{
-
-	char data[1400];
-	uint16_t len;
-	int j;
-	int sent_bytes;
-	client_connected = 0;
-
-
-	//starts the connection
-	DDrConsole_PrintF("Connecting to server %s on socket %i",  inet_ntoa(address.sin_addr), client_sock);
-	sent_bytes = NetUDPSocket_Send(client_sock, (sockaddr*)&address, (char*)packet, 255);
-	if(sent_bytes == SOCKET_ERROR) {
-		NetCatchError();
-	}
-	//loops once per second waiting for a reply.
-	for(j = 0; j < CONNECTION_TIMEOUT; j++) {
-		while(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, data, &len)){		
-			packet = (flatline_packet*)data;
-			if(packet->id == CONNECT_REPLY) {
-				if(packet->connect_reply.goodtogo){
-
-					client_connected = 1;
-
-					client_slot = ((connect_reply*)packet->data)->player_slot;
-
-					PlayerList[client_slot] = Players+client_slot;
-					PlayerList[client_slot]->Chr = ONgGameState->PlayerCharacter;
-
-					DDrConsole_PrintColored("Connection successful!",0,green, grey);
-
-					sprintf_s( PlayerList[client_slot]->name, 32, "%s", player_name );
-
-					//disable local input.
-					DDrPatch_NOOP(0x004FA929, 5 + 6 + 5);
-					
-					//Disable local turning
-					//DDrPatch_NOOP(0x004F7EA8, 2);
-					//DDrPatch_Byte( 0x004F7EB1 , 0xE9);
-					//DDrPatch_MakeJump( 0x004F7EB1, 0x004F8030 );
-
-
-					//DDrPatch_Byte(0x04ED6FB, 0xEB);
-
-					//DDrConsole_PrintF("Slot %i",  ((connect_reply*)packet)->player_slot);
-					//DDrPatch_NOOP(0x43B23,0x10);
-					//DDrPatch_NOOP(0x4EC248,(0x5A-0x48));
-					//DDrPatch_NOOP(0x4EC861, 6);
-					break;
-				}
-				else {
-					DDrConsole_PrintF("Connection rejected: %s", ((connect_reply*)packet->data)->message);
-					return false;
-					break;
-				}
-			}
-		}
-		if(client_connected) break;
-		DDrConsole_PrintF("Connection timing out in %i seconds...", CONNECTION_TIMEOUT - j);
-		Sleep(1000);
-	}
-	//the client timed out without recieving an error message.
-	if(!client_connected) {
-		DDrConsole_PrintColored("Connection timed out.",0,red, grey);
-		return false;
-	}
-
-	return true;
-}
+
+
+
 
 //wtf, this needs cleaned up...
@@ -551,12 +279,4 @@
 static flatline_packet cache_input = {0};
 
-bool ShouldSendUpdate( int i, Character* Player, ActiveCharacter* Active_Player )
-{
-	return
-		MultiplayerStatus.PleaseUpdateAllPlayers ? 1 :
-		strcmp(PlayerList[i]->player_data.Animation, 
-		TMrInstance_GetInstanceName(Active_Player->Animation)) ? 1 :
-		PlayerList[i]->player_data.Health != Player->Health ? 1 : 0;
-}
 
 void * ONICALL FLrInput_Update_Keys(void) 
@@ -588,19 +308,21 @@
 	if(!(server_started || client_connected)) return ONgGameState;
 
-	all_input.id = PK_ALL_INPUT;
-
-	if(server_started && ONgGameState->GameTime % 120 == 0)
+
+	if(server_started)
 	{
-		FLsPingAll();
-	}
-
-	if(server_started && PlayerList[0])
-	{
-		PlayerList[0]->Actions1 = ONgGameState->Input.Current.Actions1;
-		PlayerList[0]->Actions2 = ONgGameState->Input.Current.Actions2;
-		PlayerList[0]->MouseDeltaX = ONgGameState->Input.MouseDeltaX;
-		PlayerList[0]->MouseDeltaY = ONgGameState->Input.MouseDeltaY;
-	}
-
+		if(ONgGameState->GameTime % 120 == 0)
+		{
+			FLsPingAll();
+		}
+
+		if(PlayerList[0])
+		{
+			PlayerList[0]->InputFromClient.Actions1 = ONgGameState->Input.Current.Actions1;
+			PlayerList[0]->InputFromClient.Actions2 = ONgGameState->Input.Current.Actions2;
+			PlayerList[0]->InputFromClient.MouseDeltaX = ONgGameState->Input.MouseDeltaX;
+			PlayerList[0]->InputFromClient.MouseDeltaY = ONgGameState->Input.MouseDeltaY;
+		}
+		FLsSendPlayerData();
+	}
 	for(i = 0; i < max_connections; i++) {
 		ActiveCharacter * Active_Player;
@@ -617,34 +339,13 @@
 			continue;
 		}
-		if(server_started && PlayerList[i]->Chr->Health > 0 )
-		{
-
-			//Set up input packets
-
-			all_input.all_input[InputIndex].Actions1 = PlayerList[i]->Actions1;
-			all_input.all_input[InputIndex].Actions2 = PlayerList[i]->Actions2;
-			all_input.all_input[InputIndex].MouseDeltaX = PlayerList[i]->MouseDeltaX;
-			all_input.all_input[InputIndex].MouseDeltaY = PlayerList[i]->MouseDeltaY;
-
-			all_input.all_input[InputIndex].Facing = Player->Facing;
-			all_input.all_input[InputIndex].DesiredFacing = Player->DesiredFacing;
-
-			//Infinity...
-			*(int *)&all_input.all_input[InputIndex].Position.X = 0x7f800000;
-			if(Active_Player)
-			{
-				all_input.all_input[InputIndex].Position = Active_Player->PhyContext->Position;
-			}
-
-
-			all_input.all_input[InputIndex].PlayerNum = i;
-			InputIndex++;
-		}
+
 
 		
 		//Set the health properly first.
-		if( client_connected && PlayerList[i]->DataApplied == FirstPass )
-		{
-			ONrCharacter_SetHitPoints(  PlayerList[i]->Chr, PlayerList[i]->player_data.Health);
+		if( client_connected && DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Health) )
+		{
+			PlayerList[i]->Chr->MaxHealth = PlayerList[i]->Health.MaxHealth;
+			ONrCharacter_SetHitPoints(  PlayerList[i]->Chr, PlayerList[i]->Health.Health);
+			PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Health );
 		}
 		//If the player is dead
@@ -688,5 +389,5 @@
 				else
 				{
-					Actions = PlayerList[i]->Actions1;
+					Actions = PlayerList[i]->InputFromClient.Actions1;
 				}
 
@@ -711,230 +412,147 @@
 		PlayerList[i]->state = STATE_ALIVE;
 
-		
-		
+		if( DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Facing ) )
+		{
+			PlayerList[i]->Chr->Facing = PlayerList[i]->Facings.Facing;					
+			PlayerList[i]->Chr->DesiredFacing = PlayerList[i]->Facings.DesiredFacing;
+			PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Facing );
+		}
+
 		if(Active_Player == 0) continue;
 
-
+		if( client_connected && DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Position) )
+		{
+			Active_Player->PhyContext->Position = PlayerList[i]->Position;
+			
+			PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Position );
+		}
+
+
+
+
+		if (!(Player->Flags & ONcCharacterFlag_BeingThrown) &&
+			DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Animation) && (PlayerList[i]->Animation))
+		{
+			// get a pointer to the animation
+
+			
+			if (PlayerList[i]->Animation != Active_Player->Animation)
+			{
+
+				///////////////////////////////////
+				//TODO: Check age of animation
+				///////////////////////////////////
+
+				// set the characters animation
+				/*ONrCharacter_SetAnimationInternal(Player,
+				Active_Player,
+				Active_Player->AnimationToState,
+				0,
+				Animation);*/
+				//ONrCharacter_NewAnimationHook(Player, Active_Player);
+				ONrCharacter_SetAnimationExternal(Player, TRrAnimation_GetFrom(PlayerList[i]->Animation), PlayerList[i]->Animation, 0);
+				//ONrCharacter_NewAnimationHook(Player, Active_Player);
+			}
+			
+			
+		}
+		PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Animation );
+
+		//Don't update the frame if we are waiting to change the animation
+		if(DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_FramePing) && PlayerList[i]->Frame != -1 
+			//&& !DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Animation) 
+			)
+		{
+			if( abs(PlayerList[i]->Frame - Active_Player->Frame) > 2 )
+			{
+				short AnimationLength;
+				AnimationLength = TRrAnimation_GetDuration(Active_Player->Animation);
+				if (PlayerList[i]->Frame >= AnimationLength)
+				{
+					Active_Player->Frame = AnimationLength - 1;
+					//Active_Player->Frame = 0;
+				}
+				else
+				{
+					Active_Player->Frame = PlayerList[i]->Frame;
+				}
+			}
+			PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_FramePing );
+		}
+
+		//Increment frame in case we were waiting
+		PlayerList[i]->Frame++;
+
+		if (DoWeUpdateThis( PlayerList[i]->UpdateFlags, PFlag_Throws) 
+			&& PlayerList[i]->ThrowData.throwName[0] != 0)
+		{
+			if(PlayerList[PlayerList[i]->ThrowData.throwing])
+			{
+				short throwTarget = PlayerList[PlayerList[i]->ThrowData.throwing]->spawnnumber;
+				if ((throwTarget != Active_Player->throwing) &&
+					(PlayerList[i]->ThrowData.throwFrame < 10))
+				{
+					void	*throw_animation;
+					ActiveCharacter* Target;
+					// get the animation
+
+					TMrInstance_GetDataPtr(
+						'TRAM',
+						PlayerList[i]->ThrowData.throwName,
+						&throw_animation);
+					//if (error) return;
+
+					// set the throw target
+					Active_Player->ThrowTargetCharacter = &ONgGameState->CharacterStorage[throwTarget];
+					Target = ONrGetActiveCharacter(Active_Player->ThrowTargetCharacter);
+					if ((Target->Animation != throw_animation) &&
+					//	(OldAnimation != Animation) &&
+						!(Active_Player->ThrowTargetCharacter->Flags & ONcCharacterFlag_BeingThrown))
+					{
+						// set the throw variables
+						Active_Player->targetThrow	= throw_animation;
+						Active_Player->throwing		= throwTarget;
+
+						// run the throw
+						ONrCharacter_NewAnimationHook(Player, Active_Player);
+
+						if (Active_Player->ThrowTargetCharacter)
+						{
+							Target->Frame += 2;
+							Target->thrownBy = Player->Number;
+						}
+					}
+				}
+			}
+			else
+			{
+				DDrConsole_PrintF("Warning, tried to throw nonexistant player %hi", 
+					PlayerList[i]->ThrowData.throwing );
+			}
+		} 
+
+		//Always discard old throw data, even if it isnt applied
+		PlayerList[i]->UpdateFlags &= ~( 1 << PFlag_Throws );
 
 		//Active_Player->PlayingFilm.Flags = 1;
 		Active_Input = &(Active_Player->Input);
 
-		if(server_started && 
-			ShouldSendUpdate( i, PlayerList[i]->Chr, Active_Player) )
-		{
-			player_data * data;
-			flatline_packet data_out = {0};
-
-			
-			data_out.id = PLAYER_DATA;
-			data = (void*)&(data_out.data);
-			data->PlayerNum = i;
-			data->Health = PlayerList[i]->Chr->Health;
-			data->MaxHealth = PlayerList[i]->Chr->MaxHealth;
-			//data->Position = PlayerList[i]->Chr->Position;
-			//data->Facing = PlayerList[i]->Chr->Facing;
-			//data->DesiredFacing = PlayerList[i]->Chr->DesiredFacing;
-			//data->Position = Active_Player->PhyContext->Position;
-			memcpy(data->Animation, TMrInstance_GetInstanceName(Active_Player->Animation), 31);
-			data->Frame = Active_Player->Frame;
-
-			data->UD = Active_Player->HeadPitch;	
-			data->LR = Active_Player->HeadFacing;
-
-			if(Active_Player->targetThrow)
-			{
-				data->throw_data.throwing = Players[Active_Player->throwing].list_slot;
-				memcpy(data->throw_data.throwName, TMrInstance_GetInstanceName(Active_Player->targetThrow), 31);
-				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) ) )
-			{
-				PlayerList[i]->OldClass = PlayerList[i]->Chr->ONCC;
-				memcpy( &(PlayerList[i]->Inventory), &(PlayerList[i]->Chr->Inventory), sizeof(Inventory) );
-				PlayerList[i]->rare_sync_index++;
-
-			}
-
-			data->rare_sync_index = PlayerList[i]->rare_sync_index;
-
-
-			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 ) 
 		{
-			Active_Input->Stop.Actions1 = ~PlayerList[i]->Actions1 & Active_Input->Current.Actions1;
-			Active_Input->Stop.Actions2 = ~PlayerList[i]->Actions2 & Active_Input->Current.Actions2;
-			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;
+			Active_Input->Stop.Actions1 = ~PlayerList[i]->Input.Actions1 & Active_Input->Current.Actions1;
+			Active_Input->Stop.Actions2 = ~PlayerList[i]->Input.Actions2 & Active_Input->Current.Actions2;
+			Active_Input->Start.Actions1 = ~Active_Input->Current.Actions1 & PlayerList[i]->Input.Actions1;
+			Active_Input->Start.Actions2 = ~Active_Input->Current.Actions2 & PlayerList[i]->Input.Actions2;
+
+			Active_Input->Current.Actions1 = PlayerList[i]->Input.Actions1;
+			Active_Input->Current.Actions2 = PlayerList[i]->Input.Actions2;
 			Active_Input->Stopped.Actions1 = ~Active_Input->Current.Actions1;
 			Active_Input->Stopped.Actions2 = ~Active_Input->Current.Actions2;
-			Active_Input->MouseDeltaX = PlayerList[i]->MouseDeltaX;
-			Active_Input->MouseDeltaY = PlayerList[i]->MouseDeltaY;
-
-
-			if( !server_started && PlayerList[i]->player_data.Health != 0 && PlayerList[i]->Chr->Health != 0) {
-				void* OldAnimation;
-				void* Animation;
-				player_data* pd = &PlayerList[i]->player_data;
-				
-				//This is getting crazy. WTB new packet system
-				if(PlayerList[i]->NeedToSetFP)
-				{
-					PlayerList[i]->Chr->Facing = PlayerList[i]->Facing;					
-					PlayerList[i]->Chr->DesiredFacing = PlayerList[i]->DesiredFacing;
-				
-					if(*(int*)&PlayerList[i]->Chr->Position.X != 0x7f800000)
-					{
-						Active_Player->PhyContext->Position = Player->Location = PlayerList[i]->Position;					
-
-					}
-					PlayerList[i]->NeedToSetFP = 0;
-				}
-
-				if( PlayerList[i]->DataApplied == FirstPass )
-				{
-					PlayerList[i]->DataApplied = SecondPass;
-
-					//Player->Health = PlayerList[i]->player_data.Health;
-					PlayerList[i]->Chr->MaxHealth = PlayerList[i]->player_data.MaxHealth;
-
-				}
-				else if( PlayerList[i]->DataApplied == SecondPass )
-				{
-					OldAnimation = Active_Player->Animation;
-
-					PlayerList[i]->DataApplied = NoPass;
-
-					PlayerList[i]->player_data.Frame++;
-
-					if (!(Player->Flags & ONcCharacterFlag_BeingThrown) &&
-						(pd->Animation[0] != 0))
-					{
-						// get a pointer to the animation
-
-						TMrInstance_GetDataPtr(
-							'TRAM',
-							pd->Animation,
-							&Animation);
-						if (Animation != OldAnimation)
-						{
-							short	num_frames;
-							bool	updateAnimation = true;
-
-							// 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;
-							}
-							}
-							*/
-							if ((updateAnimation) && (Active_Player->Animation == Animation))
-							{
-								int		oldFrame = Active_Player->Frame;
-								int		newFrame = pd->Frame;
-
-								if (abs(oldFrame - newFrame) < 2)
-								{
-									updateAnimation = false;
-								}
-							}
-
-							if (updateAnimation)
-							{
-								// set the characters animation
-								/*	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);
-								//ONrCharacter_NewAnimationHook(Player, Active_Player);
-							}
-
-							num_frames = TRrAnimation_GetDuration(Active_Player->Animation);
-
-							if (pd->Frame == num_frames)
-							{
-								Active_Player->Frame = num_frames - 1;
-								//Active_Player->Frame = 0;
-							}
-							else
-							{
-								Active_Player->Frame = pd->Frame;
-							}
-						}
-					} //animation check
-
-					if (PlayerList[i]->player_data.throw_data.throwName[0] != 0)
-					{
-						if(PlayerList[pd->throw_data.throwing])
-						{
-							short throwTarget = PlayerList[pd->throw_data.throwing]->spawnnumber;
-							if ((throwTarget != Active_Player->throwing) &&
-								(pd->throw_data.throwFrame < 10))
-							{
-								void	*throw_animation;
-								ActiveCharacter* Target;
-								// get the animation
-
-								TMrInstance_GetDataPtr(
-									'TRAM',
-									pd->throw_data.throwName,
-									&throw_animation);
-								//if (error) return;
-
-								// set the throw target
-								Active_Player->ThrowTargetCharacter = &ONgGameState->CharacterStorage[throwTarget];
-								Target = ONrGetActiveCharacter(Active_Player->ThrowTargetCharacter);
-								if ((Target->Animation != throw_animation) &&
-									(OldAnimation != Animation) &&
-									!(Active_Player->ThrowTargetCharacter->Flags & ONcCharacterFlag_BeingThrown))
-								{
-									// set the throw variables
-									Active_Player->targetThrow	= throw_animation;
-									Active_Player->throwing		= throwTarget;
-
-									// run the throw
-									ONrCharacter_NewAnimationHook(Player, Active_Player);
-
-									if (Active_Player->ThrowTargetCharacter)
-									{
-										Target->Frame += 2;
-										Target->thrownBy = Player->Number;
-									}
-								}
-							}
-						}
-						else
-						{
-							DDrConsole_PrintF("Warning, tried to throw nonexistant player %hi", pd->throw_data.throwing );
-						}
-					} //throw check
-				} //second pass
-			} //if not dead
-		} //if( (server_started && i !=0)  || !server_started ) 
+			Active_Input->MouseDeltaX = PlayerList[i]->Input.MouseDeltaX;
+			Active_Input->MouseDeltaY = PlayerList[i]->Input.MouseDeltaY;
+		} 
 		
 		//Check for character switching requests
-		if(server_started && PlayerList[i]->player_data.Health != 0 && PlayerList[i]->Chr->Health != 0 && PlayerList[i]->Actions1 & Action_Block && PlayerList[i]->ShapeshiftCooldown < ONgGameState->GameTime)
+		if(server_started && PlayerList[i]->Chr->Health != 0 && PlayerList[i]->InputFromClient.Actions1 & Action_Block && PlayerList[i]->ShapeshiftCooldown < ONgGameState->GameTime)
 		{
 			int error;
@@ -955,5 +573,5 @@
 			}
 			*/
-			if (PlayerList[i]->Actions1 & Action_Crouch) {
+			if (PlayerList[i]->InputFromClient.Actions1 & Action_Crouch) {
 				Player->ONCCnumber += numClasses - 1;
 			}
@@ -976,10 +594,5 @@
 
 	}
-	if(server_started)
-	{
-		all_input.all_input[InputIndex].PlayerNum = -1;
-		UDPServer_SendToAll(&all_input, 
-			FLATLINE_HEADER + sizeof(player_input) * InputIndex + sizeof(int16_t));
-	}
+	
 	MultiplayerStatus.PleaseUpdateAllPlayers = 0;
 	return ONgGameState;
@@ -1059,5 +672,5 @@
 				TSrContext_DrawText(ScoreboardInstance, DrawString, 255, 0, &DrawLocation);
 				DrawLocation.x += 50;
-				sprintf(DrawString, "%i", PlayerList[i]->player_data.Ping);
+				sprintf(DrawString, "%i", PlayerList[i]->Ping);
 				TSrContext_DrawText(ScoreboardInstance, DrawString, 255, 0, &DrawLocation);
 			}
Index: /Daodan/MSVC/Flatline.h
===================================================================
--- /Daodan/MSVC/Flatline.h	(revision 583)
+++ /Daodan/MSVC/Flatline.h	(revision 584)
@@ -36,5 +36,5 @@
 #include "Daodan_Console.h"
 #include "Oni_Character.h"
-
+#include "Flatline_Packet.h"
 
 #define pad1_size (sizeof(int64_t) - sizeof(short))
@@ -114,4 +114,5 @@
 	char					throwName[32];
 } td;
+/*
 typedef struct {
 	uint16_t PlayerNum;
@@ -139,5 +140,5 @@
 
 //todo, move health in...
-typedef struct {
+/*typedef struct {
 	short unsigned int PlayerNum;
 	unsigned int index;
@@ -145,10 +146,10 @@
 	char Class[32];
 } rare_sync_data;
-
+*/
 typedef struct {
 	unsigned int event_index;
 	int intArray[];
 } flatline_event;
-
+/*
 typedef struct {
 	int16_t PlayerNum;
@@ -161,5 +162,5 @@
 	Vector3 Position;
 } player_input;
-
+*/
 //used for storing data about each player
 typedef struct {
@@ -175,10 +176,10 @@
 		new_player		new_player;
 		server_status	server_status;
-		player_data		player_data;
-		rare_sync_data  rare_sync_data;
+		//player_data		player_data;
+		//rare_sync_data  rare_sync_data;
 		uint16_t		sync_request;
 		flatline_event	flatline_event;
 		uint32_t		ping;
-		player_input	all_input[33];
+		//player_input	all_input[33];
 	};
 } flatline_packet;
@@ -202,11 +203,12 @@
 	NEW_PLAYER,
 	PLAYER_INPUT,
-	PLAYER_DATA,
-	RARE_SYNC_DATA,
-	RARE_SYNC_DATA_REQUEST,
+	//PLAYER_DATA,
+	//RARE_SYNC_DATA,
+	//RARE_SYNC_DATA_REQUEST,
 	FLATLINE_EVENT,
 	PK_PING,
 	PK_PONG,
-	PK_ALL_INPUT,
+	//PK_ALL_INPUT,
+	PK_PLAYER_DATA,
 };
 
@@ -248,21 +250,29 @@
 	uint16_t spawnnumber;
 	uint16_t list_slot;
-	
-	//Todo: move into struct for slightly faster copying
-	float MouseDeltaX;
-	float MouseDeltaY;
-	uint32_t Actions1;
-	uint32_t Actions2;
-	float Facing;
-	float DesiredFacing;
-	//float Height;
+
+	PlayerInput InputFromClient;
+
+	////////////////////////////
+	//Sync stuff
+	////////////////////////////
+	uint16_t UpdateFlags;
+
+	PlayerInput Input;
+	PlayerHealth Health;
+	PlayerFacing Facings;
+	PlayerScore Score;
+	void* Animation;
+	uint16_t Frame;
+	PlayerThrowData ThrowData;
+	void* Class;
+	PlayerInventory Inventory;
 	Vector3 Position;
+	////////////////////////////
+	bool HasAppliedThrow;
 
 	unsigned int LastInputTime;
-	input_struct CacheInput;
-	player_data player_data;
-	unsigned int rare_sync_index;
-	void* OldClass;
-	Inventory Inventory;
+
+
+
 	uint16_t state;
 	int flags;
@@ -302,4 +312,7 @@
 int FLrEvent_GetNumArgs( int eventIndex );
 bool FlatlineInitialize();
+
+bool DoWeUpdateThis( uint16_t BitSet, uint16_t Flag );
+
 extern unsigned int lastPingTime;
 #endif
Index: /Daodan/MSVC/Flatline_Client.c
===================================================================
--- /Daodan/MSVC/Flatline_Client.c	(revision 584)
+++ /Daodan/MSVC/Flatline_Client.c	(revision 584)
@@ -0,0 +1,185 @@
+#include "Flatline.h"
+#include "Flatline_Client.h"
+
+int client_slot = 0;
+RGBA green = {0, 0xFF, 0, 0};
+RGBA red = {0, 0, 0xFF, 0};
+RGBA grey = {0x80,0x80,0x80,0x80};
+
+
+int FLcEventHandler( int eventIndex, int args[] )
+{
+	switch(eventIndex)
+	{
+	case(EV_DISCONNECT):
+		FLrPlayerDisconnect( args[0] );
+		break;
+	case(EV_KILLED):
+		ONrCharacter_SetHitPoints( PlayerList[args[0]]->Chr, 0);
+	case(EV_DOOR_OPEN):
+		OBJrDoor_ForceOpen( args[0] );
+		break;
+	case(EV_CONSOLE_USE):
+		OBJrConsole_OnActivate( OBJrConsole_GetByID(args[0]), PlayerList[args[1]]->Chr );
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+
+bool FLrClient_Run(flatline_packet* packet)
+{
+
+	char data[1400];
+	uint16_t len;
+	int j;
+	int sent_bytes;
+	client_connected = 0;
+
+
+	//starts the connection
+	DDrConsole_PrintF("Connecting to server %s on socket %i",  inet_ntoa(address.sin_addr), client_sock);
+	sent_bytes = NetUDPSocket_Send(client_sock, (sockaddr*)&address, (char*)packet, 255);
+	if(sent_bytes == SOCKET_ERROR) {
+		NetCatchError();
+	}
+	//loops once per second waiting for a reply.
+	for(j = 0; j < CONNECTION_TIMEOUT; j++) {
+		while(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, data, &len)){		
+			packet = (flatline_packet*)data;
+			if(packet->id == CONNECT_REPLY) {
+				if(packet->connect_reply.goodtogo){
+
+					client_connected = 1;
+
+					client_slot = ((connect_reply*)packet->data)->player_slot;
+
+					PlayerList[client_slot] = Players+client_slot;
+					PlayerList[client_slot]->Chr = ONgGameState->PlayerCharacter;
+
+					DDrConsole_PrintColored("Connection successful!",0,green, grey);
+
+					sprintf_s( PlayerList[client_slot]->name, 32, "%s", player_name );
+
+					//disable local input.
+					DDrPatch_NOOP(0x004FA929, 5 + 6 + 5);
+					
+					//Disable local turning
+					//DDrPatch_NOOP(0x004F7EA8, 2);
+					//DDrPatch_Byte( 0x004F7EB1 , 0xE9);
+					//DDrPatch_MakeJump( 0x004F7EB1, 0x004F8030 );
+
+
+					//DDrPatch_Byte(0x04ED6FB, 0xEB);
+
+					//DDrConsole_PrintF("Slot %i",  ((connect_reply*)packet)->player_slot);
+					//DDrPatch_NOOP(0x43B23,0x10);
+					//DDrPatch_NOOP(0x4EC248,(0x5A-0x48));
+					//DDrPatch_NOOP(0x4EC861, 6);
+					break;
+				}
+				else {
+					DDrConsole_PrintF("Connection rejected: %s", ((connect_reply*)packet->data)->message);
+					return false;
+					break;
+				}
+			}
+		}
+		if(client_connected) break;
+		DDrConsole_PrintF("Connection timing out in %i seconds...", CONNECTION_TIMEOUT - j);
+		Sleep(1000);
+	}
+	//the client timed out without recieving an error message.
+	if(!client_connected) {
+		DDrConsole_PrintColored("Connection timed out.",0,red, grey);
+		return false;
+	}
+
+	return true;
+}
+
+
+void FLrClient_GetPackets()
+{
+	flatline_packet packet;
+	uint16_t len;
+	//#define SPAM_INPUT
+#ifdef SPAM_INPUT
+	struct timeval lasttime;
+	struct timeval thistime;
+	gettimeofday(&lasttime, 0);
+#endif
+	
+
+		while(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, &packet, &len)) {
+			//packet = (flatline_packet*)data;
+			//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 CHANGE_NAME:
+				if(PlayerList[(char)packet.data[0]])
+				{
+					char message_buffer[1024];
+					sprintf(message_buffer,"%s changed their name to %s", PlayerList[(char)packet.data[0]]->name, packet.data + 1);
+					COrMessage_Print(message_buffer, "name_change", 0);
+
+					sprintf_s(PlayerList[packet.data[0]]->name, 32, "%s", packet.data + 1);
+
+				}
+				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) ;
+						sprintf_s(Players[chr_index].name, 32, "%s", ((new_player*)(packet.data))->Character.OSD.Name);
+					}
+					//Players[((new_player*)(packet.data))->Playernumber].spawnnumber = ONrGameState_NewCharacter(&(((new_player*)(packet.data))->Character), NULL, NULL, 0);
+					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;
+			case PK_PLAYER_DATA:
+				FLcReadPlayerData( &packet, len );
+				break;
+			default:
+				DDrConsole_PrintF("Warning, recieved badly formed packet!");
+				break;
+			}
+	}
+}
+
Index: /Daodan/MSVC/Flatline_Client.h
===================================================================
--- /Daodan/MSVC/Flatline_Client.h	(revision 584)
+++ /Daodan/MSVC/Flatline_Client.h	(revision 584)
@@ -0,0 +1,11 @@
+#ifndef FLATLINE_CLIENT_H
+#define FLATLINE_CLIENT_H
+#include "Flatline.h"
+
+int FLcEventHandler( int eventIndex, int Args[] );
+bool FLrClient_Run(flatline_packet* packet);
+void FLrClient_GetPackets();
+
+extern int client_slot;
+
+#endif
Index: /Daodan/MSVC/Flatline_Events.c
===================================================================
--- /Daodan/MSVC/Flatline_Events.c	(revision 584)
+++ /Daodan/MSVC/Flatline_Events.c	(revision 584)
@@ -0,0 +1,16 @@
+#include "Flatline.h"
+#include "Flatline_Hooks.h"
+
+const int EventArgs[EV_MAX] =
+{
+	1,//EV_RESPAWN,
+	1,//EV_KILLED,
+	1,//EV_DISCONNECT,
+	2,//EV_DOOR_OPEN,
+	2//EV_CONSOLE_USE,
+};
+
+int FLrEvent_GetNumArgs( int eventIndex )
+{
+	return EventArgs[eventIndex];
+}
Index: /Daodan/MSVC/Flatline_Hooks.c
===================================================================
--- /Daodan/MSVC/Flatline_Hooks.c	(revision 584)
+++ /Daodan/MSVC/Flatline_Hooks.c	(revision 584)
@@ -0,0 +1,33 @@
+#include "Flatline.h"
+#include "Flatline_Hooks.h"
+#include "Flatline_Server.h"
+
+//Don't modify this.
+char * FLrHook_DoorOpen( DoorObject *Door, Character *Char)
+{
+	int crashStop;		
+	int Args[2] = {Door->Door.ID, 0};
+	if(server_started)
+	{
+		if(Char)
+		{
+			Args[1] = Char->Number;
+		}
+		else
+		{
+			Args[1] = -1;
+		}
+	}
+	crashStop = !server_started || FLsPublic_Event(EV_DOOR_OPEN, Args);
+	return (char*)(Door->Door.class);
+}
+short FLrHook_ConsoleActivate( void *inObject, Character *inCharacter )
+{
+	if(server_started)
+	{
+		int Args[2] = {*((char*)inObject + 0x2C), inCharacter->Number};
+		FLsPublic_Event(EV_CONSOLE_USE, Args);
+	}
+	return OBJrConsole_OnActivate( inObject, inCharacter );
+}
+
Index: /Daodan/MSVC/Flatline_Hooks.h
===================================================================
--- /Daodan/MSVC/Flatline_Hooks.h	(revision 584)
+++ /Daodan/MSVC/Flatline_Hooks.h	(revision 584)
@@ -0,0 +1,3 @@
+#include "Oni.h"
+char * FLrHook_DoorOpen( DoorObject *Door, Character *Char);
+short FLrHook_ConsoleActivate( void *inObject, Character *inCharacter );
Index: /Daodan/MSVC/Flatline_Net.c
===================================================================
--- /Daodan/MSVC/Flatline_Net.c	(revision 583)
+++ /Daodan/MSVC/Flatline_Net.c	(revision 584)
@@ -58,5 +58,5 @@
 {
 	//DDrConsole_PrintF("Sending data size %u to %s on socket %i", datalen, inet_ntoa( ((sockaddr_in*)address)->sin_addr ), UDPServer_Socket);
-	data->FLATLINE = *(int*)"FLATLINE";
+	//data->FLATLINE = *(int*)"FLATLINE";
 	return NetUDPSocket_Send(UDPServer_Socket, address, data, datalen);
 }
@@ -149,5 +149,5 @@
 	data->packet_index = packet_index;
 #endif
-	data->FLATLINE = *(int*)"FLATLINE";
+	//data->FLATLINE = *(int*)"FLATLINE";
 	switch (address->sa_family)
 	{
Index: /Daodan/MSVC/Flatline_Packet.c
===================================================================
--- /Daodan/MSVC/Flatline_Packet.c	(revision 584)
+++ /Daodan/MSVC/Flatline_Packet.c	(revision 584)
@@ -0,0 +1,25 @@
+#include "Flatline_Packet.h"
+
+
+//Always keep this mirrored with the PFlags
+uint8_t sizes[] = 
+{
+	0,
+	sizeof(PlayerInput),	//PFlag_Input,
+	sizeof(PlayerFacing),	//PFlag_Facing,	
+	sizeof(PlayerHealth),	//PFlag_Health,		
+	sizeof(PlayerScore),	//PFlag_Score,		
+	sizeof(PlayerFP),		//PFlag_FramePing,
+	sizeof(PlayerInventory),//PFlag_Inventory,
+	32,						//PFlag_Class,	
+	12,						//PFlag_Position
+	32,						//PFlag_Animation,	
+	sizeof(PlayerThrowData),//PFlag_Throws,
+};
+
+//please oh please name this better
+uint16_t FLpData_PartSize( uint8_t e)
+{
+	if( e >= PFlag_Max ) return 0;
+	return sizes[e];
+}
Index: /Daodan/MSVC/Flatline_Packet.h
===================================================================
--- /Daodan/MSVC/Flatline_Packet.h	(revision 584)
+++ /Daodan/MSVC/Flatline_Packet.h	(revision 584)
@@ -0,0 +1,83 @@
+#ifndef FLATLINE_PACKET_H
+#define FLATLINE_PACKET_H
+
+
+#include "bool.h"
+
+
+uint16_t FLpData_PartSize( uint8_t e);
+void FLsSendPlayerData();
+//void FLcReadPlayerData( flatline_packet* Packet, int16_t Size );
+
+typedef struct
+{
+	uint16_t ID;
+	uint16_t Size;
+	uint16_t UpdateFlags;
+	uint8_t  data[255];
+} PlayerData;
+
+
+typedef struct {
+	uint32_t Actions1;
+	uint32_t Actions2;
+	float MouseDeltaX;
+	float MouseDeltaY;	
+} PlayerInput;
+
+typedef struct {
+	float Facing;
+	float DesiredFacing;
+} PlayerFacing;
+
+typedef struct {
+	uint16_t Health;
+	uint16_t MaxHealth;
+} PlayerHealth;
+
+typedef struct {
+	uint16_t Score;
+	uint16_t Deaths;
+} PlayerScore;
+
+//Change this later to be misc info
+typedef struct {
+	uint16_t Frame;
+	uint16_t Ping;
+} PlayerFP;
+
+typedef struct {
+	uint8_t Ammo;
+	uint8_t Cells;
+	uint8_t Hypo;
+	uint8_t pad;
+	uint16_t Invis;
+	uint16_t Shield;
+} PlayerInventory;
+
+typedef struct {
+	uint16_t				throwing;
+	uint16_t				throwFrame;
+	char					throwName[32];
+} PlayerThrowData;
+
+enum
+{
+	PFlag_None,
+	PFlag_Input,
+	PFlag_Facing,	
+	PFlag_Health,		
+	PFlag_Score,		//TODO
+	PFlag_FramePing,
+	PFlag_Inventory, //TODO
+	PFlag_Class,	
+	PFlag_Position,
+	PFlag_Animation,	
+	PFlag_Throws,
+	PFlag_Max,
+	PFlag_AnimationWait,//Clients only!
+};
+
+
+
+#endif
Index: /Daodan/MSVC/Flatline_PacketBuilder.c
===================================================================
--- /Daodan/MSVC/Flatline_PacketBuilder.c	(revision 584)
+++ /Daodan/MSVC/Flatline_PacketBuilder.c	(revision 584)
@@ -0,0 +1,192 @@
+#include "Flatline.h"
+#include <assert.h>
+
+#define FLAG_AND_INCREMENT( FLAG )	PD->UpdateFlags |= (1 << FLAG ); DataPointer += FLpData_PartSize( FLAG );
+
+void FLsPacketBuild( uint8_t p, PlayerData* PD )
+{
+	Character* Player = PlayerList[p]->Chr;
+	ActiveCharacter* APlayer = ONrGetActiveCharacter(Player);
+	player_info * PI = PlayerList[p];
+	uint8_t * DataPointer = PD->data;
+	PD->ID = p;
+	
+	//if ( data has changed )
+	//{
+	//	copy it to the buffer
+	//  copy it to the player info
+	//  set the changed flag
+	//  increment the buffer pointer
+	//}
+
+	/* 
+	//Could probably send this every frame, but afk players can save a few bytes, eh?
+	if( PI->Input.Actions1 != PI->InputFromClient.Actions1 ||
+		PI->Input.Actions2 != PI->InputFromClient.Actions2 ||
+		PI->Input.MouseDeltaX != PI->InputFromClient.MouseDeltaX ||
+		PI->Input.MouseDeltaY != PI->InputFromClient.MouseDeltaY )
+	{*/
+
+	//Better in case of dropped packets to send input every frame
+	if(1)
+	{
+		memcpy( DataPointer, &PI->InputFromClient, sizeof(PlayerInput));
+		PI->InputFromClient = PI->Input;
+
+		FLAG_AND_INCREMENT( PFlag_Input );
+	}
+
+	if( PI->Facings.Facing != Player->Facing ||
+		PI->Facings.DesiredFacing != Player->DesiredFacing )
+	{
+		PlayerFacing* ptr = (void*)DataPointer;
+		ptr->Facing = Player->Facing;
+		ptr->DesiredFacing = Player->DesiredFacing;
+
+		PI->Facings = *ptr;
+
+		FLAG_AND_INCREMENT( PFlag_Facing );
+	}
+
+	if(PI->Health.Health != Player->Health ||
+		PI->Health.MaxHealth != Player->MaxHealth )
+	{
+		PlayerHealth* ptr = (void*)DataPointer;
+		ptr->Health = Player->Health;
+		ptr->MaxHealth = Player->MaxHealth;
+
+		PI->Health = *ptr;
+
+		FLAG_AND_INCREMENT( PFlag_Health );
+	}
+
+	//Score
+	//skipping for now
+
+	//Frame and ping can be sent every frame, i guess. Improve this later,
+	if( 1 )
+	{
+		PlayerFP* ptr = (void*)DataPointer;
+		if(APlayer)
+		{
+			ptr->Frame = APlayer->Frame;
+		}
+		else
+		{
+			ptr->Frame = -1;
+		}
+		ptr->Ping = PI->Ping;
+
+		PI->Frame = ptr->Frame;
+
+		FLAG_AND_INCREMENT( PFlag_FramePing );
+	}
+	
+	//Skipping inventory because we dont need it right now
+	if( 0 )
+	{
+		//Do inventory
+	}
+
+	if( PI->Class != Player->ONCC )
+	{
+		sprintf_s( DataPointer, 32, "%s", TMrInstance_GetInstanceName( Player->ONCC ) );
+		PI->Class = Player->ONCC;
+
+		FLAG_AND_INCREMENT( PFlag_Class );
+	}
+
+	if(APlayer)
+	{
+		if( memcmp(&PI->Position, &APlayer->PhyContext->Position, sizeof(Vector3)) )
+		{
+			Vector3* ptr = (Vector3*)DataPointer;
+			*ptr = PI->Position = APlayer->PhyContext->Position;
+		
+			FLAG_AND_INCREMENT( PFlag_Position );
+		}
+
+		if(APlayer->Animation != PI->Animation)
+		{
+			sprintf_s( DataPointer, 32, "%s", TMrInstance_GetInstanceName( PI->Animation ) );
+			PI->Animation = APlayer->Animation;
+			
+			FLAG_AND_INCREMENT( PFlag_Animation );
+		}
+
+		if(APlayer->targetThrow)
+		{
+			if(!PI->HasAppliedThrow)
+			{
+				PlayerThrowData* ptr = (void*)DataPointer;
+				ptr->throwing = Players[APlayer->throwing].list_slot;
+				memcpy(ptr->throwName, TMrInstance_GetInstanceName(APlayer->targetThrow), 31);
+				ptr->throwFrame = ONrGetActiveCharacter(APlayer->targetThrow)->Frame;
+
+				PI->ThrowData = *ptr;
+
+				PI->HasAppliedThrow = 1;
+
+				FLAG_AND_INCREMENT( PFlag_Throws );
+			}
+		}
+		else
+		{
+			PI->HasAppliedThrow = 0;
+		}
+	}
+	
+	PD->Size = (char)DataPointer - (char)PD;
+
+	PI->UpdateFlags = PD->UpdateFlags;	
+	
+}
+
+
+
+void FLsSendPlayerData()
+{
+	PlayerData BuildData[32] = {0};
+	uint8_t p = 0;
+	uint32_t PacketSize = 0;
+	flatline_packet OutputPacket = {0};
+	uint8_t* OutputPointer = OutputPacket.data;
+	//Most of the time we won't even hit this. Could probably be bumped up a few hundred bytes
+	const uint32_t max_packet_size = 1000;
+
+	//Prepare buffers
+	OutputPacket.id = PK_PLAYER_DATA;
+	memset( BuildData, 0, sizeof(PlayerData) * 32 );
+
+	//Build data
+	for(p = 0; p < MAX_PLAYERS; p++)
+	{
+		if(PlayerList[p] && PlayerList[p]->Chr)
+		{
+			FLsPacketBuild(p, &BuildData[p]);
+			
+			assert( BuildData[p].Size < 255 );
+			
+			//If we hit maximum size, send the packet and reset the buffer for a new one
+			if( BuildData[p].Size + PacketSize > max_packet_size )
+			{
+				UDPServer_SendToAll(&OutputPacket, PacketSize + FLATLINE_HEADER);
+			
+				memset( OutputPacket.data, 0, PacketSize );
+				OutputPointer = OutputPacket.data;
+				PacketSize = 0;
+			}
+			
+			//add to the packet
+			memcpy( OutputPointer, &BuildData[p], BuildData[p].Size );
+			
+			OutputPointer += BuildData[p].Size;
+			PacketSize += BuildData[p].Size;
+		}
+	}
+	//Send data
+	if( PacketSize > 0 )
+	{
+		UDPServer_SendToAll(&OutputPacket, PacketSize + FLATLINE_HEADER);
+	}
+}
Index: /Daodan/MSVC/Flatline_PacketReader.c
===================================================================
--- /Daodan/MSVC/Flatline_PacketReader.c	(revision 584)
+++ /Daodan/MSVC/Flatline_PacketReader.c	(revision 584)
@@ -0,0 +1,115 @@
+#include "Flatline.h"
+
+bool DoWeUpdateThis( uint16_t BitSet, uint16_t Flag )
+{
+	if( BitSet & (1 << Flag) ) return true;
+	return false;
+}
+
+//Long winded?
+
+void FLcPacketBufferToPlayerData( PlayerData* PD)
+{
+	player_info* PI = PlayerList[PD->ID];
+	uint8_t * DataPointer = PD->data;
+
+	if(!PI)
+	{
+		//TODO: Store this data and then apply it once we have a character that matches!
+		return;
+	}
+
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Input) )
+	{
+		PI->Input = *(PlayerInput*)DataPointer;
+		DataPointer += FLpData_PartSize( PFlag_Input);
+	}
+
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Facing) )
+	{
+		PI->Facings = *(PlayerFacing*)DataPointer;
+		DataPointer += FLpData_PartSize( PFlag_Facing);
+	}
+
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Health) )
+	{
+		PI->Health = *(PlayerHealth*)DataPointer;
+		DataPointer += FLpData_PartSize( PFlag_Health);
+	}
+
+	//Not done
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Score) )
+	{
+		PI->Score = *(PlayerScore*)DataPointer;
+		DataPointer += FLpData_PartSize( PFlag_Score);
+	}
+	
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_FramePing) )
+	{
+		PlayerFP* FP = (PlayerFP*)DataPointer;
+		PI->Ping = FP->Ping;
+		
+		if(FP->Frame != -1)
+		{
+			PI->Frame = FP->Frame;
+		}
+		else
+		{
+			PD->UpdateFlags &= ~( 1 << PFlag_FramePing );
+		}
+		DataPointer += FLpData_PartSize( PFlag_FramePing);
+	}
+	
+	//Not done
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Inventory) )
+	{
+		PI->Inventory = *(PlayerInventory*)DataPointer;
+		DataPointer += FLpData_PartSize( PFlag_Inventory );
+	}
+		
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Class ) )
+	{
+		TMrInstance_GetDataPtr( 'ONCC', (char*)DataPointer, &PI->Class );
+		DataPointer += FLpData_PartSize( PFlag_Class );
+	}
+		
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Position ) )
+	{
+		PI->Position = *(Vector3*)DataPointer;
+		DataPointer += FLpData_PartSize( PFlag_Position );
+	}
+		
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Animation ) )
+	{
+		TMrInstance_GetDataPtr( 'TRAM', (char*)DataPointer, &PI->Animation );
+		DataPointer += FLpData_PartSize( PFlag_Animation );
+	}
+		
+	if( DoWeUpdateThis( PD->UpdateFlags, PFlag_Throws ) )
+	{
+		PI->ThrowData = *(PlayerThrowData*)DataPointer;
+		DataPointer += FLpData_PartSize( PFlag_Throws );
+	}
+
+
+	PI->UpdateFlags |= PD->UpdateFlags;
+}
+
+void FLcReadPlayerData( flatline_packet* Packet, int16_t Size )
+{
+	PlayerData* PDCast = (PlayerData*)Packet->data;
+	Size -= FLATLINE_HEADER;
+	while(Size > 0)
+	{
+		if(PDCast->Size > Size)
+		{
+			DDrConsole_PrintF( "Warning, (almost) read %hi bytes too much of player data buffer", -Size );
+			break;
+		}
+		FLcPacketBufferToPlayerData( PDCast );
+		Size -= PDCast->Size;
+		PDCast = (PlayerData*)((char*)PDCast + PDCast->Size);
+	}
+
+	//Packet
+}
Index: /Daodan/MSVC/Oni_GameState.h
===================================================================
--- /Daodan/MSVC/Oni_GameState.h	(revision 583)
+++ /Daodan/MSVC/Oni_GameState.h	(revision 584)
@@ -996,6 +996,6 @@
   int field_1668;
   char gap_166c[4];
-  int Kills;
-  int Damage;
+  uint32_t Kills;
+  uint32_t Damage;
   int field_1678;
   int field_167C;
@@ -1237,5 +1237,5 @@
   __int16 thrownBy;
   Character* ThrowTargetCharacter;
-  int targetThrow; //animation
+  void* targetThrow; //animation
   int field_1EE4;
   int field_1EE8;
@@ -1442,5 +1442,5 @@
   int field_1679DC;
 } GameState;
-#endif
+
 
 typedef struct 
@@ -1476,2 +1476,3 @@
 			int blah3;
 } COtTextArea;
+#endif
