/*============================================================================= Name : titannet.c Purpose : All of the logic for the titan game interface stuff. Created 6/23/1998 by ddunlop Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include "titannet.h" #include "types.h" #include "debug.h" #include "statscript.h" #include "TitanInterfaceC.h" #include "CommandNetwork.h" #include "multiplayergame.h" #include "multiplayerlangame.h" #include "utility.h" #include "teams.h" #include "scenpick.h" #include "colpick.h" #include "Captaincy.h" #include "color.h" #include "file.h" #include "titan.h" #define DEBUG_GAME_BW /*============================================================================= Data: =============================================================================*/ unsigned long TitanActive = FALSE; unsigned long TitanReadyToShutdown = FALSE; TPChannelList tpChannelList; TPServerList tpServerList; CaptainGameInfo tpGameCreated; wchar_t CurrentChannel[MAX_CHANNEL_NAME_LEN] = L""; wchar_t CurrentChannelDescription[MAX_CHANNEL_DESCRIPTION_LEN] = L""; unsigned long myIP; unsigned long myPort; int ChannelProtectedFlag = 0; wchar_t ChannelPassword[MAX_PASSWORD_LEN] = L""; wchar_t RemoveGameRequest[MAX_TITAN_GAME_NAME_LEN] = L""; long CONNECT_TIMEOUT = 8000; #define VALIDVERSIONS_MAXLEN 2000 bool HaveValidVersions = FALSE; char ValidVersions[VALIDVERSIONS_MAXLEN] = ""; /*============================================================================= Tweakables: =============================================================================*/ real32 TITAN_PICKER_REFRESH_TIME = 1.0f; unsigned short TITAN_GAME_EXPIRE_TIME = 3600; unsigned long TITAN_CHANNEL_EXPIRE_TIME = 300; unsigned long DIRSERVER_NUM = 1; unsigned long AUTHSERVER_NUM = 0; // get from dirserver now unsigned long PATCHSERVER_NUM = 1; unsigned long DIRSERVER_PORTS[MAX_PORTS]; unsigned long AUTHSERVER_PORTS[MAX_PORTS]; unsigned long PATCHSERVER_PORTS[MAX_PORTS]; ipString AUTHSERVER_IPSTRINGS[MAX_IPS]; ipString DIRSERVER_IPSTRINGS[MAX_IPS]; ipString PATCHSERVER_IPSTRINGS[MAX_IPS]; unsigned long GAME_PORT = 2500; unsigned long AD_PORT = 2501; char PATCHNAME[50] = "HomeworldPatch.exe"; char ROUTING_SERVER_NAME[30] = "routingserv"; real32 LAN_ADVERTISE_USER_TIME = 1.0f; real32 LAN_ADVERTISE_USER_TIMEOUT = 5.0f; real32 LAN_ADVERTISE_GAME_TIME = 1.0f; real32 LAN_ADVERTISE_GAME_TIMEOUT = 5.0f; real32 KEEPALIVE_SEND_IAMALIVE_TIME = 10.0f; real32 KEEPALIVE_IAMALIVE_TIMEOUT = 25.0f; real32 KEEPALIVE_SEND_ALIVESTATUS_TIME = 30.0f; color PATCHBARCOLOR = colRGB(255, 0, 0); color PATCHBAROUTLINECOLOR = colWhite; udword PRINTLAG_IFGREATERTHAN = 10; udword PRINTLAG_MINFRAMES = 20; udword ROOM_MIN_THRESHOLD = 1; udword ROOM_MAX_THRESHOLD = 50; unsigned long WAIT_SHUTDOWN_MS = 1000; void scriptSetIPStrings(char *directory,char *field,void *dataToFillIn); void scriptSetPortNumbers(char *directory,char *field,void *dataToFillIn); extern sdword TimedOutWaitingForPauseAcksGiveUpAfterNumTimes; extern real32 HorseRacePlayerDropoutTime; extern color HorseRaceDropoutColor; scriptEntry NetTweaks[] = { makeEntry(PATCHBARCOLOR,scriptSetRGBCB), makeEntry(PATCHBAROUTLINECOLOR,scriptSetRGBCB), makeEntry(TITAN_PICKER_REFRESH_TIME,scriptSetReal32CB), makeEntry(TITAN_GAME_EXPIRE_TIME,scriptSetUwordCB), makeEntry(TITAN_CHANNEL_EXPIRE_TIME,scriptSetUdwordCB), makeEntry(DIRSERVER_NUM, scriptSetUdwordCB), makeEntry(PATCHSERVER_NUM, scriptSetUdwordCB), makeEntry(DIRSERVER_PORTS,scriptSetPortNumbers), makeEntry(PATCHSERVER_PORTS,scriptSetPortNumbers), makeEntry(DIRSERVER_IPSTRINGS,scriptSetIPStrings), makeEntry(PATCHSERVER_IPSTRINGS,scriptSetIPStrings), makeEntry(GAME_PORT,scriptSetUdwordCB), makeEntry(T1_Timeout,scriptSetReal32CB), makeEntry(T2_Timeout,scriptSetReal32CB), makeEntry(TWAITFORPAUSEACKS_Timeout,scriptSetReal32CB), makeEntry(TimedOutWaitingForPauseAcksGiveUpAfterNumTimes,scriptSetSdwordCB), makeEntry(HorseRacePlayerDropoutTime,scriptSetReal32CB), makeEntry(HorseRaceDropoutColor,scriptSetRGBCB), makeEntry(ROUTING_SERVER_NAME,scriptSetStringCB), makeEntry(PATCHNAME,scriptSetStringCB), makeEntry(LAN_ADVERTISE_USER_TIME,scriptSetReal32CB), makeEntry(LAN_ADVERTISE_USER_TIMEOUT,scriptSetReal32CB), makeEntry(LAN_ADVERTISE_GAME_TIME,scriptSetReal32CB), makeEntry(LAN_ADVERTISE_GAME_TIMEOUT,scriptSetReal32CB), makeEntry(AD_PORT,scriptSetUdwordCB), makeEntry(CONNECT_TIMEOUT,scriptSetSdwordCB), makeEntry(KEEPALIVE_SEND_IAMALIVE_TIME,scriptSetReal32CB), makeEntry(KEEPALIVE_IAMALIVE_TIMEOUT,scriptSetReal32CB), makeEntry(KEEPALIVE_SEND_ALIVESTATUS_TIME,scriptSetReal32CB), makeEntry(PRINTLAG_MINFRAMES,scriptSetUdwordCB), makeEntry(PRINTLAG_IFGREATERTHAN,scriptSetUdwordCB), makeEntry(ROOM_MIN_THRESHOLD,scriptSetUdwordCB), makeEntry(ROOM_MAX_THRESHOLD,scriptSetUdwordCB), makeEntry(WAIT_SHUTDOWN_MS,scriptSetUdwordCB), endEntry }; /*============================================================================= Functions: =============================================================================*/ void scriptSetPortNumbers(char *directory,char *field,void *dataToFillIn) { char *param; sdword i; udword *ptr = (udword *)dataToFillIn; for (i=0;i=tpGameCreated.numPlayers) { tpGameCreated.numPlayers--; } else { tpGameCreated.numPlayers--; for (j=i;j=tpGameCreated.numPlayers) { tpGameCreated.numPlayers--; } else { tpGameCreated.numPlayers--; for (j=i;jstringdata,tpGameCreated.Password); passwordnamelen = wcslen(tpGameCreated.Password) + 1; } else { wcscpy(buildDirectoryCustomInfo->stringdata,L""); passwordnamelen = wcslen(L"") + 1; } dbgAssert(passwordnamelen <= MAX_PASSWORD_LEN); mbstowcs(buildDirectoryCustomInfo->stringdata + passwordnamelen, tpGameCreated.DisplayMapName, mapnamelen); buildDirectoryCustomInfo->stringdatalength = (mapnamelen + passwordnamelen) * 2; dbgAssert(tpGameCreated.numPlayers > 0); buildDirectoryCustomInfo->userBehindFirewall = 0; for(n=0; nuserBehindFirewall = 1; break; } } tpGameCreated.userBehindFirewall = buildDirectoryCustomInfo->userBehindFirewall; buildDirectoryCustomInfo->numPlayers = tpGameCreated.numPlayers; buildDirectoryCustomInfo->flag = tpGameCreated.flag; buildDirectoryCustomInfo->captainAddress = myAddress; buildDirectoryCustomInfo->pingAddress = titanGetMyPingAddress(); memcpy(buildDirectoryCustomInfo->sessionKey,titanGetGameKey(),GAMEKEY_SIZE); memcpy(buildDirectoryCustomInfo->versionInfo,networkVersion,MAX_NETWORKVERSION_STRING_LEN); } signed long titanRequestReceivedCB(Address *address,const void *blob,unsigned short bloblen) { sdword i; DirectoryCustomInfoMax buildDirectoryCustomInfo; const PlayerJoinInfo* pInfo; if (AddressesAreEqual(*address,myAddress)) { return REQUEST_RECV_CB_JUSTDENY; // can't join your own game } // reject if got multiple join requests by the same person for (i=0;i= MAX_MULTIPLAYER_PLAYERS) || (tpGameCreated.flag & GAME_IN_PROGRESS)) { return REQUEST_RECV_CB_DENYANDCLOSE; } if ((mgPlayerLimit) && (tpGameCreated.numPlayers >= mgPlayerLimit)) { return REQUEST_RECV_CB_DENYANDCLOSE; } if (tpGameCreated.numPlayers + tpGameCreated.numComputers >= spScenarios[spCurrentSelected].maxplayers) { if (tpGameCreated.numPlayers >= spScenarios[spCurrentSelected].maxplayers) { return REQUEST_RECV_CB_DENYANDCLOSE; // too many people for this map } else { // let's bump computers out for humans to join tpGameCreated.numComputers = spScenarios[spCurrentSelected].maxplayers - tpGameCreated.numPlayers - 1; dbgAssert(tpGameCreated.numComputers >= 0); dbgAssert(tpGameCreated.numPlayers + tpGameCreated.numComputers < spScenarios[spCurrentSelected].maxplayers); } } pInfo = (PlayerJoinInfo*)blob; if (mgIsUserBanned((char *)pInfo->PersonalName)) { return REQUEST_RECV_CB_JUSTDENY; } // update directory server dbgAssert(bloblen == sizeof(PlayerJoinInfo)); tpGameCreated.playerInfo[tpGameCreated.numPlayers].address = *address; tpGameCreated.playerInfo[tpGameCreated.numPlayers].playerIndex = tpGameCreated.numPlayers; tpGameCreated.playerInfo[tpGameCreated.numPlayers].colorsPicked = pInfo->colorsPicked; if (!pInfo->colorsPicked) { tpGameCreated.playerInfo[tpGameCreated.numPlayers].baseColor = teColorSchemes[tpGameCreated.numPlayers].textureColor.base; tpGameCreated.playerInfo[tpGameCreated.numPlayers].stripeColor = teColorSchemes[tpGameCreated.numPlayers].textureColor.detail; } else { tpGameCreated.playerInfo[tpGameCreated.numPlayers].baseColor = pInfo->baseColor; tpGameCreated.playerInfo[tpGameCreated.numPlayers].stripeColor = pInfo->stripeColor; } tpGameCreated.playerInfo[tpGameCreated.numPlayers].race = pInfo->race; tpGameCreated.playerInfo[tpGameCreated.numPlayers].behindFirewall = pInfo->behindFirewall; strcpy(tpGameCreated.playerInfo[tpGameCreated.numPlayers].PersonalName, pInfo->PersonalName); tpGameCreated.numPlayers++; if (!LANGame) { generateDirectoryCustomInfo(&buildDirectoryCustomInfo); titanReplaceGameInfo(tpGameCreated.Name,(DirectoryCustomInfo *)&buildDirectoryCustomInfo, FALSE); mgUpdateGameInfo(); } else { generateDirectoryCustomInfo(&lgMyGameInfo.directoryCustomInfo); wcscpy(lgMyGameInfo.Name,tpGameCreated.Name); lgUpdateGameInfo(); } return REQUEST_RECV_CB_ACCEPT; } void titanGameMsgReceivedCB(const void *blob,unsigned short bloblen) { ReceivedPacketCB((ubyte *)blob,(udword)bloblen); } void titanSendBroadcastMessage(ubyte *packet,udword sizeofPacket) { #ifdef DEBUG_GAME_BW titanDebug("bw: broadcast gamepkt %x size %d",((HWPacketHeader *)packet)->type,sizeofPacket); #endif titanBroadcastPacket(TITANMSGTYPE_GAME,packet,(uword)sizeofPacket); // Fix later for non-captain broadcasting stuff } void titanSendPointMessage(int playerIndex,ubyte *packet,udword sizeofPacket) { #ifdef DEBUG_GAME_BW titanDebug("bw: pointmsg gamepkt %x size %d",((HWPacketHeader *)packet)->type,sizeofPacket); #endif titanSendPacketTo(&tpGameCreated.playerInfo[playerIndex].address,TITANMSGTYPE_GAME,packet,(uword)sizeofPacket); } void titanAnyoneSendBroadcastMessage(ubyte *packet,udword sizeofPacket) { #ifdef DEBUG_GAME_BW titanDebug("bw: broadcastany gamepkt %x size %d",((HWPacketHeader *)packet)->type,sizeofPacket); #endif titanAnyoneBroadcastPacket(TITANMSGTYPE_GAME,packet,(uword)sizeofPacket); // Fix later for non-captain broadcasting stuff } void titanAnyoneSendPointMessage(int playerIndex,ubyte *packet,udword sizeofPacket) { #ifdef DEBUG_GAME_BW titanDebug("bw: pointmsgany gamepkt %x size %d",((HWPacketHeader *)packet)->type,sizeofPacket); #endif titanAnyoneSendPacketTo(&tpGameCreated.playerInfo[playerIndex].address,TITANMSGTYPE_GAME,packet,(uword)sizeofPacket); } void captainGameStartCB(void) { sigsPlayerIndex = 0; sigsNumPlayers = tpGameCreated.numPlayers; sigsPressedStartGame = TRUE; if (LANGame) lgShutdownMultiPlayerGameScreens(); else mgShutdownMultiPlayerGameScreens(); } void titanUpdatePlayer(bool captain) { PlayerJoinInfo pInfo; if (captain) { tpGameCreated.playerInfo[0].baseColor = utyBaseColor; tpGameCreated.playerInfo[0].stripeColor = utyStripeColor; tpGameCreated.playerInfo[0].colorsPicked = cpColorsPicked; tpGameCreated.playerInfo[0].race = whichRaceSelected; titanBroadcastPacket(TITANMSGTYPE_UPDATEGAMEDATA, &tpGameCreated, sizeof(tpGameCreated)); if (LANGame) lgUpdateGameInfo(); else mgUpdateGameInfo(); } else { pInfo.baseColor = utyBaseColor; pInfo.stripeColor = utyStripeColor; pInfo.colorsPicked = cpColorsPicked; pInfo.race = whichRaceSelected; titanSendPacketTo(&tpGameCreated.playerInfo[0].address,TITANMSGTYPE_UPDATEPLAYER,&pInfo,sizeof(pInfo)); } } void titanUpdatePlayerCB(Address *address, const void *blob, unsigned short bloblen) { udword i; PlayerJoinInfo *pinfo=(PlayerJoinInfo *)blob; dbgAssert(bloblen == sizeof(PlayerJoinInfo)); for (i=0;ibaseColor; tpGameCreated.playerInfo[i].stripeColor = pinfo->stripeColor; tpGameCreated.playerInfo[i].colorsPicked = pinfo->colorsPicked; tpGameCreated.playerInfo[i].race = pinfo->race; titanBroadcastPacket(TITANMSGTYPE_UPDATEGAMEDATA, &tpGameCreated, sizeof(tpGameCreated)); if (LANGame) lgUpdateGameInfo(); else mgUpdateGameInfo(); } } } void PrintAddressToString(char *buffer,Address *address) { if (!IPGame) { sprintf(buffer,"(Ether:%x,%x,%x,%x,%x,%x Port:%x)",address->AddrPart.etherAddr[0],address->AddrPart.etherAddr[1], address->AddrPart.etherAddr[2],address->AddrPart.etherAddr[3],address->AddrPart.etherAddr[4],address->AddrPart.etherAddr[5], address->Port); } else { sprintf(buffer,"(IP:%x Port:%d)",address->AddrPart.IP,address->Port); } } int titanLoadPublicKey(char *filename,unsigned char** buffer) { sdword fileLength = fileSizeGet(filename, 0); (*buffer) = (unsigned char*)malloc(fileLength); return fileLoad(filename, *buffer, 0); } void titanResetValidVersions() { HaveValidVersions = FALSE; ValidVersions[0] = 0; } /*----------------------------------------------------------------------------- Name : titanGotValidVersionStrings Description : callback for when titan gets valid version strings (one string, multiple version strings seperated by tabs) Inputs : validversions Outputs : Return : ----------------------------------------------------------------------------*/ void titanGotValidVersionStrings(char *vversions) { strcpy(ValidVersions,vversions); HaveValidVersions = TRUE; } bool VersionFoundInValidVersions(char *myversion) { char copyValidVersions[VALIDVERSIONS_MAXLEN]; char *strtokptr; char *ptr; strcpy(copyValidVersions,ValidVersions); // have to make a copy since strtok converts delimiters to NULLs strtokptr = copyValidVersions; for (;;) { ptr = strtok(strtokptr, "\r\n"); // only use "\n", "\t" is contained in the version strings to sepearte language, etc. strtokptr = NULL; if (!ptr) return FALSE; if (stricmp(ptr,myversion) == 0) { return TRUE; } } return FALSE; } bool titanCheckValidVersion(char *myversion) { if (ShortCircuitWON) return(TRUE); if (!HaveValidVersions) { return TRUE; // assume we have valid version if we don't have any information yet } if (VersionFoundInValidVersions(myversion)) { return TRUE; } return FALSE; } bool CheckNetworkVersionCompatibility(char *netversion) { if (stricmp(netversion,networkVersion) == 0) return TRUE; else return FALSE; } #if 0 void titanCDKeyNotFoundCB(void) { mgDisplayMessage(strGetString(strNoCDKey)); return; } void titanInvalidCDKeyCB(void) { mgDisplayMessage(strGetString(strLightweightBadKey)); return; } #endif