// --------------------------------------------------------------------------- // // // ROUTINE: CTronPlayerObj::AcquireSubroutine // // PURPOSE: A message came telling us to acquire this // // --------------------------------------------------------------------------- // bool CTronPlayerObj::AcquireSubroutine(char const* pName, char const* pState, char const* pCondition) { // Send a message to the client CAutoMessage cMsg; cMsg.Writeuint8(MID_SUBROUTINE_OBTAINED); cMsg.WriteString(pName); if(pState) { // Sanity check if(CheckSubState(pState)) { cMsg.WriteString(pState); } else { // We have a bad subroutine state! // Bad level deisgner... BAD!!! g_pLTServer->CPrint("ERROR - Could not give subroutine to the player with alpha/beta/gold state = (%s). Bad level designer. BAD!!!\n",pState); ASSERT(FALSE); return false; } } else { cMsg.WriteString("ALPHA"); } if(pCondition) { // Sanity check if(CheckSubCondition(pCondition)) { cMsg.WriteString(pCondition); } else { // We have a bad subroutine condition! // Bad level deisgner... BAD!!! g_pLTServer->CPrint("ERROR - Could not give subroutine to the player with condition = (%s). Bad level designer. BAD!!!\n",pCondition); ASSERT(FALSE); return false; } } else { cMsg.WriteString("NORMAL"); } g_pLTServer->SendToClient(cMsg.Read(), GetClient(), MESSAGE_GUARANTEED); return true; }
bool CServerMissionMgr::SendExitLevelMessage( ) { // Tell the players to prepare to exit a level. CPlayerObj::PlayerObjList::const_iterator iter = CPlayerObj::GetPlayerObjList( ).begin( ); while( iter != CPlayerObj::GetPlayerObjList( ).end( )) { CPlayerObj* pPlayerObj = *iter; pPlayerObj->HandlePreExit(); g_pGameServerShell->SendPlayerInfoMsgToClients(NULL,pPlayerObj,MID_PI_UPDATE); iter++; } CTeamMgr::Instance().UpdateClient(); // See if we have already visited the level we are going to. CString sLoadGameFile = g_pServerSaveLoadMgr->GetWorldSaveFile( m_sCurrentWorldName ); bool bRestoringLevel = !!CWinUtil::FileExist( sLoadGameFile ); // Tell client's we're exiting. Wait for their response. CAutoMessage cMsg; cMsg.Writeuint8( MID_EXIT_LEVEL ); cMsg.WriteString( m_sCurrentWorldName ); cMsg.Writebool( m_bNewMission ); cMsg.Writebool( bRestoringLevel ); cMsg.Writebool( true ); g_pLTServer->SendToClient(cMsg.Read(), LTNULL, MESSAGE_GUARANTEED); return true; }
// --------------------------------------------------------------------------- // // // ROUTINE: CTronPlayerObj::AcquirePrimitive // // PURPOSE: A message came telling us to acquire this // // --------------------------------------------------------------------------- // bool CTronPlayerObj::AcquirePrimitive(char const* pName) { // Send a message to the client CAutoMessage cMsg; cMsg.WriteString(pName); g_pLTServer->SendToClient(cMsg, MID_PRIMITIVE_OBTAINED, GetClient(), MESSAGE_GUARANTEED); return true; }
// --------------------------------------------------------------------------- // // // ROUTINE: CTronPlayerObj::AcquireProcedural // // PURPOSE: A message came telling us to acquire this // // --------------------------------------------------------------------------- // bool CTronPlayerObj::AcquireProcedural(char const* pName) { // Send a message to the client CAutoMessage cMsg; cMsg.Writeuint8(MID_PROCEDURAL_OBTAINED); cMsg.WriteString(pName); g_pLTServer->SendToClient(cMsg.Read(), GetClient(), MESSAGE_GUARANTEED); return true; }
bool CServerMissionMgr::ExitLevelToSavedGame( char const* pszNewLevel ) { TRACE( "CServerMissionMgr::ExitLevelToSavedGame\n" ); // Check if we're already exiting a level. if( m_bExitingLevel ) return true; // Verify inputs. if( !pszNewLevel ) { ASSERT( !"CServerMissionMgr::ExitLevelToSavedGame: Invalid inputs." ); return false; } // Default to this not being a mission change. m_bNewMission = false; // Check if the new level is a new mission. int nCurMission = m_nCurrentMission; if( !SetMissionBasedOnLevel( pszNewLevel )) return false; // If we switch to a custom level, then consider it a new mission. if( m_bCustomLevel ) { m_bNewMission = true; m_nCurCampaignIndex = -1; } // If it's not a custom world, check if our mission changed. else { m_bNewMission = ( nCurMission != m_nCurrentMission ); // If we had a mission switch, advance our campaign index. if( m_bNewMission ) { // See if we can find the campaign index from our previous position. m_nCurCampaignIndex = FindNextCampaignIndex( m_nCurCampaignIndex, m_nCurrentMission ); } } if (IsMultiplayerGame()) { // Tell clients we're exiting. Don't wait for their response. CAutoMessage cMsg; cMsg.Writeuint8( MID_EXIT_LEVEL ); cMsg.WriteString( m_sCurrentWorldName ); cMsg.Writebool( m_bNewMission ); cMsg.Writebool( false ); cMsg.Writebool( false ); g_pLTServer->SendToClient(cMsg.Read(), LTNULL, MESSAGE_GUARANTEED); } return true; }
void CAISensorDamageFX::CreateDamageFX( EnumAIDamageFXState eDamageFXState ) { CAutoMessage cMsg; cMsg.Writeuint8( MID_SFX_MESSAGE ); cMsg.Writeuint8( SFX_CHARACTER_ID ); cMsg.WriteObject( m_pAI->m_hObject ); // Kill looping FX, or create looping FX corresponding to level of health. const char* pszFX; std::string strFX = m_pAI->GetAIAttributes()->strName; switch( eDamageFXState ) { case kDamageFX_None: cMsg.WriteBits(CFX_KILL_LOOP_FX_MSG, FNumBitsExclusive<CFX_COUNT>::k_nValue ); break; case kDamageFX_75: strFX += DAMAGE_FX_75; pszFX = g_pAIDB->GetMiscString( strFX.c_str() ); cMsg.WriteBits(CFX_CREATE_LOOP_FX_MSG, FNumBitsExclusive<CFX_COUNT>::k_nValue ); cMsg.WriteString( pszFX ); break; case kDamageFX_50: strFX += DAMAGE_FX_50; pszFX = g_pAIDB->GetMiscString( strFX.c_str() ); cMsg.WriteBits(CFX_CREATE_LOOP_FX_MSG, FNumBitsExclusive<CFX_COUNT>::k_nValue ); cMsg.WriteString( pszFX ); break; case kDamageFX_25: strFX += DAMAGE_FX_25; pszFX = g_pAIDB->GetMiscString( strFX.c_str() ); cMsg.WriteBits(CFX_CREATE_LOOP_FX_MSG, FNumBitsExclusive<CFX_COUNT>::k_nValue ); cMsg.WriteString( pszFX ); break; } g_pLTServer->SendToClient(cMsg.Read(), NULL, MESSAGE_GUARANTEED); }
void PickupItem::CreateSpecialFX( bool bUpdateClients /* = false */ ) { { CAutoMessage cMsg; cMsg.Writeuint8(SFX_PICKUPITEM_ID); cMsg.Writebool(!!m_bRotate); cMsg.Writebool(!!m_bBounce); cMsg.WriteString( m_sClientFX.c_str() ); cMsg.Writeuint8(m_nTeamId); g_pLTServer->SetObjectSFXMessage(m_hObject, cMsg.Read()); } }
bool ScmdServer_Impl::HandleListClients( HCLIENT hClient, ILTMessage_Read& msg ) { float fPing = 0.0f; uint16 nClientID = 0; uint8 aClientIP[4]; uint16 nPort; std::string sPlayerHandle = ""; // Write out the message header. CAutoMessage cMsg; cMsg.Writeuint8( MID_SCMD ); cMsg.Writeuint8( kScmdCommandListClients ); cMsg.Writeuint8( kScmdCommandStatusOk ); // Iterate over all the clients and put their id, ping, ip and name in the message. HCLIENT hIterClient = g_pLTServer->GetNextClient( NULL ); while( hIterClient ) { nClientID = ( uint16 )g_pLTServer->GetClientID( hIterClient ); g_pLTServer->GetClientPing( hIterClient, fPing ); g_pLTServer->GetClientAddr( hIterClient, aClientIP, &nPort ); cMsg.Writeuint16(( uint16 )nClientID ); cMsg.Writeuint16(( uint16 )( fPing + 0.5f )); cMsg.Writeuint8( aClientIP[0] ); cMsg.Writeuint8( aClientIP[1] ); cMsg.Writeuint8( aClientIP[2] ); cMsg.Writeuint8( aClientIP[3] ); // Get the player for this client. If there is none, // then we can't determine the name. CPlayerObj* pPlayerObj = ( CPlayerObj* )g_pLTServer->GetClientUserData( hIterClient ); if( !pPlayerObj ) { sPlayerHandle = ""; } else { sPlayerHandle = pPlayerObj->GetNetUniqueName( ); } cMsg.WriteString( sPlayerHandle.c_str( )); hIterClient = g_pLTServer->GetNextClient( hIterClient ); } // Write out the the list terminator. cMsg.Writeuint16(0xFFFF); SendMessage( hClient, *cMsg ); return true; }
void PickupItem::SetClientFX( const char *pszFX ) { m_sClientFX = pszFX; CAutoMessage cMsg; cMsg.Writeuint8( MID_SFX_MESSAGE ); cMsg.Writeuint8( SFX_PICKUPITEM_ID ); cMsg.WriteObject( m_hObject ); cMsg.Writeuint8( PUFX_CLIENTFX ); cMsg.WriteString( m_sClientFX.c_str() ); g_pLTServer->SendToClient( cMsg.Read(), LTNULL, MESSAGE_GUARANTEED ); CreateSpecialFX( ); }
void CHUDChatInput::Send() { Show(false,false); // Ignore empty messages. if( !m_szChatStr[0] ) return; // First check and see if it was a cheat that was entered... ConParse cParse( m_szChatStr ); if( LT_OK == g_pCommonLT->Parse( &cParse )) { CParsedMsg parsedMsg( cParse.m_nArgs, cParse.m_Args ); if (g_pCheatMgr->Check( parsedMsg )) { g_pClientSoundMgr->PlayInterfaceSound("Interface\\Menu\\Snd\\Cheat.wav"); return; } // Check if this is an scmd command. else if( ScmdConsole::Instance( ).SendParsedCommand( parsedMsg )) { // If it was, it was sent. Don't send chat. return; } } // Send the Message to the server CAutoMessage cMsg; uint8 nMsgID; if (g_pPlayerMgr->GetPlayerState() == PS_GHOST) nMsgID = MID_PLAYER_GHOSTMESSAGE; else nMsgID = MID_PLAYER_MESSAGE; cMsg.Writeuint8(nMsgID); cMsg.WriteString(m_szChatStr); cMsg.Writebool(m_bTeamMessage); g_pLTClient->SendToServer(cMsg.Read(), MESSAGE_GUARANTEED); // cache this string in the chat history for (int i = kMaxChatHistory-1; i > 0; i--) { SAFE_STRCPY(m_szChatHistory[i], m_szChatHistory[i-1]); } SAFE_STRCPY(m_szChatHistory[0], m_szChatStr); }
void SpecialFX::TurnON() { if (!m_bLoop) { // We can turn on (create) non-looping fx as often as we want... ::PlayClientFX(m_sFxName, m_hObject, m_hTargetObj, LTNULL, LTNULL, LTNULL, m_dwFxFlags); if (m_bOneTime) { g_pLTServer->RemoveObject(m_hObject); } if( m_bRemoveTarget ) { g_pLTServer->RemoveObject( m_hTargetObj ); } } else if (!m_bIsOn) { CAutoMessage cMsg; cMsg.Writeuint8( SFX_CLIENTFXGROUP ); cMsg.WriteString( m_sFxName ); cMsg.Writeuint32( m_dwFxFlags ); if( m_hTargetObj ) { cMsg.Writeuint8( true ); cMsg.WriteObject( m_hTargetObj ); LTVector vPos; g_pLTServer->GetObjectPos( m_hTargetObj, &vPos ); cMsg.WriteCompPos( vPos ); } else { cMsg.Writeuint8( false ); } g_pLTServer->SetObjectSFXMessage( m_hObject, cMsg.Read() ); // Set flags so the client knows we are on... g_pCommonLT->SetObjectFlags( m_hObject, OFT_Flags, FLAG_FORCECLIENTUPDATE, FLAG_FORCECLIENTUPDATE ); g_pCommonLT->SetObjectFlags( m_hObject, OFT_User, USRFLG_SFX_ON, USRFLG_SFX_ON ); } m_bIsOn = true; }
void SetObjectClientFXMsg( HOBJECT hObj, char *sName, uint32 dwFlags ) { // [KLS 5/19/02] This really should be depricated, the only place that is // currently using it is the KeyItem and that object really shouldn't be // turning itself into a half-prop/half-special fx mutant. CAutoMessage cMsg; cMsg.Writeuint8( SFX_CLIENTFXGROUP ); cMsg.WriteString( sName ); cMsg.Writeuint32( dwFlags ); // Do not use any target information... cMsg.Writeuint8( false ); g_pLTServer->SetObjectSFXMessage( hObj, cMsg.Read() ); }
bool ScmdServer_Impl::HandleListMissions( HCLIENT hClient, ILTMessage_Read& msg ) { CAutoMessage cMsg; cMsg.Writeuint8( MID_SCMD ); cMsg.Writeuint8( kScmdCommandListMissions ); cMsg.Writeuint8( kScmdCommandStatusOk ); // Write out the current campaign. cMsg.Writeuint8(( uint8 )g_pServerMissionMgr->GetCurrentCampaignIndex( )); Campaign& campaign = g_pServerMissionMgr->GetCampaign( ); // Write out the number of entries. cMsg.Writeuint8( campaign.size( )); // Write out all the missions. char fname[_MAX_FNAME] = ""; for( Campaign::iterator iter = campaign.begin( ); iter != campaign.end( ); iter++ ) { // Get the mission in the campaign. int nMission = *iter; MISSION* pMission = g_pMissionButeMgr->GetMission( nMission ); if( !pMission ) continue; // Show the current level if this is the current mission. int nLevel = 0; if( g_pServerMissionMgr->GetCurrentMission( ) == nMission ) { nLevel = g_pServerMissionMgr->GetCurrentLevel( ); } LEVEL& level = pMission->aLevels[nLevel]; _splitpath( level.szLevel, NULL, NULL, fname, NULL ); cMsg.WriteString( fname ); } // Send the message. SendMessage( hClient, *cMsg ); return true; }
void CDestructibleModel::CreateDestroyedFX(const DamageStruct& DamageInfo) { // If no destroyed fx is specifed, return... if ( LTStrEmpty( m_pszDestroyedFXName ) || !LTStrICmp(m_pszDestroyedFXName, FX_NONE)) return; // Use the position/rotation of the object for the fx... LTRigidTransform tObjTrans; g_pLTServer->GetObjectTransform(m_hObject, &tObjTrans); CAutoMessage cMsg; cMsg.Writeuint8(SFX_CLIENTFXGROUPINSTANT); cMsg.WriteString(m_pszDestroyedFXName); cMsg.Writebool( false ); // loop cMsg.Writebool( false ); // smooth shutdown cMsg.Writebool( false ); // No special parent cMsg.WriteLTVector(tObjTrans.m_vPos); cMsg.WriteCompLTRotation(tObjTrans.m_rRot); cMsg.Writebool( false ); // No target info g_pLTServer->SendSFXMessage(cMsg.Read(), 0); }
bool CMissionMgr::FinishStartGameFromLevel() { m_eStartGameState = eStartGameStarted; // Make sure we have a server started. if( !g_pClientMultiplayerMgr->StartClientServer( )) { g_pInterfaceMgr->LoadFailed( ); return false; } // Send the start game message. if( !SendStartGameMessage( )) return false; // Tell the server to start with this level. CAutoMessage cMsg; cMsg.Writeuint8( MID_START_LEVEL ); cMsg.WriteString( m_sCurrentWorldName ); g_pLTClient->SendToServer( cMsg.Read(), MESSAGE_GUARANTEED ); return true; }
bool ScmdServer_Impl::HandleListBans( HCLIENT hClient, ILTMessage_Read& msg ) { CAutoMessage cMsg; cMsg.Writeuint8( MID_SCMD ); cMsg.Writeuint8( kScmdCommandListBans ); cMsg.Writeuint8( kScmdCommandStatusOk ); char szBannedIP[16] = ""; // Tell client about all the bans. BanIPMgr::BanList const& banList = BanIPMgr::Instance( ).GetBanList( ); cMsg.Writeuint16( banList.size( )); for( BanIPMgr::BanList::const_iterator iter = banList.begin( ); iter != banList.end( ); iter++ ) { BanIPMgr::ClientIP const& clientIP = *iter; BanIPMgr::Instance( ).ConvertClientIPToString( clientIP, szBannedIP, ARRAY_LEN( szBannedIP )); cMsg.WriteString( szBannedIP ); } SendMessage( hClient, *cMsg ); return true; }
// ----------------------------------------------------------------------- // // // ROUTINE: CDebugLineFX::Update // // PURPOSE: Checks for new lines, clients, or a clear line and sends // the data down to any clients. // // ----------------------------------------------------------------------- // void DebugLineSystem::Update() { if( !m_hObject ) return; if( nextLineToSend != lines.end() || m_bClearOldLines ) { // Set up the message. CAutoMessage cMsg; cMsg.Writeuint8( MID_SFX_MESSAGE ); // Record the ID and server object, used to route the message. cMsg.Writeuint8( SFX_DEBUGLINE_ID ); cMsg.WriteObject( m_hObject ); // Record the number of entries. const int num_lines_left = (lines.end() - nextLineToSend); if( num_lines_left < s_MaxLinesPerMessage ) { cMsg.Writeuint16( num_lines_left ); } else { cMsg.Writeuint16( s_MaxLinesPerMessage ); } // Record the maximum number of lines. cMsg.Writeuint32( m_nMaxLines ); // Tell whether we want to clear old lines or not, cMsg.Writeuint8( m_bClearOldLines ); // Record each entry. int num_lines_sent = 0; LTVector system_center(0,0,0); LTFLOAT system_center_count = 0; while( nextLineToSend != lines.end() && num_lines_sent < s_MaxLinesPerMessage) { cMsg.WriteType( *nextLineToSend ); ++nextLineToSend; ++num_lines_sent; } #ifdef LINESYSTEM_DEBUG g_pLTServer->CPrint("Sent %d lines. %d lines left to send.", num_lines_sent, lines.end() - nextLineToSend ); #endif cMsg.WriteString( m_DebugString.c_str() ); // Send the message! g_pLTServer->SendToClient(cMsg.Read(), LTNULL, MESSAGE_GUARANTEED); // If we have cleared out our lines and have no more to send, // why should we exist? if( m_bClearOldLines && lines.empty() ) { char szObjectName[256]; g_pLTServer->GetObjectName(m_hObject, szObjectName, 256); LineSystem::SystemMap::iterator iter = LineSystem::g_systems.find( std::string(szObjectName) ); if( iter != LineSystem::g_systems.end() ) { LineSystem::g_systems.erase(iter); } g_pLTServer->RemoveObject(m_hObject); } // Reset m_bClearOldLines so that we don't re-enter this block. m_bClearOldLines = false; } }
void CTO2GameServerShell::Update(LTFLOAT timeElapsed) { // Update the main server first CGameServerShell::Update(timeElapsed); m_VersionMgr.Update(); if (!GetServerDir()) return; //if we're hosting LANOnly game, don't publish the server if( m_ServerGameOptions.m_bLANOnly ) return; // Are we still waiting? static std::string status; switch (GetServerDir()->GetCurStatus()) { case IServerDirectory::eStatus_Processing : status =""; break; case IServerDirectory::eStatus_Waiting : if (status.empty()) status = GetServerDir()->GetLastRequestResultString(); break; case IServerDirectory::eStatus_Error : { IServerDirectory::ERequest eErrorRequest = GetServerDir()->GetLastErrorRequest(); status = GetServerDir()->GetLastRequestResultString(); GetServerDir()->ProcessRequestList(); } break; }; // Publish the server if we've waited long enough since the last directory update uint32 nCurTime = (uint32)GetTickCount(); if ((m_nLastPublishTime == 0) || ((nCurTime - m_nLastPublishTime) > k_nRepublishDelay)) { status = ""; m_nLastPublishTime = nCurTime; uint32 nMax = 0; g_pLTServer->GetMaxConnections(nMax); // If not run by a dedicated server, we need to add one connection // for the local host. if( !m_ServerGameOptions.m_bDedicated ) nMax++; GetServerDir()->SetActivePeer(0); CAutoMessage cMsg; // Update the summary info cMsg.WriteString(GetHostName()); GetServerDir()->SetActivePeerInfo(IServerDirectory::ePeerInfo_Name, *cMsg.Read()); char fname[_MAX_FNAME] = ""; _splitpath( GetCurLevel(), NULL, NULL, fname, NULL ); // Update the summary info cMsg.WriteString(g_pVersionMgr->GetBuild()); cMsg.WriteString( fname ); cMsg.Writeuint8(GetNumPlayers()); cMsg.Writeuint8(nMax); cMsg.Writebool(m_ServerGameOptions.m_bUsePassword); cMsg.Writeuint8((uint8)GetGameType()); cMsg.WriteString( m_ServerGameOptions.m_sModName.c_str() ); GetServerDir()->SetActivePeerInfo(IServerDirectory::ePeerInfo_Summary, *cMsg.Read()); // Update the details ServerMissionSettings sms = g_pServerMissionMgr->GetServerSettings(); cMsg.Writebool(sms.m_bUseSkills); cMsg.Writebool(sms.m_bFriendlyFire); cMsg.Writeuint8(sms.m_nMPDifficulty); cMsg.Writefloat(sms.m_fPlayerDiffFactor); CPlayerObj* pPlayer = GetFirstNetPlayer(); while (pPlayer) { //has player info cMsg.Writebool(true); cMsg.WriteString(pPlayer->GetNetUniqueName()); cMsg.Writeuint16( Min( GetPlayerPing(pPlayer), ( uint32 )65535 )); pPlayer = GetNextNetPlayer(); }; //end of player info cMsg.Writebool(false); cMsg.Writeuint8(sms.m_nRunSpeed); cMsg.Writeuint8(sms.m_nScoreLimit); cMsg.Writeuint8(sms.m_nTimeLimit); GetServerDir()->SetActivePeerInfo(IServerDirectory::ePeerInfo_Details, *cMsg.Read()); // Update the port char aHostAddr[16]; uint16 nHostPort; g_pLTServer->GetTcpIpAddress(aHostAddr, sizeof(aHostAddr), nHostPort); cMsg.Writeuint16(nHostPort); GetServerDir()->SetActivePeerInfo(IServerDirectory::ePeerInfo_Port, *cMsg.Read()); // Tell serverdir again about info, but in service specific manner. PeerInfo_Service_Titan peerInfo; peerInfo.m_sHostName = GetHostName( ); peerInfo.m_sCurWorld = fname; peerInfo.m_nCurNumPlayers = GetNumPlayers( ); peerInfo.m_nMaxNumPlayers = nMax; peerInfo.m_bUsePassword = m_ServerGameOptions.m_bUsePassword; peerInfo.m_sGameType = GameTypeToString( GetGameType( )); peerInfo.m_nScoreLimit = sms.m_nScoreLimit; peerInfo.m_nTimeLimit = sms.m_nTimeLimit; PeerInfo_Service_Titan::Player player; CPlayerObj::PlayerObjList::const_iterator iter = CPlayerObj::GetPlayerObjList( ).begin( ); while( iter != CPlayerObj::GetPlayerObjList( ).end( )) { CPlayerObj* pPlayerObj = *iter; player.m_sName = pPlayerObj->GetNetUniqueName( ); player.m_nScore = pPlayerObj->GetPlayerScore()->GetScore( ); float fPing; g_pLTServer->GetClientPing( pPlayerObj->GetClient( ), fPing ); player.m_nPing = ( uint16 )( fPing + 0.5f ); peerInfo.m_PlayerList.push_back( player ); iter++; } cMsg.Writeuint32(( uint32 )&peerInfo ); GetServerDir()->SetActivePeerInfo(IServerDirectory::ePeerInfo_Service, *cMsg.Read()); // Tell the world about me... GetServerDir()->QueueRequest(IServerDirectory::eRequest_Publish_Server); } }
// ----------------------------------------------------------------------- // // // ROUTINE: CDebugLineFX::Update // // PURPOSE: Checks for new lines, clients, or a clear line and sends // the data down to any clients. // // ----------------------------------------------------------------------- // void DebugLineSystem::Update() { if( !m_hObject ) return; while( ( !m_lstDebugLines.empty() ) || m_bClearOldLines ) { // Set up the message. CAutoMessage cMsg; cMsg.Writeuint8( MID_SFX_MESSAGE ); // Record the ID and server object, used to route the message. cMsg.Writeuint8( SFX_DEBUGLINE_ID ); cMsg.WriteObject( m_hObject ); // Record the number of entries. int cLines = m_lstDebugLines.size(); if( cLines < s_MaxLinesPerMessage ) { cMsg.Writeuint16( cLines ); } else { cMsg.Writeuint16( s_MaxLinesPerMessage ); } // Tell whether we want to clear old lines or not, cMsg.Writebool( m_bClearOldLines ); cMsg.Writebool( m_bRelative ); // Record each entry. int iLine=0; DEBUG_LINE_LIST::iterator itLine; for( itLine = m_lstDebugLines.begin(); itLine != m_lstDebugLines.end(); ++itLine ) { cMsg.WriteType( *itLine ); ++iLine; if( iLine >= s_MaxLinesPerMessage ) { break; } } m_lstDebugLines.erase( m_lstDebugLines.begin(), itLine ); cMsg.WriteString( m_DebugString.c_str() ); cMsg.WriteLTVector( m_vDebugStringPos ); // Send the message! g_pLTServer->SendToClient(cMsg.Read(), NULL, MESSAGE_GUARANTEED); // If we have cleared out our lines and have no more to send, // why should we exist? if( m_bClearOldLines && ( cLines == 0 ) ) { char szObjectName[256]; g_pLTServer->GetObjectName(m_hObject, szObjectName, LTARRAYSIZE(szObjectName)); LineSystem::SystemMap::iterator iter = LineSystem::g_systems.find( szObjectName ); if( iter != LineSystem::g_systems.end() ) { LineSystem::g_systems.erase(iter); } g_pLTServer->RemoveObject(m_hObject); } // Reset m_bClearOldLines so that we don't re-enter this block. m_bClearOldLines = false; } }