#include "Flatline.h" #include "Flatline_Server.h" #include #include "PortForwardWrapper.h" #include "Mariusnet_Public.h" //I hereby apologize for the uglyness of the below code. //It was never intended to be "final" code, much less shared with anyone int total_players = 0; uint16_t max_connections = MAX_CONNECTIONS; player_info* FLrServer_AddPlayer(int ip, char* name, bool is_server, bool is_bot) { flatline_packet new_char = {0}; CharacterObject* Char; uint32_t player_slot = 0; int playerlist_slot = 0; if(is_server || total_players < max_connections) { int i = 0; int k = 0; //Skip for the host if(!is_server) { char* zero = strchr(name, 0); playerlist_slot = FLr_FindEmptyListSlot(); total_players++; //checks to see if a name exists or not //then appends [#] on the end of it if it does //May be buggy, come back to this. if(zero - name > 28) zero = name + 28; for(i = 0; i < max_connections; i++) { if(PlayerList[i] != 0 && !strcmp(name, PlayerList[i]->name)) { k++; sprintf(zero, "[%i]", k); i = 0; } } } new_char.new_player.Playernumber = playerlist_slot; //Set up a new Character structure to be spawned as the new player. //Can this code be surrounded with if(!is_server){}? Char = &new_char.new_player.Character; memset(Char, 0, sizeof(CharacterObject)); Char->Header.Type = 'CHAR'; sprintf(Char->OSD.Name,"%s",name); sprintf(Char->OSD.Class, "%s", "konoko_generic"); if(is_bot) { Char->OSD.MeleeID = 22; Char->OSD.JobID = 1; Char->OSD.MinimalAlertLevel = 4; Char->OSD.InvestigatingAlertLevel = 4; Char->OSD.InitialAlertLevel = 4; Char->OSD.StartJobAlertLevel = 4; } else if( !is_server ) { Char->Header.Position.X = PlayerList[0]->Chr->Position.X; Char->Header.Position.Y = PlayerList[0]->Chr->Position.Y; Char->Header.Position.Z = PlayerList[0]->Chr->Position.Z; } //TMrInstance_GetDataPtr('ONCC', "striker_easy_1", PlayerList[playerlist_slot]->Chr->ONCC); new_char.id = NEW_PLAYER; if(!is_server) { ONrGameState_NewCharacter(Char, NULL, NULL, &(player_slot)); //move this to a set up characters function... if(!is_bot) ONgGameState->CharacterStorage[player_slot].charType = 0; PlayerList[playerlist_slot] = Players+player_slot; PlayerList[playerlist_slot]->spawnnumber = player_slot; PlayerList[playerlist_slot]->Chr = &(ONgGameState->CharacterStorage)[player_slot]; //PlayerList[playerlist_slot]->Chr->Flags = chr_dontaim | chr_unkillable; //&= 0xFFBFFFFF; //WTF if(!is_bot) PlayerList[playerlist_slot]->Chr->Flags &= 0xFFBFFFFF; //WTF, magic number. sprintf_s(PlayerList[playerlist_slot]->Chr->Name, 32, "%s", name); sprintf_s(PlayerList[playerlist_slot]->name, 32, "%s", name); UDPServer_SendToAll( (char*)&new_char, sizeof(new_player) + FLATLINE_HEADER ); } else { PlayerList[0] = Players; PlayerList[0]->Chr = (Character *)(((GameState * )(ONgGameState))->CharacterStorage); } //add player to list PlayerList[playerlist_slot]->ip = ip; PlayerList[playerlist_slot]->list_slot = playerlist_slot; sprintf_s(PlayerList[playerlist_slot]->name, 32, "%s", name); MultiplayerStatus.PleaseUpdateAllPlayers = 1; return &Players[player_slot]; } return (player_info*)(-1); } void FLrServer_Initialize(){ FLrServer_AddPlayer(inet_addr("127.0.0.1"), "host", 1, 0); } //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 && (PlayerList[j]->ip != inet_addr("127.0.0.1"))) { int sent_bytes; address.sin_addr.s_addr = htonl(PlayerList[j]->ip);//*((struct in_addr*)(int*)&(Players[j].ip)); sent_bytes = NetUDPServer_Send((sockaddr *) &address, (char*)packet, size); if(sent_bytes == SOCKET_ERROR) NetCatchError(); else players++; } } return players; } //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. ;). //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 ) { int numArgs = FLrEvent_GetNumArgs( eventIndex ); int ret; flatline_packet eventPacket = {0}; eventPacket.id = FLATLINE_EVENT; eventPacket.flatline_event.event_index = eventIndex; ret = memcpy( eventPacket.flatline_event.intArray, args, sizeof(int) * numArgs ); ret = UDPServer_SendToAll( &eventPacket, sizeof(int) * (numArgs + 1) + FLATLINE_HEADER ); return 0; } void FLsPingAll() { flatline_packet ping; ping.id = PK_PING; lastPingTime = ping.ping = GetTickCount(); UDPServer_SendToAll(&ping, FLATLINE_HEADER + 4); } void FLsUpdateName( int index, char* name ) { flatline_packet message; int message_size; char message_buffer[1024]; sprintf(message_buffer,"%s changed their name to %s", PlayerList[index]->name, name); COrMessage_Print(message_buffer, "name_change", 0); sprintf_s(PlayerList[index]->name, 32, "%s", name); sprintf_s(PlayerList[index]->Chr->Name, 32, "%s", name); message.id = CHANGE_NAME; message.data[0] = index; message_size = sprintf(message.data + 1, "%s", name); UDPServer_SendToAll(&message, message_size + 2 + FLATLINE_HEADER); } void FLsSend_BINACHAR( short j, sockaddr* socket ) { ActiveCharacter* AC = ONrGetActiveCharacter( PlayerList[j]->Chr); flatline_packet new_char = {0}; CharacterObject* Char = &new_char.new_player.Character; new_char.id = NEW_PLAYER; new_char.new_player.Playernumber = j; // memset(Char, 0, sizeof(CharacterObject)); Char->Header.Type = 'CHAR'; Char->OSD.Options = chr_dontaim; sprintf(Char->OSD.Name,"%s",PlayerList[j]->name); sprintf(Char->OSD.Class, "%s", TMrInstance_GetInstanceName(PlayerList[j]->Chr->ONCC)); if(AC && AC->PhyContext) { Char->Header.Position = AC->PhyContext->Position; } else { Char->Header.Position.X = 0; Char->Header.Position.Y = 0; Char->Header.Position.Z = 0; } NetTCPServer_Send(socket, (char*)&new_char, sizeof(new_player) + FLATLINE_HEADER ); } bool FLrServer_PacketCallback(char* data, int datalen, int from) { int i, j; bool found_player = 0; 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 switch(packet->id) { flatline_packet connect_recv; player_info * playah; //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: ; 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)) { 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. NetUDPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetUDPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetUDPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetUDPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); NetUDPServer_Send((sockaddr *) &sender, (char*)&connect_recv, sizeof(connect_reply) + FLATLINE_HEADER); Sleep(100); for(j = 0; j < max_connections; j++) { if(PlayerList[j] != 0) { FLsSend_BINACHAR( j, (sockaddr *)&sender); } } } 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.")); } 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) break; 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 CHANGE_NAME: for(i = 0; i < MAX_PLAYERS; i++) { if(PlayerList[i] && PlayerList[i]->ip == sender.sin_addr.S_un.S_addr) { found_player = 1; break; } } if(found_player == 0) break; else { bool name_exists = 0; for(j = 0; j < MAX_PLAYERS; j++) { if(PlayerList[j] && !strcmp(packet->data, PlayerList[j]->name)) { name_exists = 1; break; } } if(!name_exists) { FLsUpdateName( i, packet->data ); } 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) break; else { input_struct * packet_input = &packet->input_struct; 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]->FacingFromClient = packet_input->DesiredFacing; //PlayerList[i]->LastInputTime = packet_input->Time; 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; } } if(found_player == 0) break; if(packet->ping != lastPingTime) { PlayerList[i]->Ping = 999; } else { PlayerList[i]->Ping = GetTickCount() - packet->ping; } break; case PK_MISSING_PLAYER: if(packet->integer < MAX_PLAYERS) { FLsSend_BINACHAR( packet->integer, &sender); } break; default: DDrConsole_PrintF("Warning, recieved badly formed packet!"); break; } return true; } bool FLrServer_Run() { m_announcegame Game; HRESULT ret; PortMappingContainer_C PMC = { "", "27777", "27777", "UDP", "", "", "Flatline!" }; // Get the local hostname char szHostName[255]; struct hostent *host_entry; gethostname(szHostName, 255); host_entry=gethostbyname(szHostName); strcpy( PMC.InternalClient, inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list) ); ret = uPnP_Forward( &PMC ); if(!ret) { DDrConsole_Print( "Port Forwarded" ); } else { LPSTR Message; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, &ret,0,0,&Message,0,NULL); DDrConsole_Print( Message ); } DDrConsole_PrintF("Server started at %s...", inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list)); Game.port = htons(27777); sprintf_s(Game.g.Buffer, 128, "%s's Game", MariusLogin); MSNet_CreateGame( &Game ); return NetUDPServer_Listen(27777, FLrServer_PacketCallback); }