/////////////////////////////////////////////////////////////// // // CModelCacheManagerImpl::OnRestreamModel // // Uncache here, now. // /////////////////////////////////////////////////////////////// void CModelCacheManagerImpl::OnRestreamModel ( ushort usModelId ) { std::map < ushort, SModelCacheInfo >* mapList[] = { &m_PedModelCacheInfoMap, &m_VehicleModelCacheInfoMap }; for ( uint i = 0 ; i < NUMELMS( mapList ) ; i++ ) { std::map < ushort, SModelCacheInfo >& cacheInfoMap = *mapList[i]; SModelCacheInfo* pInfo = MapFind ( cacheInfoMap, usModelId ); if ( pInfo ) { if ( pInfo->bIsModelCachedHere ) { SubModelRefCount ( usModelId ); pInfo->bIsModelCachedHere = false; MapRemove ( cacheInfoMap, usModelId ); OutputDebugLine ( SString ( "[Cache] End caching model %d (OnRestreamModel)", usModelId ) ); } } } // Also check the permo list if ( MapContains ( m_PermoLoadedModels, usModelId ) ) { SubModelRefCount ( usModelId ); MapRemove ( m_PermoLoadedModels, usModelId ); OutputDebugLine ( SString ( "[Cache] End permo-caching model %d (OnRestreamModel)", usModelId ) ); } }
/////////////////////////////////////////////////////////////// // // CSpatialDatabaseImpl::FlushUpdateQueue // // Process all entities that have changed since the last call // /////////////////////////////////////////////////////////////// void CSpatialDatabaseImpl::FlushUpdateQueue ( void ) { int iTotalUpdated = 0; for ( std::map < CElement*, int >::iterator it = m_UpdateQueue.begin (); it != m_UpdateQueue.end (); ++it ) { CElement* pEntity = it->first; // Get the new bounding box SEntityInfo newInfo; CSphere sphere = pEntity->GetWorldBoundingSphere (); newInfo.box = CBox ( sphere.vecPosition, fabsf ( sphere.fRadius ) ); // Make everything 2D for now newInfo.box.vecMin.fZ = SPATIAL_2D_Z; newInfo.box.vecMax.fZ = SPATIAL_2D_Z; // Get previous info if ( SEntityInfo* pOldInfo = MapFind ( m_InfoMap, pEntity ) ) { // Don't update if bounding box is the same if ( pOldInfo->box == newInfo.box ) continue; // Remove old bounding box from tree m_Tree.Remove ( &pOldInfo->box.vecMin.fX, &pOldInfo->box.vecMax.fX, pEntity ); } if ( !IsValidSphere ( sphere ) ) continue; // Add new bounding box m_Tree.Insert( &newInfo.box.vecMin.fX, &newInfo.box.vecMax.fX, pEntity ); // Update info map MapSet ( m_InfoMap, pEntity, newInfo ); iTotalUpdated++; #ifdef SPATIAL_DATABASE_DEBUG_OUTPUTA OutputDebugLine ( SString ( "SpatialDatabase::UpdateEntity %08x %2.0f,%2.0f,%2.0f %2.0f,%2.0f,%2.0f" ,pEntity ,info.box.vecMin.fX ,info.box.vecMin.fY ,info.box.vecMin.fZ ,info.box.vecMax.fX ,info.box.vecMax.fY ,info.box.vecMax.fZ ) ); #endif } m_UpdateQueue.clear (); #ifdef SPATIAL_DATABASE_DEBUG_OUTPUTB int iTotalToUpdate = m_UpdateQueue.size (); if ( iTotalToUpdate ) OutputDebugLine ( SString ( "SpatialDatabase::FlushUpdateQueue TotalToUpdate: %d TotalUpdated: %d m_InfoMap: %d tree: %d ", iTotalToUpdate, iTotalUpdated, m_InfoMap.size (), m_Tree.Count () ) ); #endif }
void DebugDestroyCount ( const SString& strName ) { SDebugCountInfo& info = MapGet ( ms_DebugCountMap, strName ); info.iCount--; if ( info.iCount < 0 ) OutputDebugLine ( SString ( "[InstanceCount] Count is negative (%d) for %s", info.iCount, *strName ) ); }
bool CRegistry::SetLastErrorMessage ( const std::string& strLastErrorMessage, const std::string& strQuery ) { m_strLastErrorMessage = strLastErrorMessage; m_strLastErrorQuery = strQuery; OutputDebugLine ( SString ( "[Database] %s [Query was:%s]", *m_strLastErrorMessage, *m_strLastErrorQuery ) ); return false; }
/////////////////////////////////////////////////////////////// // // CResourceFileDownloadManager::BeginResourceFileDownload // // Return false if file could not be queued // /////////////////////////////////////////////////////////////// bool CResourceFileDownloadManager::BeginResourceFileDownload(CDownloadableResource* pResourceFile, uint uiHttpServerIndex) { if (uiHttpServerIndex >= m_HttpServerList.size()) return false; // Find enabled server while (m_HttpServerList[uiHttpServerIndex].bEnabled == false) { uiHttpServerIndex++; if (uiHttpServerIndex >= m_HttpServerList.size()) return false; } pResourceFile->SetHttpServerIndex(uiHttpServerIndex); const SHttpServerInfo& serverInfo = m_HttpServerList[uiHttpServerIndex]; CNetHTTPDownloadManagerInterface* pHTTP = g_pCore->GetNetwork()->GetHTTPDownloadManager(serverInfo.downloadChannel); SString strHTTPDownloadURLFull("%s/%s/%s", *serverInfo.strUrl, pResourceFile->GetResource()->GetName(), pResourceFile->GetShortName()); SHttpRequestOptions options; options.uiConnectionAttempts = serverInfo.uiConnectionAttempts; options.uiConnectTimeoutMs = serverInfo.uiConnectTimeoutMs; options.bCheckContents = true; options.bIsLocal = g_pClientGame->IsLocalGame(); SString* pstrContext = MakeDownloadContextString(pResourceFile); SString strFilename = pResourceFile->GetName(); bool bUniqueDownload = pHTTP->QueueFile(strHTTPDownloadURLFull, strFilename, pstrContext, StaticDownloadFinished, options); if (!bUniqueDownload) { // TODO - If piggybacking on another matching download, then adjust progress bar OutputDebugLine(SString("[ResourceFileDownload] Using existing download for %s", *strHTTPDownloadURLFull)); } return true; }
/////////////////////////////////////////////////////////////// // // CSpatialDatabaseImpl::SphereQuery // // Return the list of entities that intersect the sphere // /////////////////////////////////////////////////////////////// void CSpatialDatabaseImpl::SphereQuery ( CElementResult& outResult, const CSphere& sphere ) { // Do any pending updates first FlushUpdateQueue (); if ( !IsValidSphere ( sphere ) ) return; // Make a box from the sphere CBox box ( sphere.vecPosition, fabsf ( sphere.fRadius ) ); // Make everything 2D for now box.vecMin.fZ = SPATIAL_2D_Z; box.vecMax.fZ = SPATIAL_2D_Z; // Find all entiites which overlap the box m_Tree.Search( &box.vecMin.fX, &box.vecMax.fX, outResult ); #ifdef SPATIAL_DATABASE_DEBUG_OUTPUTA OutputDebugLine ( SString ( "SpatialDatabase::SphereQuery %d results for %2.0f,%2.0f,%2.0f %2.2f" ,outResult.size () ,sphere.vecPosition.fX ,sphere.vecPosition.fY ,sphere.vecPosition.fZ ,sphere.fRadius ) ); #endif }
//////////////////////////////////////////////////////////////// // // CEffectClonerImpl::MaybeTidyUp // // Tidy up if been a little while since last time // //////////////////////////////////////////////////////////////// void CEffectClonerImpl::MaybeTidyUp ( bool bForceDrasticMeasures, CEffectTemplate* pKeepThis ) { if ( !bForceDrasticMeasures && m_TidyupTimer.Get () < 1000 ) return; m_TidyupTimer.Reset (); // Everything in Old List can go if not being used for ( uint i = 0 ; i < m_OldList.size () ; i++ ) { CEffectTemplate* pEffectTemplate = m_OldList[i]; if ( pEffectTemplate != pKeepThis && pEffectTemplate->GetTicksSinceLastUsed () > ( bForceDrasticMeasures ? 0 : 1 ) ) { OutputDebugLine ( "[Shader] CEffectClonerImpl::MaybeTidyUp: Releasing old EffectTemplate" ); SAFE_RELEASE( pEffectTemplate ); ListRemoveIndex ( m_OldList, i-- ); } } // Complex calculation to guess how long to leave an effect unused before deleting // 0=30 mins 100=25 mins 200=16 mins 300=1 sec float fTicksAlpha = UnlerpClamped ( 0, m_ValidMap.size (), 300 ); int iTicks = static_cast < int > ( ( 1 - fTicksAlpha * fTicksAlpha ) * 30 * 60 * 1000 ) + 1000; #ifdef MTA_DEBUG iTicks /= 60; // Mins to seconds for debug #endif // Valid Effect not used for a little while can go for ( std::map < SString, CEffectTemplate* >::iterator iter = m_ValidMap.begin () ; iter != m_ValidMap.end () ; ) { CEffectTemplate* pEffectTemplate = iter->second; if ( pEffectTemplate != pKeepThis && pEffectTemplate->GetTicksSinceLastUsed () > ( bForceDrasticMeasures ? 0 : iTicks ) ) { OutputDebugLine ( "[Shader] CEffectClonerImpl::MaybeTidyUp: Releasing valid EffectTemplate" ); SAFE_RELEASE( pEffectTemplate ); m_ValidMap.erase ( iter++ ); } else ++iter; } if ( bForceDrasticMeasures ) { CGraphics::GetSingleton().GetDevice()->EvictManagedResources(); } }
long long Get ( void ) { #ifdef _DEBUG if ( m_TimeSinceUpdated.Get () > 10000 ) OutputDebugLine ( "WARNING: UpdateModuleTickCount64 not being called for the current module" ); #endif return m_ResultValue.GetValue (); }
void CPlayer::MovePlayerToNearList ( CPlayer* pOther ) { OutputDebugLine ( SString ( "[Sync] ++ %s: Move %s to nearlist", GetNick (), pOther->GetNick () ) ); dassert ( !MapContains ( m_NearPlayerList, pOther ) && MapContains ( m_FarPlayerList, pOther ) ); SViewerInfo* pInfo = MapFind ( m_FarPlayerList, pOther ); MapSet ( m_NearPlayerList, pOther, *pInfo ); MapRemove ( m_FarPlayerList, pOther ); }
void DebugCreateCount ( const SString& strName ) { SDebugCountInfo& info = MapGet ( ms_DebugCountMap, strName ); info.iCount++; if ( info.iCount > info.iHigh ) { info.iHigh = info.iCount; OutputDebugLine ( SString ( "[InstanceCount] New high of %d for %s", info.iCount, *strName ) ); } }
// // Dynamically increase the interval between near sync updates depending on stuffs // bool CPlayer::IsTimeToReceiveNearSyncFrom ( CPlayer* pOther, SNearInfo& nearInfo ) { int iZone = GetSyncZone ( pOther ); int iUpdateInterval = g_pBandwidthSettings->ZoneUpdateIntervals [ iZone ]; #if MTA_DEBUG if ( m_iLastZoneDebug != iZone ) { // Calc direction from our camera to the other player const CVector& vecOtherPosition = pOther->GetPosition (); CVector vecDirToOther = pOther->GetPosition () - m_vecCamPosition; // Get distance float fDistSq = vecDirToOther.LengthSquared (); // Get angle between camera direction and direction to other vecDirToOther.Normalize (); float fDot = m_vecCamFwd.DotProduct ( &vecDirToOther ); OutputDebugLine ( SString ( "Dist:%1.0f Dot:%0.3f %s SyncTo %s zone changing: %d -> %d [Interval:%d] CamPos:%1.0f,%1.0f,%1.0f CamFwd:%1.2f,%1.2f,%1.2f " ,sqrtf ( fDistSq ) ,fDot ,pOther->GetNick () ,GetNick () ,m_iLastZoneDebug ,iZone ,iUpdateInterval ,m_vecCamPosition.fX ,m_vecCamPosition.fY ,m_vecCamPosition.fZ ,m_vecCamFwd.fX ,m_vecCamFwd.fY ,m_vecCamFwd.fZ ) ); m_iLastZoneDebug = iZone; } #endif long long llTimeNow = GetModuleTickCount64 (); long long llNextUpdateTime = nearInfo.llLastUpdateTime + iUpdateInterval; if ( llNextUpdateTime > llTimeNow ) { g_pStats->puresync.llSkippedPacketsByZone[ iZone ]++; return false; } nearInfo.llLastUpdateTime = llTimeNow; g_pStats->puresync.llSentPacketsByZone[ iZone ]++; return true; }
void SharedUtil::AddReportLog ( uint uiId, const SString& strText ) { SString strPathFilename = PathJoin ( GetMTADataPath (), "report.log" ); MakeSureDirExists ( strPathFilename ); SString strMessage ( "%u: %s %s - %s\n", uiId, GetTimeString ( true, false ).c_str (), GetReportLogHeaderText ().c_str (), strText.c_str () ); FileAppend ( strPathFilename, &strMessage.at ( 0 ), strMessage.length () ); #if MTA_DEBUG OutputDebugLine ( SStringX ( "[ReportLog] " ) + strMessage ); #endif }
//////////////////////////////////////////////////////////////// // // CEffectClonerImpl::CreateD3DEffect // // // //////////////////////////////////////////////////////////////// ID3DXEffect* CEffectClonerImpl::CreateD3DEffect ( const SString& strFilename, const SString& strRootPath, SString& strOutStatus, bool bDebug ) { // Do we have a match with the initial path CEffectTemplate* pEffectTemplate = MapFindRef ( m_ValidMap, ConformPathForSorting ( strFilename ) ); if ( pEffectTemplate ) { // Have files changed since create? if ( pEffectTemplate->HaveFilesChanged () ) { // EffectTemplate is no good for cloning now, so move it to the old list MapRemove ( m_ValidMap, ConformPathForSorting ( strFilename ) ); m_OldList.push_back ( pEffectTemplate ); pEffectTemplate = NULL; } } // Need to create new EffectTemplate? if ( !pEffectTemplate ) { pEffectTemplate = NewEffectTemplate ( m_pManager, strFilename, strRootPath, strOutStatus, bDebug ); if ( !pEffectTemplate->IsValid () ) { SAFE_RELEASE( pEffectTemplate ); return NULL; } OutputDebugLine ( SString ( "[Shader] CEffectClonerImpl::CreateD3DEffect - New EffectTemplate for %s", *strFilename ) ); // Add to active map MapSet ( m_ValidMap, ConformPathForSorting ( strFilename ), pEffectTemplate ); } // // Now we have a valid EffectTemplate to clone the effect from // // Clone D3DXEffect ID3DXEffect* pNewD3DEffect = pEffectTemplate->CloneD3DEffect ( &strOutStatus ); if( !pNewD3DEffect ) { if ( strOutStatus.empty () ) strOutStatus = "Error: Clone failed"; return NULL; } // Cross ref clone with original MapSet ( m_CloneMap, pNewD3DEffect, pEffectTemplate ); // Return result return pNewD3DEffect; }
VOID CModelInfoSA::Request( bool bAndLoad, bool bWaitForLoad, bool bHighPriority ) { DEBUG_TRACE("VOID CModelInfoSA::Request( BOOL bAndLoad, BOOL bWaitForLoad )"); // don't bother loading it if it already is if ( IsLoaded () ) return; if ( m_dwModelID <= 288 && m_dwModelID != 7 && !pGame->GetModelInfo ( 7 )->IsLoaded () ) { // Skin 7 must be loaded in order for other skins to work. No, really. (#4010) pGame->GetModelInfo ( 7 )->Request ( bAndLoad, false ); } // Bikes can sometimes get stuck when loading unless the anim file is handled like what is does here // Don't change the code below unless you can test it (by recreating the problem it solves) if ( IsVehicle () ) { uint uiAnimFileIndex = GetAnimFileIndex (); if ( uiAnimFileIndex != 0xffffffff ) { uint uiAnimId = uiAnimFileIndex + 25575; CModelInfoSA* pAnim = static_cast < CModelInfoSA* > ( pGame->GetModelInfo ( uiAnimId ) ); if ( !pAnim ) LogEvent ( 505, "Model no anim", "", SString ( "%d (%d)", m_dwModelID, uiAnimId ) ); else if ( !pAnim->IsLoaded() ) { OutputDebugLine ( SString ( "[Models] Requesting anim file %d for model %d", uiAnimId, m_dwModelID ) ); pAnim->Sure2Load ( 0x16 ); } } } DWORD dwFlags; if ( bHighPriority ) dwFlags = 0x16; else dwFlags = 6; pGame->GetStreaming()->RequestModel(m_dwModelID, dwFlags); if(bAndLoad) { pGame->GetStreaming()->LoadAllRequestedModels(); if(bWaitForLoad) { Sure2Load ( dwFlags ); } } }
CWebView::~CWebView () { if ( IsMainThread () ) { if ( g_pCore->GetWebCore ()->GetFocusedWebView () == this ) g_pCore->GetWebCore ()->SetFocusedWebView ( nullptr ); } // Ensure that CefRefPtr::~CefRefPtr doesn't try to release it twice (it has already been released in CWebView::OnBeforeClose) m_pWebView = nullptr; #ifdef MTA_DEBUG OutputDebugLine ( "CWebView::~CWebView" ); #endif }
bool CWebCore::UpdateListsFromMaster () { if ( !m_pXmlConfig ) return false; CXMLNode* pRootNode = m_pXmlConfig->GetRootNode (); if ( !pRootNode || !MakeSureXMLNodesExist () ) return false; // Fetch white- and blacklist revision from config CXMLNode* pWhiteRevNode = pRootNode->FindSubNode ( "whitelistrev" ); if ( !pWhiteRevNode || !pWhiteRevNode->GetTagContent ( m_iWhitelistRevision ) ) { m_iWhitelistRevision = 0; } CXMLNode* pBlackRevNode = pRootNode->FindSubNode ( "blacklistrev" ); if ( !pBlackRevNode || !pBlackRevNode->GetTagContent ( m_iBlacklistRevision ) ) { m_iBlacklistRevision = 0; } // Get last update timestamp and compare with current time CXMLNode* pLastUpdateNode = pRootNode->FindSubNode ( "lastupdate" ); if ( pLastUpdateNode ) { SString lastUpdateTime = pLastUpdateNode->GetTagContent (); time_t currentTime; time ( ¤tTime ); if ( lastUpdateTime < SString ( "%d", (long long)currentTime - BROWSER_LIST_UPDATE_INTERVAL ) ) { #ifdef MTA_DEBUG OutputDebugLine ( "Updating white- and blacklist..." ); #endif g_pCore->GetNetwork ()->GetHTTPDownloadManager ( EDownloadModeType::WEBBROWSER_LISTS )->QueueFile ( SString("%s?type=getrev", BROWSER_UPDATE_URL), NULL, 0, NULL, 0, false, this, &CWebCore::StaticFetchRevisionProgress, false, 3 ); pLastUpdateNode->SetTagContent ( SString ( "%d", (long long)currentTime ) ); m_pXmlConfig->Write (); } } return true; }
/////////////////////////////////////////////////////////////// // // CRemoteMasterServer::ParseListVer0 // // Standard Game Monitor reply // /////////////////////////////////////////////////////////////// bool CRemoteMasterServer::ParseListVer0 ( CServerListItemList& itemList ) { CBufferReadStream stream ( m_Data, true ); if ( stream.GetSize () < 2 ) return false; unsigned short usCount = 0; stream.Read ( usCount ); #if MTA_DEBUG uint uiNumServers = usCount; uint uiNumServersUpdated = 0; uint uiNumServersBefore = itemList.size (); #endif while ( !stream.AtEnd ( 6 ) && usCount-- ) { in_addr Address; // IP-address unsigned short usQueryPort; // Query port stream.Read ( Address.S_un.S_un_b.s_b1 ); stream.Read ( Address.S_un.S_un_b.s_b2 ); stream.Read ( Address.S_un.S_un_b.s_b3 ); stream.Read ( Address.S_un.S_un_b.s_b4 ); stream.Read ( usQueryPort ); // Add or find item to update CServerListItem* pItem = GetServerListItem ( itemList, Address, usQueryPort - SERVER_LIST_QUERY_PORT_OFFSET ); if ( pItem->ShouldAllowDataQuality ( SERVER_INFO_ASE_0 ) ) { pItem->SetDataQuality ( SERVER_INFO_ASE_0 ); #if MTA_DEBUG uiNumServersUpdated++; #endif } } #if MTA_DEBUG OutputDebugLine ( SString ( "[Browser] %d servers (%d added, %d updated) from %s", uiNumServers, itemList.size () - uiNumServersBefore, uiNumServersUpdated, *m_strURL ) ); #endif return true; }
//////////////////////////////////////////////////////////////// // // CEffectTemplateImpl::HaveFilesChanged // // Recheck MD5's to see if the content has changed // //////////////////////////////////////////////////////////////// bool CEffectTemplateImpl::HaveFilesChanged ( void ) { if ( !m_bHaveFilesChanged ) { for ( std::map < SString, SString >::const_iterator iter = m_FileMD5Map.begin () ; iter != m_FileMD5Map.end () ; ++iter ) { const SString& strPathFilename = iter->first; const SString& strMD5 = iter->second; SString strNewMD5 = CMD5Hasher::CalculateHexString ( strPathFilename ); if ( strNewMD5 != strMD5 ) { OutputDebugLine ( SString ( "[Shader] %s file has changed from %s to %s", *strPathFilename, *strMD5, *strNewMD5 ) ); m_bHaveFilesChanged = true; } } } return m_bHaveFilesChanged; }
bool CWebCore::StaticFetchBlacklistProgress ( double dDownloadNow, double dDownloadTotal, char* pCompletedData, size_t completedLength, void *pObj, bool bComplete, int iError ) { if ( !bComplete ) return false; CWebCore* pWebCore = static_cast < CWebCore* > ( pObj ); if ( !pWebCore->m_pXmlConfig ) return false; if ( !pWebCore->MakeSureXMLNodesExist () ) return false; CXMLNode* pRootNode = pWebCore->m_pXmlConfig->GetRootNode (); std::vector<SString> blacklist; SString strData = pCompletedData; strData.Split ( ";", blacklist ); CXMLNode* pListNode = pRootNode->FindSubNode ( "globalblacklist" ); if ( !pListNode ) return false; pListNode->DeleteAllSubNodes (); for ( std::vector<SString>::const_iterator iter = blacklist.begin (); iter != blacklist.end (); ++iter ) { CXMLNode* pNode = pListNode->CreateSubNode ( "url" ); pNode->SetTagContent ( *iter ); } // Set blacklist revision CXMLNode* pNode = pRootNode->FindSubNode ( "blacklistrev" ); if ( !pNode ) return false; pNode->SetTagContent ( pWebCore->m_iBlacklistRevision ); // Write changes to the XML file pWebCore->m_pXmlConfig->Write (); pWebCore->LoadListsFromXML ( false, true, false ); #ifdef MTA_DEBUG OutputDebugLine ( "Updated browser blacklist!" ); #endif return true; }
// // Called after a Lua function if post call hook has been installed // void CLuaDefs::DidUseFunction ( lua_CFunction f, lua_State* luaVM ) { // Quick cull of unknown pointer range - Deals with calls from client dll (when the server has been loaded into the same process) if ( CLuaCFunctions::IsNotFunction( f ) ) return; if ( !ms_TimingFunctionStack.empty () ) { // Check if the function used was being timed const STimingFunction& info = ms_TimingFunctionStack.back (); if ( info.f == f ) { // Finish the timing TIMEUS elapsedTime = GetTimeUs() - info.startTime; uint uiDeltaBytes = g_uiNetSentByteCounter - info.uiStartByteCount; // Record timing over a threshold if ( elapsedTime >= CPerfStatFunctionTiming::ms_PeakUsThresh || uiDeltaBytes > 1000 ) { CLuaCFunction* pFunction = CLuaCFunctions::GetFunction ( info.f ); if ( pFunction ) { CResource* pResource = g_pGame->GetResourceManager ()->GetResourceFromLuaState ( info.luaVM ); SString strResourceName = pResource ? pResource->GetName() : "unknown"; CPerfStatFunctionTiming::GetSingleton ()->UpdateTiming ( strResourceName, pFunction->GetName ().c_str (), elapsedTime, uiDeltaBytes ); } } ms_TimingFunctionStack.pop_back (); } } // Check if we should remove the hook if ( !g_pStats->bFunctionTimingActive && !g_pGame->GetDebugHookManager()->HasPostFunctionHooks() ) { ms_TimingFunctionStack.clear (); OutputDebugLine ( "[Lua] Removing PostCallHook" ); assert ( ms_bRegisterdPostCallHook ); ms_bRegisterdPostCallHook = false; lua_registerPostCallHook ( NULL ); } g_pGame->GetDebugHookManager()->OnPostFunction( f, luaVM ); }
void CWebCore::StaticFetchWhitelistFinished ( char* pCompletedData, size_t completedLength, void *pObj, bool bSuccess, int iErrorCode ) { if ( !bSuccess ) return; CWebCore* pWebCore = static_cast < CWebCore* > ( pObj ); if ( !pWebCore->m_pXmlConfig ) return; if ( !pWebCore->MakeSureXMLNodesExist () ) return; CXMLNode* pRootNode = pWebCore->m_pXmlConfig->GetRootNode (); std::vector<SString> whitelist; SString strData = pCompletedData; strData.Split ( ";", whitelist ); CXMLNode* pListNode = pRootNode->FindSubNode ( "globalwhitelist" ); if ( !pListNode ) return; pListNode->DeleteAllSubNodes (); for ( std::vector<SString>::const_iterator iter = whitelist.begin (); iter != whitelist.end (); ++iter ) { CXMLNode* pNode = pListNode->CreateSubNode ( "url" ); pNode->SetTagContent ( *iter ); } // Set whitelist revision CXMLNode* pNode = pRootNode->FindSubNode ( "whitelistrev" ); if ( !pNode ) return; pNode->SetTagContent ( pWebCore->m_iWhitelistRevision ); // Write changes to the XML file pWebCore->m_pXmlConfig->Write (); pWebCore->LoadListsFromXML ( true, false, false ); #ifdef MTA_DEBUG OutputDebugLine ( "Updated whitelist!" ); #endif }
// Assumes CSimControl::UpdatePuresyncSimPlayer is called soon after this function void CPlayer::MovePlayerToFarList ( CPlayer* pOther ) { OutputDebugLine ( SString ( "[Sync] -- %s: Move %s to farlist", GetNick (), pOther->GetNick () ) ); dassert ( MapContains ( m_NearPlayerList, pOther ) && !MapContains ( m_FarPlayerList, pOther ) ); SViewerInfo* pInfo = MapFind ( m_NearPlayerList, pOther ); #ifdef MTA_DEBUG dassert ( MapContains ( m_PureSyncSimSendList, pOther ) == pInfo->bInPureSyncSimSendList ); #endif if ( pInfo->bInPureSyncSimSendList ) { MapRemove ( m_PureSyncSimSendList, pOther ); m_bPureSyncSimSendListDirty = true; pInfo->bInPureSyncSimSendList = false; } MapSet ( m_FarPlayerList, pOther, *pInfo ); MapRemove ( m_NearPlayerList, pOther ); }
// Make sure function refs can't be used after a VM has closed void CLuaFunctionRef::RemoveLuaFunctionRefsForVM( lua_State *luaVM ) { luaVM = lua_getmainstate ( luaVM ); if ( !luaVM ) return; uint uiCount = 0; for ( CIntrusiveList < CLuaFunctionRef >::iterator iter = ms_AllRefList.begin() ; iter != ms_AllRefList.end() ; ++iter ) { CLuaFunctionRef* ref = *iter; // Compare the main state values to see if its the same VM if ( ref->m_luaVM == luaVM ) { uiCount++; luaM_dec_use ( ref->m_luaVM, ref->m_iFunction, ref->m_pFuncPtr ); ref->m_luaVM = NULL; } } if ( uiCount ) OutputDebugLine( SString( "Server RemoveLuaFunctionRefsForVM: zeroed:%d total:%d", uiCount, ms_AllRefList.size() ) ); }
/////////////////////////////////////////////////////////////// // // CCompressorJobQueueImpl::FreeCommand // // Throw away result when this job is done // Returns false if jobHandle not correct // /////////////////////////////////////////////////////////////// bool CCompressorJobQueueImpl::FreeCommand ( CCompressJobData* pJobData ) { if ( MapContains ( m_IgnoreResultList, pJobData ) ) return false; // Already ignoring query handle // if in command or result queue, then put in ignore result list bool bFound; shared.m_Mutex.Lock (); bFound = ListContains ( shared.m_CommandQueue, pJobData ) || ListContains ( shared.m_ResultQueue, pJobData ); shared.m_Mutex.Unlock (); if ( !bFound ) { // Must be in finished list if ( !MapContains ( m_FinishedList, pJobData ) ) OutputDebugLine ( "FreeCommand: Serious problem #2 here\n" ); return false; } IgnoreJobResults ( pJobData ); return true; }
//////////////////////////////////////////////////////////// // // CClientSound::Process3D // // Update position and velocity and pass on the BASS for processing. // m_pAudio->DoPulse needs to be called for non-3D sounds also. // //////////////////////////////////////////////////////////// void CClientSound::Process3D ( const CVector& vecPlayerPosition, const CVector& vecCameraPosition, const CVector& vecLookAt ) { // Update 3D things if required if ( m_b3D ) { // Update our position and velocity if we're attached CClientEntity* pAttachedToEntity = GetAttachedTo (); if ( pAttachedToEntity ) { GetPosition( m_vecPosition ); DoAttaching (); CVector vecVelocity; if ( CStaticFunctionDefinitions::GetElementVelocity ( *pAttachedToEntity, vecVelocity ) ) SetVelocity ( vecVelocity ); // Update our spatial data position UpdateSpatialData (); } } // If the sound isn't active, we don't need to process it // Moved after 3D updating as the streamer didn't know the position changed if a sound isn't streamed in when attached. if ( !m_pAudio ) return; m_pAudio->DoPulse ( vecPlayerPosition, vecCameraPosition, vecLookAt ); // Trigger script events for things SSoundEventInfo eventInfo; while ( m_pAudio->GetQueuedEvent ( eventInfo ) ) { if ( eventInfo.type == SOUND_EVENT_FINISHED_DOWNLOAD ) { CLuaArguments Arguments; Arguments.PushNumber ( eventInfo.dNumber ); CallEvent ( "onClientSoundFinishedDownload", Arguments, true ); OutputDebugLine ( SString ( "[ClientSound] onClientSoundFinishedDownload %f", eventInfo.dNumber ) ); } else if ( eventInfo.type == SOUND_EVENT_CHANGED_META ) { CLuaArguments Arguments; Arguments.PushString ( eventInfo.strString ); CallEvent ( "onClientSoundChangedMeta", Arguments, true ); OutputDebugLine ( SString ( "[ClientSound] onClientSoundChangedMeta %s", *eventInfo.strString ) ); } else if ( eventInfo.type == SOUND_EVENT_STREAM_RESULT ) { // Call onClientSoundStream LUA event CLuaArguments Arguments; Arguments.PushBoolean ( eventInfo.bBool ); Arguments.PushNumber ( eventInfo.dNumber ); if ( !eventInfo.strString.empty () ) Arguments.PushString ( eventInfo.strString ); CallEvent ( "onClientSoundStream", Arguments, true ); OutputDebugLine ( SString ( "[ClientSound] onClientSoundStream %d %f %s", eventInfo.bBool, eventInfo.dNumber, *eventInfo.strString ) ); } else if ( eventInfo.type == SOUND_EVENT_BEAT ) { CLuaArguments Arguments; Arguments.PushNumber ( eventInfo.dNumber ); CallEvent ( "onClientSoundBeat", Arguments, true ); } } }
/////////////////////////////////////////////////////////////// // // CRemoteMasterServer::ParseListVer2 // // Extended reply // /////////////////////////////////////////////////////////////// bool CRemoteMasterServer::ParseListVer2 ( CServerListItemList& itemList ) { CBufferReadStream stream ( m_Data, true ); // Check EOF marker stream.Seek ( stream.GetSize () - 4 ); uint uiEOFMarker = 0; stream.Read ( uiEOFMarker ); if ( uiEOFMarker != 0x12345679 ) return false; // Skip header stream.Seek ( 4 ); // Read flags uint uiFlags = 0; stream.Read ( uiFlags ); //bool bHasAddress = ( uiFlags & ASE_FLAG_ADDRESS ) != 0; //bool bHasPort = ( uiFlags & ASE_FLAG_PORT ) != 0; bool bHasPlayerCount = ( uiFlags & ASE_FLAG_PLAYER_COUNT ) != 0; bool bHasMaxPlayerCount = ( uiFlags & ASE_FLAG_MAX_PLAYER_COUNT ) != 0; bool bHasGameName = ( uiFlags & ASE_FLAG_GAME_NAME ) != 0; bool bHasName = ( uiFlags & ASE_FLAG_NAME ) != 0; bool bHasGameMode = ( uiFlags & ASE_FLAG_GAME_MODE ) != 0; bool bHasMap = ( uiFlags & ASE_FLAG_MAP ) != 0; bool bHasVersion = ( uiFlags & ASE_FLAG_VERSION ) != 0; bool bHasPassworded = ( uiFlags & ASE_FLAG_PASSWORDED ) != 0; bool bHasSerials = ( uiFlags & ASE_FLAG_SERIALS ) != 0; bool bHasPlayers = ( uiFlags & ASE_FLAG_PLAYER_LIST ) != 0; bool bHasRespondingFlag = ( uiFlags & ASE_FLAG_RESPONDING ) != 0; bool bHasRestrictionFlags = ( uiFlags & ASE_FLAG_RESTRICTIONS ) != 0; bool bHasSearchIgnoreSections = ( uiFlags & ASE_FLAG_SEARCH_IGNORE_SECTIONS ) != 0; bool bHasKeepFlag = ( uiFlags & ASE_FLAG_KEEP ) != 0; bool bHasHttpPort = ( uiFlags & ASE_FLAG_HTTP_PORT ) != 0; bool bHasSpecialFlags = ( uiFlags & ASE_FLAG_SPECIAL_FLAGS ) != 0; // Rate quality of data supplied here uint uiDataQuality = SERVER_INFO_ASE_2; if ( bHasSearchIgnoreSections ) uiDataQuality = SERVER_INFO_ASE_2b; // Read sequence number uint uiSequenceNumber = 0; stream.Read ( uiSequenceNumber ); // Read server count uint uiCount = 0; stream.Read ( uiCount ); #if MTA_DEBUG struct SItem { int iTotal; int iNoResponse; }; std::map < SString, SItem > totalMap; uint uiNumServers = uiCount; uint uiNumServersUpdated = 0; uint uiNumServersBefore = itemList.size (); #endif // Add all servers until we hit the count or run out of data while ( !stream.AtEnd ( 6 ) && uiCount-- ) { ushort usLength = 0; // Length of data for this server stream.Read ( usLength ); uint uiSkipPos = stream.Tell () + usLength - 2; in_addr Address; // IP-address unsigned short usGamePort; // Game port stream.Read ( Address.S_un.S_addr ); stream.Read ( usGamePort ); // Add or find item to update CServerListItem* pItem = GetServerListItem ( itemList, Address, usGamePort ); if ( pItem->ShouldAllowDataQuality ( uiDataQuality ) ) { pItem->SetDataQuality ( uiDataQuality ); if ( bHasPlayerCount ) stream.Read ( pItem->nPlayers ); if ( bHasMaxPlayerCount ) stream.Read ( pItem->nMaxPlayers ); if ( bHasGameName ) stream.ReadString ( pItem->strGameName, true ); if ( bHasName ) stream.ReadString ( pItem->strName, true ); if ( bHasGameMode ) stream.ReadString ( pItem->strGameMode, true ); if ( bHasMap ) stream.ReadString ( pItem->strMap, true ); if ( bHasVersion ) stream.ReadString ( pItem->strVersion, true ); if ( bHasPassworded ) stream.Read ( pItem->bPassworded ); if ( bHasSerials ) stream.Read ( pItem->bSerials ); if ( bHasPlayers ) { pItem->vecPlayers.clear (); ushort usPlayerListSize = 0; stream.Read ( usPlayerListSize ); for ( uint i = 0 ; i < usPlayerListSize ; i++ ) { SString strPlayer; stream.ReadString ( strPlayer, true ); pItem->vecPlayers.push_back ( strPlayer ); } } if ( bHasRespondingFlag ) { stream.Read ( pItem->bMasterServerSaysNoResponse ); } if ( bHasRestrictionFlags ) { stream.Read ( pItem->uiMasterServerSaysRestrictions ); } if ( bHasSearchIgnoreSections ) { // Construct searchable name pItem->strSearchableName = pItem->strName; uchar ucNumItems = 0; stream.Read ( ucNumItems ); while ( ucNumItems-- ) { // Read section of name to remove uchar ucOffset = 0; uchar ucLength = 0; stream.Read ( ucOffset ); stream.Read ( ucLength ); for ( uint i = ucOffset ; i < (uint)( ucOffset + ucLength ) ; i++ ) if ( i < pItem->strSearchableName.length () ) pItem->strSearchableName[i] = '\1'; } } if ( bHasKeepFlag ) { uchar ucKeepFlag = 0; stream.Read ( ucKeepFlag ); pItem->bKeepFlag = ucKeepFlag ? true : false; } if ( bHasHttpPort ) { stream.Read ( pItem->m_usHttpPort ); } if ( bHasSpecialFlags ) { stream.Read ( pItem->m_ucSpecialFlags ); } pItem->PostChange (); #if MTA_DEBUG uiNumServersUpdated++; totalMap[ pItem->strVersion ].iTotal += 1; if ( pItem->bMasterServerSaysNoResponse ) totalMap[ pItem->strVersion ].iNoResponse += 1; #endif } // Make sure past all data for this server stream.Seek ( uiSkipPos ); } #if MTA_DEBUG OutputDebugLine ( SString ( "[Browser] %d servers (%d added, %d updated) from %s", uiNumServers, itemList.size () - uiNumServersBefore, uiNumServersUpdated, *m_strURL ) ); for ( std::map < SString, SItem >::iterator iter = totalMap.begin () ; iter != totalMap.end () ; ++iter ) OutputDebugLine ( SString ( "[Browser] version '%s' - %d total %d noresponse", *iter->first, iter->second.iTotal, iter->second.iNoResponse ) ); #endif return true; }
int CLuaDefs::CanUseFunction ( lua_CFunction f, lua_State* luaVM ) { // Quick cull of unknown pointer range if ( CLuaCFunctions::IsNotFunction( f ) ) return true; // Get associated resource CResource* pResource = m_pResourceManager->GetResourceFromLuaState( luaVM ); if ( !pResource ) return true; // Update execution time check pResource->GetVirtualMachine()->CheckExecutionTime(); // Check function right cache in resource bool bAllowed; if ( pResource->CheckFunctionRightCache( f, &bAllowed ) ) { // If in cache, and not allowed, do warning here if ( !bAllowed ) m_pScriptDebugging->LogBadAccess ( luaVM ); } else { // If not in cache, do full check bAllowed = true; // Grab the function name we're calling. If it's one of our functions, see if we can use it. CLuaCFunction* pFunction = CLuaCFunctions::GetFunction ( f ); dassert( pFunction ); if ( pFunction ) { // If it's not one of lua's functions, see if we allow it bAllowed = CLuaDefs::CanUseFunction ( pFunction->GetName ().c_str (), luaVM/*, pResource*/, pFunction->IsRestricted () ); } // Update cache in resource pResource->UpdateFunctionRightCache( f, bAllowed ); } g_pGame->GetDebugHookManager()->OnPreFunction( f, luaVM, bAllowed ); // If not allowed, do no more if ( !bAllowed ) return false; // Check if function timing is active if ( g_pStats->bFunctionTimingActive || g_pGame->GetDebugHookManager()->HasPostFunctionHooks() ) { // Check if hook needs applying if ( !ms_bRegisterdPostCallHook ) { OutputDebugLine ( "[Lua] Registering PostCallHook" ); ms_bRegisterdPostCallHook = true; lua_registerPostCallHook ( CLuaDefs::DidUseFunction ); } // Start to time the function ms_TimingFunctionStack.push_back ( STimingFunction( luaVM, f, GetTimeUs(), g_uiNetSentByteCounter ) ); } return true; }
VOID CModelInfoSA::Request( EModelRequestType requestType, const char* szTag ) { DEBUG_TRACE("VOID CModelInfoSA::Request( BOOL bAndLoad, BOOL bWaitForLoad )"); // don't bother loading it if it already is if ( IsLoaded () ) return; if ( m_dwModelID <= 288 && m_dwModelID != 7 && !pGame->GetModelInfo ( 7 )->IsLoaded () ) { // Skin 7 must be loaded in order for other skins to work. No, really. (#4010) pGame->GetModelInfo ( 7 )->Request ( requestType, "Model 7" ); } // Bikes can sometimes get stuck when loading unless the anim file is handled like what is does here // Don't change the code below unless you can test it (by recreating the problem it solves) if ( IsVehicle () ) { uint uiAnimFileIndex = GetAnimFileIndex (); if ( uiAnimFileIndex != 0xffffffff ) { uint uiAnimId = uiAnimFileIndex + 25575; CModelInfoSA* pAnim = static_cast < CModelInfoSA* > ( pGame->GetModelInfo ( uiAnimId ) ); if ( !pAnim ) { if ( uiAnimId != 25714 ) LogEvent ( 505, "Model no anim", "", SString ( "%d (%d)", m_dwModelID, uiAnimId ) ); } else if ( !pAnim->IsLoaded() ) { OutputDebugLine ( SString ( "[Models] Requesting anim file %d for model %d", uiAnimId, m_dwModelID ) ); pAnim->Request ( requestType, szTag ); } } } if ( requestType == BLOCKING ) { pGame->GetStreaming()->RequestModel ( m_dwModelID, 0x16 ); pGame->GetStreaming()->LoadAllRequestedModels ( true, szTag ); if ( !IsLoaded() ) { // Try 3 more times, final time without high priority flag int iCount = 0; while ( iCount++ < 10 && !IsLoaded() ) { bool bOnlyPriorityModels = ( iCount < 3 || iCount & 1 ); pGame->GetStreaming()->LoadAllRequestedModels ( bOnlyPriorityModels, szTag ); } if ( !IsLoaded() ) { AddReportLog ( 6641, SString ( "Blocking load fail: %d (%s)", m_dwModelID, szTag ) ); LogEvent ( 641, "Blocking load fail", "", SString ( "%d (%s)", m_dwModelID, szTag ) ); dassert ( 0 ); } else { AddReportLog ( 6642, SString ( "Blocking load: %d (%s) (Took %d attempts)", m_dwModelID, szTag, iCount ) ); LogEvent ( 642, "Blocking load", "", SString ( "%d (%s) (Took %d attempts)", m_dwModelID, szTag, iCount ) ); } } } else { pGame->GetStreaming()->RequestModel ( m_dwModelID, 0x06 ); } }
// // Called from the main thread during DoPulse // void CBassAudio::CompleteStreamConnect ( HSTREAM pSound ) { if ( pSound ) { m_pSound = pSound; BASS_ChannelGetAttribute ( pSound, BASS_ATTRIB_FREQ, &m_fDefaultFrequency ); BASS_ChannelSetAttribute ( pSound, BASS_ATTRIB_FREQ, m_fPlaybackSpeed * m_fDefaultFrequency ); if ( !m_b3D ) BASS_ChannelSetAttribute( pSound, BASS_ATTRIB_VOL, m_fVolume ); ApplyFxEffects (); // Set a Callback function for download finished or connection closed prematurely m_hSyncDownload = BASS_ChannelSetSync ( pSound, BASS_SYNC_DOWNLOAD, 0, &DownloadSync, m_uiCallbackId ); SetFinishedCallbacks (); if ( BASS_FX_BPM_CallbackSet ( pSound, (BPMPROC*)&BPMCallback, 1, 0, 0, m_uiCallbackId ) == false ) { g_pCore->GetConsole()->Print ( "BASS ERROR in BASS_FX_BPM_CallbackSet" ); } if ( BASS_FX_BPM_BeatCallbackSet ( pSound, (BPMBEATPROC*)&BeatCallback, m_uiCallbackId ) == false ) { g_pCore->GetConsole()->Print ( "BASS ERROR in BASS_FX_BPM_BeatCallbackSet" ); } // get the broadcast name const char* szIcy; szIcy = BASS_ChannelGetTags ( pSound, BASS_TAG_ICY ); if ( ( szIcy = BASS_ChannelGetTags ( pSound, BASS_TAG_ICY ) ) || ( szIcy = BASS_ChannelGetTags ( pSound, BASS_TAG_WMA ) ) || ( szIcy = BASS_ChannelGetTags ( pSound, BASS_TAG_HTTP ) ) ) { if ( szIcy ) { for ( ; *szIcy; szIcy += strlen ( szIcy ) + 1 ) { if ( !strnicmp ( szIcy, "icy-name:", 9 ) ) // ICY / HTTP { m_strStreamName = szIcy + 9; break; } else if ( !strnicmp ( szIcy, "title=", 6 ) ) // WMA { m_strStreamName = szIcy + 6; break; } //g_pCore->GetConsole()->Printf ( "BASS STREAM INFO %s", szIcy ); } } } // set sync for stream titles m_hSyncMeta = BASS_ChannelSetSync( pSound, BASS_SYNC_META, 0, &MetaSync, m_uiCallbackId ); // Shoutcast //g_pCore->GetConsole()->Printf ( "BASS ERROR %d in BASS_SYNC_META", BASS_ErrorGetCode() ); //BASS_ChannelSetSync(pSound,BASS_SYNC_OGG_CHANGE,0,&MetaSync,this); // Icecast/OGG //g_pCore->GetConsole()->Printf ( "BASS ERROR %d in BASS_SYNC_OGG_CHANGE", BASS_ErrorGetCode() ); //BASS_ChannelSetSync(pSound,BASS_SYNC_WMA_META,0,&MetaSync,this); // script/mid-stream tags //g_pCore->GetConsole()->Printf ( "BASS ERROR %d in BASS_SYNC_WMA_META", BASS_ErrorGetCode() ); //BASS_ChannelSetSync(pSound,BASS_SYNC_WMA_CHANGE,0,&WMAChangeSync,this); // server-side playlist changes //g_pCore->GetConsole()->Printf ( "BASS ERROR %d in BASS_SYNC_WMA_CHANGE", BASS_ErrorGetCode() ); } else g_pCore->GetConsole()->Printf ( "BASS ERROR %d in PlayStream b3D = %s path = %s", BASS_ErrorGetCode(), m_b3D ? "true" : "false", m_strPath.c_str() ); OutputDebugLine ( "[Bass] stream connect complete" ); AddQueuedEvent ( SOUND_EVENT_STREAM_RESULT, m_strStreamName, GetLength (), pSound ? true : false ); }
// // This will return false for non streams if the file is not correct // bool CBassAudio::BeginLoadingMedia ( void ) { assert ( !m_pSound && !m_bPendingPlay ); // Calc the flags long lFlags = BASS_STREAM_AUTOFREE | BASS_SAMPLE_SOFTWARE; #if 0 // Everything sounds better in ste-reo if ( m_b3D ) lFlags |= BASS_SAMPLE_MONO; #endif if ( m_bLoop ) lFlags |= BASS_SAMPLE_LOOP; if ( m_bStream ) { // // For streams, begin the connect sequence // assert ( !m_pVars ); m_pVars = new SSoundThreadVariables (); m_pVars->strURL = m_strPath; m_pVars->lFlags = lFlags; CreateThread ( NULL, 0, reinterpret_cast <LPTHREAD_START_ROUTINE> ( &CBassAudio::PlayStreamIntern ), m_uiCallbackId, 0, NULL ); m_bPendingPlay = true; OutputDebugLine ( "[Bass] stream connect started" ); } else { // // For non streams, try to load the sound file // // First x streams need to be decoders rather than "real" sounds but that's dependent on if we need streams or not so we need to adapt. /* We are the Borg. Lower your shields and surrender your ships. We will add your biological and technological distinctiveness to our own. Your culture will adapt to service us. Resistance is futile. */ long lCreateFlags = BASS_MUSIC_PRESCAN|BASS_STREAM_DECODE; if ( !m_pBuffer ) { m_pSound = BASS_StreamCreateFile ( false, m_strPath, 0, 0, lCreateFlags ); if ( !m_pSound ) m_pSound = BASS_MusicLoad ( false, m_strPath, 0, 0, BASS_MUSIC_RAMP|BASS_MUSIC_PRESCAN|BASS_STREAM_DECODE, 0 ); // Try again if ( !m_pSound && m_b3D ) m_pSound = ConvertFileToMono ( m_strPath ); // Last try if 3D } else { m_pSound = BASS_StreamCreateFile ( true, m_pBuffer, 0, m_uiBufferLength, lCreateFlags ); if ( !m_pSound ) m_pSound = BASS_MusicLoad ( true, m_pBuffer, 0, m_uiBufferLength, lCreateFlags, 0 ); } // Failed to load ? if ( !m_pSound ) { g_pCore->GetConsole()->Printf ( "BASS ERROR %d in LoadMedia path:%s 3d:%d loop:%d", BASS_ErrorGetCode(), *m_strPath, m_b3D, m_bLoop ); return false; } m_pSound = BASS_FX_ReverseCreate ( m_pSound, 2.0f, BASS_STREAM_DECODE | BASS_FX_FREESOURCE | BASS_MUSIC_PRESCAN ); BASS_ChannelSetAttribute ( m_pSound, BASS_ATTRIB_REVERSE_DIR, BASS_FX_RVS_FORWARD ); // Sucks. /*if ( BASS_FX_BPM_CallbackSet ( m_pSound, (BPMPROC*)&BPMCallback, 1, 0, 0, m_uiCallbackId ) == false ) { g_pCore->GetConsole()->Printf ( "BASS ERROR %d in BASS_FX_BPM_CallbackSet path:%s 3d:%d loop:%d", BASS_ErrorGetCode(), *m_strPath, m_b3D, m_bLoop ); }*/ if ( BASS_FX_BPM_BeatCallbackSet ( m_pSound, (BPMBEATPROC*)&BeatCallback, m_uiCallbackId ) == false ) { g_pCore->GetConsole()->Printf ( "BASS ERROR %d in BASS_FX_BPM_BeatCallbackSet path:%s 3d:%d loop:%d", BASS_ErrorGetCode(), *m_strPath, m_b3D, m_bLoop ); } if ( !m_pSound ) { g_pCore->GetConsole()->Printf ( "BASS ERROR %d in BASS_FX_ReverseCreate path:%s 3d:%d loop:%d", BASS_ErrorGetCode(), *m_strPath, m_b3D, m_bLoop ); return false; } m_pSound = BASS_FX_TempoCreate ( m_pSound, lFlags | BASS_FX_FREESOURCE ); if ( !m_pSound ) { g_pCore->GetConsole()->Printf ( "BASS ERROR %d in CreateTempo path:%s 3d:%d loop:%d", BASS_ErrorGetCode(), *m_strPath, m_b3D, m_bLoop ); return false; } BASS_ChannelGetAttribute ( m_pSound, BASS_ATTRIB_TEMPO, &m_fTempo ); BASS_ChannelGetAttribute ( m_pSound, BASS_ATTRIB_TEMPO_PITCH, &m_fPitch ); BASS_ChannelGetAttribute ( m_pSound, BASS_ATTRIB_TEMPO_FREQ, &m_fSampleRate ); // Validation of some sort if ( m_bLoop && BASS_ChannelFlags ( m_pSound, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP ) == -1 ) g_pCore->GetConsole()->Printf ( "BASS ERROR %d in LoadMedia ChannelFlags LOOP path:%s 3d:%d loop:%d", BASS_ErrorGetCode(), *m_strPath, m_b3D, m_bLoop ); BASS_ChannelGetAttribute ( m_pSound, BASS_ATTRIB_FREQ, &m_fDefaultFrequency ); m_bPendingPlay = true; SetFinishedCallbacks (); OutputDebugLine ( "[Bass] sound loaded" ); } return true; }