905 lines
29 KiB
C++
905 lines
29 KiB
C++
#include <AmbrosiaTools/reggie.h>
|
|
#include <AmbrosiaTools/network_tool.h>
|
|
#include <AmbrosiaTools/platform.h>
|
|
#include <AmbrosiaTools/lsockets.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "tracker.h"
|
|
#include "gameinitexit.h"
|
|
#include "gametime.h"
|
|
#include "carphysics.h"
|
|
#include "config.h"
|
|
#include "text.h"
|
|
#include "gameframe.h"
|
|
#include "error.h"
|
|
#include "initexit.h"
|
|
#include "network.h"
|
|
#include "interfaceutil.h"
|
|
#include "gamesystem.h"
|
|
#include "screen.h"
|
|
|
|
ReggieRef gReggieRef=NULL;
|
|
int gReggieConnected=false;
|
|
int gReggieSearching=false;
|
|
int gReggieLastUpdateGInfoVersion;
|
|
int gHasCheckedLonelyServer;
|
|
int gReggiePortMapped=false;
|
|
int gReggieCounting=false;
|
|
float gLastQuery=-1000;
|
|
float gConnectionTime;
|
|
float gReportedIdle=false;
|
|
char gMOTD[1024];
|
|
|
|
extern NT_SessionRef gSessionRef;
|
|
extern NetworkDatagramRef NT_GetSessionEndpoint(NT_SessionRef ref);
|
|
|
|
#define kReggieUpdateInterval 1
|
|
|
|
int CouldMyNATCauseMyServerToBeLonely() {
|
|
NetworkAddress local;
|
|
DatagramGetAddress(NT_GetSessionEndpoint(gSessionRef),&local);
|
|
ReggieNetworkType network = ReggieProbeCheck(gReggieRef,false,&local,nil);
|
|
return((network != kReggieNetworkOffline) && (network <=kReggieNetworkProtective) ? true : false);
|
|
}
|
|
|
|
#define kMessageInputBufferSize 8
|
|
#define kMaxMessageSize 1024
|
|
char gMessageInputBuffer[kMessageInputBufferSize][kMaxMessageSize];
|
|
int gMessageInputBufferPos=0;
|
|
int gCheckingVersion=false;
|
|
char *gRedlineURL=NULL;
|
|
char *gAutoUpdateURL=NULL;
|
|
|
|
void TrackerStartVersionCheck()
|
|
{
|
|
if(NetworkStackGetActive(eNetworkStackTCPIP))
|
|
{
|
|
ReggieVersionBegin(nil,"REDLINE");
|
|
gCheckingVersion = true;
|
|
}
|
|
}
|
|
|
|
int TrackerVersionCheck(char **newVersion)
|
|
{
|
|
if(gCheckingVersion)
|
|
{
|
|
HashRef hashRef=ReggieVersionCheck(nil,"REDLINE");
|
|
if(hashRef)
|
|
{
|
|
if(gConfig->useBetaBuilds)
|
|
{
|
|
gRedlineURL=HashLookup(hashRef, "$BETAURL", nil);
|
|
gAutoUpdateURL=HashLookup(hashRef, "$BETAAUTOUPDATEURL", nil);
|
|
Char8 *hashLookupResult;
|
|
int versionNum=0;
|
|
if(hashLookupResult=HashLookup(hashRef, "$BETAVERSIONNUM", nil))
|
|
sscanf(hashLookupResult,"%d",&versionNum);
|
|
if(*newVersion=HashLookup(hashRef, "$BETAVERSION", nil))
|
|
{
|
|
gCheckingVersion = false; /* Don't check again */
|
|
if(versionNum)
|
|
return versionNum>kVersion;
|
|
else
|
|
return _stricmp(*newVersion,kVersionString);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gRedlineURL=HashLookup(hashRef, "$URL", nil);
|
|
gAutoUpdateURL=HashLookup(hashRef, "$AUTOUPDATEURL", nil);
|
|
Char8 *hashLookupResult;
|
|
int versionNum=0;
|
|
if(hashLookupResult=HashLookup(hashRef, "$VERSIONNUM", nil))
|
|
sscanf(hashLookupResult,"%d",&versionNum);
|
|
if(*newVersion=HashLookup(hashRef, "$VERSION", nil))
|
|
{
|
|
gCheckingVersion = false; /* Don't check again */
|
|
if(versionNum)
|
|
return versionNum>kVersion;
|
|
else
|
|
return _stricmp(*newVersion,kVersionString);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int TrackerConnect()
|
|
{
|
|
gStartIdleTime=TimeGetSeconds();
|
|
if(!gSessionRef)
|
|
NetworkPreSession();
|
|
if(!ReggieCreateShared(&gReggieRef,NULL,NULL,NT_GetSessionEndpoint(gSessionRef),NULL,"redline",gConfig->playerName,""))
|
|
{
|
|
gReggieLastUpdateGInfoVersion=-1;
|
|
gHasCheckedLonelyServer=false;
|
|
gConnectionTime=0;
|
|
gReggiePortMapped=false;
|
|
gReggieConnected=true;
|
|
gReggieSearching=false;
|
|
gReggieCounting=false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int ValidateUpdateURL()
|
|
{
|
|
if(!gAutoUpdateURL)
|
|
return false;
|
|
char *pos=strstr(gAutoUpdateURL,"://");
|
|
if(!pos)return false;
|
|
pos+=3;
|
|
char *dash=strstr(pos,"/");
|
|
if(!dash)return false;
|
|
char validurl[]=".ambrosiasw.com";
|
|
char test[256];
|
|
memcpy(test,dash-strlen(validurl),strlen(validurl));
|
|
test[strlen(validurl)]='\0';
|
|
if(_stricmp(test,validurl)) {printf("update URL invaild\n");return false;}
|
|
return true;
|
|
}
|
|
|
|
void TrackerGetNewVersion()
|
|
{
|
|
if(ValidateUpdateURL())
|
|
{
|
|
if(!ScreenNoWindow())
|
|
{
|
|
if(gConfig->fullscreen)
|
|
{
|
|
gConfig->fullscreen=false;
|
|
ScreenReInit();
|
|
gConfig->fullscreen=true;
|
|
}
|
|
InterfaceDrawStrings("Trying automatic update","Please wait a moment...",-1);
|
|
char updateURL[1024];
|
|
char failStr[1024]="";
|
|
sprintf(updateURL,"%s%s",gAutoUpdateURL,kVersionString);
|
|
if(AutoUpdateRedline(updateURL,failStr))
|
|
// if(AutoUpdateRedline(gAutoUpdateURL))
|
|
{
|
|
InterfaceDisplayMessage(-1,"Update successful!","You will have to relaunch Redline now.");
|
|
return;
|
|
}
|
|
else
|
|
InterfaceDisplayMessage(-1,"Automatic update failed.",failStr);
|
|
}
|
|
}
|
|
if(gRedlineURL)
|
|
{
|
|
CFStringRef str=CFStringCreateWithCString(kCFAllocatorDefault,gRedlineURL, kCFStringEncodingASCII);
|
|
CFURLRef url=CFURLCreateWithString(kCFAllocatorDefault,str,NULL);
|
|
//LSOpenCFURLRef(url,NULL);
|
|
LSLaunchURLSpec inLaunchSpec;
|
|
inLaunchSpec.appURL=NULL;
|
|
inLaunchSpec.itemURLs=CFArrayCreate(kCFAllocatorDefault,(const void**)&url,1,NULL);
|
|
inLaunchSpec.passThruParams=NULL;
|
|
inLaunchSpec.launchFlags=kLSLaunchNoParams;
|
|
inLaunchSpec.asyncRefCon=NULL;
|
|
LSOpenFromURLSpec(&inLaunchSpec,NULL);
|
|
}
|
|
else
|
|
{
|
|
CFURLRef url=CFURLCreateWithString(kCFAllocatorDefault,CFSTR("http://www.AmbrosiaSW.com/"),NULL);
|
|
//LSOpenCFURLRef(url,NULL);
|
|
LSLaunchURLSpec inLaunchSpec;
|
|
inLaunchSpec.appURL=NULL;
|
|
inLaunchSpec.itemURLs=CFArrayCreate(kCFAllocatorDefault,(const void**)&url,1,NULL);
|
|
inLaunchSpec.passThruParams=NULL;
|
|
inLaunchSpec.launchFlags=kLSLaunchNoParams;
|
|
inLaunchSpec.asyncRefCon=NULL;
|
|
LSOpenFromURLSpec(&inLaunchSpec,NULL);
|
|
}
|
|
}
|
|
|
|
enum{
|
|
kReggieAdvGameChannel=1,
|
|
kReggieSearchGameChannel,
|
|
kReggieSearchPlayersChannel=4,
|
|
kReggiePortMapChannel,
|
|
kReggieInsertRecordChannel,
|
|
kReggieRegistryChannel,
|
|
kReggieRecordChannel
|
|
};
|
|
|
|
void TrackerMessageSend(char *message)
|
|
{
|
|
if(gReggieConnected)
|
|
{
|
|
HashRef hashRef = HashCreate(kHashFlagReggieKeys);
|
|
HashAppend(hashRef, "$KIND", "REDLINE");
|
|
HashAppend(hashRef, "$MESSAGE", message);
|
|
|
|
ReggieMessageSend(gReggieRef,nil,hashRef);
|
|
HashDispose(hashRef);
|
|
if(gMessageInputBufferPos<kMessageInputBufferSize)
|
|
strcpy(gMessageInputBuffer[gMessageInputBufferPos++],message);
|
|
}
|
|
}
|
|
|
|
int TrackerMessageReceive(tChatMessage *msg)
|
|
{
|
|
static char motd[1024]="";
|
|
static char lastMessage[1024]="";
|
|
|
|
if(gReggieConnected)
|
|
{
|
|
if(strcmp(motd,gMOTD))
|
|
{
|
|
strcpy(motd,gMOTD);
|
|
sprintf(msg->str,"### %s",motd);
|
|
msg->flags=kChatFlagSystem|kChatFlagSilent;
|
|
return true;
|
|
}
|
|
HashRef hash=ReggieMessageCheck(gReggieRef);
|
|
if(hash)
|
|
{
|
|
char *hashResult=nil;
|
|
do{
|
|
hashResult=HashLookup(hash,"$MESSAGE",hashResult);
|
|
if(hashResult)
|
|
if(gMessageInputBufferPos<kMessageInputBufferSize&&strlen(hashResult)<kMaxMessageSize)
|
|
{
|
|
int dupe=false;
|
|
for(int i=0;i<gMessageInputBufferPos;i++)
|
|
if(strcmp(gMessageInputBuffer[i],hashResult)==0)
|
|
dupe=true;
|
|
if(!dupe)
|
|
strcpy(gMessageInputBuffer[gMessageInputBufferPos++],hashResult);
|
|
}
|
|
}while(hashResult);
|
|
}
|
|
if(gMessageInputBufferPos)
|
|
{
|
|
strcpy(msg->str,gMessageInputBuffer[--gMessageInputBufferPos]);
|
|
msg->flags=0;
|
|
if(strcmp(lastMessage,msg->str))
|
|
{
|
|
strcpy(lastMessage,msg->str);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void NetworkAdvertiseIdle(tGameInfo *gInfo,int *showLonelyMessage,int locked,int forceUpdate)
|
|
{
|
|
if(showLonelyMessage)
|
|
*showLonelyMessage=false;
|
|
if(gReggieConnected)
|
|
{
|
|
UInt32 state=ReggieGetStatus(gReggieRef,gMOTD,NULL);
|
|
if(state==kReggieStateOnline)
|
|
{
|
|
if(gConnectionTime==0)
|
|
gConnectionTime=TimeGetSeconds();
|
|
if((gReggieLastUpdateGInfoVersion!=gInfo->version||forceUpdate)&&gConfig->trackerEnable)
|
|
{
|
|
char hashString[1024];
|
|
if(gInfo->map==kFileErr)
|
|
return;
|
|
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(gInfo->map,kParserTypeMapInfoDesc,sizeof(tMapInfo));
|
|
while(char *ch=strchr(gConfig->gameName,'\''))
|
|
*ch='`';
|
|
sprintf(hashString,"$REDLINE$HOSTING=1 $REDLINE$PASSWORD='%d' $REDLINE$NUMPLAYERS=%d $REDLINE$NUMNETPLAYERS=%d $REDLINE$MAXPLAYERS=%d $REDLINE$ARCADE=%d $REDLINE$LOCKED=%d $REDLINE$ONLYREGISTERED=%d $REDLINE$LAPS=%d",strlen(gConfig->password)?1:0,gInfo->numPlayers,gInfo->numNetPlayers,gConfig->maxPlayers,gInfo->arcade,locked,gConfig->onlyRegisteredPlayers,gInfo->numLaps);
|
|
HashRef hashRef = HashInitialize(kHashFlagReggieKeys,hashString);
|
|
HashAppend(hashRef, "$MESSAGE", gConfig->gameName);
|
|
HashAppend(hashRef, "$REDLINE$MAP", mapInfo->name);
|
|
HashAppend(hashRef, "$REDLINE$MAPFILE",FileGetName(gInfo->map));
|
|
|
|
for(int i=0;i<gInfo->numPlayers;i++)
|
|
{
|
|
NT_MemberInfo memberInfo;
|
|
char key[256];
|
|
sprintf(key,"$REDLINE$PLAYER%dNAME",i);
|
|
HashAppend(hashRef, key, gInfo->playerNames[i]);
|
|
if(gInfo->playerCars[i]!=-1)
|
|
{
|
|
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(gInfo->playerCars[i],kParserTypeCarDesc,sizeof(tCarDefinition));
|
|
sprintf(key,"$REDLINE$PLAYER%dCAR",i);
|
|
HashAppend(hashRef, key, car->carName);
|
|
}
|
|
if(i>0&&i<gInfo->numNetPlayers)
|
|
{
|
|
if(NT_GetMemberInfo(gSessionRef,gInfo->netID[i],&memberInfo))
|
|
{
|
|
char address[256];
|
|
AddressTranscribe(&memberInfo.address,address);
|
|
sprintf(key,"$ADDRESS$PLAYER%d",i);
|
|
HashAppend(hashRef, key, address);
|
|
}
|
|
}
|
|
else if(i==0)
|
|
{
|
|
NetworkAddress local,publicAdd;
|
|
char address[256];
|
|
DatagramGetAddress(NT_GetSessionEndpoint(gSessionRef),&local);
|
|
ReggieProbeCheck(gReggieRef,false,&local,&publicAdd);
|
|
if(!AddressIsEmpty(&publicAdd))
|
|
{
|
|
AddressTranscribe(&publicAdd,address);
|
|
HashAppend(hashRef, "$ADDRESS$PLAYER0", address);
|
|
}
|
|
}
|
|
}
|
|
|
|
ReggieInsertBegin(gReggieRef,kReggieAdvGameChannel, kReggieRecordAdvertise ,hashRef);/* Makes own copy of hash */
|
|
HashDispose(hashRef); /* Not needed any more */
|
|
gReggieLastUpdateGInfoVersion=gInfo->version;
|
|
}
|
|
if(!gHasCheckedLonelyServer)
|
|
if(TimeGetSeconds()>gConnectionTime+3)
|
|
if(showLonelyMessage)
|
|
{
|
|
*showLonelyMessage=CouldMyNATCauseMyServerToBeLonely();
|
|
//printf("CouldMyNATCauseMyServerToBeLonely sez %d\n",*showLonelyMessage);
|
|
gHasCheckedLonelyServer=true;
|
|
}
|
|
if(!gReggiePortMapped)
|
|
if(TimeGetSeconds()>gConnectionTime+1)
|
|
{
|
|
NetworkAddress local;
|
|
UInt16 localPort;
|
|
DatagramGetAddress(NT_GetSessionEndpoint(gSessionRef),&local);
|
|
AddressDecomposeTCPIP(&local,&localPort,nil);
|
|
U16Swap(localPort);
|
|
//printf("PORTMAP: %d\n",ReggiePortmapStatus(gReggieRef, nil, nil, &local));
|
|
//if (ReggiePortmapStatus(gReggieRef, nil, nil, &local) > kReggiePortmapNone)
|
|
ReggiePortmapBegin(gReggieRef,kReggiePortMapChannel,false,localPort,localPort,"Redline");
|
|
gReggiePortMapped=true;
|
|
}
|
|
}
|
|
else if(state!=kReggieStatePending)
|
|
{
|
|
NetworkStopAdvertising();
|
|
ReggieDispose(gReggieRef,true);
|
|
gReggieConnected=false;
|
|
}
|
|
}
|
|
else
|
|
TrackerConnect();
|
|
}
|
|
|
|
void NetworkStopAdvertising()
|
|
{
|
|
if(gReggieConnected)
|
|
{
|
|
ReggieChannelClose(gReggieRef,kReggieAdvGameChannel);
|
|
// ReggieDispose(gReggieRef,true);
|
|
// gReggieConnected=false;
|
|
}
|
|
}
|
|
|
|
|
|
void QueryGameSearch()
|
|
{
|
|
HashRef hashRef = HashInitialize(kHashFlagReggieKeys, "$KIND=redline $REDLINE$HOSTING=1");
|
|
ReggieSearchBegin(gReggieRef,kReggieSearchGameChannel,kReggieRecordAdvertise,kReggieSearchFlagNotify,hashRef); /* Makes own copy of hash */
|
|
HashDispose(hashRef); /* Not needed any more */
|
|
}
|
|
|
|
void QueryPlayerSearch()
|
|
{
|
|
HashRef hashRef = HashInitialize(kHashFlagReggieKeys,"$KIND=redline $REDLINE$HOSTING=0");
|
|
ReggieSearchBegin(gReggieRef,kReggieSearchPlayersChannel,kReggieRecordAdvertise,kReggieSearchFlagNotify,hashRef);
|
|
HashDispose(hashRef); /* Not needed any more */
|
|
}
|
|
|
|
void AdvertisePlayer()
|
|
{
|
|
char hashString[1024];
|
|
float idleAdd=TimeGetSeconds()-gStartIdleTime;
|
|
int reportIdle=(idleAdd>300);
|
|
gReportedIdle=reportIdle;
|
|
UInt32 startIdleLocalTime=TimerGetLocalSeconds()-idleAdd;
|
|
if(reportIdle)
|
|
sprintf(hashString,"$REDLINE$HOSTING=0 $TIME$IDLE=%d",startIdleLocalTime);
|
|
else
|
|
sprintf(hashString,"$REDLINE$HOSTING=0");
|
|
HashRef hashRef = HashInitialize(kHashFlagReggieKeys,hashString);
|
|
char name[1024];
|
|
sprintf(name,"%s%s",RT3_IsRegistered()?"":"\255demo.png\255 ",gConfig->playerName);
|
|
HashAppend(hashRef, "$NAME", name);
|
|
ReggieInsertBegin(gReggieRef,kReggieAdvGameChannel,kReggieRecordAdvertise,hashRef);
|
|
HashDispose(hashRef);
|
|
}
|
|
|
|
void NetworkSearchGamesInit()
|
|
{
|
|
gLastQuery=0;
|
|
QueryGameSearch();
|
|
QueryPlayerSearch();
|
|
AdvertisePlayer();
|
|
//ReggieMessageBlock(gReggieRef,NULL,false);
|
|
gReggieSearching=true;
|
|
}
|
|
|
|
int NetworkCountPlayers()
|
|
{
|
|
static UInt32 lastPlayerStamp=-1;
|
|
static int lastCount=0;
|
|
if(gReggieConnected)
|
|
{
|
|
UInt32 state=ReggieGetStatus(gReggieRef,gMOTD,NULL);
|
|
if(!(state==kReggieStateRefused||state==kReggieStateOffline))
|
|
{
|
|
if(!gReggieCounting)
|
|
{
|
|
HashRef hashRef = HashInitialize(kHashFlagReggieKeys,"$KIND=redline $REDLINE$HOSTING=0 COUNT");
|
|
ReggieSearchBegin(gReggieRef,kReggieSearchPlayersChannel,kReggieRecordAdvertise,kReggieSearchFlagNotify,hashRef);
|
|
HashDispose(hashRef); /* Not needed any more */
|
|
gReggieCounting=true;
|
|
}
|
|
|
|
SInt32 reggieCount,totalCount;
|
|
UInt32 reggieStamp;
|
|
Bool8 outdated;
|
|
reggieStamp=ReggieSearchStatus(gReggieRef,kReggieSearchPlayersChannel,®gieCount,&totalCount,&outdated);
|
|
if(reggieStamp!=lastPlayerStamp)
|
|
{
|
|
if(outdated)
|
|
{
|
|
HashRef hashRef = HashInitialize(kHashFlagReggieKeys,"$KIND=redline $REDLINE$HOSTING=0 COUNT");
|
|
ReggieSearchBegin(gReggieRef,kReggieSearchPlayersChannel,kReggieRecordAdvertise,kReggieSearchFlagNotify,hashRef);
|
|
HashDispose(hashRef); /* Not needed any more */
|
|
}
|
|
lastPlayerStamp=reggieStamp;
|
|
}
|
|
if(reggieCount!=-1)
|
|
lastCount=totalCount;
|
|
return lastCount;
|
|
}
|
|
else
|
|
{
|
|
ReggieDispose(gReggieRef,true);
|
|
gReggieConnected=false;
|
|
}
|
|
}
|
|
else
|
|
TrackerConnect();
|
|
return 0;
|
|
}
|
|
|
|
void NetworkSearchGames(int *updated,tGameListEntry *games,int *numGames,int maxGames,tGameListPlayerEntry *players,int *numPlayers,int maxPlayers)
|
|
{
|
|
static UInt32 lastGameStamp=-1,lastPlayerStamp=-1;
|
|
static float lastIdleAdd;
|
|
*updated=false;
|
|
|
|
if(gReggieConnected)
|
|
{
|
|
UInt32 state=ReggieGetStatus(gReggieRef,gMOTD,NULL);
|
|
if(!(state==kReggieStateRefused||state==kReggieStateOffline))
|
|
{
|
|
if(!gReggieSearching)
|
|
{
|
|
NetworkSearchGamesInit();
|
|
lastGameStamp=-1;
|
|
lastPlayerStamp=-1;
|
|
gReportedIdle=0;
|
|
}
|
|
float idleAdd=TimeGetSeconds()-gStartIdleTime;
|
|
if(idleAdd>lastIdleAdd+15)
|
|
AdvertisePlayer();
|
|
|
|
lastIdleAdd=idleAdd;
|
|
int reportIdle=(idleAdd>300);
|
|
|
|
if(reportIdle!=gReportedIdle)
|
|
AdvertisePlayer();
|
|
SInt32 reggieCount,totalCount;
|
|
UInt32 reggieStamp;
|
|
Bool8 outdated;
|
|
reggieStamp=ReggieSearchStatus(gReggieRef,kReggieSearchGameChannel,®gieCount,&totalCount,&outdated);
|
|
if(reggieStamp!=lastGameStamp)
|
|
{
|
|
if(reggieCount==totalCount||reggieCount>*numGames)
|
|
// if(reggieCount>-1)
|
|
{
|
|
int oldNumGames=*numGames;
|
|
*numGames=0;
|
|
lastGameStamp=reggieStamp;
|
|
*updated=true;
|
|
NetworkAddress local;
|
|
DatagramGetAddress(NT_GetSessionEndpoint(gSessionRef),&local);
|
|
|
|
int index=0;
|
|
for(;index<reggieCount;index++)
|
|
{
|
|
HashRef hashRef = ReggieSearchIndex(gReggieRef, kReggieSearchGameChannel ,index);
|
|
if(hashRef&&*numGames<maxGames)
|
|
{
|
|
hashRef=HashClone(hashRef);
|
|
if(HashLookup(hashRef, "$UNIQUEID", nil))
|
|
{
|
|
Char8 *hashLookupResult;
|
|
|
|
strcpy(games[*numGames].host,"127.0.0.1");
|
|
strcpy(games[*numGames].alias,"");
|
|
strcpy(games[*numGames].map,"");
|
|
strcpy(games[*numGames].name,"");
|
|
games[*numGames].numPlayers=0;
|
|
games[*numGames].locked=false;
|
|
games[*numGames].numNetPlayers=0;
|
|
games[*numGames].arcade=false;
|
|
games[*numGames].password=false;
|
|
games[*numGames].loaded=true;
|
|
games[*numGames].mapRef=kFileErr;
|
|
games[*numGames].onlyRegistered=false;
|
|
|
|
NetworkAddress addy;
|
|
ReggieNetworkType type;
|
|
ReggieSearchAddress(gReggieRef,kReggieSearchGameChannel,hashRef,&addy,&type);
|
|
ReggiePrejoinType prejoin = ReggieProbePrejoin(gReggieRef,false,&local,&addy);
|
|
if(prejoin==kReggiePrejoinSorry)
|
|
games[*numGames].joinState=kJoinStateFail;
|
|
else if(prejoin!=kReggiePrejoinNormal)
|
|
games[*numGames].joinState=kJoinStateReggie;
|
|
else
|
|
games[*numGames].joinState=kJoinStateOK;
|
|
AddressTranscribe(&addy,games[*numGames].host);
|
|
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$ALIASES", nil))
|
|
{
|
|
char aliases[256];
|
|
strcpy(aliases,hashLookupResult);
|
|
if(strchr(aliases,','))
|
|
*strchr(aliases,',')='\0';
|
|
strcpy(games[*numGames].alias,aliases);
|
|
}
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$MAP", nil))
|
|
strcpy(games[*numGames].map,hashLookupResult);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$MAPFILE",nil))
|
|
games[*numGames].mapRef=FileGetReference(hashLookupResult);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$NUMPLAYERS", nil))
|
|
sscanf(hashLookupResult,"%d",&games[*numGames].numPlayers);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$NUMNETPLAYERS", nil))
|
|
sscanf(hashLookupResult,"%d",&games[*numGames].numNetPlayers);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$MAXPLAYERS", nil))
|
|
sscanf(hashLookupResult,"%d",&games[*numGames].maxPlayers);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$ARCADE", nil))
|
|
sscanf(hashLookupResult,"%d",&games[*numGames].arcade);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$PASSWORD", nil))
|
|
sscanf(hashLookupResult,"%d",&games[*numGames].password);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$LOCKED", nil))
|
|
sscanf(hashLookupResult,"%d",&games[*numGames].locked);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$REDLINE$ONLYREGISTERED", nil))
|
|
sscanf(hashLookupResult,"%d",&games[*numGames].onlyRegistered);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$MESSAGE", nil))
|
|
strcpy(games[*numGames].name,hashLookupResult);
|
|
|
|
for(int i=0;i<games[*numGames].numPlayers;i++)
|
|
{
|
|
strcpy(games[*numGames].players[i].name,"");
|
|
strcpy(games[*numGames].players[i].car,"");
|
|
strcpy(games[*numGames].players[i].location,"");
|
|
|
|
char hashString[32];
|
|
sprintf(hashString,"$REDLINE$PLAYER%dNAME",i);
|
|
if(hashLookupResult=HashLookup(hashRef,hashString,nil))
|
|
strcpy(games[*numGames].players[i].name,hashLookupResult);
|
|
|
|
sprintf(hashString,"$REDLINE$PLAYER%dCAR",i);
|
|
if(hashLookupResult=HashLookup(hashRef,hashString,nil))
|
|
strcpy(games[*numGames].players[i].car,hashLookupResult);
|
|
|
|
sprintf(hashString,"$LOCATION$PLAYER%d",i);
|
|
if(hashLookupResult=HashLookup(hashRef,hashString,nil))
|
|
strcpy(games[*numGames].players[i].location,hashLookupResult);
|
|
else
|
|
{
|
|
sprintf(hashString,"$DOMAIN$PLAYER%d",i);
|
|
if(hashLookupResult=HashLookup(hashRef,hashString,nil))
|
|
strcpy(games[*numGames].players[i].location,hashLookupResult);
|
|
else
|
|
{
|
|
sprintf(hashString,"$HOSTNAMEPLAYER%d",i);
|
|
if(hashLookupResult=HashLookup(hashRef,hashString,nil))
|
|
strcpy(games[*numGames].players[i].location,hashLookupResult);
|
|
}
|
|
}
|
|
if(i>0)
|
|
if(strcmp(games[*numGames].players[i].location,"Reserved Location")==0)
|
|
strcpy(games[*numGames].players[i].location,games[*numGames].players[0].location);
|
|
if(char *loc=strrchr(games[*numGames].players[i].location,','))
|
|
memmove(games[*numGames].players[i].location,loc+1,strlen(loc)+1);
|
|
}
|
|
|
|
|
|
|
|
(*numGames)++;
|
|
}
|
|
HashDispose(hashRef);
|
|
}
|
|
}
|
|
for(;index<totalCount;index++)
|
|
if(*numGames<maxGames)
|
|
{
|
|
if(oldNumGames<*numGames)
|
|
games[*numGames].loaded=false;
|
|
/* games[*numGames].loaded=true;
|
|
strcpy(games[*numGames].name,"Test");
|
|
strcpy(games[*numGames].host,"127.0.0.1");
|
|
strcpy(games[*numGames].map,"");
|
|
strcpy(games[*numGames].players[0].name,"kalle");
|
|
strcpy(games[*numGames].players[0].location,"unna");
|
|
games[*numGames].numPlayers=1;
|
|
games[*numGames].locked=false;
|
|
games[*numGames].numNetPlayers=0;
|
|
games[*numGames].arcade=false;
|
|
games[*numGames].password=false;
|
|
games[*numGames].loaded=true;
|
|
games[*numGames].mapRef=kFileErr;*/
|
|
(*numGames)++;
|
|
}
|
|
}
|
|
if(outdated&®gieCount==totalCount)
|
|
QueryGameSearch();
|
|
}
|
|
|
|
reggieStamp=ReggieSearchStatus(gReggieRef,kReggieSearchPlayersChannel,®gieCount,&totalCount,&outdated);
|
|
if(reggieStamp!=lastPlayerStamp)
|
|
{
|
|
if(reggieCount==totalCount||reggieCount>*numPlayers)
|
|
//if(reggieCount>-1)
|
|
{
|
|
int oldNumPlayers=*numPlayers;
|
|
*numPlayers=0;
|
|
lastPlayerStamp=reggieStamp;
|
|
*updated=true;
|
|
int index=0;
|
|
for(;index<reggieCount;index++)
|
|
{
|
|
HashRef hashRef = ReggieSearchIndex(gReggieRef, kReggieSearchPlayersChannel ,index);
|
|
if(hashRef&&*numPlayers<maxPlayers)
|
|
if(HashLookup(hashRef, "$UNIQUEID", nil))
|
|
{
|
|
Char8 *hashLookupResult;
|
|
|
|
strcpy(players[*numPlayers].location,"");
|
|
strcpy(players[*numPlayers].name,"");
|
|
players[*numPlayers].startIdleTime=-1;
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$NAME", nil))
|
|
strcpy(players[*numPlayers].name,hashLookupResult);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$LOCATION", nil))
|
|
strcpy(players[*numPlayers].location,hashLookupResult);
|
|
if(char *loc=strrchr(players[*numPlayers].location,','))
|
|
memmove(players[*numPlayers].location,loc+1,strlen(loc)+1);
|
|
|
|
if(hashLookupResult=HashLookup(hashRef, "$TIME$IDLE", nil))
|
|
sscanf(hashLookupResult,"%d",&players[*numPlayers].startIdleTime);
|
|
(*numPlayers)++;
|
|
}
|
|
}
|
|
for(;index<totalCount;index++)
|
|
if(*numPlayers<maxPlayers)
|
|
{
|
|
if(oldNumPlayers<*numPlayers)
|
|
{
|
|
strcpy(players[*numPlayers].location,"");
|
|
strcpy(players[*numPlayers].name,"");
|
|
players[*numPlayers].startIdleTime=-1;
|
|
//strcpy(players[*numPlayers].location,"area 51");
|
|
//sprintf(players[*numPlayers].name,"joe %d",*numPlayers);
|
|
}
|
|
(*numPlayers)++;
|
|
}
|
|
//printf("%d,%d=>%d\n",reggieCount,totalCount,*numPlayers);
|
|
}
|
|
if(outdated&®gieCount==totalCount)
|
|
QueryPlayerSearch();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetworkSearchGamesStop();
|
|
ReggieDispose(gReggieRef,true);
|
|
gReggieConnected=false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*numGames=0;
|
|
TrackerConnect();
|
|
}
|
|
}
|
|
|
|
void NetworkSearchGamesStop()
|
|
{
|
|
if(gReggieConnected)
|
|
{
|
|
//ReggieMessageBlock(gReggieRef,NULL,true);
|
|
ReggieChannelClose(gReggieRef,kReggieAdvGameChannel);
|
|
ReggieChannelClose(gReggieRef, kReggieSearchGameChannel);
|
|
ReggieChannelClose(gReggieRef, kReggieSearchPlayersChannel);
|
|
}
|
|
gReggieSearching=false;
|
|
}
|
|
|
|
void NetworkCountPlayersStop()
|
|
{
|
|
if(gReggieConnected)
|
|
{
|
|
ReggieChannelClose(gReggieRef, kReggieSearchPlayersChannel);
|
|
}
|
|
gReggieCounting=false;
|
|
}
|
|
|
|
|
|
int gWaitingForRegistry=false;
|
|
int gWaitingForRecord=false;
|
|
|
|
void TrackerFetchRecord(tFileRef track,tFileRef car,int arcade,int reverse)
|
|
{
|
|
if(gConfig->registerLapTimes)
|
|
{
|
|
if(!gReggieConnected)
|
|
if(!TrackerConnect())
|
|
{
|
|
TextPrintfToBufferFormatedFading(Vector(0,-0.2),0.07,kTextAlignMiddle,1,2,"Unable to Connect lap time server");
|
|
return;
|
|
}
|
|
|
|
char hashString[512];
|
|
HashRef hashRef;
|
|
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(track,kParserTypeMapInfoDesc,sizeof(tMapInfo));
|
|
if(!mapInfo->builtIn)return;
|
|
tCarDefinition *carDef=(tCarDefinition*)FileGetParsedDataPtr(car,kParserTypeCarDesc,sizeof(tCarDefinition));
|
|
if(!carDef->builtIn)return;
|
|
|
|
sprintf(hashString,"$REDLINE$MODE='%d' $REDLINE$REVERSE='%d'",arcade,reverse);
|
|
|
|
hashRef = HashInitialize(kHashFlagReggieKeys, hashString);
|
|
HashAppend(hashRef, "$REDLINE$MAP", mapInfo->name);
|
|
HashAppend(hashRef, "$REDLINE$CAR", carDef->carName);
|
|
HashAppend(hashRef, "SORT", ">$REDLINE$TIME,>$TIME");
|
|
HashAppend(hashRef, "LIMIT", "1");
|
|
|
|
//printf("hash:%s\n",(char*)(*HashSave(hashRef)));
|
|
ReggieSearchBegin(gReggieRef,kReggieRecordChannel,kReggieRecordHighScore,0,hashRef);
|
|
HashDispose(hashRef);
|
|
gWaitingForRecord=true;
|
|
|
|
}
|
|
}
|
|
|
|
void TrackerRegisterLapTime(tFileRef track,tFileRef car,int time,int arcade,int reverse)
|
|
{
|
|
if(gConfig->registerLapTimes)
|
|
{
|
|
if(!gReggieConnected)
|
|
if(!TrackerConnect())
|
|
{
|
|
TextPrintfToBufferFormatedFading(Vector(0,-0.2),0.07,kTextAlignMiddle,1,2,"Unable to Connect to lap time server");
|
|
return;
|
|
}
|
|
char hashString[512];
|
|
HashRef hashRef;
|
|
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(track,kParserTypeMapInfoDesc,sizeof(tMapInfo));
|
|
if(!mapInfo->builtIn)return;
|
|
tCarDefinition *carDef=(tCarDefinition*)FileGetParsedDataPtr(car,kParserTypeCarDesc,sizeof(tCarDefinition));
|
|
if(!carDef->builtIn)return;
|
|
|
|
sprintf(hashString,"$REDLINE$TIME='%d' $REDLINE$MODE='%d' $REDLINE$REVERSE='%d' $REDLINE$MAPCHECK='%8X' $REDLINE$CARCHECK='%8X'",time,arcade,reverse,FileGetChecksum(track),FileGetChecksum(car));
|
|
hashRef = HashInitialize(kHashFlagReggieKeys, hashString);
|
|
HashAppend(hashRef, "$REDLINE$MAPFILE", FileGetName(track));
|
|
HashAppend(hashRef, "$REDLINE$CARFILE", FileGetName(car));
|
|
HashAppend(hashRef, "$REDLINE$MAP", mapInfo->name);
|
|
HashAppend(hashRef, "$REDLINE$CAR", carDef->carName);
|
|
HashAppend(hashRef, "$REDLINE$NAME", gConfig->playerName);
|
|
|
|
ReggieInsertBegin(gReggieRef, kReggieInsertRecordChannel, kReggieRecordHighScore ,hashRef);
|
|
HashDispose(hashRef);
|
|
|
|
sprintf(hashString,"$REDLINE$TIME<='%d' $REDLINE$TIME!='%d' $REDLINE$MODE='%d' $REDLINE$REVERSE='%d' COUNT",time,time,arcade,reverse);
|
|
hashRef = HashInitialize(kHashFlagReggieKeys, hashString);
|
|
HashAppend(hashRef, "$REDLINE$MAP", mapInfo->name);
|
|
HashAppend(hashRef, "$REDLINE$CAR", carDef->carName);
|
|
ReggieSearchBegin(gReggieRef,kReggieRegistryChannel,kReggieRecordHighScore,kReggieSearchFlagCount,hashRef);
|
|
HashDispose(hashRef);
|
|
gWaitingForRegistry=true;
|
|
}
|
|
}
|
|
|
|
void TrackerLapTimeRegistryClose()
|
|
{
|
|
if(gWaitingForRegistry||gWaitingForRecord)
|
|
{
|
|
ReggieChannelClose(gReggieRef,kReggieInsertRecordChannel);
|
|
ReggieChannelClose(gReggieRef,kReggieRegistryChannel);
|
|
ReggieChannelClose(gReggieRef,kReggieRecordChannel);
|
|
gWaitingForRegistry=gWaitingForRecord=false;
|
|
}
|
|
}
|
|
|
|
void TrackerWaitForLapTimeRegistry()
|
|
{
|
|
if(gWaitingForRegistry||gWaitingForRecord)
|
|
{
|
|
if(gWaitingForRegistry)
|
|
TextPrintfToBufferFormated(Vector(0,-0.2),0.05,kTextAlignMiddle,"Registering Lap Time");
|
|
|
|
UInt32 state=ReggieGetStatus(gReggieRef,gMOTD,NULL);
|
|
if(state==kReggieStateRefused||state==kReggieStateOffline)
|
|
{
|
|
if(state==kReggieStateRefused)
|
|
TextPrintfToBufferFormatedFading(Vector(0,-0.2),0.07,kTextAlignMiddle,1,2,"Connection Refused by lap time server");
|
|
else
|
|
TextPrintfToBufferFormatedFading(Vector(0,-0.2),0.07,kTextAlignMiddle,1,2,"No response from lap time server");
|
|
gWaitingForRegistry=false;
|
|
gWaitingForRecord=false;
|
|
gReggieConnected=false;
|
|
ReggieDispose(gReggieRef,false);
|
|
}
|
|
else
|
|
{
|
|
if(gWaitingForRegistry)
|
|
{
|
|
SInt32 reggieCount,totalCount;
|
|
ReggieSearchStatus(gReggieRef,kReggieRegistryChannel,®gieCount,&totalCount,NULL);
|
|
if(reggieCount!=-1)
|
|
{
|
|
if(totalCount==0)
|
|
TextPrintfToBufferFormatedFading(Vector(0,-0.2),0.1,kTextAlignMiddle,1,2,"World Record!!!");
|
|
else if(totalCount<=25)
|
|
TextPrintfToBufferFormatedFading(Vector(0,-0.2),0.1,kTextAlignMiddle,1,2,"Place %d on World List",totalCount+1);
|
|
gWaitingForRegistry=false;
|
|
ReggieChannelClose(gReggieRef,kReggieRegistryChannel);
|
|
TrackerFetchRecord(gGameInfo->map,gGameInfo->playerCars[0],gGameInfo->arcade,gGameInfo->reverse^gMapInfo->reverse);
|
|
}
|
|
}
|
|
if(gWaitingForRecord)
|
|
{
|
|
SInt32 reggieCount,totalCount;
|
|
ReggieSearchStatus(gReggieRef,kReggieRecordChannel,®gieCount,&totalCount,NULL);
|
|
if(reggieCount!=-1)
|
|
{
|
|
if(totalCount==0)
|
|
{
|
|
gWorldRecord=0;
|
|
gWaitingForRecord=false;
|
|
}
|
|
else if(reggieCount>0){
|
|
HashRef hashRef = ReggieSearchIndex(gReggieRef,kReggieRecordChannel,0);
|
|
//printf("$REDLINE$TIME%s\n",HashLookup(hashRef,"$REDLINE$TIME",nil));
|
|
//printf("$REDLINE$NAME%s\n",HashLookup(hashRef,"$REDLINE$NAME",nil));
|
|
//printf("hash:%s\n",(char*)(*HashSave(hashRef)));
|
|
sscanf(HashLookup(hashRef,"$REDLINE$TIME",nil),"%d",&gWorldRecord);
|
|
strcpy(gRecordName,HashLookup(hashRef,"$REDLINE$NAME",nil));
|
|
|
|
int numChars=0,index=0;
|
|
while(numChars<12)
|
|
{
|
|
if(gRecordName[index]=='\255')
|
|
while(gRecordName[++index]!='\255');
|
|
index++;
|
|
numChars++;
|
|
}
|
|
gRecordName[index]='\0';
|
|
gWaitingForRecord=false;
|
|
ReggieChannelClose(gReggieRef,kReggieRecordChannel);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |