Ejemplo n.º 1
0
void ReRaceAbort()
{
	ReShutdownUpdaters();

	RePhysicsEngine().shutdown();
	RaceEngine::self().unloadPhysicsEngine();

	ReUI().onRaceFinishing();

	ReRaceCleanDrivers();

	if (NetGetNetwork())
		NetGetNetwork()->Disconnect();

	FREEZ(ReInfo->_reCarInfo);
	
	if (ReInfo->params != ReInfo->mainParams)
	{
		GfParmReleaseHandle(ReInfo->params);
		ReInfo->params = ReInfo->mainParams;
	}

	// Return to race configuration step
	ReStateApply((void*)RE_STATE_CONFIG);
}
Ejemplo n.º 2
0
int
ReRaceEnd(void)
{
	int curDrvIdx;
	int nCars;
	void *params = ReInfo->params;
	void *results = ReInfo->results;
	const char *sessionName = ReInfo->_reRaceName;

	ReShutdownUpdaters();

	ReUI().onRaceFinishing();
	
	ReRaceCleanup();

	if (NetGetNetwork())
		NetGetNetwork()->RaceDone();

	// If we are at the end of a qualification or practice session for a competitor,
	// select the next competitor : it is his turn for the same session.
	// If no more competitor, this is the end of the session for all the competitors.
	bool bEndOfSession = true;
	if ((ReInfo->s->_raceType == RM_TYPE_QUALIF || ReInfo->s->_raceType == RM_TYPE_PRACTICE)
		&& ReInfo->s->_totTime < 0.0f)
	{
		// Up to the next competitor now, if not the last one.
		nCars = MIN(GfParmGetEltNb(params, RM_SECT_DRIVERS),
				(int)GfParmGetNum(params, sessionName, RM_ATTR_MAX_DRV, NULL, 100));
		ReCurrDriverNr++;
		if (ReStartingOrderIdx != NULL) {
			if (ReCurrDriverNr < nCars) {curDrvIdx = ReStartingOrderIdx[ReCurrDriverNr];}
			else {curDrvIdx = nCars + 1;}
		}
		else {
			curDrvIdx = 1;
		}
		if (ReCurrDriverNr < nCars) 
			bEndOfSession = false;
		else {
			ReCurrDriverNr = 0; // Was the last one : end of session !
			curDrvIdx = 1;
		}
		GfParmSetNum(results, RE_SECT_CURRENT, RE_ATTR_CUR_DRIVER, NULL, (tdble)curDrvIdx);
	}

	// Calculate class points if we just finished a session.
	if (bEndOfSession)
	{
		ReCalculateClassPoints (ReInfo->_reRaceName);
		if (ReStartingOrderIdx != NULL) {
			delete[] ReStartingOrderIdx;
			ReStartingOrderIdx = NULL;
		}
	}
	
	// Determine the new race state automation mode.
	const bool bGoOn = ReUI().onRaceFinished(bEndOfSession);
	
	return (bEndOfSession ? RM_NEXT_STEP : RM_NEXT_RACE) | (bGoOn ? RM_SYNC : RM_ASYNC);
}
Ejemplo n.º 3
0
void
ReNetworkCheckEndOfRace()
{
	// Check for end of online race.
	if (NetGetNetwork() && NetGetNetwork()->FinishRace(ReInfo->s->currentTime))
		ReInfo->s->_raceState = RM_RACE_ENDED;
}
Ejemplo n.º 4
0
static void onClientPlayerReady(tCheckBoxInfo* pInfo)
{
	int nDriverIdx = NetGetNetwork()->GetDriverIdx();

	// Local Human Driver
	if (nDriverIdx > -1) {
		SetReadyStatus(nDriverIdx-1, pInfo->bChecked);
		NetGetNetwork()->SetDriverReady(pInfo->bChecked);
	}

	EnableMenuClientButtons(pInfo->bChecked);
}
Ejemplo n.º 5
0
static void
rmCarSettingsMenu(void *pMenu)
{
	int nDriverIdx = NetGetNetwork()->GetDriverIdx();

	if (nDriverIdx > -1) {
		NetDriver driver;
		// char newName[64]; Never used
		char dname[256];

		// check for car change
		GfLogInfo("Car %d changed \n", nDriverIdx);

		tRmInfo* reInfo = LmRaceEngine().inData();
		reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_REREAD);
		reInfo->_reName = GfParmGetStr(reInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, "");

		sprintf(dname, "%s/%d", RM_SECT_DRIVERS, nDriverIdx);
		int idx = GfParmGetNum(reInfo->params, dname, RM_ATTR_IDX, "",0);

		// Garage menu to change clients car
		GfDriver* PCurrentDriver = GfDrivers::self()->getDriver(NETWORKROBOT, idx);

		GarageMenu.setPreviousMenuHandle(racemanMenuHdle);
		GarageMenu.runMenu(LmRaceEngine().race(), PCurrentDriver);
		bGarage = true;
	}
}
Ejemplo n.º 6
0
void
RmNetworkMenu(void *)
{
	GfLogTrace("Entering Network menu.\n");
	
 	tRmInfo* reInfo = LmRaceEngine().inData();
	void *params = reInfo->params;

	if (NetGetNetwork())
	{
		NetGetNetwork()->ResetNetwork();
	}

	racemanMenuHdle = GfuiScreenCreate(NULL,  NULL, (tfuiCallback)NULL, 
								NULL, (tfuiCallback)NULL, 1);

	void *mparam = GfuiMenuLoad("networkmenu.xml");

	GfuiMenuCreateStaticControls(racemanMenuHdle, mparam);

	const int nTitleLabelId = GfuiMenuCreateLabelControl(racemanMenuHdle, mparam, "TitleLabel");
	const char* pszTitle = GfParmGetStr(params, RM_SECT_HEADER, RM_ATTR_NAME, 0);
	if (pszTitle)
		GfuiLabelSetText(racemanMenuHdle, nTitleLabelId, pszTitle);
	
	GfuiMenuCreateButtonControl(racemanMenuHdle, mparam, "HostButton",
								0, RmNetworkHostMenu);

	GfuiMenuCreateButtonControl(racemanMenuHdle, mparam, "JoinButton",
								0, NetworkClientConnectMenu);

	GfuiMenuCreateButtonControl(racemanMenuHdle, mparam, "BackButton",
								RmRaceSelectMenuHandle, GfuiScreenActivate);

	GfuiMenuDefaultKeysAdd(racemanMenuHdle);
	GfuiAddKey(racemanMenuHdle, GFUIK_ESCAPE, "Back to previous menu",
								RmRaceSelectMenuHandle, 0, GfuiScreenActivate);

	GfParmReleaseHandle(mparam);
	
	GfuiScreenActivate(racemanMenuHdle);
}
Ejemplo n.º 7
0
static void
reNetworkSetLapStatus(LapStatus *pStatus)
{
	int idx = NetGetNetwork()->GetCarIndex(pStatus->startRank,ReInfo->s);

	tCarElt *pCar = ReInfo->s->cars[idx];
	pCar->race.bestLapTime = pStatus->bestLapTime;
	*pCar->race.bestSplitTime = (double)pStatus->bestSplitTime;
	pCar->race.laps = pStatus->laps;
	GfLogTrace("Setting network lap status\n");
}
Ejemplo n.º 8
0
static void
OnActivateNetworkHost(void *)
{
	tRmInfo* reInfo = LmRaceEngine().inData();

	// Set everyone to the 'not-ready' state
	bRobotsReady = 0;
	NetMutexData *pNData = NetGetNetwork()->LockNetworkData();
	for (unsigned int i=0;i<pNData->m_vecReadyStatus.size();i++)
		pNData->m_vecReadyStatus[i] = false;
	NetGetNetwork()->UnlockNetworkData();

	NetGetServer()->SetRaceInfoChanged(true);

	reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_REREAD);
	assert(reInfo->params);
	reInfo->_reName = GfParmGetStr(reInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, "");
	GfuiApp().eventLoop().setRecomputeCB(HostServerIdle);	

	NetGetServer()->SetRefreshDisplay(true);
}
Ejemplo n.º 9
0
// This member function decorates the situation updater as a normal function,
// thus hiding the possible separate thread behind to the main updater. 
void ReSituationUpdater::computeCurrentStep()
{
	// Nothing to do if actually threaded :
	// the updater thread is already doing the job on his side.
	if (_bThreaded)
		return;

	// Non-threaded mode.
	GfProfStartProfile("reOneStep*");
			
	tRmInfo* pCurrReInfo = ReSituation::self().data();

	// Stable but slowed-down frame rate mode.
	if (_fOutputTick > 0)
	{
		while ((pCurrReInfo->_reCurTime - _fLastOutputTime) < _fOutputTick)

			runOneStep(_fSimuTick);

		_fLastOutputTime = pCurrReInfo->_reCurTime;
	}

	// Real-time but variable frame rate mode.
	else
	{
		const double t = GfTimeClock();
		
		while (pCurrReInfo->_reRunning && ((t - pCurrReInfo->_reCurTime) > RCM_MAX_DT_SIMU))
				
			runOneStep(_fSimuTick);
	}

	GfProfStopProfile("reOneStep*");
		
	// Send car physics to network if needed
	if (NetGetNetwork())
		NetGetNetwork()->SendCarControlsPacket(pCurrReInfo->s);
}
Ejemplo n.º 10
0
static void OnActivateNetworkClient(void *)
{
	int nDriverIdx = NetGetNetwork()->GetDriverIdx();

	if(NetGetNetwork()->IsConnected() && nDriverIdx > -1) {
		// Menu reactivated after garage menu is done
		NetDriver driver;
		char newName[64];
		char dname[256];

		// check for car change
		if (bGarage == true ) {
			bGarage = false;

			tRmInfo* reInfo = LmRaceEngine().inData();
			reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_REREAD);
			reInfo->_reName = GfParmGetStr(reInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, "");

			sprintf(dname, "%s/%d", RM_SECT_DRIVERS, nDriverIdx);
			int idx = GfParmGetNum(reInfo->params, dname, RM_ATTR_IDX, "",0);

			GfDriver* PCurrentDriver = GfDrivers::self()->getDriver(NETWORKROBOT, idx);
			strncpy(newName, PCurrentDriver->getCar()->getId().c_str(), sizeof(newName));

			GfLogInfo("Client: Index %d changed to %s\n", idx, newName);
			NetGetNetwork()->SetCarInfo(newName);
		} else {
			// Ensure menu system knows about all cars
			GfDrivers::self()->reload();
			// tRmInfo* reInfo = LmRaceEngine().inData(); // Never used
			LmRaceEngine().race()->load(LmRaceEngine().race()->getManager(), true);
		}
	}

	GfuiApp().eventLoop().setRecomputeCB(ClientIdle);
	bGarage = false;
}
Ejemplo n.º 11
0
static void
reNetworkSetCarPhysics(double timeDelta,CarControlsData *pCt)
{
	tDynPt *pDynCG = RePhysicsEngine().getCar(pCt->startRank);

	// double errX = pDynCG->pos.x-pCt->DynGCg.pos.x;
	// double errY = pDynCG->pos.y-pCt->DynGCg.pos.y;
	// double errZ = pDynCG->pos.z-pCt->DynGCg.pos.z;

	int idx = NetGetNetwork()->GetCarIndex(pCt->startRank,ReInfo->s);
	
	//Car controls (steering,gas,brake, gear
	tCarElt *pCar = ReInfo->s->cars[idx];
	pCar->ctrl.accelCmd = pCt->throttle;
	pCar->ctrl.brakeCmd = pCt->brake;
	pCar->ctrl.clutchCmd = pCt->clutch;
	pCar->ctrl.gear = pCt->gear;
	pCar->ctrl.steer = pCt->steering;

	pDynCG->pos = pCt->DynGCg.pos;
	pDynCG->acc = pCt->DynGCg.acc;
	pDynCG->vel = pCt->DynGCg.vel;

	double step = 0.0;
	if (timeDelta>0.0)
	{
		//predict car position
		while(timeDelta>0.0)
		{
			if (timeDelta>RCM_MAX_DT_SIMU)
			{
				step = RCM_MAX_DT_SIMU;
			}
			else
				step = timeDelta;

			timeDelta-=step;
			RePhysicsEngine().updateCar(ReInfo->s, step, pCt->startRank);
		}
	}

	//GfLogTrace("Network position error is %lf %lf %lf and delta is %lf\n",errX,errY,errZ,timeDelta);

	//Car physics
//	RePhysicsEngine().setCar(pCt->DynGCg, pCt->startRank);
}
bool CarSettingsMenu::initialize(void* pMenu,const char *pszCar)
{
	std::string strCarCat;
	bool bCollisions;
	NetGetNetwork()->GetHostSettings(strCarCat,bCollisions);
	pPrevMenu = pMenu;

	void* pMenuHandle = GfuiScreenCreate(NULL,NULL,onActivate, 
										   NULL, (tfuiCallback)NULL, 
										   1);
	setMenuHandle(pMenuHandle);

    openXMLDescriptor();
    
    createStaticControls();
    
	int carCatId = createComboboxControl("modelcombo",NULL,onCarPick);
	createComboboxControl("skincombo",NULL,NULL);
	createStaticImageControl("carpreviewimage");
	createProgressbarControl("topspeedprogress");
	createProgressbarControl("accelerationprogress");
	createProgressbarControl("handlingprogress");
	createProgressbarControl("brakingprogress");

	const std::vector<std::string> vecCarRealNames =
		GfCars::self()->getCarNamesInCategory(strCarCat);
	
	m_strCar = pszCar;
	int carIndex = 0;
	for (unsigned i=0;i<vecCarRealNames.size();i++)
	{
		GfuiComboboxAddText(pMenuHandle,carCatId,vecCarRealNames[i].c_str());
		if (vecCarRealNames[i] == m_strCar)
			carIndex = i;
	}
	
	GfuiComboboxSetSelectedIndex(pMenuHandle,carCatId,carIndex);

	createButtonControl("accept",NULL,onAccept);
    createButtonControl("cancel",NULL,onCancel);

    closeXMLDescriptor();
    
	return true;
}
Ejemplo n.º 13
0
static void
reNetworkSetCarStatus(CarStatus *pStatus)
{
	int idx = NetGetNetwork()->GetCarIndex(pStatus->startRank,ReInfo->s);

	tCarElt *pCar = ReInfo->s->cars[idx];

	if (pStatus->dammage > 0.0)
		pCar->priv.dammage = pStatus->dammage;
	if (pStatus->fuel >0.0)
		pCar->priv.fuel = pStatus->fuel;
	if (pStatus->topSpeed >0.0)
		pCar->race.topSpeed = pStatus->topSpeed;

	pCar->pub.state = pStatus->state;
	

}
Ejemplo n.º 14
0
int
ReNetworkWaitReady()
{
	// No wait if not an online race.
	if (!NetGetNetwork())
		return RM_SYNC | RM_NEXT_STEP;

	// If network race, wait for other players and start when the server tells to
	bool bWaitFinished = false;
	if (NetGetClient())
	{
		NetGetClient()->SendReadyToStartPacket();
		ReInfo->s->currentTime = NetGetClient()->WaitForRaceStart();
		GfLogInfo("Client beginning race in %lf seconds!\n", - ReInfo->s->currentTime);
		bWaitFinished = true;
	}
	
	else if (NetGetServer())
	{
		if (NetGetServer()->ClientsReadyToRace())
		{
			ReInfo->s->currentTime = NetGetServer()->WaitForRaceStart();
			GfLogInfo("Server beginning race in %lf seconds!\n", - ReInfo->s->currentTime);
			bWaitFinished = true;
		}
	}

	if (bWaitFinished)
	{
		ReSituation::self().setRaceMessage("", -1/*always*/, /*big=*/true);
		return RM_SYNC | RM_NEXT_STEP;
	}
	else
	{
		ReSituation::self().setRaceMessage("Waiting for online players",
										   -1/*always*/, /*big=*/true);
		return RM_ASYNC;
	}
}
Ejemplo n.º 15
0
static void
CheckDriversCategory()
{
	bool bDriversChange = false;
	std::string strCarCat;
	bool bCollisions;
	NetGetNetwork()->GetHostSettings(strCarCat,bCollisions);
	if (strCarCat =="All")
		return;

	const std::vector<std::string> vecCars =
		GfCars::self()->getCarIdsInCategory(strCarCat);

	//Make sure all cars are in the correct category or force change of car
	unsigned int count = 0;
	NetServerMutexData *pSData = NetGetServer()->LockServerData();

	count = pSData->m_vecNetworkPlayers.size();
	
	for (unsigned int i=0;i<count;i++)
	{
		const GfCar* pCar = GfCars::self()->getCar(pSData->m_vecNetworkPlayers[i].car);
		if (pCar->getCategoryId() != strCarCat)
		{
			//Pick first car in categroy
			//strncpy(pSData->m_vecNetworkPlayers[i].car,vecCars[0].c_str(),64);
			bDriversChange = true;
			NetGetServer()->OverrideDriverReady(pSData->m_vecNetworkPlayers[i].idx,false);
		}
	}

	if(bDriversChange)
	{
		NetGetServer()->CreateNetworkRobotFile();
	}
	
	//NetGetServer()->UnlockDrivers();
	NetGetServer()->UnlockServerData();
}
Ejemplo n.º 16
0
static void 
UpdateNetworkPlayers()
{
	GfDriver* newDriver;
	NetNetwork *pNetwork = NetGetNetwork();

	if (pNetwork->GetRefreshDisplay() == false)
		return;

	tRmInfo* reInfo = LmRaceEngine().inData();

	//Set current driver that camera will look at
	pNetwork->SetCurrentDriver();

	//reload xml file
	NetGetNetwork()->SetRaceXMLFile("config/raceman/networkrace.xml");
	reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_REREAD);
	assert(reInfo->params);

	reInfo->_reName = GfParmGetStr(reInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, "");
	assert(reInfo->_reName);

	// Scan each of the human drivers to see if they're active in this race
	if (NetIsServer()) {
		NetServerMutexData *pSData = NetGetServer()->LockServerData();
		assert(pSData);

		// Ensure that garage menu knows about driver
		for (unsigned int i=0; i < pSData->m_vecNetworkPlayers.size(); i++) {
			newDriver = GfDrivers::self()->getDriver(NETWORKROBOT, pSData->m_vecNetworkPlayers[i].idx);

			if (!newDriver) { 
				GfLogInfo("Driver %s not found, reloading drivers\n", pSData->m_vecNetworkPlayers[i].name);
				GfDrivers::self()->reload();
				LmRaceEngine().race()->load(LmRaceEngine().race()->getManager(), true);
				break;
			}
		}

		for (unsigned int i=0; i < pSData->m_vecNetworkPlayers.size(); i++) {
			int k = 1;
			char path2[256];

			pSData->m_vecNetworkPlayers[i].active = false;
			newDriver = GfDrivers::self()->getDriver(NETWORKROBOT, pSData->m_vecNetworkPlayers[i].idx);

			// Scan through drivers listed in 'networkrace.xml'
			while (pSData->m_vecNetworkPlayers[i].active == false) {
				sprintf(path2, "%s/%d", RM_SECT_DRIVERS, k++);
				if (GfParmExistsSection(reInfo->params, path2) == 0) {
					GfLogInfo("UpdateNetworkPlayers: Removing driver %s\n", pSData->m_vecNetworkPlayers[i].name);

					if (pSData->m_vecNetworkPlayers[i].client) {
						//need to tell/force client to disconnect
					}
					break;
				}

				if ((tdble)pSData->m_vecNetworkPlayers[i].idx == GfParmGetNum(reInfo->params, path2, RM_ATTR_IDX, NULL, 1.0) &&
						strcmp(NETWORKROBOT, GfParmGetStr(reInfo->params, path2, RM_ATTR_MODULE, "")) == 0) {
					pSData->m_vecNetworkPlayers[i].active = true;
				}
			}

			// add or remove from competitor list (for garage menu)
			GfDriver* activeDriver = LmRaceEngine().race()->getCompetitor(NETWORKROBOT, pSData->m_vecNetworkPlayers[i].idx);
			if (pSData->m_vecNetworkPlayers[i].active) {
				if (!activeDriver) LmRaceEngine().race()->appendCompetitor(newDriver);
			} else {
				if (activeDriver) LmRaceEngine().race()->removeCompetitor(newDriver);
			}
		}
		NetGetServer()->UnlockServerData();
	} else {
#if 1
		// Client XML files already written to disk - this works but is not the best solution....
		GfDrivers::self()->reload();
		LmRaceEngine().race()->load(LmRaceEngine().race()->getManager(), true);
#endif
	}

	//Update track info
	std::string strTrackPath = GfParmGetStr(reInfo->params, "Tracks/1", RM_ATTR_NAME, "");
	std::string strCategory = GfParmGetStr(reInfo->params, "Tracks/1", RM_ATTR_CATEGORY, "");

	std::string strTrackName = GetTrackName(strCategory.c_str(),strTrackPath.c_str());

	sprintf(buf, "%s", strTrackName.c_str());
	GfuiLabelSetText(racemanMenuHdle,g_trackHd,buf);

	//Store current track - client needs this
	GfTrack* PCurTrack = GfTracks::self()->getTrackWithName(buf);
	LmRaceEngine().race()->getManager()->setEventTrack(0, PCurTrack);
	
	int laps = (int)GfParmGetNum(reInfo->params, reInfo->_reName,"laps", "", 1);
	sprintf(buf, "%i", laps);
	GfuiLabelSetText(racemanMenuHdle,g_lapsHd,buf);

	GfuiScreenAddBgImg(racemanMenuHdle,
					   GetTrackPreviewFileName(strCategory.c_str(),strTrackPath.c_str()).c_str());
	GfuiStaticImageSet(racemanMenuHdle, g_OutlineId,
					   GetTrackOutlineFileName(strCategory.c_str(),strTrackPath.c_str()).c_str());

	// Update category info
	std::string strCarCat;
	bool bCollisions;
	NetGetNetwork()->GetHostSettings(strCarCat,bCollisions);
	GfuiLabelSetText(racemanMenuHdle,g_catHd,strCarCat.c_str());

	//fill in player data
	int nCars = GfParmGetEltNb(reInfo->params, RM_SECT_DRIVERS);

	char	dname[256];
	char    robpath[256];

	float *pColor = &green[0];

	bool bEveryoneReadyToRace = true;
	
	for (int i = 1; i < nCars+1; i++) 
	{
		sprintf(dname, "%s/%d", RM_SECT_DRIVERS, i);

		const char* robot = GfParmGetStr(reInfo->params, dname, RM_ATTR_MODULE, "");

		//lookup playerName and car name
		sprintf(robpath,"drivers/%s/%s.xml",robot,robot);
		void *pMod = GfParmReadFileLocal(robpath,GFPARM_RMODE_REREAD);

		if (pMod == NULL)
		{
			//try again in other path
			sprintf(robpath,"drivers/%s/%s.xml",robot,robot);
			pMod = GfParmReadFile(robpath,GFPARM_RMODE_REREAD);
			if (pMod == NULL)
				continue;
		}

		assert(pMod);

		char ppname[256];
		int idx = GfParmGetNum(reInfo->params, dname, RM_ATTR_IDX, "",0);
		sprintf(ppname,"Robots/index/%d",idx);
		const char* name = GfParmGetStr(pMod, ppname, RM_ATTR_NAME, "");

		const char* car = GfParmGetStr(pMod, ppname, "car name", "");
		std::string strRealCar = GfCars::self()->getCar(car)->getName();

		// WAIT : pNData->m_vecReadyStatus[i-1] ?!
		//        This can only work when _only_ networkhuman drivers in the race
		//        (that is _no_robot_driver_) ; because m_vecReadyStatus is indexed
		//        by the networkhuman drivers list.
		// TO fix this, 2 solutions:
		// 1) make the networking module take care of the robot drivers too
		//    (in m_vecReadyStatus, m_vecNetworkPlayers, ...)
		// 2) make the networking _menu_ only take care of the networkhuman drivers.
		bool bReady = bRobotsReady;
		if(strcmp(NETWORKROBOT, GfParmGetStr(reInfo->params, dname, RM_ATTR_MODULE, "")) == 0) {
			// Write car model, as it may have changed via garage menu
			if (NetIsServer()) {
				NetServerMutexData *pSData = NetGetServer()->LockServerData();
				strncpy(pSData->m_vecNetworkPlayers[idx-1].car, car, 64);
				GfLogInfo("idx %d car set to %s\n", idx, car);

				// also need to write back for garage menu
				const GfCar* newCar = GfCars::self()->getCar(car);
				newDriver = GfDrivers::self()->getDriver(NETWORKROBOT, pSData->m_vecNetworkPlayers[idx-1].idx);
				newDriver->setCar(newCar);
				NetGetServer()->UnlockServerData();
			}

			//GfLogInfo("idx %d, m_vecReadyStatus.size() %d\n", idx, pNData->m_vecReadyStatus.size());
			NetMutexData *pNData = NetGetNetwork()->LockNetworkData();
			bReady = pNData->m_vecReadyStatus[idx-1];
			NetGetNetwork()->UnlockNetworkData();
		}

		int readyindex = 0;
		if (bReady)
			readyindex = 1;	
		else
			bEveryoneReadyToRace = false;

		if (strcmp(NetGetNetwork()->GetDriverName(),name)==0)
		{
			pColor = &green[0];
			g_strCar = strRealCar;
			//Make sure checkbox matches ready state
			GfuiCheckboxSetChecked(racemanMenuHdle, g_ReadyCheckboxId, bReady);
			if (NetGetClient())
				EnableMenuClientButtons(bReady);
			else
				EnableMenuHostButtons(bReady);
		}
		else
			pColor = &white[0];

		GfuiVisibilitySet(racemanMenuHdle,g_readystatus[i-1],true);
		GfuiStaticImageSetActive(racemanMenuHdle,g_readystatus[i-1],readyindex);
		GfuiLabelSetColor(racemanMenuHdle, g_playerNames[i-1], pColor);
		GfuiLabelSetText(racemanMenuHdle,g_playerNames[i-1],name);

		GfuiLabelSetColor(racemanMenuHdle, g_carNames[i-1], pColor);
		GfuiLabelSetText(racemanMenuHdle,g_carNames[i-1],strRealCar.c_str());
		GfParmReleaseHandle(pMod);
	}

	//Clear out rest of table
	for (int i=nCars;i<MAXNETWORKPLAYERS;i++)
	{
		GfuiVisibilitySet(racemanMenuHdle,g_readystatus[i],false);
		GfuiLabelSetText(racemanMenuHdle,g_playerNames[i],"");
		GfuiLabelSetText(racemanMenuHdle,g_carNames[i],"");
	}

	pNetwork->SetRefreshDisplay(false);
	GfuiApp().eventLoop().postRedisplay();

	if (NetIsClient())
	{	
		NetGetClient()->ConnectToClients();

		if (!NetGetClient()->TimeSynced())
		{
			NetGetClient()->SendServerTimeRequest();
		}
	}

	if (NetIsServer())
	{
		if (bEveryoneReadyToRace && nCars > 1)
			ServerPrepareStartNetworkRace(NULL);
	}
}
Ejemplo n.º 17
0
void
ReNetworkOneStep()
{
	tSituation *s = ReInfo->s;

	//Do network updates if needed
	//CarControlsData *pControls = NULL;
	int numCars = 0;
	
	NetMutexData *pNData = NetGetNetwork()->LockNetworkData();

	numCars = pNData->m_vecCarCtrls.size();
	if (numCars>0)
	{
		for (int i=0;i<numCars;i++)
		{
			double timeDelta = s->currentTime-pNData->m_vecCarCtrls[i].time;
			if (timeDelta >= 0)
			{
				reNetworkSetCarPhysics(timeDelta,&pNData->m_vecCarCtrls[i]);
			}
			else if (timeDelta <= -1.0)
			{
				GfLogTrace("Ignoring physics packet (delta is %lf)\n", timeDelta);
			}
		}
	}

	NetGetNetwork()->SetCurrentTime(s->currentTime);
	pNData->m_vecCarCtrls.clear();

	//do car status updates if needed
	numCars = pNData->m_vecCarStatus.size();

	if (numCars>0)
	{
		for (int i=0;i<numCars;i++)
		{
			double delta = s->currentTime-pNData->m_vecCarStatus[i].time;
			if (delta>=0)
				reNetworkSetCarStatus(&pNData->m_vecCarStatus[i]);
		}
	}

	std::vector<CarControlsData>::iterator p = pNData->m_vecCarCtrls.begin();
	while(p!=pNData->m_vecCarCtrls.end())
	{
		if(p->time<s->currentTime)
			p = pNData->m_vecCarCtrls.erase(p);
		else 
			p++;
	}

	//do lap status updates if needed
	numCars = 0;
	numCars = pNData->m_vecLapStatus.size();
	if (numCars>0)
	{
		for (int i=0;i<numCars;i++)
		{
			reNetworkSetLapStatus(&pNData->m_vecLapStatus[i]);
		}
	}

	pNData->m_vecLapStatus.clear();

	NetGetNetwork()->UnlockNetworkData();
}
Ejemplo n.º 18
0
/* return state mode */
int
ReRaceRealStart(void)
{
	int i, j;
	tRobotItf *robot;
	tReCarInfo *carInfo;
	char buf[128];
	int foundHuman;
	void *params = ReInfo->params;
	tSituation *s = ReInfo->s;
	tMemoryPool oldPool = NULL;
	void* carHdle;

	// Load the physics engine
	if (!RaceEngine::self().loadPhysicsEngine())
		return RM_ERROR;

	// Get the session display mode (default to "All sessions" ones, or else "normal").
	std::string strDispMode =
		GfParmGetStr(params, ReInfo->_reRaceName, RM_ATTR_DISPMODE, "");
	if (strDispMode.empty())
		strDispMode =
			GfParmGetStr(params, RM_VAL_ANYRACE, RM_ATTR_DISPMODE, RM_VAL_VISIBLE);

	if (strDispMode == RM_VAL_INVISIBLE)
		ReInfo->_displayMode = RM_DISP_MODE_NONE;
	else if (strDispMode == RM_VAL_VISIBLE)
		ReInfo->_displayMode = RM_DISP_MODE_NORMAL;
	else if (strDispMode == RM_VAL_SIMUSIMU)
		ReInfo->_displayMode = RM_DISP_MODE_SIMU_SIMU;
	else
	{
		GfLogError("Unsupported display mode '%s' loaded from race file ; "
				   "assuming 'normal'\n", strDispMode.c_str());
		ReInfo->_displayMode = RM_DISP_MODE_NORMAL;
	}

	//GfLogDebug("ReRaceRealStart: Loaded dispMode=0x%x\n", ReInfo->_displayMode);
	
	// Check if there is a human in the driver list
	foundHuman = ReHumanInGroup() ? 2 : 0;

	// Reset SimuSimu bit if any human in the race.
	// Note: Done here in order to make SimuSimu faster. 
	if ((ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU) && foundHuman)
	{
		ReInfo->_displayMode &= ~RM_DISP_MODE_SIMU_SIMU;
	}
	
	// Initialize & place cars
	// Note: if SimuSimu display mode, robot->rbNewTrack isn't called. This is a lot faster.
	if (ReInitCars())
		return RM_ERROR;

	// Check if there is a human in the current race
	// Warning: Don't move this before ReInitCars (initializes s->cars).
	for (i = 0; i < s->_ncars; i++) {
		if (s->cars[i]->_driverType == RM_DRV_HUMAN) {
			foundHuman = 1;
			break;
		}//if human
	}//for i

	// Force "normal" display mode if any human in the session
	if (foundHuman == 1)
	{
		ReInfo->_displayMode = RM_DISP_MODE_NORMAL;
	}
	// Force "result only" mode in Practice / Qualif. sessions without any human,
	// but at least 1 in another session (why this ?), and SimuSimu bit on.
	else if (foundHuman == 2 && (ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU)
		     && (ReInfo->s->_raceType == RM_TYPE_QUALIF
				 || ReInfo->s->_raceType == RM_TYPE_PRACTICE))
	{
		ReInfo->_displayMode = RM_DISP_MODE_NONE;
	}

	GfLogInfo("Display mode : %s\n",
			  (ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU) ? "SimuSimu" :
			  ((ReInfo->_displayMode & RM_DISP_MODE_NORMAL) ? "Normal" : "Results-only"));
	
	// Notify the UI that it's "race loading time".
	ReUI().onRaceLoadingDrivers();

	// Load drivers for the race
	for (i = 0; i < s->_ncars; i++)
	{
		snprintf(buf, sizeof(buf), "cars/%s/%s.xml",
				 s->cars[i]->_carName, s->cars[i]->_carName);
		carHdle = GfParmReadFile(buf, GFPARM_RMODE_STD);
		snprintf(buf, sizeof(buf), "Loading %s driver (%s) ...",
				 s->cars[i]->_name, GfParmGetName(carHdle));
		
		ReUI().addLoadingMessage(buf);

		if (!(ReInfo->_displayMode & RM_DISP_MODE_SIMU_SIMU))
		{
			//Tell robots they are to start a new race
			robot = s->cars[i]->robot;
			GfPoolMove( &s->cars[i]->_newRaceMemPool, &oldPool );
			robot->rbNewRace(robot->index, s->cars[i], s);
			GfPoolFreePool( &oldPool );
		}//if ! simusimu
	}//for i
	
	RtTeamManagerStart();

	// Notify the UI that the drivers have been loaded now.
	ReUI().onRaceDriversLoaded();

	// Initialize the physics engine
	RePhysicsEngine().updateSituation(s, RCM_MAX_DT_SIMU);

	carInfo = ReInfo->_reCarInfo;
	for (i = 0; i < s->_ncars; i++) {
		carInfo[i].prevTrkPos = s->cars[i]->_trkPos;
	}

	// All cars start with max brakes on
	ReUI().addLoadingMessage("Running Prestart ...");
	
	for (i = 0; i < s->_ncars; i++)
	{
		memset(&(s->cars[i]->ctrl), 0, sizeof(tCarCtrl));
		s->cars[i]->ctrl.brakeCmd = 1.0;
	}

	for (j = 0; j < (int)(1.0 / RCM_MAX_DT_SIMU); j++)
		RePhysicsEngine().updateSituation(s, RCM_MAX_DT_SIMU);

	// Initialize current result manager.
	ReInitCurRes();

	// More initializations.
	ReInfo->_reTimeMult = 1.0;
	ReInfo->_reLastRobTime = -1.0;
	if (NetGetNetwork())
		ReInfo->s->currentTime = GfTimeClock() - NetGetNetwork()->GetRaceStartTime();
	else
		ReInfo->s->currentTime = -2.0;	// We start 2 seconds before the real race start
	ReInfo->s->deltaTime = RCM_MAX_DT_SIMU;
	ReInfo->s->_raceState = RM_RACE_STARTING;

	ReInfo->_rePitRequester = 0;
	ReInfo->_reMessage = 0;
	ReInfo->_reMessageEnd = 0.0;
	ReInfo->_reBigMessage = 0;
	ReInfo->_reBigMessageEnd = 0.0;
	
	ReInitUpdaters();

	// Notify the UI that the race simulation is ready now.
	ReUI().onRaceSimulationReady();

	// Initialize the network if needed.
	if (NetGetNetwork())
	{
		ReUI().addLoadingMessage("Preparing online race ...");
		
		NetGetNetwork()->RaceInit(ReOutputSituation()->s);
		NetGetNetwork()->SetRaceActive(true);
	}

	// Notify the UI that the race is now started.
	ReUI().addLoadingMessage("Ready.");

	ReUI().onRaceStarted();

	// And go on looping the race state automaton.
	return RM_SYNC | RM_NEXT_STEP;
}//ReRaceRealStart
Ejemplo n.º 19
0
static void
NetworkRaceInfo()
{
	NetDriver driver;
	int i = 1;

	NetGetServer()->SetRaceXMLFile("config/raceman/networkrace.xml");

	//Look up race info
	tRmInfo* reInfo = LmRaceEngine().inData();
	reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_STD);

	int nCars = GfParmGetEltNb(reInfo->params, RM_SECT_DRIVERS);

	if (nCars == 0)
	{
		// Add all local humans if there are no drivers already specified
		while (GetHumanDriver(driver,i++)) {
			driver.client = false;
			driver.active = true;
			NetGetServer()->UpdateDriver(driver);
			NetGetServer()->SetDriverName(driver.name);
			GfLogInfo("NetworkRaceInfo: Adding default driver %s\n",driver.name);

		}

		// ensure changes writen to 'networkrace.xml'
		NetGetServer()->GenerateDriversForXML();

		// add drivers so they show up in race config dialogue
		GfDrivers::self()->reload();
		LmRaceEngine().race()->load(LmRaceEngine().race()->getManager(), true);
	} else {
		// Add the humans which are already in the race
		char	dname[256];

		for (i = 1; i < nCars+1; i++) {
			sprintf(dname, "%s/%d", RM_SECT_DRIVERS, i);

			if(strcmp(NETWORKROBOT, GfParmGetStr(reInfo->params, dname, RM_ATTR_MODULE, "")) == 0) {
				if (GetHumanDriver(driver,i) > -1) {
					driver.client = false;
					driver.active = true;
					NetGetServer()->UpdateDriver(driver);
					NetGetServer()->SetDriverName(driver.name);
					GfLogInfo("NetworkRaceInfo: Adding default driver %s\n",driver.name);
				}
			}
		}
	}

	// make sure nobody is 'ready to race'
	NetMutexData *pNData = NetGetNetwork()->LockNetworkData();
	for (unsigned int i=0; i < pNData->m_vecReadyStatus.size(); i++)
		pNData->m_vecReadyStatus[i] = false;
	NetGetNetwork()->UnlockNetworkData();
	bRobotsReady = false;

	// ensure the system knows about 'new' network drivers
	reInfo->params = GfParmReadFileLocal("config/raceman/networkrace.xml",GFPARM_RMODE_REREAD);
	reInfo->_reName = GfParmGetStr(reInfo->params, RM_SECT_HEADER, RM_ATTR_NAME, "");
}
void CarSettingsMenu::onAccept(void *p)
{
	GfCar *pCar = GfCars::self()->getCarWithName(m_strCar);
	NetGetNetwork()->SetCarInfo(pCar->getId().c_str());
	GfuiScreenActivate(pPrevMenu);
}
Ejemplo n.º 21
0
int ReSituationUpdater::threadLoop()
{
	// Wait delay for each loop, from bRunning value (index 0 = false, 1 = true).
	static const unsigned KWaitDelayMS[2] = { 1, (unsigned)(RCM_MAX_DT_SIMU * 1000 / 10) };

	// Termination flag.
	bool bEnd = false;

	// Local state (false = paused, true = simulating).
	bool bRunning = false;

	// Current real time.
	double realTime;
	
	// Apply thread affinity to the current = situation updater thread if specified.
	// Note: No need to reset the affinity, as the thread is just born.
	if (_bThreadAffinity)
		GfSetThreadAffinity(NSituationUpdaterCPUId);

	tRmInfo* pCurrReInfo = ReSituation::self().data();

	GfLogInfo("SituationUpdater thread is started.\n");
	
	do
	{
		// Let's make current step the next one (update).
		// 1) Lock the race engine data.
		ReSituation::self().lock("ReSituationUpdater::threadLoop");

		// 2) Check if time to terminate has come.
		if (_bTerminate)
			
			bEnd = true;
		
		// 3) If not time to terminate, and running, do the update job.
		else if (pCurrReInfo->_reRunning)
		{
			if (!bRunning)
			{
				bRunning = true;
				GfLogInfo("SituationUpdater thread is running.\n");
			}
			
			realTime = GfTimeClock();
		
			GfProfStartProfile("reOneStep*");
		
			while (pCurrReInfo->_reRunning
				   && ((realTime - pCurrReInfo->_reCurTime) > RCM_MAX_DT_SIMU))
			{
				// One simu + robots (if any) step
				runOneStep(RCM_MAX_DT_SIMU);
			}
		
			GfProfStopProfile("reOneStep*");
		
			// Send car physics to network if needed
			if (NetGetNetwork())
				NetGetNetwork()->SendCarControlsPacket(pCurrReInfo->s);
		}
		
		// 3) If not time to terminate, and not running, do nothing.
		else
		{
			if (bRunning)
			{
				bRunning = false;
				GfLogInfo("SituationUpdater thread is paused.\n");
			}
		}
			
		// 4) Unlock the race engine data.
		ReSituation::self().unlock("ReSituationUpdater::threadLoop");
		
		// 5) Let the CPU take breath if possible (but after unlocking data !).
		SDL_Delay(KWaitDelayMS[(int)bRunning]);
	}
	while (!bEnd);

	GfLogInfo("SituationUpdater thread has been terminated.\n");
	
	return 0;
}
Ejemplo n.º 22
0
void ReSituationUpdater::runOneStep(double deltaTimeIncrement)
{
	tRmInfo* pCurrReInfo = ReSituation::self().data();
	tSituation *s = pCurrReInfo->s;

	// Race messages life cycle management.
	ReRaceMsgManage(pCurrReInfo);
	
	if (NetGetNetwork())
	{
		// Resync clock in case computer falls behind
		if (s->currentTime < 0.0)
		{
			s->currentTime = GfTimeClock() - NetGetNetwork()->GetRaceStartTime();
		}

		if (s->currentTime < -2.0)
		{
			std::ostringstream ossMsg;
			ossMsg << "Race will start in " << -(int)s->currentTime << " seconds";
			ReRaceMsgSetBig(pCurrReInfo, ossMsg.str().c_str());
		}
	}

	//GfLogDebug("ReSituationUpdater::runOneStep: currTime=%.3f\n", s->currentTime);
	if (s->currentTime >= -2.0 && s->currentTime < deltaTimeIncrement - 2.0) {
		ReRaceMsgSetBig(pCurrReInfo, "Ready", 1.0);
		GfLogInfo("Ready.\n");
	} else if (s->currentTime >= -1.0 && s->currentTime < deltaTimeIncrement - 1.0) {
		ReRaceMsgSetBig(pCurrReInfo, "Set", 1.0);
		GfLogInfo("Set.\n");
	} else if (s->currentTime >= 0.0 && s->currentTime < deltaTimeIncrement) {
		ReRaceMsgSetBig(pCurrReInfo, "Go", 1.0);
		GfLogInfo("Go.\n");
	}

	// Update times.
	pCurrReInfo->_reCurTime += deltaTimeIncrement * pCurrReInfo->_reTimeMult; /* "Real" time */
	s->currentTime += deltaTimeIncrement; /* Simulated time */

	if (s->currentTime < 0) {
		/* no simu yet */
		pCurrReInfo->s->_raceState = RM_RACE_PRESTART;
	} else if (pCurrReInfo->s->_raceState == RM_RACE_PRESTART) {
		pCurrReInfo->s->_raceState = RM_RACE_RUNNING;
		s->currentTime = 0.0; /* resynchronize */
		pCurrReInfo->_reLastRobTime = 0.0;
	}

	tTrackLocalInfo *trackLocal = &ReInfo->track->local;
	if (s->currentTime > 0 && trackLocal->timeofdayindex == 9) { //RM_VAL_TIME_24HR
		if (s->_totTime > 0) {
			// Scaled on Total Time
			s->accelTime = 24 * 3600 * s->currentTime / s->_totTime;
		} else {
			// Scaled on Number of Laps that the lead driver has completed
			if (s->cars[0]->_laps > 0 && s->cars[0]->_laps <= s->_totLaps) {
				// prevent issues if lead driver crosses line the wrong way
				if (pCurrReInfo->raceEngineInfo.carInfo->lapFlag)
					s->accelTime = s->cars[0]->_laps - 1;
				else
					s->accelTime = s->cars[0]->_laps - 1 + (s->cars[0]->_distFromStartLine / pCurrReInfo->track->length);

				s->accelTime = 24 * 3600 * s->accelTime / s->_totLaps;
			} else
				s->accelTime = 0;
		}
	} else
		s->accelTime = s->currentTime;

	GfProfStartProfile("rbDrive*");
	GfSchedBeginEvent("raceupdate", "robots");
	if ((s->currentTime - pCurrReInfo->_reLastRobTime) >= RCM_MAX_DT_ROBOTS) {
		s->deltaTime = s->currentTime - pCurrReInfo->_reLastRobTime;
		tRobotItf *robot;
		for (int i = 0; i < s->_ncars; i++) {
			if ((s->cars[i]->_state & RM_CAR_STATE_NO_SIMU) == 0) {
				robot = s->cars[i]->robot;
				robot->rbDrive(robot->index, s->cars[i], s);
			}
			else if (! (s->cars[i]->_state & RM_CAR_STATE_ENDRACE_CALLED ) && ( s->cars[i]->_state & RM_CAR_STATE_OUT ) == RM_CAR_STATE_OUT )
			{ // No simu, look if it is out
				robot = s->cars[i]->robot;
				if (robot->rbEndRace)
					robot->rbEndRace(robot->index, s->cars[i], s);
				s->cars[i]->_state |= RM_CAR_STATE_ENDRACE_CALLED;
			}
		}
		pCurrReInfo->_reLastRobTime = s->currentTime;
	}
	GfSchedEndEvent("raceupdate", "robots");
	GfProfStopProfile("rbDrive*");


	if (NetGetNetwork())
		ReNetworkOneStep();

	GfProfStartProfile("physicsEngine.update*");
	GfSchedBeginEvent("raceupdate", "physics");
	RePhysicsEngine().updateSituation(s, deltaTimeIncrement);
	bool bestLapChanged = false;
	for (int i = 0; i < s->_ncars; i++)
		ReCarsManageCar(s->cars[i], bestLapChanged);

	GfSchedEndEvent("raceupdate", "physics");
	GfProfStopProfile("physicsEngine.update*");
	
	ReCarsSortCars();

	// Update results if a best lap changed
	if (pCurrReInfo->_displayMode == RM_DISP_MODE_NONE && s->_ncars > 1 && bestLapChanged)
	{
		if (pCurrReInfo->s->_raceType == RM_TYPE_PRACTICE)
			ReUpdatePracticeCurRes(pCurrReInfo->s->cars[0]);
		else if (pCurrReInfo->s->_raceType == RM_TYPE_QUALIF)
			ReUpdateQualifCurRes(pCurrReInfo->s->cars[0]);
	}
}
Ejemplo n.º 23
0
// Host on-line race menu.
void
RmNetworkHostMenu(void * /* dummy */)
{
	GfLogTrace("Entering Network Host menu.\n");
	
	if (!NetGetNetwork())
	{
		NetSetServer(true);
		NetSetClient(false);
		if (!NetGetServer()->Start(SPEEDDREAMSPORT))
		{
			NetSetServer(false);
			return;
		}
	}

	if (racemanMenuHdle)
		GfuiScreenRelease(racemanMenuHdle);

	racemanMenuHdle = GfuiScreenCreate(NULL,  NULL, (tfuiCallback)OnActivateNetworkHost, 
								   NULL, (tfuiCallback)NULL, 1);

	void *mparam = GfuiMenuLoad("networkhostmenu.xml");

	GfuiMenuCreateStaticControls(racemanMenuHdle, mparam);

	RmSetRacemanMenuHandle(racemanMenuHdle);

	NetworkRaceInfo();

	g_trackHd = GfuiMenuCreateLabelControl(racemanMenuHdle,mparam,"trackname");

	g_lapsHd = GfuiMenuCreateLabelControl(racemanMenuHdle,mparam,"lapcountname");
	g_catHd = GfuiMenuCreateLabelControl(racemanMenuHdle,mparam,"carcatname");
    
	g_OutlineId = GfuiMenuCreateStaticImageControl(racemanMenuHdle,mparam,"outlineimage");
	
	//Show players
	for (int i = 0; i < MAXNETWORKPLAYERS; i++) {
		char buf[1024];
		sprintf(buf,"ready%i",i);
		g_readystatus[i] = GfuiMenuCreateStaticImageControl(racemanMenuHdle,mparam,buf);
		GfuiVisibilitySet(racemanMenuHdle,g_readystatus[i],false);

		sprintf(buf,"driver%i",i);
		g_playerNames[i] = GfuiMenuCreateLabelControl(racemanMenuHdle,mparam,buf);
		GfuiLabelSetText(racemanMenuHdle,g_playerNames[i],"");

		sprintf(buf,"car%i",i);
		g_carNames[i] =  GfuiMenuCreateLabelControl(racemanMenuHdle,mparam,buf);
		GfuiLabelSetText(racemanMenuHdle,g_carNames[i],"");
	}

	g_ReadyCheckboxId =
		GfuiMenuCreateCheckboxControl(racemanMenuHdle, mparam, "playerreadycheckbox",
								NULL, onHostPlayerReady);

	g_HostSettingsButtonId =
		GfuiMenuCreateButtonControl(racemanMenuHdle, mparam, "networkhostsettings",
								racemanMenuHdle, rmNetworkHostSettingsMenu);
	GfuiEnable(racemanMenuHdle, g_HostSettingsButtonId, GFUI_DISABLE);

	g_RaceSetupId =
		GfuiMenuCreateButtonControl(racemanMenuHdle, mparam, "racesetup",
								racemanMenuHdle, RmConfigureRace);

	GfuiMenuCreateButtonControl(racemanMenuHdle, mparam, "start race",
								NULL, ServerPrepareStartNetworkRace);
	g_CancelButtonId = GfuiMenuCreateButtonControl(racemanMenuHdle, mparam, "cancel",
								NULL, rmNetworkServerDisconnect);

	GfParmReleaseHandle(mparam);
	
	GfuiMenuDefaultKeysAdd(racemanMenuHdle);
	GfuiAddKey(racemanMenuHdle, GFUIK_ESCAPE, "Back to previous menu",
								0, 0, rmNetworkServerDisconnect);

	UpdateNetworkPlayers();

	GfuiScreenActivate(racemanMenuHdle);
}