#include "Flatline.h" #include "Oni_Character.h" #include "Flatline_Server.h" #include #include uint32_t last1 = 0; uint32_t last2 = 0; player_info Players[MAX_PLAYERS] = {{0}, {0}, {0}, {0}}; player_info * PlayerList[MAX_CONNECTIONS] = {0}; const char * Rejection_Messages[][255] = { {"Server is full"}, {"-2"}, {"-3"}, {"-4"}, {"-5"}, }; bool FLrServer_PacketCallback(char* data, int datalen, int from) { flatline_packet * packet = (flatline_packet*)data; static int recieved = 0; sockaddr_in sender; sender.sin_family = AF_INET; 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 int i, j; //stupid C90, won't let me declare my counter inside a for loop. bool found_player = 0; switch(packet->id) { //rewrite this when we get TCP support. //rewrite this before we get TCP support* //the way of seeing if there is room for players sucks. case CONNECT_SEND: ; flatline_packet connect_recv; connect_recv.id = CONNECT_REPLY; //if(Players[i].ip == sender.sin_addr.S_un.S_addr) break; //needs to send an error message DDrConsole_PrintF("%s connected from IP_ADDRESS", ((connect_send*)(packet->data))->name); sender.sin_addr.S_un.S_addr = htonl(sender.sin_addr.S_un.S_addr); player_info * playah = FLrServer_AddPlayer(from,((connect_send*)(packet->data))->name, 0); if(!((int)playah > -5 && (int)playah <= 0)) { ((connect_reply*)(connect_recv.data))->goodtogo = 1; ((connect_reply*)(connect_recv.data))->player_slot = playah->list_slot; DDrConsole_PrintF("Slot: %i", playah->list_slot); NetTCPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) - 256 + FLATLINE_HEADER); Sleep(100); //remove when we implement TCP. flatline_packet new_char = {0}; new_char.id = NEW_PLAYER; CharacterObject* Char = &(((new_player*)(new_char.data))->Character); memset(Char, 0, sizeof(CharacterObject)); Char->Header.Type = 'CHAR'; Char->OSD.Options = char_dontaim; for(j = 0; j < max_connections; j++) { if(PlayerList[j] != 0) { (*(new_player*)(void*)&new_char.data).Playernumber = j; sprintf(Char->OSD.Name,"%s",PlayerList[j]->name); sprintf(Char->OSD.Class, "%s", TMrInstance_GetInstanceName(PlayerList[j]->Chr->ONCC)); NetTCPServer_Send((sockaddr *) &sender, (char*)&new_char, sizeof(new_player) + FLATLINE_HEADER ); } } } else { //fix the error messages... DDrConsole_PrintF("Server is full. :("); ((connect_reply*)(connect_recv.data))->goodtogo = 0; sender.sin_addr.S_un.S_addr = htonl(sender.sin_addr.S_un.S_addr); memcpy(((connect_reply*)(connect_recv.data))->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; data[datalen] = 0; char message_buffer[512] = {0}; DDrConsole_PrintF("%s: %s", Players[i].name, packet->data); sprintf(message_buffer, "%s: %s", Players[i].name, packet->data); flatline_packet message; message.id = MESSAGE; int message_size = sprintf(message.data, "%s", message_buffer); COrMessage_Print(message_buffer, "chat", 0); UDPServer_SendToAll(&message, message_size + 1 + FLATLINE_HEADER); 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; 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); } 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; input_struct * packet_input = (input_struct*)(packet->data); PlayerList[i]->Actions1 = packet_input->Actions1; PlayerList[i]->Actions2 = packet_input->Actions2; PlayerList[i]->MouseDeltaX = packet_input->MouseDeltaX; PlayerList[i]->MouseDeltaY = packet_input->MouseDeltaY; break; default: DDrConsole_PrintF("Warning, recieved badly formed packet!"); break; } return true; } bool FLrServer_Run() { // Get the local hostname char szHostName[255]; gethostname(szHostName, 255); struct hostent *host_entry; host_entry=gethostbyname(szHostName); DDrConsole_PrintF("Server started at %s...", inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list)); return NetUDPServer_Listen(27777, FLrServer_PacketCallback); } 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. //TODO: Convert connection packet stuff to TCP int client_slot = 0; bool FLrClient_Run(flatline_packet* packet) { client_connected = 0; char data[1400]; uint16_t len; int j; //starts the connection DDrConsole_PrintF("Connecting to server %s on socket %i", inet_ntoa(address.sin_addr), client_sock); int 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(((connect_reply*)packet->data)->goodtogo){ client_connected = 1; client_slot = ((connect_reply*)packet->data)->player_slot; DDrConsole_PrintColored("Connection successful!",0,green, grey); //DDrConsole_PrintF("Slot %i", ((connect_reply*)packet)->player_slot); 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; } #define SPAM_INPUT #ifdef SPAM_INPUT struct timeval lasttime; gettimeofday(&lasttime, 0); struct timeval thistime; #endif while(1) { #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); //checks to see if enough time has passed since the last input update (by default once every 10ms) if( ((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)) ) { lasttime.tv_usec = ++thistime.tv_usec; //in case recieving packets takes less than 1 ms. flatline_packet input_packet; 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 if(NetUDPSocket_Recieve(client_sock, (sockaddr_storage *) &client_address, data, &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 CONNECT_SEND: ; flatline_packet connect_recv; memcpy(((connect_reply*)&(connect_recv.data))->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: ; uint32_t chr_index; DDrConsole_PrintF("%i | %i", ((new_player*)(packet->data))->Playernumber ,client_slot); if(((new_player*)(packet->data))->Playernumber == client_slot) { PlayerList[((new_player*)(packet->data))->Playernumber] = Players; Character* PC = (Character*)(((GameState*)ONgGameState)->PlayerCharacter); Players[0].Chr = PC; } else { ONrGameState_NewCharacter(&(((new_player*)(packet->data))->Character), NULL, NULL, &chr_index); PlayerList[((new_player*)(packet->data))->Playernumber] = &Players[chr_index]; Players[chr_index].Chr = &(((GameState*)ONgGameState)->CharacterStorage[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:; player_data * data = (void*)packet->data; uint16_t i = data->PlayerNum; //DDrConsole_PrintF("Got data for Player %i, %x", i, PlayerList[i]); if (!PlayerList[i] || i > max_connections) break; PlayerList[i]->Chr = ((GameState *)ONgGameState)->CharacterStorage; PlayerList[i]->Chr->Health = data->Health; PlayerList[i]->Chr->MaxHealth = data->MaxHealth; PlayerList[i]->Chr->Position = data->Position; PlayerList[i]->Chr->Location = data->Location; PlayerList[i]->Chr->LastPosition = data->LastPosition; PlayerList[i]->Chr->Facing = data->Facing; PlayerList[i]->Chr->DesiredFacing = data->DesiredFacing; PlayerList[i]->Chr->CosmeticFacing = data->CosmeticFacing; PlayerList[i]->Actions1 = data->Inputs.Actions1; PlayerList[i]->Actions2 = data->Inputs.Actions2; ActiveCharacter * Active = ((ActiveCharacter*)(ONrGetActiveCharacter(PlayerList[i]->Chr))); //needs special case for jumping\possibly falling characters Active->PhyContext_->Position = data->Position; //antilag, lol. if((int)*((char*)(Active + 0x1AF8) + 0x166) > data->Frame) *(uint16_t *)((char*)Active + 0x1C88) = data->Frame; break; default: DDrConsole_PrintF("Warning, recieved badly formed packet!"); break; } } else { Sleep(1); } } return true; } //UDPServer_SendToAll //Sends a packet to all the clients currently connected. //Returns the number of players sent to. int UDPServer_SendToAll(void* packet, int size) { int j; int players = 0; sockaddr_in address; memset(&address, 0, sizeof(sockaddr_in)); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_ANY); address.sin_port = htons(27777); for(j = 0; j < max_connections; j++) { if (PlayerList[j] != 0 && PlayerList[j]->ip != inet_addr("127.0.0.1")) { address.sin_addr.s_addr = htonl(PlayerList[j]->ip);//*((struct in_addr*)(int*)&(Players[j].ip)); int sent_bytes = NetUDPServer_Send((sockaddr *) &address, (char*)packet, size); if(sent_bytes == SOCKET_ERROR) NetCatchError(); else players++; } } return players; } player_info *FLr_FindEmptySlot() { int j; for(j = 0; j < MAX_PLAYERS; j++) { if (Players[j].ip == 0) { return &Players[j]; } } return 0; } extern uint16_t max_connections; uint16_t FLr_FindEmptyListSlot() { int j; for(j = 0; j < max_connections; j++) { if (PlayerList[j] == 0) { return j; } } return -1; } void * ONICALL FLrInput_Update_Keys(void) { #ifndef SPAM_INPUT if(client_connected) { flatline_packet input_packet; input_packet.id = PLAYER_INPUT; ((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; int sent_bytes = NetUDPSocket_Send(client_sock,(sockaddr *) &address, (char*)&input_packet, sizeof(input_struct) + FLATLINE_HEADER); return ONgGameState; } #endif if(!server_started) return ONgGameState; uint16_t i; for(i = 0; i < max_connections; i++) { if(!PlayerList[i]) continue; char * Active_Player = (void*)ONrGetActiveCharacter(PlayerList[i]->Chr); if(!Active_Player) return ONgGameState; GameInput * Active_Input = (void*)( Active_Player + 0x2158); flatline_packet data_out = {0}; data_out.id = PLAYER_DATA; 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->Location = PlayerList[i]->Chr->Location; data->LastPosition = PlayerList[i]->Chr->LastPosition; data->Facing = PlayerList[i]->Chr->Facing; data->DesiredFacing = PlayerList[i]->Chr->DesiredFacing; data->CosmeticFacing = PlayerList[i]->Chr->CosmeticFacing; data->Frame = *(Active_Player + 0x1C88); data->Inputs.Actions1 = PlayerList[i]->Actions1; data->Inputs.Actions2 = PlayerList[i]->Actions2; if(!server_started || i != 0 ) { 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->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; UDPServer_SendToAll(&data_out, sizeof(player_data) + FLATLINE_HEADER); } } return ONgGameState; }