// BT - 7/15 - Send currently connected players to the CSS webservice.
void CLobbyApp::SendGameInfoToCss()
{
	if (g_pLobbyApp->GetCssGameInfoEnabled() == false)
		return;

	CCssSoap cssSoap(g_pLobbyApp->GetCssServerDomain(), g_pLobbyApp->GetCssClientServicePath(), g_pLobbyApp->GetCssLobbyServicePath(), g_pLobbyApp->GetCssGameDataServicePath());

	std::vector<ConnectedPlayerInfo> connectedPlayers;

	PlayerByName::iterator iterPlayer = m_playerByName.begin();
	while (iterPlayer != m_playerByName.end())
	{
		ConnectedPlayerInfo connectedPlayerInfo;

		char szPlayerName[256];
		Strcpy(connectedPlayerInfo.szPlayerName, (*(*iterPlayer).second).second.GetName());

		FMD_LS_LOBBYMISSIONINFO *missionInfo = (*(*iterPlayer).second).second.GetMission()->GetMissionInfo();
		Strcpy(connectedPlayerInfo.szGameName, FM_VAR_REF(missionInfo, szGameName));
		Strcpy(connectedPlayerInfo.szServerName, FM_VAR_REF(missionInfo, szServerName));
		
		connectedPlayers.push_back(connectedPlayerInfo);

		iterPlayer++;
	}

	if (connectedPlayers.size() > 0)
	{
		cssSoap.SendConnectedPlayerInfo(connectedPlayers);
	}
}
void CFSShip::QueueLoadoutChange(bool bForce)
{
  const PartListIGC*  pplist = GetIGCShip()->GetParts();
  const ShipListIGC*  pslist = GetIGCShip()->GetChildShips();

  BEGIN_PFM_CREATE(g.fm, pfmLoadoutChange, S, LOADOUT_CHANGE)
      FM_VAR_PARM(NULL, GetIGCShip()->ExportShipLoadout(NULL))
      FM_VAR_PARM(NULL, pslist->n() * sizeof(PassengerData))
  END_PFM_CREATE

  GetIGCShip()->ExportShipLoadout((ShipLoadout*)(FM_VAR_REF(pfmLoadoutChange, loadout)));

  pfmLoadoutChange->sidShip = bForce ? NA : GetIGCShip()->GetObjectID();

  //Queue any children and their positions
  {
      PassengerData*   pd = (PassengerData*)(FM_VAR_REF(pfmLoadoutChange, rgPassengers));
      for (ShipLinkIGC*   psl = pslist->first();
           (psl != NULL);
           psl = psl->next())
      {
          pd->shipID = psl->data()->GetObjectID();
          pd->turretID = psl->data()->GetTurretID();

          pd++;
      }
  }
}
示例#3
0
HRESULT LobbyServerSite::OnAppMessage(FedMessaging * pthis, CFMConnection & cnxnFrom, FEDMESSAGE * pfm)
{
  CFLServer * pServer = CFLServer::FromConnection(cnxnFrom);
  assert(pServer);

  cnxnFrom.ResetAbsentCount();

  switch (pfm->fmid)
  {
    case FM_S_LOGON_LOBBY:
    {
      CASTPFM(pfmLogon, S, LOGON_LOBBY, pfm);
	  pfmLogon->cbvStaticCoreInfo;
	  char szRemote[16];
      if (pfmLogon->verLobby == LOBBYVER_LS)
      {
        if(pfmLogon->dwPort != 0)						// A port of 0 means the server couldn't find out its listening port
          pServer->SetServerPort(pfmLogon->dwPort);
        else
          pServer->SetServerPort(6073);				// Tell the client to enum the old fashioned way
		//KGJV #114
		// fill in StaticCoreInfo
		StaticCoreInfo* pcoreinfo  = (StaticCoreInfo*)FM_VAR_REF(pfmLogon, vStaticCoreInfo);
		pServer->SetStaticCoreInfo(pfmLogon->cStaticCoreInfo, pcoreinfo);
		//Imago: reorganized some stuff to get a better debug message		
		// location
		char * szLoc =  FM_VAR_REF(pfmLogon, szLocation);
		pServer->SetLocation(szLoc);
		//Imago #2 6/10
		char * szPrivilegedUsers =  FM_VAR_REF(pfmLogon, szPrivilegedUsers);
		pServer->SetPrivilegedUsers(szPrivilegedUsers);
		//Imago #62 6/10
		char * szVersion =  FM_VAR_REF(pfmLogon, szServerVersion);
		pServer->SetVersion(szVersion);
		// max games
		pServer->SetMaxGamesAllowed(pfmLogon->MaxGames);
		
		// current games (allow servers to update) - Imago 6/25/08
		pServer->SetCurrentGamesCount(pfmLogon->CurGames);

		// rebuild the master core list
		g_pLobbyApp->BuildStaticCoreInfo();
		// break; mmf took out break so we can check ip below
		// KGJV moved mmf's stuff inside lobby version check
		// mmf add check to see if they are an allowed or blocked server

		  pthis->GetIPAddress(cnxnFrom, szRemote);
		  debugf("FM_S_LOGON_LOBBY: %s:%d loc:%s #games:%i\n",&szRemote,pfmLogon->dwPort,pServer->GetLocation(),pfmLogon->CurGames);
		  if (!strncmp("127.0.0.1",szRemote,9)) break;  // check for loopback and always allow
		  if (IsServerAllowed(szRemote)) break;
	  }

	  char * szReason;

	  // if we got this far we are not on the approved list fall through to reject below
	  szReason = "Your server IP address is not approved for connection to this Lobby.  Please contact the Lobby Admin."; //Imago fix typo 6/10
	  // end mmf
	  
      if (pfmLogon->verLobby > LOBBYVER_LS)
        szReason = "The Public Lobby server that you connected to is older than your version.  The Zone needs to update their lobby server.  Please try again later.";
      if (pfmLogon->verLobby < LOBBYVER_LS) // mmf took out the else and made this an explicit if for above szReason
        szReason = "Your server's version did not get auto-updated properly.  Please try again later.";

      BEGIN_PFM_CREATE(*pthis, pfmNewMissionAck, L, LOGON_SERVER_NACK)
          FM_VAR_PARM((char *)szReason, CB_ZTS)
      END_PFM_CREATE
      pthis->SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
      pthis->DeleteConnection(cnxnFrom);
      break;
    }

    case FM_S_NEW_MISSION:
    {
      // a server has created a mission of their own volition. We need to map it into our "cookie space"
      CASTPFM(pfmNewMission, S, NEW_MISSION, pfm);
      CFLMission * pMission = pServer->CreateMission(NULL); // NULL = no client created this
      BEGIN_PFM_CREATE(*pthis, pfmNewMissionAck, L, NEW_MISSION_ACK)
      END_PFM_CREATE
      pfmNewMissionAck->dwIGCMissionID = pfmNewMission->dwIGCMissionID;
      pfmNewMissionAck->dwCookie = (DWORD) pMission;
      pthis->SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
      // we won't broadcast it until the server sends us a lobby mission info, when it's good and ready
	  debugf("FM_S_NEW_MISSION id:%d cookie:%d\n",pfmNewMissionAck->dwIGCMissionID,pfmNewMissionAck->dwCookie);
    }
    break;

    case FM_LS_LOBBYMISSIONINFO:
    {
      CASTPFM(pfmLobbyMissionInfo, LS, LOBBYMISSIONINFO, pfm);
      CFLMission * pMission = CFLMission::FromCookie(pfmLobbyMissionInfo->dwCookie);
      if (pMission) // if it's already gone away--just ignore it. 
      {		  
		  //Imago 6/26/08
		  //Moved this code inside the mission check
		  //now the lobby does not crash trying to find a disconnected server's IP


			//KGJV #114 - server didnt fill szServerAddr but only reserved the bits. We fill it here.
			debugf("FM_LS_LOBBYMISSIONINFO:%d (pmission:%x cookie:%x) sent cookie:%x connected?%i\n",pfmLobbyMissionInfo->dwPort,pMission,pfmLobbyMissionInfo->dwCookie,pfmLobbyMissionInfo->dwCookie,(pthis->IsConnected()) ? 1 : 0);  
			char szAddr[16];
			pthis->GetIPAddress(cnxnFrom, szAddr); // get the real addr
			debugf("\tFM_LS_LOBBYMISSIONINFO:%s sent port %d\n",&szAddr,pfmLobbyMissionInfo->dwPort);		
			char *pfmdata = FM_VAR_REF(pfmLobbyMissionInfo, szServerAddr); // get the addr in the message	  
			Strcpy(pfmdata,szAddr); // overwrite with the real addr

			//end move code

        pMission->SetLobbyInfo(pfmLobbyMissionInfo);
        pMission->NotifyCreator();
      }
      // else TODO: do something about waiting client, if there is one
    }
    break;

    case FM_LS_MISSION_GONE:
    {
      CASTPFM(pfmMissionGone, LS, MISSION_GONE, pfm);
      CFLMission * pMission = CFLMission::FromCookie(pfmMissionGone->dwCookie);
	  debugf("deleting GONE mission: %x\n",pfmMissionGone->dwCookie);
      pServer->DeleteMission(pMission);
    }
    break;

    case FM_S_HEARTBEAT:
      // don't boot for missing roll call until we get one from them
      pServer->SetHere();
    break;
    
    case FM_S_PLAYER_JOINED:
    {
      CASTPFM(pfmPlayerJoined, S, PLAYER_JOINED, pfm);
      CFLMission * pMission = CFLMission::FromCookie(pfmPlayerJoined->dwMissionCookie);
      const char* szCharacterName = FM_VAR_REF(pfmPlayerJoined, szCharacterName);
      const char* szCDKey = FM_VAR_REF(pfmPlayerJoined, szCDKey);

      if (NULL == szCharacterName || '\0' != szCharacterName[pfmPlayerJoined->cbszCharacterName-1])
          /* || NULL == szCDKey || '\0' != szCDKey[pfmPlayerJoined->cbszCDKey-1]  
		  Imago 6/25/08 removed above
		  */ 
      {
        // corrupt data
        g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_ERROR_TYPE, LE_CorruptPlayerJoinMsg,
          cnxnFrom.GetName());
      }
      else if (NULL == pMission)
      {
        // the requested game does not exist
        g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_WARNING_TYPE, LE_PlayerJoinInvalidMission,
          szCharacterName, cnxnFrom.GetName(), pfmPlayerJoined->dwMissionCookie);
      }
      else
      {
        if (g_pLobbyApp->EnforceCDKey())
        {
          char * szUnencryptedCDKey = (char*)_alloca(strlen(szCDKey) + 1);
          ZUnscramble(szUnencryptedCDKey, szCDKey, szCharacterName);

          szCDKey = szUnencryptedCDKey;
        }

        g_pLobbyApp->SetPlayerMission(szCharacterName, szCDKey, pMission);
      }
    }
    break;

    case FM_S_PLAYER_QUIT:
    {
      CASTPFM(pfmPlayerQuit, S, PLAYER_QUIT, pfm);
      CFLMission * pMission = CFLMission::FromCookie(pfmPlayerQuit->dwMissionCookie);
      const char* szCharacterName = FM_VAR_REF(pfmPlayerQuit, szCharacterName);

      if (NULL == szCharacterName || '\0' != szCharacterName[pfmPlayerQuit->cbszCharacterName-1])
      {
        // corrupt data
        g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_ERROR_TYPE, LE_CorruptPlayerQuitMsg,
          cnxnFrom.GetName());
      }
      else
        g_pLobbyApp->RemovePlayerFromMission(szCharacterName, pMission);
    }
    break;

    case FM_S_PAUSE:
    {
      CASTPFM(pfmPause, S, PAUSE, pfm);
      pServer->Pause(pfmPause->fPause);
	  // KGJV #114 cant create game on paused server
      g_pLobbyApp->BuildStaticCoreInfo();
      break;
    }      

    default:
      ZError("unknown message\n");
  }
  return S_OK;
}
示例#4
0
HRESULT FedSrvLobbySite::OnAppMessage(FedMessaging * pthis, CFMConnection & cnxnFrom, FEDMESSAGE * pfm)
{
	HRESULT hr = S_OK;
	assert(&g.fmLobby == pthis);

	static CTempTimer timerOnAppMessage("in FedSrvLobbySite::OnAppMessage", .02f);
	timerOnAppMessage.Start();

	switch (pfm->fmid)
	{
		// KGJV #114 - reactivate create mission
	  //#if !defined(ALLSRV_STANDALONE)
	case FM_L_CREATE_MISSION_REQ:
	{
#if !defined(SRV_CHILD)
		CASTPFM(pfmCreateMissionReq, L, CREATE_MISSION_REQ, pfm);
		MissionParams mp;
		Strcpy(mp.strGameName, ZString(FM_VAR_REF(pfmCreateMissionReq, GameName)));// + "'s game");
		Strcpy(mp.szIGCStaticFile, ZString(FM_VAR_REF(pfmCreateMissionReq, IGCStaticFile)));
		mp.bScoresCount = false;// dont set to true till clients can change this!
		mp.iMaxImbalance = 0x7ffe;// added
		assert(!mp.Invalid());
#endif

		//Imago - give birth right here, feed it and off it goes...

#if defined(SRV_PARENT)
		//start missions as thier own process
		STARTUPINFO si;
		PROCESS_INFORMATION pi;
		ZeroMemory(&si, sizeof(si));
		si.cb = sizeof(si);
		ZeroMemory(&pi, sizeof(pi));
		char szCmd[255]; char szName[32]; char szFile[32];
		ZString strName = mp.strGameName;
		ZString strFile = mp.szIGCStaticFile;
		si.lpTitle = mp.strGameName;
		Strcpy(szName, (PCC)strName);
		Strcpy(szFile, (PCC)strFile);
		sprintf(szCmd, "AllSrv.exe \"%s\" %s %x", szName, szFile, pfmCreateMissionReq->dwCookie);

		// Create a NULL dacl to give "everyone" access
		SECURITY_DESCRIPTOR sd;
		SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, false };
		InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
		SetSecurityDescriptorDacl(&sd, true, NULL, FALSE);

		if (!CreateProcess(
			NULL,                   // No module name (use command line). 
			szCmd,
			NULL,
			NULL,
			FALSE,                  // Set handle inheritance to FALSE. 
			CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, // we're destined to do amazing things
			NULL,                   // Use parent's environment block. 
			NULL,                   // Use parent's starting directory. 
			&si,                    // Pointer to STARTUPINFO structure.
			&pi)                   // Pointer to PROCESS_INFORMATION structure.
			)
		{
			debugf("CreateProcess failed (%d).\n", GetLastError());
		}

		// check to make sure the child is ready before restart
		char strFilename[10] = "\0";
		sprintf(strFilename, "%d.pid", pi.dwProcessId);
		HANDLE hFile = (HANDLE)CreateFile(strFilename, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
		DWORD dwError = GetLastError();
		int i = 0;
		while (hFile == INVALID_HANDLE_VALUE || dwError == ERROR_FILE_NOT_FOUND) {
			if (i >= 14) //30s
				break;

			Sleep(2500);
			hFile = (HANDLE)CreateFile(strFilename, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
			dwError = GetLastError();
			i++;
		}
		_Module.AddPID(pi.dwProcessId);
		CloseHandle(hFile);
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
		g.bRestarting = true;
		PostQuitMessage(0);

#endif 

#if !defined(SRV_CHILD)
#if !defined(SRV_PARENT)
		// pkk 2011-07-24 - Create games only with IGCs from cores.txt
		bool ValidCore = false;
		for (int i = 0; i < g.cStaticCoreInfo; i++)
		{
			if (!strcmpi(mp.szIGCStaticFile, g.vStaticCoreInfo[i].cbIGCFile))
			{
				ValidCore = true;
				break; // quit loop
			}
		}
		if (ValidCore == true)
		{
			//Imago - start the mission in this thread as usual 
			FedSrvSite * psiteFedSrv = new FedSrvSite();
			CFSMission * pfsMissionNew = new CFSMission(mp, "", psiteFedSrv, psiteFedSrv, NULL, NULL);
			pfsMissionNew->SetCookie(pfmCreateMissionReq->dwCookie);
		}
		else
		{
			debugf("Lobby sent invalid core information %s, ignoring message\n", mp.szIGCStaticFile);
		}
		// pkk end
#endif
#endif
	} //Imago 6/22/08
	break;
	//#endif -- reactivate create mission

	case FM_L_NEW_MISSION_ACK:
	{
		CASTPFM(pfmNewMissionAck, L, NEW_MISSION_ACK, pfm);
		CFSMission * pfsm = CFSMission::GetMissionFromIGCMissionID(pfmNewMissionAck->dwIGCMissionID);
		if (pfsm)
		{
			pfsm->SetCookie(pfmNewMissionAck->dwCookie);
			// If we already have players (e.g. reconnect), tell the lobby who's in the game
			const ShipListIGC * plistShip = pfsm->GetIGCMission()->GetShips();
			for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
			{
				IshipIGC * pShip = plinkShip->data();
				CFSShip * pfsShip = GETFSSHIP(pShip);
				if (pfsShip->IsPlayer() && !pShip->IsGhost())
				{
					CFSPlayer* pfsPlayer = pfsShip->GetPlayer();
					BEGIN_PFM_CREATE(g.fmLobby, pfmPlayerJoined, S, PLAYER_JOINED)
						FM_VAR_PARM(pfsPlayer->GetName(), CB_ZTS)
						END_PFM_CREATE
						pfmPlayerJoined->dwMissionCookie = pfsm->GetCookie();
				}
			}
			HRESULT hr = pthis->SendMessages(pthis->GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
		}
	}
	break;

	case FM_L_TOKEN:
	{
		CASTPFM(pfmToken, L, TOKEN, pfm);
		Strcpy(g.m_szToken, FM_VAR_REF(pfmToken, Token));
	}
	break;

	case FM_L_REMOVE_PLAYER:
	{
		CASTPFM(pfmRemovePlayer, L, REMOVE_PLAYER, pfm);
		CFSMission * pfsMission = CFSMission::GetMission(pfmRemovePlayer->dwMissionCookie);
		const char* szCharacterName = FM_VAR_REF(pfmRemovePlayer, szCharacterName);
		const char* szMessageParam = FM_VAR_REF(pfmRemovePlayer, szMessageParam);

		// try to find the player in question
		if (!pfsMission)
		{
			debugf("Asked to boot character %s from mission %x by lobby, "
				"but the mission was not found.\n",
				szCharacterName, pfmRemovePlayer->dwMissionCookie);
		}
		else if (!pfsMission->RemovePlayerByName(szCharacterName,
			(pfmRemovePlayer->reason == RPR_duplicateCDKey) ? QSR_DuplicateCDKey : QSR_DuplicateRemoteLogon,
			szMessageParam))
		{
			debugf("Asked to boot character %s from mission %x by lobby, "
				"but the character was not found.\n",
				szCharacterName, pfmRemovePlayer->dwMissionCookie);
		}
	}
	break;

	case FM_L_LOGON_SERVER_NACK:
	{
		char * szReason;

		CASTPFM(pfmLogonNack, L, LOGON_SERVER_NACK, pfm);

		szReason = FM_VAR_REF(pfmLogonNack, Reason);

		OnMessageBox(pthis, szReason ? szReason : "Error while try to log onto server.", "Allegiance Server Error", MB_SERVICE_NOTIFICATION);
		// TODO: consider firing out an event message
		PostQuitMessage(-1);
	}

	// BT - 12/21/2010 ACSS - The lobby server will relay the rank details back to the game server.
	case FM_LS_PLAYER_RANK:
	{
		CQLogonStats * pquery = new CQLogonStats(GotLogonDetails);
		CQLogonStatsData * pqd = pquery->GetData();

		CASTPFM(pfmPlayerRank, LS, PLAYER_RANK, pfm);

		Strcpy(pqd->szCDKey, FM_VAR_REF(pfmPlayerRank, szCDKey));
		Strcpy(pqd->szCharacterName, FM_VAR_REF(pfmPlayerRank, szCharacterName));
		Strcpy(pqd->szPassword, FM_VAR_REF(pfmPlayerRank, szPassword));
		Strcpy(pqd->szReason, FM_VAR_REF(pfmPlayerRank, szReason));

		pqd->characterID = pfmPlayerRank->characterID;
		pqd->fCanCheat = pfmPlayerRank->fCanCheat;
		pqd->fRetry = pfmPlayerRank->fRetry;
		pqd->dwCookie = pfmPlayerRank->dwCookie;
		pqd->fValid = pfmPlayerRank->fValid;
		pqd->dwConnectionID = pfmPlayerRank->dwConnectionID;

		pqd->rank = pfmPlayerRank->rank;
		pqd->sigma = pfmPlayerRank->sigma;
		pqd->mu = pfmPlayerRank->mu;
		pqd->commandRank = pfmPlayerRank->commandRank;
		pqd->commandSigma = pfmPlayerRank->commandSigma;
		pqd->commandMu = pfmPlayerRank->commandMu;

		PostThreadMessage(g.idReceiveThread, wm_sql_querydone, (WPARAM)NULL, (LPARAM)pquery);
		break;
	}

	break;
	}

	timerOnAppMessage.Stop("...for message type %s\n", g_rgszMsgNames[pfm->fmid]);
	return hr;
}
//This should only be called from the ChangeCluster() callback.
void CFSPlayer::SetCluster(IclusterIGC* pcluster, bool bViewOnly)
{
  CFSShip::SetCluster(pcluster, bViewOnly);

  if (pcluster)
  {
    SetDPGroup((CFSCluster*)(pcluster->GetPrivateData()), true);

    IshipIGC*   pshipParent = GetIGCShip()->GetParentShip();
    if ((pshipParent == NULL) || bViewOnly)
    {
        ShipID      shipID = GetIGCShip()->GetObjectID();
        assert(0 == g.fm.CbUsedSpaceInOutbox());
        if (!bViewOnly)
        {
            //Move the player to his destination
            BEGIN_PFM_CREATE(g.fm, pfmSetCluster, S, SET_CLUSTER)
            END_PFM_CREATE
            pfmSetCluster->sectorID = pcluster->GetObjectID();

            //Send the position of the parent ship if we are a child, otherwise our position
            IshipIGC*   pshipSource = pshipParent ? pshipParent : GetIGCShip();
            pshipSource->ExportShipUpdate(&(pfmSetCluster->shipupdate));
            pfmSetCluster->cookie = NewCookie();
        }

        {
            for (ShipLinkIGC*   pshiplink = pcluster->GetShips()->first(); pshiplink; pshiplink = pshiplink->next())
            {
                IshipIGC * pshipExist = pshiplink->data();
                if ((pshipExist != GetIGCShip()) && (pshipExist != pshipParent))
                {
                  IshipIGC*   pshipExistParent = pshipExist->GetParentShip();

                  //Tell the new player where the existing ship is/was
                  //provided the existing ship is not the child of some other ship
                  //and is not the parent of the new ship
                  if (pshipExistParent == NULL) 
                  {
                    CFSShip * pfsShipExist = (CFSShip *) pshipExist->GetPrivateData();

                    pfsShipExist->QueueLoadoutChange();

                    BEGIN_PFM_CREATE(g.fm, pfmSSU, S, SINGLE_SHIP_UPDATE)
                    END_PFM_CREATE

                    //Always use the ship update based on the server's current view of the universe
                    //(this shouldn't be a lot worse than anything the player sent and it is easier)
                    pshipExist->ExportShipUpdate(&(pfmSSU->shipupdate));

                    {
                        ImodelIGC*  pmodelTarget = pshipExist->GetCommandTarget(c_cmdCurrent);
                        if (pmodelTarget)
                        {
                            pfmSSU->otTarget = pmodelTarget->GetObjectType();
                            pfmSSU->oidTarget = pmodelTarget->GetObjectID();
                        }
                        else
                        {
                            pfmSSU->otTarget = NA;
                            pfmSSU->oidTarget = NA;
                        }                    
                    }
                    pfmSSU->bIsRipcording = pshipExist->fRipcordActive();
                  }
                }
            }
        }

        {
            // Let's build up a list of station updates so we can batch 'em down
            IsideIGC* pside = GetIGCShip()->GetSide();

            {
                const StationListIGC * pstnlist = pcluster->GetStations();
                int nStations = 0;
                {
                    //Count the number of visible stations
                    for (StationLinkIGC* pstnlink = pstnlist->first(); pstnlink; pstnlink = pstnlink->next())
                    {
                        IstationIGC*  pstation = pstnlink->data();
                        if (pstation->SeenBySide(pside))
                            nStations++;
                    }
                }

                if (nStations != 0)
                {
                    // tell the client what happened
                    BEGIN_PFM_CREATE(g.fm, pfmStationsUpdate, S, STATIONS_UPDATE)
                      FM_VAR_PARM(NULL, nStations * sizeof(StationState))
                    END_PFM_CREATE

                    StationState* pss = (StationState*)(FM_VAR_REF(pfmStationsUpdate, rgStationStates));
                    for (StationLinkIGC* pstnlink = pstnlist->first(); pstnlink; pstnlink = pstnlink->next())
                    {
                        IstationIGC * pstation = pstnlink->data();
                        if (pstation->SeenBySide(pside))
                        {
                            pss->stationID            = pstation->GetObjectID();
                            pss->bpHullFraction       = pstation->GetFraction();
                            (pss++)->bpShieldFraction = pstation->GetShieldFraction();
                        }
                    }
                }
            }

            {
                //Let's build up a list of probe updates and batch them on down (only damage & visible probes)
                const ProbeListIGC * pprblist = pcluster->GetProbes();
                int nProbes = 0;
                {
                    for (ProbeLinkIGC* pprblink = pprblist->first(); pprblink; pprblink = pprblink->next())
                    {
                        if (pprblink->data()->SeenBySide(pside))
                            nProbes++;
                    }
                }

                if (nProbes != 0)
                {
                    BEGIN_PFM_CREATE(g.fm, pfmProbesUpdate, S, PROBES_UPDATE)
                      FM_VAR_PARM(NULL, nProbes * sizeof(ProbeState))
                    END_PFM_CREATE

                    ProbeState* pps = (ProbeState*)(FM_VAR_REF(pfmProbesUpdate, rgProbeStates));
                    for (ProbeLinkIGC* pprblink = pprblist->first(); pprblink; pprblink = pprblink->next())
                    {
                        IprobeIGC * pprobe = pprblink->data();

                        if (pprobe->SeenBySide(pside))
                        {
                            pps->probeID        = pprobe->GetObjectID();
                            (pps++)->bpFraction = pprobe->GetFraction();
                        }
                    }
                }
            }

            {
                //Let's build up a list of asteroid updates and batch them on down
                const AsteroidListIGC * pastlist = pcluster->GetAsteroids();
                int nAsteroids = 0;
                {
                    for (AsteroidLinkIGC* pastlink = pastlist->first(); pastlink; pastlink = pastlink->next())
                    {
                        if (pastlink->data()->SeenBySide(pside))
                            nAsteroids++;
                    }
                }

                if (nAsteroids != 0)
                {
                    BEGIN_PFM_CREATE(g.fm, pfmAsteroidsUpdate, S, ASTEROIDS_UPDATE)
                      FM_VAR_PARM(NULL, nAsteroids * sizeof(AsteroidState))
                    END_PFM_CREATE

                    AsteroidState* pas = (AsteroidState*)(FM_VAR_REF(pfmAsteroidsUpdate, rgAsteroidStates));
                    for (AsteroidLinkIGC* pastlink = pastlist->first(); pastlink; pastlink = pastlink->next())
                    {
                        IasteroidIGC * pasteroid = pastlink->data();

                        if (pasteroid->SeenBySide(pside))
                        {
                            pas->asteroidID         = pasteroid->GetObjectID();
                            pas->ore                = short(pasteroid->GetOre());
                            pas->co.Set(pasteroid->GetOrientation());
                            (pas++)->bpFraction     = pasteroid->GetFraction();
                        }
                    }
                }
            }
        }
    
        //Also send the identical message to all of the ship's children]
		if (!bViewOnly) //TheRock 4-1-2010 fixed ships overlaying in f3 while on a turret
        {
            for (ShipLinkIGC*   psl = GetIGCShip()->GetChildShips()->first(); (psl != NULL); psl = psl->next())
            {
                CFSShip*    pfsShip = (CFSShip*)(psl->data()->GetPrivateData());
                assert (pfsShip->IsPlayer());
                pfsShip->GetPlayer()->ResetLastUpdate();
                g.fm.SendMessages(pfsShip->GetPlayer()->GetConnection(), FM_GUARANTEED, FM_DONT_FLUSH);
            }
        }
        g.fm.SendMessages(GetConnection(), FM_GUARANTEED, FM_FLUSH);
    }
  }
  else if (bViewOnly)
  {
    IstationIGC*    pstation = GetIGCShip()->GetStation();
    assert (pstation);

    CFSCluster*     pfsCluster = (CFSCluster*)(pstation->GetCluster()->GetPrivateData());
    SetDPGroup(pfsCluster, false);
  }
  else
    SetDPGroup(NULL, false);
}