Torque3D Documentation / _generateds / assetManager.cpp

assetManager.cpp

Engine/source/assets/assetManager.cpp

More...

Public Variables

Detailed Description

Public Variables

AssetManager AssetDatabase 

Public Functions

descendingAssetDefinitionLoadCount(const void * a, const void * b)

IMPLEMENT_CONOBJECT(AssetManager )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2013 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "assetManager.h"
  25
  26#ifndef _ASSET_PTR_H_
  27#include "assetPtr.h"
  28#endif
  29
  30#ifndef _REFERENCED_ASSETS_H_
  31#include "assets/referencedAssets.h"
  32#endif
  33
  34#ifndef _DECLARED_ASSETS_H_
  35#include "assets/declaredAssets.h"
  36#endif
  37
  38#ifndef _TAML_ASSET_REFERENCED_VISITOR_H_
  39#include "tamlAssetReferencedVisitor.h"
  40#endif
  41
  42#ifndef _TAML_ASSET_DECLARED_VISITOR_H_
  43#include "tamlAssetDeclaredVisitor.h"
  44#endif
  45
  46#ifndef _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_
  47#include "tamlAssetDeclaredUpdateVisitor.h"
  48#endif
  49
  50#ifndef _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_
  51#include "tamlAssetReferencedUpdateVisitor.h"
  52#endif
  53
  54#ifndef _CONSOLETYPES_H_
  55#include "console/consoleTypes.h"
  56#endif
  57
  58// Script bindings.
  59#include "assetManager_ScriptBinding.h"
  60
  61//-----------------------------------------------------------------------------
  62
  63IMPLEMENT_CONOBJECT( AssetManager );
  64
  65//-----------------------------------------------------------------------------
  66
  67AssetManager AssetDatabase;
  68
  69//-----------------------------------------------------------------------------
  70
  71AssetManager::AssetManager() :
  72    mLoadedInternalAssetsCount( 0 ),
  73    mLoadedExternalAssetsCount( 0 ),
  74    mLoadedPrivateAssetsCount( 0 ),
  75    mMaxLoadedInternalAssetsCount( 0 ),
  76    mMaxLoadedExternalAssetsCount( 0 ),
  77    mMaxLoadedPrivateAssetsCount( 0 ),
  78    mAcquiredReferenceCount( 0 ),
  79    mEchoInfo( false ),
  80    mIgnoreAutoUnload( true )
  81{
  82}
  83
  84//-----------------------------------------------------------------------------
  85
  86bool AssetManager::onAdd()
  87{
  88    // Call parent.
  89    if ( !Parent::onAdd() )
  90        return false;
  91
  92    return true;
  93}
  94
  95//-----------------------------------------------------------------------------
  96
  97void AssetManager::onRemove()
  98{
  99    // Do we have an asset tags manifest?
 100    if ( !mAssetTagsManifest.isNull() )
 101    {
 102        // Yes, so remove it.
 103        mAssetTagsManifest->deleteObject();
 104    }
 105
 106    // Call parent.
 107    Parent::onRemove();
 108}
 109
 110//-----------------------------------------------------------------------------
 111
 112void AssetManager::initPersistFields()
 113{
 114    // Call parent.
 115    Parent::initPersistFields();
 116
 117    addField( "EchoInfo", TypeBool, Offset(mEchoInfo, AssetManager), "Whether the asset manager echos extra information to the console or not." );
 118    addField( "IgnoreAutoUnload", TypeBool, Offset(mIgnoreAutoUnload, AssetManager), "Whether the asset manager should ignore unloading of auto-unload assets or not." );
 119}
 120
 121//-----------------------------------------------------------------------------
 122
 123bool AssetManager::compileReferencedAssets( ModuleDefinition* pModuleDefinition )
 124{
 125    // Debug Profiling.
 126    PROFILE_SCOPE(AssetManager_CompileReferencedAsset);
 127
 128    // Sanity!
 129    AssertFatal( pModuleDefinition != NULL, "Cannot add declared assets using a NULL module definition" );
 130
 131    // Clear referenced assets.
 132    mReferencedAssets.clear();
 133
 134    // Iterate the module definition children.
 135    for( SimSet::iterator itr = pModuleDefinition->begin(); itr != pModuleDefinition->end(); ++itr )
 136    {
 137        // Fetch the referenced assets.
 138        ReferencedAssets* pReferencedAssets = dynamic_cast<ReferencedAssets*>( *itr );
 139
 140        // Skip if it's not a referenced assets location.
 141        if ( pReferencedAssets == NULL )
 142            continue;
 143
 144        // Expand asset manifest location.
 145        char filePathBuffer[1024];
 146        dSprintf( filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pReferencedAssets->getPath() );
 147
 148        // Scan referenced assets at location.
 149        if ( !scanReferencedAssets( filePathBuffer, pReferencedAssets->getExtension(), pReferencedAssets->getRecurse() ) )
 150        {
 151            // Warn.
 152            Con::warnf( "AssetManager::compileReferencedAssets() - Could not scan for referenced assets at location '%s' with extension '%s'.", filePathBuffer, pReferencedAssets->getExtension() );
 153        }
 154    }  
 155
 156    return true;
 157}
 158
 159//-----------------------------------------------------------------------------
 160
 161bool AssetManager::addModuleDeclaredAssets( ModuleDefinition* pModuleDefinition )
 162{
 163    // Debug Profiling.
 164    PROFILE_SCOPE(AssetManager_AddDeclaredAssets);
 165
 166    // Sanity!
 167    AssertFatal( pModuleDefinition != NULL, "Cannot add declared assets using a NULL module definition" );
 168
 169    // Does the module have any assets associated with it?
 170    if ( pModuleDefinition->getModuleAssets().size() > 0 )
 171    {
 172        // Yes, so warn.
 173        Con::warnf( "Asset Manager: Cannot add declared assets to module '%s' as it already has existing assets.", pModuleDefinition->getSignature() );
 174        return false;
 175    }
 176
 177    // Iterate the module definition children.
 178    for( SimSet::iterator itr = pModuleDefinition->begin(); itr != pModuleDefinition->end(); ++itr )
 179    {
 180        // Fetch the declared assets.
 181        DeclaredAssets* pDeclaredAssets = dynamic_cast<DeclaredAssets*>( *itr );
 182
 183        // Skip if it's not a declared assets location.
 184        if ( pDeclaredAssets == NULL )
 185            continue;
 186
 187        // Expand asset manifest location.
 188        char filePathBuffer[1024];
 189        String mdldfpth = pModuleDefinition->getModulePath();
 190        String astfpth = pDeclaredAssets->getPath();
 191
 192        //dSprintf( filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pDeclaredAssets->getPath() );
 193        dSprintf(filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pDeclaredAssets->getPath());
 194
 195        // Scan declared assets at location.
 196        if ( !scanDeclaredAssets( filePathBuffer, pDeclaredAssets->getExtension(), pDeclaredAssets->getRecurse(), pModuleDefinition ) )
 197        {
 198            // Warn.
 199            Con::warnf( "AssetManager::addModuleDeclaredAssets() - Could not scan for declared assets at location '%s' with extension '%s'.", filePathBuffer, pDeclaredAssets->getExtension() );
 200        }
 201    }  
 202
 203    return true;
 204}
 205
 206//-----------------------------------------------------------------------------
 207
 208bool AssetManager::addDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath )
 209{
 210    // Debug Profiling.
 211    PROFILE_SCOPE(AssetManager_AddSingleDeclaredAsset);
 212
 213    // Sanity!
 214    AssertFatal( pModuleDefinition != NULL, "Cannot add single declared asset using a NULL module definition" );
 215    AssertFatal( pAssetFilePath != NULL, "Cannot add single declared asset using a NULL asset file-path." );
 216
 217    // Expand asset file-path.
 218    char assetFilePathBuffer[1024];
 219    Con::expandPath( assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath );
 220
 221    // Find the final slash which should be just before the file.
 222    char* pFileStart = dStrrchr( assetFilePathBuffer, '/' );
 223
 224    // Did we find the final slash?
 225    if ( pFileStart == NULL )
 226    {
 227        // No, so warn.
 228        Con::warnf( "AssetManager::addDeclaredAsset() - Could not add single declared asset file '%s' as file-path '%s' is not valid.",
 229            assetFilePathBuffer,
 230            pModuleDefinition->getModulePath() );
 231        return false;
 232    }
 233
 234    // Terminate path at slash.
 235    *pFileStart = 0;
 236
 237    // Move to next character which should be the file start.
 238    pFileStart++;
 239
 240    // Scan declared assets at location.
 241    if ( !scanDeclaredAssets( assetFilePathBuffer, pFileStart, false, pModuleDefinition ) )
 242    {
 243        // Warn.
 244        Con::warnf( "AssetManager::addDeclaredAsset() - Could not scan declared assets at location '%s' with extension '%s'.", assetFilePathBuffer, pFileStart );
 245        return false;
 246    }
 247
 248    return true;
 249}
 250
 251//-----------------------------------------------------------------------------
 252
 253StringTableEntry AssetManager::addPrivateAsset( AssetBase* pAssetBase )
 254{
 255    // Debug Profiling.
 256    PROFILE_SCOPE(AssetManager_AddPrivateAsset);
 257
 258    // Sanity!
 259    AssertFatal( pAssetBase != NULL, "Cannot add a NULL private asset." );
 260
 261    // Is the asset already added?
 262    if (pAssetBase->mpAssetDefinition->mAssetId != StringTable->EmptyString())
 263    {
 264        // Yes, so warn.
 265        Con::warnf( "Cannot add private asset '%d' as it has already been assigned.", pAssetBase->mpAssetDefinition->mAssetId );
 266        return StringTable->EmptyString();
 267    }
 268
 269    static U32 masterPrivateAssetId = 1;
 270
 271    // Create asset definition.
 272    AssetDefinition* pAssetDefinition = new AssetDefinition();
 273
 274    // Fetch source asset definition.
 275    AssetDefinition* pSourceAssetDefinition = pAssetBase->mpAssetDefinition;
 276
 277    // Configure asset.
 278    pAssetDefinition->mpAssetBase = pAssetBase;
 279    pAssetDefinition->mAssetDescription = pSourceAssetDefinition->mAssetDescription;
 280    pAssetDefinition->mAssetCategory = pSourceAssetDefinition->mAssetCategory;
 281    pAssetDefinition->mAssetAutoUnload = true;
 282    pAssetDefinition->mAssetRefreshEnable = false;
 283    pAssetDefinition->mAssetType = StringTable->insert( pAssetBase->getClassName() );
 284    pAssetDefinition->mAssetLoadedCount = 0;
 285    pAssetDefinition->mAssetInternal = false;
 286    pAssetDefinition->mAssetPrivate = true;
 287
 288    // Format asset name.
 289    char assetNameBuffer[256];
 290    dSprintf(assetNameBuffer, sizeof(assetNameBuffer), "%s_%d", pAssetDefinition->mAssetType, masterPrivateAssetId++ );    
 291
 292    // Set asset identity.
 293    pAssetDefinition->mAssetName = StringTable->insert( assetNameBuffer );
 294    pAssetDefinition->mAssetId = pAssetDefinition->mAssetName;
 295
 296    // Ensure that the source asset is fully synchronized with the new asset definition.
 297    pSourceAssetDefinition->mAssetName = pAssetDefinition->mAssetName;
 298    pSourceAssetDefinition->mAssetAutoUnload = pAssetDefinition->mAssetAutoUnload;
 299    pSourceAssetDefinition->mAssetInternal = pAssetDefinition->mAssetInternal;
 300
 301    // Set ownership by asset manager.
 302    pAssetDefinition->mpAssetBase->setOwned( this, pAssetDefinition );
 303
 304    // Store in declared assets.
 305    mDeclaredAssets.insert( pAssetDefinition->mAssetId, pAssetDefinition );
 306
 307    // Increase the private loaded asset count.
 308    if ( ++mLoadedPrivateAssetsCount > mMaxLoadedPrivateAssetsCount )
 309        mMaxLoadedPrivateAssetsCount = mLoadedPrivateAssetsCount;
 310
 311    return pAssetDefinition->mAssetId;
 312}
 313
 314//-----------------------------------------------------------------------------
 315
 316bool AssetManager::removeDeclaredAssets( ModuleDefinition* pModuleDefinition )
 317{
 318    // Debug Profiling.
 319    PROFILE_SCOPE(AssetManager_RemoveDeclaredAssets);
 320
 321    // Sanity!
 322    AssertFatal( pModuleDefinition != NULL, "Cannot remove declared assets using a NULL module definition" );
 323
 324    // Fetch module assets.
 325    ModuleDefinition::typeModuleAssetsVector& moduleAssets = pModuleDefinition->getModuleAssets();
 326
 327    // Remove all module assets.
 328    while ( moduleAssets.size() > 0 )
 329    {
 330        // Fetch asset definition.
 331        AssetDefinition* pAssetDefinition = *moduleAssets.begin();
 332
 333        // Remove this asset.
 334        removeDeclaredAsset( pAssetDefinition->mAssetId );
 335    }
 336
 337    // Info.
 338    if ( mEchoInfo )
 339        Con::printSeparator();
 340
 341    return true;
 342}
 343
 344//-----------------------------------------------------------------------------
 345
 346bool AssetManager::removeDeclaredAsset( const char* pAssetId )
 347{
 348    // Debug Profiling.
 349    PROFILE_SCOPE(AssetManager_RemoveSingleDeclaredAsset);
 350
 351    // Sanity!
 352    AssertFatal( pAssetId != NULL, "Cannot remove single declared asset using NULL asset Id." );
 353
 354    // Fetch asset Id.
 355    StringTableEntry assetId = StringTable->insert( pAssetId );
 356
 357    // Find declared asset.
 358    typeDeclaredAssetsHash::iterator declaredAssetItr = mDeclaredAssets.find( assetId );
 359
 360    // Did we find the declared asset?
 361    if ( declaredAssetItr == mDeclaredAssets.end() )
 362    {
 363        // No, so warn.
 364        Con::warnf( "Asset Manager: Cannot remove single asset Id '%s' it could not be found.", assetId );
 365        return false;
 366    }
 367
 368    // Fetch asset definition.
 369    AssetDefinition* pAssetDefinition = declaredAssetItr->value;
 370
 371    // Is the asset private?
 372    if ( !pAssetDefinition->mAssetPrivate )
 373    {
 374        // No, so fetch module assets.
 375        ModuleDefinition::typeModuleAssetsVector& moduleAssets = pAssetDefinition->mpModuleDefinition->getModuleAssets();
 376
 377        // Remove module asset.
 378        for ( ModuleDefinition::typeModuleAssetsVector::iterator moduleAssetItr = moduleAssets.begin(); moduleAssetItr != moduleAssets.end(); ++moduleAssetItr )
 379        {
 380            if ( *moduleAssetItr == pAssetDefinition )
 381            {
 382                moduleAssets.erase( moduleAssetItr );
 383                break;
 384            }
 385        }
 386
 387        // Remove asset dependencies.
 388        removeAssetDependencies( pAssetId );
 389    }
 390
 391    // Do we have an asset loaded?
 392    if ( pAssetDefinition->mpAssetBase != NULL )
 393    {
 394        // Yes, so delete it.
 395        // NOTE: If anything is using this then this'll cause a crash.  Objects should always use safe reference methods however.
 396        pAssetDefinition->mpAssetBase->deleteObject();
 397    }
 398
 399    // Remove from declared assets.
 400    mDeclaredAssets.erase( declaredAssetItr );
 401
 402    // Info.
 403    if ( mEchoInfo )
 404    {
 405        Con::printf( "Asset Manager: Removing Asset Id '%s' of type '%s' in asset file '%s'.",
 406            pAssetDefinition->mAssetId,
 407            pAssetDefinition->mAssetType,
 408            pAssetDefinition->mAssetBaseFilePath );
 409    }
 410
 411    // Destroy asset definition.
 412    delete pAssetDefinition;
 413
 414    return true;
 415}
 416
 417//-----------------------------------------------------------------------------
 418
 419StringTableEntry AssetManager::getAssetName( const char* pAssetId )
 420{
 421    // Find asset definition.
 422    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 423
 424    // Did we find the asset?
 425    if ( pAssetDefinition == NULL )
 426    {
 427        // No, so warn.
 428        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 429        return NULL;
 430    }
 431
 432    return pAssetDefinition->mAssetName;
 433}
 434
 435//-----------------------------------------------------------------------------
 436
 437StringTableEntry AssetManager::getAssetDescription( const char* pAssetId )
 438{
 439    // Find asset definition.
 440    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 441
 442    // Did we find the asset?
 443    if ( pAssetDefinition == NULL )
 444    {
 445        // No, so warn.
 446        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 447        return NULL;
 448    }
 449
 450    return pAssetDefinition->mAssetDescription;
 451}
 452
 453//-----------------------------------------------------------------------------
 454
 455StringTableEntry AssetManager::getAssetCategory( const char* pAssetId )
 456{
 457    // Find asset definition.
 458    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 459
 460    // Did we find the asset?
 461    if ( pAssetDefinition == NULL )
 462    {
 463        // No, so warn.
 464        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 465        return NULL;
 466    }
 467
 468    return pAssetDefinition->mAssetCategory;
 469}
 470
 471//-----------------------------------------------------------------------------
 472
 473StringTableEntry AssetManager::getAssetType( const char* pAssetId )
 474{
 475    // Find asset definition.
 476    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 477
 478    // Did we find the asset?
 479    if ( pAssetDefinition == NULL )
 480    {
 481        // No, so warn.
 482        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 483        return NULL;
 484    }
 485
 486    return pAssetDefinition->mAssetType;
 487}
 488
 489//-----------------------------------------------------------------------------
 490
 491StringTableEntry AssetManager::getAssetFilePath( const char* pAssetId )
 492{
 493    // Find asset definition.
 494    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 495
 496    // Did we find the asset?
 497    if ( pAssetDefinition == NULL )
 498    {
 499        // No, so warn.
 500        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 501        return StringTable->EmptyString();
 502    }
 503
 504    return pAssetDefinition->mAssetBaseFilePath;
 505}
 506
 507//-----------------------------------------------------------------------------
 508
 509StringTableEntry AssetManager::getAssetPath( const char* pAssetId )
 510{
 511    // Debug Profiling.
 512    PROFILE_SCOPE(AssetManager_GetAssetPath);
 513
 514    // Fetch asset file-path.
 515    StringTableEntry assetFilePath = getAssetFilePath( pAssetId );
 516
 517    // Finish if no file-path.
 518    if ( assetFilePath == StringTable->EmptyString()  )
 519        return assetFilePath;
 520
 521    // Find the final slash which should be just before the file.
 522    const char* pFinalSlash = dStrrchr( assetFilePath, '/' );
 523
 524    // Sanity!
 525    AssertFatal( pFinalSlash != NULL, "Should always be able to find final slash in the asset file-path." );
 526
 527    // Fetch asset path.
 528    return StringTable->insertn( assetFilePath, (U32)(pFinalSlash - assetFilePath) );
 529}
 530
 531//-----------------------------------------------------------------------------
 532
 533ModuleDefinition* AssetManager::getAssetModuleDefinition( const char* pAssetId )
 534{
 535    // Find asset definition.
 536    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 537
 538    // Did we find the asset?
 539    if ( pAssetDefinition == NULL )
 540    {
 541        // No, so warn.
 542        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 543        return NULL;
 544    }
 545
 546    return pAssetDefinition->mpModuleDefinition;
 547}
 548
 549//-----------------------------------------------------------------------------
 550
 551bool AssetManager::isAssetInternal( const char* pAssetId )
 552{
 553    // Find asset definition.
 554    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 555
 556    // Did we find the asset?
 557    if ( pAssetDefinition == NULL )
 558    {
 559        // No, so warn.
 560        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 561        return false;
 562    }
 563
 564    return pAssetDefinition->mAssetInternal;
 565}
 566
 567//-----------------------------------------------------------------------------
 568
 569bool AssetManager::isAssetPrivate( const char* pAssetId )
 570{
 571    // Find asset definition.
 572    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 573
 574    // Did we find the asset?
 575    if ( pAssetDefinition == NULL )
 576    {
 577        // No, so warn.
 578        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 579        return false;
 580    }
 581
 582    return pAssetDefinition->mAssetPrivate;
 583}
 584
 585//-----------------------------------------------------------------------------
 586
 587bool AssetManager::isAssetAutoUnload( const char* pAssetId )
 588{
 589    // Find asset definition.
 590    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 591
 592    // Did we find the asset?
 593    if ( pAssetDefinition == NULL )
 594    {
 595        // No, so warn.
 596        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 597        return false;
 598    }
 599
 600    return pAssetDefinition->mAssetAutoUnload;
 601}
 602
 603//-----------------------------------------------------------------------------
 604
 605bool AssetManager::isAssetLoaded( const char* pAssetId )
 606{
 607    // Find asset definition.
 608    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 609
 610    // Did we find the asset?
 611    if ( pAssetDefinition == NULL )
 612    {
 613        // No, so warn.
 614        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
 615        return false;
 616    }
 617
 618    return pAssetDefinition->mpAssetBase != NULL;
 619}
 620
 621
 622//-----------------------------------------------------------------------------
 623
 624bool AssetManager::isDeclaredAsset( const char* pAssetId )
 625{
 626    return findAsset( pAssetId ) != NULL;
 627}
 628
 629//-----------------------------------------------------------------------------
 630
 631bool AssetManager::doesAssetDependOn( const char* pAssetId, const char* pDependsOnAssetId )
 632{
 633    // Debug Profiling.
 634    PROFILE_SCOPE(AssetManager_DoesAssetDependOn);
 635
 636    // Sanity!
 637    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
 638    AssertFatal( pDependsOnAssetId != NULL, "Cannot use NULL depends-on asset Id." );
 639
 640    // Fetch asset Id.
 641    StringTableEntry assetId = StringTable->insert( pAssetId );
 642
 643    // Fetch depends-on asset Id.
 644    StringTableEntry dependsOnAssetId = StringTable->insert( pDependsOnAssetId );
 645
 646    // Find depends-on entry.
 647    typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find( assetId );
 648
 649    // Iterate all dependencies.
 650    while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == assetId )
 651    {
 652        // Finish if a depends on.
 653        if ( dependsOnItr->value == dependsOnAssetId )
 654            return true;
 655
 656        // Next dependency.
 657        dependsOnItr++;
 658    }
 659
 660    return false;
 661}
 662
 663//-----------------------------------------------------------------------------
 664
 665bool AssetManager::isAssetDependedOn( const char* pAssetId, const char* pDependedOnByAssetId )
 666{
 667    // Debug Profiling.
 668    PROFILE_SCOPE(AssetManager_IsAssetDependedOn);
 669
 670    // Sanity!
 671    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
 672    AssertFatal( pDependedOnByAssetId != NULL, "Cannot use NULL depended-on-by asset Id." );
 673
 674    // Fetch asset Id.
 675    StringTableEntry assetId = StringTable->insert( pAssetId );
 676
 677    // Fetch depended-on-by asset Id.
 678    StringTableEntry dependedOnByAssetId = StringTable->insert( pDependedOnByAssetId );
 679
 680    // Find depended-on-by entry.
 681    typeAssetDependsOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find(assetId);
 682
 683    // Iterate all dependencies.
 684    while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
 685    {
 686        // Finish if depended-on.
 687        if ( dependedOnItr->value == dependedOnByAssetId )
 688            return true;
 689
 690        // Next dependency.
 691        dependedOnItr++;
 692    }
 693
 694    return false;
 695}
 696
 697//-----------------------------------------------------------------------------
 698
 699bool AssetManager::isReferencedAsset( const char* pAssetId )
 700{
 701    // Debug Profiling.
 702    PROFILE_SCOPE(AssetManager_IsReferencedAsset);
 703
 704    // Sanity!
 705    AssertFatal( pAssetId != NULL, "Cannot check if NULL asset Id is referenced." );
 706
 707    // Fetch asset Id.
 708    StringTableEntry assetId = StringTable->insert( pAssetId );
 709
 710    // Is asset Id the correct format?
 711    if ( StringUnit::getUnitCount( assetId, ASSET_SCOPE_TOKEN ) != 2 )
 712    {
 713        // No, so warn.
 714        Con::warnf( "Asset Manager: Cannot check if asset Id '%s' is referenced as it is not the correct format.", assetId );
 715        return false;
 716    }
 717
 718    return mReferencedAssets.count( assetId ) > 0;
 719}
 720
 721//-----------------------------------------------------------------------------
 722
 723bool AssetManager::renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo )
 724{
 725    // Debug Profiling.
 726    PROFILE_SCOPE(AssetManager_RenameDeclaredAsset);
 727
 728    // Sanity!
 729    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
 730    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
 731
 732    // Fetch asset Ids.
 733    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
 734    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
 735
 736    // Is asset Id from the correct format?
 737    if ( StringUnit::getUnitCount( assetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
 738    {
 739        // No, so warn.
 740        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as source asset Id is not the correct format.", assetIdFrom, assetIdTo );
 741        return false;
 742    }
 743
 744    // Is asset Id to the correct format?
 745    if ( StringUnit::getUnitCount( assetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
 746    {
 747        // No, so warn.
 748        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as target asset Id is not the correct format.", assetIdFrom, assetIdTo );
 749        return false;
 750    }
 751
 752    // Does the asset Id from exist?
 753    if ( !mDeclaredAssets.contains( assetIdFrom ) )
 754    {
 755        // No, so warn.
 756        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as source asset Id is not declared.", assetIdFrom, assetIdTo );
 757        return false;
 758    }
 759
 760    // Does the asset Id to exist?
 761    if ( mDeclaredAssets.contains( assetIdTo ) )
 762    {
 763        // No, so warn.
 764        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as target asset Id is already declared.", assetIdFrom, assetIdTo );
 765        return false;
 766    }
 767
 768    // Split module Ids from asset Ids.
 769    StringTableEntry moduleIdFrom = StringTable->insert( StringUnit::getUnit( assetIdFrom, 0, ASSET_SCOPE_TOKEN ) );
 770    StringTableEntry moduleIdTo   = StringTable->insert( StringUnit::getUnit( assetIdTo, 0, ASSET_SCOPE_TOKEN ) );
 771
 772    // Are the module Ids the same?
 773    if ( moduleIdFrom != moduleIdTo )
 774    {
 775        // No, so warn.
 776        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the module Id cannot be changed.", assetIdFrom, assetIdTo );
 777        return false;
 778    }
 779
 780    // Find asset definition.
 781    typeDeclaredAssetsHash::iterator assetDefinitionItr =  mDeclaredAssets.find( assetIdFrom );
 782
 783    // Sanity!
 784    AssertFatal( assetDefinitionItr != mDeclaredAssets.end(), "Asset Manager: Failed to find asset." );
 785
 786    // Fetch asset definition.
 787    AssetDefinition* pAssetDefinition = assetDefinitionItr->value;
 788
 789    // Is this a private asset?
 790    if ( pAssetDefinition->mAssetPrivate )
 791    {
 792        // Yes, so warn.
 793        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the source asset is private.", assetIdFrom, assetIdTo );
 794        return false;
 795    }
 796
 797    // Setup declared update visitor.
 798    TamlAssetDeclaredUpdateVisitor assetDeclaredUpdateVisitor;
 799    assetDeclaredUpdateVisitor.setAssetIdFrom( assetIdFrom );
 800    assetDeclaredUpdateVisitor.setAssetIdTo( assetIdTo );
 801
 802    // Update asset file declaration.
 803    if ( !mTaml.parse( pAssetDefinition->mAssetBaseFilePath, assetDeclaredUpdateVisitor ) )
 804    {
 805        // No, so warn.
 806        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the declared asset file could not be parsed: %s",
 807            assetIdFrom, assetIdTo, pAssetDefinition->mAssetBaseFilePath );
 808        return false;
 809    }
 810
 811    // Update asset definition.
 812    pAssetDefinition->mAssetId = assetIdTo;
 813    pAssetDefinition->mAssetName = StringTable->insert( StringUnit::getUnit( assetIdTo, 1, ASSET_SCOPE_TOKEN ) );
 814
 815    // Reinsert declared asset.
 816    mDeclaredAssets.erase( assetIdFrom );
 817    mDeclaredAssets.insert( assetIdTo, pAssetDefinition );
 818
 819    // Info.
 820    if ( mEchoInfo )
 821    {
 822        Con::printf( "Asset Manager: Renaming declared Asset Id '%s' to Asset Id '%s'.", assetIdFrom, assetIdTo );
 823        Con::printSeparator();
 824    }
 825
 826    // Rename asset dependencies.
 827    renameAssetDependencies( assetIdFrom, assetIdTo );
 828
 829    // Do we have an asset tags manifest?
 830    if ( !mAssetTagsManifest.isNull() )
 831    {
 832        // Yes, so rename any assets.
 833        mAssetTagsManifest->renameAssetId( pAssetIdFrom, pAssetIdTo );
 834
 835        // Save the asset tags.
 836        saveAssetTags();
 837    }
 838
 839    return true;
 840}
 841
 842//-----------------------------------------------------------------------------
 843
 844bool AssetManager::renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo )
 845{
 846    // Debug Profiling.
 847    PROFILE_SCOPE(AssetManager_RenameReferencedAsset);
 848
 849    // Sanity!
 850    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
 851    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
 852
 853    // Fetch asset Ids.
 854    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
 855    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
 856
 857    // Is asset Id from the correct format?
 858    if ( StringUnit::getUnitCount( assetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
 859    {
 860        // No, so warn.
 861        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as source asset Id is not the correct format.", assetIdFrom, assetIdTo );
 862        return false;
 863    }
 864
 865    // Is asset Id to the correct format?
 866    if ( StringUnit::getUnitCount( assetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
 867    {
 868        // No, so warn.
 869        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as target asset Id is not the correct format.", assetIdFrom, assetIdTo );
 870        return false;
 871    }
 872
 873    // Does the asset Id to exist?
 874    if ( !mDeclaredAssets.contains( assetIdTo ) )
 875    {
 876        // No, so warn.
 877        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as target asset Id is not declared.", assetIdFrom, assetIdTo );
 878        return false;
 879    }
 880
 881    // Rename asset references.
 882    renameAssetReferences( assetIdFrom, assetIdTo );
 883
 884    // Info.
 885    if ( mEchoInfo )
 886        Con::printSeparator();
 887
 888    return true;
 889}
 890
 891//-----------------------------------------------------------------------------
 892
 893bool AssetManager::releaseAsset( const char* pAssetId )
 894{
 895    // Debug Profiling.
 896    PROFILE_SCOPE(AssetManager_ReleaseAsset);
 897
 898    // Sanity!
 899    AssertFatal( pAssetId != NULL, "Cannot release NULL asset Id." );
 900
 901    // Find asset.
 902    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
 903
 904    // Did we find the asset?
 905    if ( pAssetDefinition == NULL )
 906    {
 907        // No, so warn.
 908        Con::warnf( "Asset Manager: Failed to release asset Id '%s' as it does not exist.", pAssetId );
 909        return false;
 910    }
 911
 912    // Is the asset loaded?
 913    if ( pAssetDefinition->mpAssetBase == NULL )
 914    {
 915        // No, so warn.
 916        Con::warnf( "Asset Manager: Failed to release asset Id '%s' as it is not acquired.", pAssetId );
 917        return false;
 918    }
 919
 920    // Info.
 921    if ( mEchoInfo )
 922    {
 923        Con::printSeparator();
 924        Con::printf( "Asset Manager: Started releasing Asset Id '%s'...", pAssetId );
 925    }
 926
 927    // Release asset reference.
 928    if ( pAssetDefinition->mpAssetBase->releaseAssetReference() )
 929    {
 930        // Are we ignoring auto-unloaded assets?
 931        if ( mIgnoreAutoUnload )
 932        {
 933            // Yes, so info.
 934            if ( mEchoInfo )
 935            {
 936                Con::printf( "Asset Manager: > Releasing to idle state." );
 937            }
 938        }
 939        else
 940        {
 941            // No, so info.
 942            if ( mEchoInfo )
 943            {
 944                Con::printf( "Asset Manager: > Unload the asset from memory." );
 945            }
 946
 947            // Unload the asset.
 948            unloadAsset( pAssetDefinition );
 949        }
 950    }
 951    // Info.
 952    else if ( mEchoInfo )
 953    {
 954        Con::printf( "Asset Manager: > Reference count now '%d'.", pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() );
 955    }
 956
 957    // Info.
 958    if ( mEchoInfo )
 959    {
 960        Con::printf( "Asset Manager: > Finished releasing Asset Id '%s'.", pAssetId );
 961        Con::printSeparator();
 962    }
 963
 964    return true;
 965}
 966
 967//-----------------------------------------------------------------------------
 968
 969void AssetManager::purgeAssets( void )
 970{
 971    // Debug Profiling.
 972    PROFILE_SCOPE(AssetManager_PurgeAssets);
 973
 974    // Info.
 975    if ( mEchoInfo )
 976    {
 977        Con::printf( "Asset Manager: Started purging assets..." );
 978    }
 979
 980    // Iterate asset definitions.
 981    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
 982    {
 983        // Fetch asset definition.
 984        AssetDefinition* pAssetDefinition = assetItr->value;
 985
 986        // Skip asset if private, not loaded or referenced.
 987        if (    pAssetDefinition->mAssetPrivate ||
 988                pAssetDefinition->mpAssetBase == NULL ||
 989                pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() > 0 )
 990            continue;
 991
 992        // Info.
 993        if ( mEchoInfo )
 994        {
 995            Con::printf( "Asset Manager: Purging asset Id '%s'...", pAssetDefinition->mAssetId );
 996        }
 997
 998        // Unload the asset.
 999        unloadAsset( pAssetDefinition );
1000    }
1001
1002    // Info.
1003    if ( mEchoInfo )
1004    {
1005        Con::printf( "Asset Manager: ... Finished purging assets." );
1006    }
1007}
1008
1009//-----------------------------------------------------------------------------
1010
1011bool AssetManager::deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies )
1012{
1013    // Debug Profiling.
1014    PROFILE_SCOPE(AssetManager_DeleteAsset);
1015
1016    // Sanity!
1017    AssertFatal( pAssetId != NULL, "Cannot delete NULL asset Id." );
1018
1019    // Find asset.
1020    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
1021
1022    // Did we find the asset?
1023    if ( pAssetDefinition == NULL )
1024    {
1025        // No, so warn.
1026        Con::warnf( "Asset Manager: Failed to delete asset Id '%s' as it does not exist.", pAssetId );
1027        return false;
1028    }
1029
1030    // Info.
1031    if ( mEchoInfo )
1032    {
1033        Con::printSeparator();
1034        Con::printf( "Asset Manager: Started deleting Asset Id '%s'...", pAssetId );
1035    }  
1036
1037    // Fetch asset Id.
1038    StringTableEntry assetId = StringTable->insert( pAssetId );
1039
1040    // Are we deleting dependencies?
1041    if ( deleteDependencies )
1042    {
1043        Vector<typeAssetId> dependantAssets;
1044
1045        // Yes, so find depended-on-by entry.
1046        typeAssetDependsOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find( assetId );
1047
1048        // Iterate all dependencies.
1049        while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
1050        {
1051            // Store asset Id.
1052            dependantAssets.push_back( dependedOnItr->value );
1053
1054            // Next dependency.
1055            dependedOnItr++;
1056        }
1057
1058        // Do we have any dependants?
1059        if ( dependantAssets.size() > 0 )
1060        {
1061            // Yes, so iterate dependants.
1062            for( Vector<typeAssetId>::const_iterator assetItr = dependantAssets.begin(); assetItr !=  dependantAssets.end(); ++assetItr )
1063            {
1064                StringTableEntry dependentAssetId = *assetItr;
1065
1066                // Info.
1067                if ( mEchoInfo )
1068                {
1069                    Con::printSeparator();
1070                    Con::printf( "Asset Manager: Deleting Asset Id '%s' dependant of '%s.'", pAssetId, dependentAssetId );
1071                }
1072
1073                // Delete dependant.
1074                deleteAsset( dependentAssetId, deleteLooseFiles, deleteDependencies );
1075            }
1076        }
1077    }
1078
1079    // Remove asset references.
1080    removeAssetReferences( assetId );
1081
1082    // Are we deleting loose files?
1083    if ( deleteLooseFiles )
1084    {
1085        // Yes, so remove loose files.
1086        Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
1087        for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
1088        {
1089            // Fetch loose file.
1090            StringTableEntry looseFile = *looseFileItr;
1091
1092            // Delete the loose file.
1093            if ( !dFileDelete( looseFile ) )
1094            {
1095                // Failed so warn.
1096                Con::warnf( "Asset Manager: Failed to delete the loose file '%s' while deleting asset Id '%s'.", looseFile, pAssetId );
1097            }
1098        }
1099    }
1100
1101    // Fetch asset definition file.
1102    StringTableEntry assetDefinitionFile = pAssetDefinition->mAssetBaseFilePath;
1103
1104    // Remove reference here as we're about to remove the declared asset.
1105    pAssetDefinition = NULL;
1106
1107    // Remove asset.
1108    removeDeclaredAsset( pAssetId );
1109
1110    // Delete the asset definition file.
1111    if ( !dFileDelete( assetDefinitionFile ) )
1112    {
1113        // Failed so warn.
1114        Con::warnf( "Asset Manager: Failed to delete the asset definition file '%s' while deleting asset Id '%s'.", assetDefinitionFile, pAssetId );
1115    }       
1116
1117    // Info.
1118    if ( mEchoInfo )
1119    {
1120        Con::printSeparator();
1121        Con::printf( "Asset Manager: Finished deleting Asset Id '%s'.", pAssetId );
1122    }
1123
1124    return true;
1125}
1126
1127//-----------------------------------------------------------------------------
1128
1129bool AssetManager::refreshAsset( const char* pAssetId )
1130{
1131    // Debug Profiling.
1132    PROFILE_SCOPE(AssetManager_RefreshAsset);
1133
1134    // Sanity!
1135    AssertFatal( pAssetId != NULL, "Cannot refresh NULL asset Id." );
1136
1137    // Find asset.
1138    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
1139
1140    // Did we find the asset?
1141    if ( pAssetDefinition == NULL )
1142    {
1143        // No, so warn.
1144        Con::warnf( "Asset Manager: Failed to refresh asset Id '%s' as it does not exist.", pAssetId );
1145        return false;
1146    }
1147
1148    // Info.
1149    if ( mEchoInfo )
1150    {
1151        Con::printSeparator();
1152        Con::printf( "Asset Manager: Started refreshing Asset Id '%s'...", pAssetId );
1153    }    
1154
1155    // Fetch asset Id.
1156    StringTableEntry assetId = StringTable->insert( pAssetId );
1157
1158    // Is the asset private?
1159    if ( pAssetDefinition->mAssetPrivate )
1160    {
1161        // Yes, so notify asset of asset refresh only.
1162        pAssetDefinition->mpAssetBase->onAssetRefresh();
1163
1164        // Asset refresh notifications.
1165        for( typeAssetPtrRefreshHash::iterator refreshNotifyItr = mAssetPtrRefreshNotifications.begin(); refreshNotifyItr != mAssetPtrRefreshNotifications.end(); ++refreshNotifyItr )
1166        {
1167            // Fetch pointed asset.
1168            StringTableEntry pointedAsset = refreshNotifyItr->key->getAssetId();
1169
1170            // Ignore if the pointed asset is not the asset or a dependency.
1171            if ( pointedAsset == StringTable->EmptyString() || ( pointedAsset != assetId && !doesAssetDependOn( pointedAsset, assetId ) ) )
1172                continue;
1173
1174            // Perform refresh notification callback.
1175            refreshNotifyItr->value->onAssetRefreshed( refreshNotifyItr->key );
1176        }
1177    }
1178    // Is the asset definition allowed to refresh?
1179    else if ( pAssetDefinition->mAssetRefreshEnable )
1180    {
1181        // Yes, so fetch the asset.
1182        AssetBase* pAssetBase = pAssetDefinition->mpAssetBase;
1183
1184        // Is the asset loaded?
1185        if ( pAssetBase != NULL )
1186        {
1187            // Yes, so notify asset of asset refresh.
1188            pAssetBase->onAssetRefresh();
1189
1190            // Save asset.
1191            mTaml.write( pAssetBase, pAssetDefinition->mAssetBaseFilePath );
1192        
1193            // Remove asset dependencies.
1194            removeAssetDependencies( pAssetId );
1195
1196            // Find any new dependencies.
1197            TamlAssetDeclaredVisitor assetDeclaredVisitor;
1198
1199            // Parse the filename.
1200            if ( !mTaml.parse( pAssetDefinition->mAssetBaseFilePath, assetDeclaredVisitor ) )
1201            {
1202                // Warn.
1203                Con::warnf( "Asset Manager: Failed to parse file containing asset declaration: '%s'.\nDependencies are now incorrect!", pAssetDefinition->mAssetBaseFilePath );
1204                return false;
1205            }
1206
1207            // Fetch asset dependencies.
1208            TamlAssetDeclaredVisitor::typeAssetIdVector& assetDependencies = assetDeclaredVisitor.getAssetDependencies();
1209
1210            // Are there any asset dependences?
1211            if ( assetDependencies.size() > 0 )
1212            {
1213                // Yes, so iterate dependencies.
1214                for( TamlAssetDeclaredVisitor::typeAssetIdVector::iterator assetDependencyItr = assetDependencies.begin(); assetDependencyItr != assetDependencies.end(); ++assetDependencyItr )
1215                {
1216                    // Fetch dependency asset Id.
1217                    StringTableEntry dependencyAssetId = *assetDependencyItr;
1218
1219                    // Insert depends-on.
1220                    mAssetDependsOn.insertEqual( assetId, dependencyAssetId );
1221
1222                    // Insert is-depended-on.
1223                    mAssetIsDependedOn.insertEqual( dependencyAssetId, assetId );
1224                }
1225            }
1226
1227            // Fetch asset loose files.
1228            TamlAssetDeclaredVisitor::typeLooseFileVector& assetLooseFiles = assetDeclaredVisitor.getAssetLooseFiles();
1229
1230            // Clear any existing loose files.
1231            pAssetDefinition->mAssetLooseFiles.clear();
1232
1233            // Are there any loose files?
1234            if ( assetLooseFiles.size() > 0 )
1235            {
1236                // Yes, so iterate loose files.
1237                for( TamlAssetDeclaredVisitor::typeLooseFileVector::iterator assetLooseFileItr = assetLooseFiles.begin(); assetLooseFileItr != assetLooseFiles.end(); ++assetLooseFileItr )
1238                {
1239                    // Store loose file.
1240                    pAssetDefinition->mAssetLooseFiles.push_back( *assetLooseFileItr );
1241                }
1242            }
1243
1244            // Asset refresh notifications.
1245            for( typeAssetPtrRefreshHash::iterator refreshNotifyItr = mAssetPtrRefreshNotifications.begin(); refreshNotifyItr != mAssetPtrRefreshNotifications.end(); ++refreshNotifyItr )
1246            {
1247                // Fetch pointed asset.
1248                StringTableEntry pointedAsset = refreshNotifyItr->key->getAssetId();
1249
1250                // Ignore if the pointed asset is not the asset or a dependency.
1251                if ( pointedAsset == StringTable->EmptyString() || ( pointedAsset != assetId && !doesAssetDependOn( pointedAsset, assetId ) ) )
1252                    continue;
1253
1254                // Perform refresh notification callback.
1255                refreshNotifyItr->value->onAssetRefreshed( refreshNotifyItr->key );
1256            }
1257
1258            // Find is-depends-on entry.
1259            typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find( assetId );
1260
1261            // Is asset depended on?
1262            if ( isDependedOnItr != mAssetIsDependedOn.end() )
1263            {
1264                // Yes, so compiled them.
1265                Vector<typeAssetId> dependedOn;
1266
1267                // Iterate all dependencies.
1268                while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == assetId )
1269                {
1270                    dependedOn.push_back( isDependedOnItr->value );
1271
1272                    // Next dependency.
1273                    isDependedOnItr++;
1274                }
1275
1276                // Refresh depended-on assets.
1277                for ( Vector<typeAssetId>::iterator isDependedOnItr = dependedOn.begin(); isDependedOnItr != dependedOn.end(); ++isDependedOnItr )
1278                {
1279                    // Refresh dependency asset.
1280                    refreshAsset( *isDependedOnItr );
1281                }
1282            }
1283        }
1284    }
1285
1286    // Info.
1287    if ( mEchoInfo )
1288    {
1289        Con::printSeparator();
1290        Con::printf( "Asset Manager: Finished refreshing Asset Id '%s'.", pAssetId );
1291    }
1292
1293    return true;
1294}
1295
1296//-----------------------------------------------------------------------------
1297
1298void AssetManager::refreshAllAssets( const bool includeUnloaded )
1299{
1300    // Debug Profiling.
1301    PROFILE_SCOPE(AssetManager_RefreshAllAssets);
1302
1303    // Info.
1304    if ( mEchoInfo )
1305    {
1306        Con::printSeparator();
1307        Con::printf( "Asset Manager: Started refreshing ALL assets." );
1308    }
1309
1310    Vector<typeAssetId> assetsToRelease;
1311
1312    // Are we including unloaded assets?
1313    if ( includeUnloaded )
1314    {
1315        // Yes, so prepare a list of assets to release and load them.
1316        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1317        {
1318            // Fetch asset Id.
1319            typeAssetId assetId = assetItr->key;
1320
1321            // Skip if asset is loaded.
1322            if ( assetItr->value->mpAssetBase != NULL )
1323                continue;
1324
1325            // Note asset as needing a release.
1326            assetsToRelease.push_back( assetId );
1327
1328            // Acquire the asset.
1329            acquireAsset<AssetBase>( assetId );
1330        }
1331    }
1332
1333    // Refresh the current loaded assets.
1334    // NOTE: This will result in some assets being refreshed more than once due to asset dependencies.
1335    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1336    {
1337        // Skip private assets.
1338        if ( assetItr->value->mAssetPrivate )
1339            continue;
1340
1341        // Refresh asset if it's loaded.
1342        refreshAsset( assetItr->key );
1343    }
1344
1345    // Are we including unloaded assets?
1346    if ( includeUnloaded )
1347    {
1348        // Yes, so release the assets we loaded.
1349        for( Vector<typeAssetId>::iterator assetItr = assetsToRelease.begin(); assetItr != assetsToRelease.end(); ++assetItr )
1350        {
1351            releaseAsset( *assetItr );
1352        }
1353    }
1354
1355    // Info.
1356    if ( mEchoInfo )
1357    {
1358        Con::printSeparator();
1359        Con::printf( "Asset Manager: Finished refreshing ALL assets." );
1360    }
1361}
1362
1363//-----------------------------------------------------------------------------
1364
1365void AssetManager::registerAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase, AssetPtrCallback* pCallback )
1366{
1367    // Find an existing notification iterator.
1368    typeAssetPtrRefreshHash::iterator notificationItr = mAssetPtrRefreshNotifications.find( pAssetPtrBase );
1369
1370    // Do we have one?
1371    if ( notificationItr != mAssetPtrRefreshNotifications.end() )
1372    {
1373        // Yes, so update the callback.
1374        notificationItr->value = pCallback;
1375        return;
1376    }
1377
1378    // No, so add one.
1379    mAssetPtrRefreshNotifications.insert( pAssetPtrBase, pCallback );
1380}
1381
1382//-----------------------------------------------------------------------------
1383
1384void AssetManager::unregisterAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase )
1385{
1386    mAssetPtrRefreshNotifications.erase( pAssetPtrBase );
1387}
1388
1389//-----------------------------------------------------------------------------
1390
1391bool AssetManager::loadAssetTags( ModuleDefinition* pModuleDefinition )
1392{
1393    // Sanity!
1394    AssertFatal( pModuleDefinition != NULL, "Cannot load asset tags manifest using a NULL module definition" );
1395
1396    // Expand manifest location.
1397    char assetTagsManifestFilePathBuffer[1024];
1398    Con::expandPath( assetTagsManifestFilePathBuffer, sizeof(assetTagsManifestFilePathBuffer), pModuleDefinition->getAssetTagsManifest() );
1399
1400    // Do we already have a manifest?
1401    if ( !mAssetTagsManifest.isNull() )
1402    {
1403        // Yes, so warn.
1404        Con::warnf( "Asset Manager: Cannot load asset tags manifest from module '%s' as one is already loaded.", pModuleDefinition->getSignature() );
1405        return false;
1406    }
1407
1408    // Is the specified file valid?
1409    if ( Platform::isFile( assetTagsManifestFilePathBuffer ) )
1410    {
1411        // Yes, so read asset tags manifest.
1412        mAssetTagsManifest = mTaml.read<AssetTagsManifest>( assetTagsManifestFilePathBuffer );
1413
1414        // Did we read the manifest?
1415        if ( mAssetTagsManifest.isNull() )
1416        {
1417            // No, so warn.
1418            Con::warnf( "Asset Manager: Failed to load asset tags manifest '%s' from module '%s'.", assetTagsManifestFilePathBuffer, pModuleDefinition->getSignature() );
1419            return false;
1420        }
1421
1422        // Set asset tags module definition.
1423        mAssetTagsModuleDefinition = pModuleDefinition;
1424    }
1425    else
1426    {
1427        // No, so generate a new asset tags manifest.
1428        mAssetTagsManifest = new AssetTagsManifest();
1429        mAssetTagsManifest->registerObject();
1430
1431        // Set asset tags module definition.
1432        mAssetTagsModuleDefinition = pModuleDefinition;
1433
1434        // Save the asset tags.
1435        saveAssetTags();
1436    }
1437
1438    return true;
1439}
1440
1441//-----------------------------------------------------------------------------
1442
1443bool AssetManager::saveAssetTags( void )
1444{
1445    // Do we have an asset tags manifest?
1446    if ( mAssetTagsManifest.isNull() || mAssetTagsModuleDefinition.isNull() )
1447    {
1448        // No, so warn.
1449        Con::warnf( "Asset Manager: Failed to save asset tags manifest as one is not loaded." );
1450        return false;
1451    }
1452
1453    // Expand manifest location.
1454    char assetTagsManifestFilePathBuffer[1024];
1455    Con::expandPath( assetTagsManifestFilePathBuffer, sizeof(assetTagsManifestFilePathBuffer), mAssetTagsModuleDefinition->getAssetTagsManifest() );
1456
1457    // Save asset tags manifest.
1458    if ( !mTaml.write( mAssetTagsManifest, assetTagsManifestFilePathBuffer ) )
1459    {
1460        // Failed so warn.
1461        Con::warnf( "Asset Manager: Failed to save asset tags manifest '%s' from module '%s'.", assetTagsManifestFilePathBuffer, mAssetTagsModuleDefinition->getSignature() );
1462        return false;
1463    }
1464
1465    return true;
1466}
1467
1468//-----------------------------------------------------------------------------
1469
1470bool AssetManager::restoreAssetTags( void )
1471{
1472    // Do we already have a manifest?
1473    if ( mAssetTagsManifest.isNull() )
1474    {
1475        // No, so warn.
1476        Con::warnf( "Asset Manager: Cannot restore asset tags manifest as one is not already loaded." );
1477        return false;
1478    }
1479
1480    // Sanity!
1481    AssertFatal( mAssetTagsModuleDefinition != NULL, "Cannot restore asset tags manifest as module definition is NULL." );
1482
1483    // Delete existing asset tags manifest.
1484    mAssetTagsManifest->deleteObject();
1485
1486    // Reload asset tags manifest.
1487    return loadAssetTags( mAssetTagsModuleDefinition );
1488}
1489
1490//-----------------------------------------------------------------------------
1491
1492S32 QSORT_CALLBACK descendingAssetDefinitionLoadCount(const void* a, const void* b)
1493{
1494    // Debug Profiling.
1495    PROFILE_SCOPE(AssetManager_DescendingAssetDefinitionLoadCount);
1496
1497    // Fetch asset definitions.
1498    const AssetDefinition* pAssetDefinitionA  = *(AssetDefinition**)a;
1499    const AssetDefinition* pAssetDefinitionB  = *(AssetDefinition**)b;
1500
1501    // Sort.
1502    return pAssetDefinitionB->mAssetLoadedCount - pAssetDefinitionA->mAssetLoadedCount;
1503}
1504
1505//-----------------------------------------------------------------------------
1506
1507void AssetManager::dumpDeclaredAssets( void ) const
1508{
1509    Vector<const AssetDefinition*> assetDefinitions;
1510
1511    // Iterate asset definitions.
1512    for( typeDeclaredAssetsHash::const_iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1513    {
1514        assetDefinitions.push_back( assetItr->value );
1515    }
1516
1517    // Sort asset definitions.
1518    dQsort( assetDefinitions.address(), assetDefinitions.size(), sizeof(const AssetDefinition*), descendingAssetDefinitionLoadCount );
1519
1520    // Info.
1521    Con::printSeparator();
1522    Con::printf( "Asset Manager: %d declared asset(s) dump as follows:", mDeclaredAssets.size() );
1523    Con::printBlankLine();
1524
1525    // Iterate sorted asset definitions.
1526    for ( Vector<const AssetDefinition*>::iterator assetItr = assetDefinitions.begin(); assetItr != assetDefinitions.end(); ++assetItr )
1527    {
1528        // Fetch asset definition.
1529        const AssetDefinition* pAssetDefinition = *assetItr;
1530
1531        // Info.
1532        Con::printf( "AssetId:'%s', RefCount:%d, LoadCount:%d, UnloadCount:%d, AutoUnload:%d, Loaded:%d, Internal:%d, Private: %d, Type:'%s', Module/Version:'%s'/'%d', File:'%s'",
1533            pAssetDefinition->mAssetId,
1534            pAssetDefinition->mpAssetBase == NULL ? 0 : pAssetDefinition->mpAssetBase->getAcquiredReferenceCount(),
1535            pAssetDefinition->mAssetLoadedCount,
1536            pAssetDefinition->mAssetUnloadedCount,
1537            pAssetDefinition->mAssetAutoUnload,
1538            pAssetDefinition->mpAssetBase != NULL,
1539            pAssetDefinition->mAssetInternal,
1540            pAssetDefinition->mAssetPrivate,
1541            pAssetDefinition->mAssetType,
1542            pAssetDefinition->mpModuleDefinition->getModuleId(),
1543            pAssetDefinition->mpModuleDefinition->getVersionId(),
1544            pAssetDefinition->mAssetBaseFilePath );
1545    }
1546
1547    // Info.
1548    Con::printSeparator();
1549    Con::printBlankLine();
1550}
1551
1552//-----------------------------------------------------------------------------
1553
1554S32 AssetManager::findAllAssets( AssetQuery* pAssetQuery, const bool ignoreInternal, const bool ignorePrivate )
1555{
1556    // Debug Profiling.
1557    PROFILE_SCOPE(AssetManager_FindAllAssets);
1558
1559    // Sanity!
1560    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1561
1562    // Reset result count.
1563    S32 resultCount = 0;
1564
1565    // Iterate declared assets.
1566    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1567    {
1568        // Fetch asset definition.
1569        AssetDefinition* pAssetDefinition = assetItr->value;
1570
1571        // Skip if internal and we're ignoring them.
1572        if ( ignoreInternal && pAssetDefinition->mAssetInternal )
1573            continue;
1574
1575        // Skip if private and we're ignoring them.
1576        if ( ignorePrivate && pAssetDefinition->mAssetPrivate )
1577            continue;
1578
1579        // Store as result.
1580        pAssetQuery->mAssetList.push_back( pAssetDefinition->mAssetId );
1581
1582        // Increase result count.
1583        resultCount++;
1584    }
1585
1586    return resultCount;
1587}
1588
1589//-----------------------------------------------------------------------------
1590
1591S32 AssetManager::findAssetName( AssetQuery* pAssetQuery, const char* pAssetName, const bool partialName )
1592{
1593    // Debug Profiling.
1594    PROFILE_SCOPE(AssetManager_FindAssetName);
1595
1596    // Sanity!
1597    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1598    AssertFatal( pAssetName != NULL, "Cannot use NULL asset name." );
1599
1600    // Reset asset name.
1601    StringTableEntry assetName = NULL;
1602    S32 partialAssetNameLength = 0;
1603        
1604    // Are we doing partial name search?
1605    if ( partialName ) 
1606    {
1607        // Yes, so fetch length of partial name.
1608        partialAssetNameLength = dStrlen( pAssetName );
1609    }
1610    else
1611    {
1612        // No, so fetch asset name.
1613        assetName = StringTable->insert( pAssetName );
1614    }
1615
1616    // Reset result count.
1617    S32 resultCount = 0;
1618
1619    // Iterate declared assets.
1620    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1621    {
1622        // Fetch asset definition.
1623        AssetDefinition* pAssetDefinition = assetItr->value;
1624
1625        // Are we doing partial name search?
1626        if ( partialName ) 
1627        {
1628            // Yes, so fetch the length of this asset name.
1629            const S32 currentAssetNameLength = dStrlen( pAssetDefinition->mAssetName );
1630
1631            // Skip if the query asset name is longer than the current asset name.
1632            if ( partialAssetNameLength > currentAssetNameLength )
1633                continue;
1634            
1635            // Skip if this is not the asset we want.
1636            if ( dStrnicmp( pAssetDefinition->mAssetName, pAssetName, partialAssetNameLength ) != 0 )
1637                continue;
1638        }
1639        else
1640        {
1641            // No, so skip if this is not the asset we want.
1642            if ( assetName != pAssetDefinition->mAssetName )
1643                continue;
1644        }
1645
1646        // Store as result.
1647        pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
1648
1649        // Increase result count.
1650        resultCount++;
1651    }
1652
1653    return resultCount;
1654}
1655    
1656//-----------------------------------------------------------------------------
1657
1658S32 AssetManager::findAssetCategory( AssetQuery* pAssetQuery, const char* pAssetCategory, const bool assetQueryAsSource )
1659{
1660    // Debug Profiling.
1661    PROFILE_SCOPE(AssetManager_FindAssetCategory);
1662
1663    // Sanity!
1664    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1665    AssertFatal( pAssetCategory != NULL, "Cannot use NULL asset category." );
1666
1667    // Fetch asset category.
1668    StringTableEntry assetCategory = StringTable->insert( pAssetCategory );
1669
1670    // Reset result count.
1671    S32 resultCount = 0;
1672
1673    // Use asset-query as the source?
1674    if ( assetQueryAsSource )
1675    {
1676        AssetQuery filteredAssets;
1677
1678        // Yes, so iterate asset query.
1679        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
1680        {
1681            // Fetch asset definition.
1682            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
1683
1684            // Skip if this is not the asset we want.
1685            if (    pAssetDefinition == NULL ||
1686                    pAssetDefinition->mAssetCategory != assetCategory )
1687                        continue;
1688
1689            // Store as result.
1690            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
1691
1692            // Increase result count.
1693            resultCount++;
1694        }
1695
1696        // Set asset query.
1697        pAssetQuery->set( filteredAssets );
1698    }
1699    else
1700    {
1701        // No, so iterate declared assets.
1702        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1703        {
1704            // Fetch asset definition.
1705            AssetDefinition* pAssetDefinition = assetItr->value;
1706
1707            // Skip if this is not the asset we want.
1708            if ( assetCategory != pAssetDefinition->mAssetCategory )
1709                continue;
1710
1711            // Store as result.
1712            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
1713
1714            // Increase result count.
1715            resultCount++;
1716        }
1717    }
1718
1719    return resultCount;
1720}
1721
1722S32 AssetManager::findAssetAutoUnload( AssetQuery* pAssetQuery, const bool assetAutoUnload, const bool assetQueryAsSource )
1723{
1724    // Debug Profiling.
1725    PROFILE_SCOPE(AssetManager_FindAssetAutoUnload);
1726
1727    // Sanity!
1728    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1729
1730    // Reset result count.
1731    S32 resultCount = 0;
1732
1733    // Use asset-query as the source?
1734    if ( assetQueryAsSource )
1735    {
1736        AssetQuery filteredAssets;
1737
1738        // Yes, so iterate asset query.
1739        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
1740        {
1741            // Fetch asset definition.
1742            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
1743
1744            // Skip if this is not the asset we want.
1745            if (    pAssetDefinition == NULL ||
1746                    pAssetDefinition->mAssetAutoUnload != assetAutoUnload )
1747                        continue;
1748
1749            // Store as result.
1750            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
1751
1752            // Increase result count.
1753            resultCount++;
1754        }
1755
1756        // Set asset query.
1757        pAssetQuery->set( filteredAssets );
1758    }
1759    else
1760    {
1761        // No, so iterate declared assets.
1762        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1763        {
1764            // Fetch asset definition.
1765            AssetDefinition* pAssetDefinition = assetItr->value;
1766
1767            // Skip if this is not the asset we want.
1768            if ( assetAutoUnload != pAssetDefinition->mAssetAutoUnload )
1769                continue;
1770
1771            // Store as result.
1772            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
1773
1774            // Increase result count.
1775            resultCount++;
1776        }
1777    }
1778
1779    return resultCount;
1780}
1781
1782//-----------------------------------------------------------------------------
1783
1784S32 AssetManager::findAssetInternal( AssetQuery* pAssetQuery, const bool assetInternal, const bool assetQueryAsSource )
1785{
1786    // Debug Profiling.
1787    PROFILE_SCOPE(AssetManager_FindAssetInternal);
1788
1789    // Sanity!
1790    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1791
1792    // Reset result count.
1793    S32 resultCount = 0;
1794
1795    // Use asset-query as the source?
1796    if ( assetQueryAsSource )
1797    {
1798        AssetQuery filteredAssets;
1799
1800        // Yes, so iterate asset query.
1801        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
1802        {
1803            // Fetch asset definition.
1804            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
1805
1806            // Skip if this is not the asset we want.
1807            if (    pAssetDefinition == NULL ||
1808                    pAssetDefinition->mAssetInternal != assetInternal )
1809                        continue;
1810
1811            // Store as result.
1812            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
1813
1814            // Increase result count.
1815            resultCount++;
1816        }
1817
1818        // Set asset query.
1819        pAssetQuery->set( filteredAssets );
1820    }
1821    else
1822    {
1823        // No, so iterate declared assets.
1824        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1825        {
1826            // Fetch asset definition.
1827            AssetDefinition* pAssetDefinition = assetItr->value;
1828
1829            // Skip if this is not the asset we want.
1830            if ( assetInternal != pAssetDefinition->mAssetInternal )
1831                continue;
1832
1833            // Store as result.
1834            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
1835
1836            // Increase result count.
1837            resultCount++;
1838        }
1839    }
1840
1841    return resultCount;
1842}
1843
1844//-----------------------------------------------------------------------------
1845
1846S32 AssetManager::findAssetPrivate( AssetQuery* pAssetQuery, const bool assetPrivate, const bool assetQueryAsSource )
1847{
1848    // Debug Profiling.
1849    PROFILE_SCOPE(AssetManager_FindAssetPrivate);
1850
1851    // Sanity!
1852    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1853
1854    // Reset result count.
1855    S32 resultCount = 0;
1856
1857    // Use asset-query as the source?
1858    if ( assetQueryAsSource )
1859    {
1860        AssetQuery filteredAssets;
1861
1862        // Yes, so iterate asset query.
1863        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
1864        {
1865            // Fetch asset definition.
1866            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
1867
1868            // Skip if this is not the asset we want.
1869            if (    pAssetDefinition == NULL ||
1870                    pAssetDefinition->mAssetPrivate != assetPrivate )
1871                        continue;
1872
1873            // Store as result.
1874            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
1875
1876            // Increase result count.
1877            resultCount++;
1878        }
1879
1880        // Set asset query.
1881        pAssetQuery->set( filteredAssets );
1882    }
1883    else
1884    {
1885        // No, so iterate declared assets.
1886        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1887        {
1888            // Fetch asset definition.
1889            AssetDefinition* pAssetDefinition = assetItr->value;
1890
1891            // Skip if this is not the asset we want.
1892            if ( assetPrivate != pAssetDefinition->mAssetPrivate )
1893                continue;
1894
1895            // Store as result.
1896            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
1897
1898            // Increase result count.
1899            resultCount++;
1900        }
1901    }
1902
1903    return resultCount;
1904}
1905
1906//-----------------------------------------------------------------------------
1907
1908S32 AssetManager::findAssetType( AssetQuery* pAssetQuery, const char* pAssetType, const bool assetQueryAsSource )
1909{
1910    // Debug Profiling.
1911    PROFILE_SCOPE(AssetManager_FindAssetType);
1912
1913    // Sanity!
1914    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1915    AssertFatal( pAssetType != NULL, "Cannot use NULL asset type." );
1916
1917    // Fetch asset type.
1918    StringTableEntry assetType = StringTable->insert( pAssetType );
1919
1920    // Reset result count.
1921    S32 resultCount = 0;
1922
1923    // Use asset-query as the source?
1924    if ( assetQueryAsSource )
1925    {
1926        AssetQuery filteredAssets;
1927
1928        // Yes, so iterate asset query.
1929        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
1930        {
1931            // Fetch asset definition.
1932            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
1933
1934            // Skip if this is not the asset we want.
1935            if (    pAssetDefinition == NULL ||
1936                    pAssetDefinition->mAssetType != assetType )
1937                        continue;
1938
1939            // Store as result.
1940            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
1941
1942            // Increase result count.
1943            resultCount++;
1944        }
1945
1946        // Set asset query.
1947        pAssetQuery->set( filteredAssets );
1948    }
1949    else
1950    {
1951        // No, so iterate declared assets.
1952        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
1953        {
1954            // Fetch asset definition.
1955            AssetDefinition* pAssetDefinition = assetItr->value;
1956
1957            // Skip if this is not the asset we want.
1958            if ( assetType != pAssetDefinition->mAssetType )
1959                continue;
1960
1961            // Store as result.
1962            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
1963
1964            // Increase result count.
1965            resultCount++;
1966        }
1967    }
1968
1969    return resultCount;
1970}
1971
1972//-----------------------------------------------------------------------------
1973
1974S32 AssetManager::findAssetDependsOn( AssetQuery* pAssetQuery, const char* pAssetId )
1975{
1976    // Debug Profiling.
1977    PROFILE_SCOPE(AssetManager_FindAssetDependsOn);
1978
1979    // Sanity!
1980    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
1981    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
1982
1983    // Fetch asset Id.
1984    StringTableEntry assetId = StringTable->insert( pAssetId );
1985
1986    // Reset result count.
1987    S32 resultCount = 0;
1988
1989    // Find depends-on entry.
1990    typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find( assetId );
1991
1992    // Iterate all dependencies.
1993    while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == assetId )
1994    {
1995        // Store as result.
1996       pAssetQuery->mAssetList.push_back(dependsOnItr->value);
1997
1998        // Next dependency.
1999        dependsOnItr++;
2000
2001        // Increase result count.
2002        resultCount++;
2003    }
2004
2005    return resultCount;
2006}
2007
2008//-----------------------------------------------------------------------------
2009
2010S32 AssetManager::findAssetIsDependedOn( AssetQuery* pAssetQuery, const char* pAssetId )
2011{
2012    // Debug Profiling.
2013    PROFILE_SCOPE(AssetManager_FindAssetIsDependedOn);
2014
2015    // Sanity!
2016    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
2017    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
2018
2019    // Fetch asset Id.
2020    StringTableEntry assetId = StringTable->insert( pAssetId );
2021
2022    // Reset result count.
2023    S32 resultCount = 0;
2024
2025    // Find depended-on entry.
2026    typeAssetIsDependedOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find( assetId );
2027
2028    // Iterate all dependencies.
2029    while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
2030    {
2031        // Store as result.
2032       pAssetQuery->mAssetList.push_back(dependedOnItr->value);
2033
2034        // Next dependency.
2035        dependedOnItr++;
2036
2037        // Increase result count.
2038        resultCount++;
2039    }
2040
2041    return resultCount;
2042}
2043
2044//-----------------------------------------------------------------------------
2045
2046S32 AssetManager::findInvalidAssetReferences( AssetQuery* pAssetQuery )
2047{
2048    // Debug Profiling.
2049    PROFILE_SCOPE(AssetManager_FindInvalidAssetReferences);
2050
2051    // Sanity!
2052    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
2053
2054    // Reset result count.
2055    S32 resultCount = 0;
2056
2057    // Iterate referenced assets.
2058    for( typeReferencedAssetsHash::Iterator assetItr = mReferencedAssets.begin(); assetItr != mReferencedAssets.end(); ++assetItr )
2059    {
2060        // Find asset definition.
2061        AssetDefinition* pAssetDefinition = findAsset( assetItr->key );
2062
2063        // Skip if the asset definition was found.
2064        if ( pAssetDefinition != NULL )
2065            continue;
2066
2067        // Store as result.
2068        pAssetQuery->mAssetList.push_back(assetItr->key);
2069
2070        // Increase result count.
2071        resultCount++;
2072    }
2073
2074    return resultCount;
2075}
2076
2077//-----------------------------------------------------------------------------
2078
2079S32 AssetManager::findTaggedAssets( AssetQuery* pAssetQuery, const char* pAssetTagNames, const bool assetQueryAsSource )
2080{
2081    // Debug Profiling.
2082    PROFILE_SCOPE(AssetManager_FindTaggedAssets);
2083
2084    // Sanity!
2085    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
2086    AssertFatal( pAssetTagNames != NULL, "Cannot use NULL asset tag name(s)." );
2087
2088    // Do we have an asset tag manifest?
2089    if ( mAssetTagsManifest.isNull() )
2090    {
2091        // No, so warn.
2092        Con::warnf( "Asset Manager: Cannot find tagged assets as no asset tag manifest is present." );
2093        return 0;
2094    }
2095
2096    // Reset result count.
2097    S32 resultCount = 0;
2098
2099    const char* pTagSeparators = " ,\t\n";
2100
2101    // Fetch tag count.
2102    U32 assetTagCount = StringUnit::getUnitCount( pAssetTagNames, pTagSeparators );
2103
2104    // Fetch asset tags.
2105    Vector<AssetTagsManifest::AssetTag*> assetTags;
2106    for( U32 tagIndex = 0; tagIndex < assetTagCount; ++tagIndex )
2107    {
2108        // Fetch asset tag name.
2109        const char* pTagName = StringUnit::getUnit( pAssetTagNames, tagIndex, pTagSeparators );
2110
2111        // Fetch asset tag.
2112        AssetTagsManifest::AssetTag* pAssetTag = mAssetTagsManifest->findAssetTag( pTagName );
2113
2114        // Did we find the asset tag?
2115        if ( pAssetTag == NULL )
2116        {
2117            // No, so warn.
2118            Con::warnf( "AssetTagsManifest: Asset Manager: Cannot find tagged assets of '%s' as it does not exist.  Ignoring tag.", pTagName );
2119            continue;
2120        }
2121
2122        assetTags.push_back( pAssetTag );
2123    }
2124
2125    // Fetch found asset tag count.
2126    assetTagCount = assetTags.size();
2127
2128    // Did we find any tags?
2129    if ( assetTagCount == 0 )
2130    {
2131        // No, so warn.
2132        Con::warnf( "AssetTagsManifest: Asset Manager: No specified tagged assets found in '%s'.", pAssetTagNames );
2133        return 0;
2134    } 
2135
2136    // Use asset-query as the source?
2137    if ( assetQueryAsSource )
2138    {
2139        AssetQuery filteredAssets;
2140
2141        // Yes, so iterate asset query.
2142        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
2143        {
2144            // Fetch asset Id.
2145            StringTableEntry assetId = *assetItr;
2146
2147            // Skip if asset is not valid.
2148            if ( !isDeclaredAsset( assetId ) )
2149                continue;
2150
2151            // Reset matched flag.
2152            bool assetTagMatched = false;
2153
2154            // Iterate asset tags.
2155            for ( Vector<AssetTagsManifest::AssetTag*>::iterator assetTagItr = assetTags.begin(); assetTagItr != assetTags.end(); ++assetTagItr )
2156            {
2157                // Fetch asset tag.
2158                AssetTagsManifest::AssetTag* pAssetTag = *assetTagItr;
2159
2160                // Skip if asset is not tagged.
2161                if ( !pAssetTag->containsAsset( assetId ) )
2162                    continue;
2163                
2164                // Flag as matched.
2165                assetTagMatched = true;
2166                break;
2167            }
2168
2169            // Did we find a match?
2170            if ( assetTagMatched )
2171            {
2172                // Yes, so is asset already present?
2173                if ( !filteredAssets.containsAsset( assetId ) )
2174                {
2175                    // No, so store as result.
2176                   filteredAssets.mAssetList.push_back(assetId);
2177
2178                    // Increase result count.
2179                    resultCount++;
2180                }
2181            }
2182        }
2183
2184        // Set asset query.
2185        pAssetQuery->set( filteredAssets );
2186    }
2187    else
2188    {
2189        // Iterate asset tags.
2190        for ( Vector<AssetTagsManifest::AssetTag*>::iterator assetTagItr = assetTags.begin(); assetTagItr != assetTags.end(); ++assetTagItr )
2191        {
2192            // Fetch asset tag.
2193            AssetTagsManifest::AssetTag* pAssetTag = *assetTagItr;
2194
2195            // Iterate tagged assets.
2196            for ( Vector<typeAssetId>::iterator assetItr = pAssetTag->mAssets.begin(); assetItr != pAssetTag->mAssets.end(); ++assetItr )
2197            {
2198                // Fetch asset Id.
2199                StringTableEntry assetId = *assetItr;
2200
2201                // Skip if asset Id is already present.
2202                if ( pAssetQuery->containsAsset( assetId ) )
2203                    continue;
2204
2205                // Store as result.
2206                pAssetQuery->mAssetList.push_back(assetId);
2207
2208                // Increase result count.
2209                resultCount++;
2210            }
2211        }
2212    }
2213
2214    return resultCount;
2215}
2216
2217//-----------------------------------------------------------------------------
2218
2219S32 AssetManager::findAssetLooseFile( AssetQuery* pAssetQuery, const char* pLooseFile, const bool assetQueryAsSource )
2220{
2221    // Debug Profiling.
2222    PROFILE_SCOPE(AssetManager_FindAssetLooseFile);
2223
2224    // Sanity!
2225    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
2226    AssertFatal( pLooseFile != NULL, "Cannot use NULL loose file." );
2227
2228    // Expand loose file.
2229    char looseFileBuffer[1024];
2230    Con::expandPath(looseFileBuffer, sizeof(looseFileBuffer), pLooseFile, NULL, false );
2231
2232    // Fetch asset loose file.
2233    StringTableEntry looseFile = StringTable->insert( looseFileBuffer );
2234
2235    // Reset result count.
2236    S32 resultCount = 0;
2237
2238    // Use asset-query as the source?
2239    if ( assetQueryAsSource )
2240    {
2241        AssetQuery filteredAssets;
2242
2243        // Yes, so iterate asset query.
2244        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
2245        {
2246            // Fetch asset definition.
2247            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
2248
2249            // Fetch loose files.
2250            Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
2251
2252            // Skip if this asset has no loose files.
2253            if ( assetLooseFiles.size() == 0 )
2254                continue;
2255
2256            // Search the assets loose files.
2257            for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
2258            {
2259                // Is this the loose file we are searching for?
2260                if ( *looseFileItr != looseFile )
2261                    continue;
2262
2263                // Store as result.
2264                filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
2265
2266                // Increase result count.
2267                resultCount++;
2268
2269                break;
2270            }
2271        }
2272
2273        // Set asset query.
2274        pAssetQuery->set( filteredAssets );
2275    }
2276    else
2277    {
2278        // No, so iterate declared assets.
2279        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
2280        {
2281            // Fetch asset definition.
2282            AssetDefinition* pAssetDefinition = assetItr->value;
2283
2284            // Fetch loose files.
2285            Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
2286
2287            // Skip if this asset has no loose files.
2288            if ( assetLooseFiles.size() == 0 )
2289                continue;
2290
2291            // Search the assets loose files.
2292            for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
2293            {
2294                // Is this the loose file we are searching for?
2295                if ( *looseFileItr != looseFile )
2296                    continue;
2297
2298                // Store as result.
2299                pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
2300
2301                // Increase result count.
2302                resultCount++;
2303
2304                break;
2305            }
2306        }
2307    }
2308
2309    return resultCount;
2310}
2311
2312//-----------------------------------------------------------------------------
2313
2314bool AssetManager::scanDeclaredAssets( const char* pPath, const char* pExtension, const bool recurse, ModuleDefinition* pModuleDefinition )
2315{
2316    // Debug Profiling.
2317    PROFILE_SCOPE(AssetManager_ScanDeclaredAssets);
2318
2319    // Sanity!
2320    AssertFatal( pPath != NULL, "Cannot scan declared assets with NULL path." );
2321    AssertFatal( pExtension != NULL, "Cannot scan declared assets with NULL extension." );
2322
2323    // Expand path location.
2324    char pathBuffer[1024];
2325    Con::expandPath( pathBuffer, sizeof(pathBuffer), pPath );
2326
2327    // Find files.
2328    Vector<Platform::FileInfo> files;
2329    if ( !Platform::dumpPath( pathBuffer, files, recurse ? -1 : 0 ) )
2330    {
2331        // Failed so warn.
2332        Con::warnf( "Asset Manager: Failed to scan declared assets in directory '%s'.", pathBuffer );
2333        return false;
2334    }
2335
2336    // Is the asset file-path located within the specified module?
2337    if ( !Con::isBasePath( pathBuffer, pModuleDefinition->getModulePath() ) )
2338    {
2339        // No, so warn.
2340        Con::warnf( "Asset Manager: Could not add declared asset file '%s' as file does not exist with module path '%s'",
2341            pathBuffer,
2342            pModuleDefinition->getModulePath() );
2343        return false;
2344    }
2345
2346    // Info.
2347    if ( mEchoInfo )
2348    {
2349        Con::printSeparator();
2350        Con::printf( "Asset Manager: Scanning for declared assets in path '%s' for files with extension '%s'...", pathBuffer, pExtension );
2351    }
2352
2353    // Fetch extension length.
2354    const U32 extensionLength = dStrlen( pExtension );
2355
2356    // Fetch module assets.
2357    ModuleDefinition::typeModuleAssetsVector& moduleAssets = pModuleDefinition->getModuleAssets();
2358
2359    TamlAssetDeclaredVisitor assetDeclaredVisitor;
2360
2361    // Iterate files.
2362    for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr )
2363    {
2364        // Fetch file info.
2365        Platform::FileInfo& fileInfo = *fileItr;
2366
2367        // Fetch filename.
2368        const char* pFilename = fileInfo.pFileName;
2369
2370        // Find filename length.
2371        const U32 filenameLength = dStrlen( pFilename );
2372
2373        // Skip if extension is longer than filename.
2374        if ( extensionLength > filenameLength )
2375            continue;
2376
2377        // Skip if extension not found.
2378        if ( dStricmp( pFilename + filenameLength - extensionLength, pExtension ) != 0 )
2379            continue;
2380
2381        // Clear declared assets.
2382        assetDeclaredVisitor.clear();
2383
2384        // Format full file-path.
2385        char assetFileBuffer[1024];
2386        dSprintf( assetFileBuffer, sizeof(assetFileBuffer), "%s/%s", fileInfo.pFullPath, fileInfo.pFileName );
2387
2388        // Parse the filename.
2389        if ( !mTaml.parse( assetFileBuffer, assetDeclaredVisitor ) )
2390        {
2391            // Warn.
2392            Con::warnf( "Asset Manager: Failed to parse file containing asset declaration: '%s'.", assetFileBuffer );
2393            continue;
2394        }
2395
2396        // Fetch asset definition.
2397        AssetDefinition& foundAssetDefinition = assetDeclaredVisitor.getAssetDefinition();
2398
2399        // Did we get an asset name?
2400        if ( foundAssetDefinition.mAssetName == StringTable->EmptyString() )
2401        {
2402            // No, so warn.
2403            Con::warnf( "Asset Manager: Parsed file '%s' but did not encounter an asset.", assetFileBuffer );
2404            continue;
2405        }
2406
2407        // Set module definition.
2408        foundAssetDefinition.mpModuleDefinition = pModuleDefinition;
2409
2410        // Format asset Id.
2411        char assetIdBuffer[1024];
2412        dSprintf(assetIdBuffer, sizeof(assetIdBuffer), "%s%s%s",
2413            pModuleDefinition->getModuleId(),
2414            ASSET_SCOPE_TOKEN,
2415            foundAssetDefinition.mAssetName );
2416
2417        // Set asset Id.
2418        foundAssetDefinition.mAssetId = StringTable->insert( assetIdBuffer );
2419
2420        // Does this asset already exist?
2421        if ( mDeclaredAssets.contains( foundAssetDefinition.mAssetId ) )
2422        {
2423            // Yes, so warn.
2424            Con::warnf( "Asset Manager: Encountered asset Id '%s' in asset file '%s' but it conflicts with existing asset Id in asset file '%s'.",
2425                foundAssetDefinition.mAssetId,
2426                foundAssetDefinition.mAssetBaseFilePath,
2427                mDeclaredAssets.find( foundAssetDefinition.mAssetId )->value->mAssetBaseFilePath );
2428
2429            continue;
2430        }
2431
2432        // Create new asset definition.
2433        AssetDefinition* pAssetDefinition = new AssetDefinition( foundAssetDefinition );
2434
2435        // Store in declared assets.
2436        mDeclaredAssets.insert( pAssetDefinition->mAssetId, pAssetDefinition );
2437
2438        // Store in module assets.
2439        moduleAssets.push_back( pAssetDefinition );
2440        
2441        // Info.
2442        if ( mEchoInfo )
2443        {
2444            Con::printSeparator();
2445            Con::printf( "Asset Manager: Adding Asset Id '%s' of type '%s' in asset file '%s'.",
2446                pAssetDefinition->mAssetId,
2447                pAssetDefinition->mAssetType,
2448                pAssetDefinition->mAssetBaseFilePath );
2449        }
2450
2451        // Fetch asset Id.
2452        StringTableEntry assetId = pAssetDefinition->mAssetId;
2453
2454        // Fetch asset dependencies.
2455        TamlAssetDeclaredVisitor::typeAssetIdVector& assetDependencies = assetDeclaredVisitor.getAssetDependencies();
2456
2457        // Are there any asset dependencies?
2458        if ( assetDependencies.size() > 0 )
2459        {
2460            // Yes, so iterate dependencies.
2461            for( TamlAssetDeclaredVisitor::typeAssetIdVector::iterator assetDependencyItr = assetDependencies.begin(); assetDependencyItr != assetDependencies.end(); ++assetDependencyItr )
2462            {
2463                // Fetch asset Ids.
2464                StringTableEntry dependencyAssetId = *assetDependencyItr;
2465
2466                // Insert depends-on.
2467                mAssetDependsOn.insertEqual( assetId, dependencyAssetId );
2468
2469                // Insert is-depended-on.
2470                mAssetIsDependedOn.insertEqual( dependencyAssetId, assetId );
2471
2472                // Info.
2473                if ( mEchoInfo )
2474                {
2475                    Con::printf( "Asset Manager: Asset Id '%s' has dependency of Asset Id '%s'", assetId, dependencyAssetId );
2476                }
2477            }
2478        }
2479
2480        // Fetch asset loose files.
2481        TamlAssetDeclaredVisitor::typeLooseFileVector& assetLooseFiles = assetDeclaredVisitor.getAssetLooseFiles();
2482
2483        // Are there any loose files?
2484        if ( assetLooseFiles.size() > 0 )
2485        {
2486            // Yes, so iterate loose files.
2487            for( TamlAssetDeclaredVisitor::typeLooseFileVector::iterator assetLooseFileItr = assetLooseFiles.begin(); assetLooseFileItr != assetLooseFiles.end(); ++assetLooseFileItr )
2488            {
2489                // Fetch loose file.
2490                StringTableEntry looseFile = *assetLooseFileItr;
2491
2492                // Info.
2493                if ( mEchoInfo )
2494                {
2495                    Con::printf( "Asset Manager: Asset Id '%s' has loose file '%s'.", assetId, looseFile );
2496                }
2497
2498                // Store loose file.
2499                pAssetDefinition->mAssetLooseFiles.push_back( looseFile );
2500            }
2501        }
2502    }
2503
2504    // Info.
2505    if ( mEchoInfo )
2506    {
2507        Con::printSeparator();
2508        Con::printf( "Asset Manager: ... Finished scanning for declared assets in path '%s' for files with extension '%s'.", pathBuffer, pExtension );
2509        Con::printSeparator();
2510        Con::printBlankLine();
2511    }
2512
2513    return true;
2514}
2515
2516//-----------------------------------------------------------------------------
2517
2518bool AssetManager::scanReferencedAssets( const char* pPath, const char* pExtension, const bool recurse )
2519{
2520    // Debug Profiling.
2521    PROFILE_SCOPE(AssetManager_ScanReferencedAssets);
2522
2523    // Sanity!
2524    AssertFatal( pPath != NULL, "Cannot scan referenced assets with NULL path." );
2525    AssertFatal( pExtension != NULL, "Cannot scan referenced assets with NULL extension." );
2526
2527    // Expand path location.
2528    char pathBuffer[1024];
2529    Con::expandPath( pathBuffer, sizeof(pathBuffer), pPath );
2530
2531    // Find files.
2532    Vector<Platform::FileInfo> files;
2533    if ( !Platform::dumpPath( pathBuffer, files, recurse ? -1 : 0 ) )
2534    {
2535        // Failed so warn.
2536        Con::warnf( "Asset Manager: Failed to scan referenced assets in directory '%s'.", pathBuffer );
2537        return false;
2538    }
2539
2540    // Info.
2541    if ( mEchoInfo )
2542    {
2543        Con::printSeparator();
2544        Con::printf( "Asset Manager: Scanning for referenced assets in path '%s' for files with extension '%s'...", pathBuffer, pExtension );
2545    }
2546
2547    // Fetch extension length.
2548    const U32 extensionLength = dStrlen( pExtension );
2549
2550    TamlAssetReferencedVisitor assetReferencedVisitor;
2551
2552    // Iterate files.
2553    for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr )
2554    {
2555        // Fetch file info.
2556        Platform::FileInfo& fileInfo = *fileItr;
2557
2558        // Fetch filename.
2559        const char* pFilename = fileInfo.pFileName;
2560
2561        // Find filename length.
2562        const U32 filenameLength = dStrlen( pFilename );
2563
2564        // Skip if extension is longer than filename.
2565        if ( extensionLength > filenameLength )
2566            continue;
2567
2568        // Skip if extension not found.
2569        if ( dStricmp( pFilename + filenameLength - extensionLength, pExtension ) != 0 )
2570            continue;
2571
2572        // Clear referenced assets.
2573        assetReferencedVisitor.clear();
2574
2575        // Format full file-path.
2576        char assetFileBuffer[1024];
2577        dSprintf( assetFileBuffer, sizeof(assetFileBuffer), "%s/%s", fileInfo.pFullPath, fileInfo.pFileName );
2578
2579        // Format reference file-path.
2580        typeReferenceFilePath referenceFilePath = StringTable->insert( assetFileBuffer );
2581
2582        // Parse the filename.
2583        if ( !mTaml.parse( referenceFilePath, assetReferencedVisitor ) )
2584        {
2585            // Warn.
2586            Con::warnf( "Asset Manager: Failed to parse file containing asset references: '%s'.", referenceFilePath );
2587            continue;
2588        }
2589
2590        // Fetch usage map.
2591        const TamlAssetReferencedVisitor::typeAssetReferencedHash& assetReferencedMap = assetReferencedVisitor.getAssetReferencedMap();
2592
2593        // Do we have any asset references?
2594        if ( assetReferencedMap.size() > 0 )
2595        {
2596            // Info.
2597            if ( mEchoInfo )
2598            {
2599                Con::printSeparator();
2600            }
2601
2602            // Iterate usage.
2603            for( TamlAssetReferencedVisitor::typeAssetReferencedHash::const_iterator usageItr = assetReferencedMap.begin(); usageItr != assetReferencedMap.end(); ++usageItr )
2604            {
2605                // Fetch asset name.
2606                typeAssetId assetId = usageItr->key;
2607
2608                // Info.
2609                if ( mEchoInfo )
2610                {
2611                    Con::printf( "Asset Manager: Found referenced Asset Id '%s' in file '%s'.", assetId, referenceFilePath );
2612                }
2613
2614                // Add referenced asset.
2615                addReferencedAsset( assetId, referenceFilePath );
2616            }
2617        }
2618    }
2619
2620    // Info.
2621    if ( mEchoInfo )
2622    {
2623        Con::printf( "Asset Manager: ... Finished scanning for referenced assets in path '%s' for files with extension '%s'.", pathBuffer, pExtension );
2624        Con::printSeparator();
2625        Con::printBlankLine();
2626    }
2627
2628    return true;
2629}
2630
2631//-----------------------------------------------------------------------------
2632
2633AssetDefinition* AssetManager::findAsset( const char* pAssetId )
2634{
2635    // Debug Profiling.
2636    PROFILE_SCOPE(AssetManager_FindAsset);
2637
2638    // Sanity!
2639    AssertFatal( pAssetId != NULL, "Cannot find NULL asset Id." );
2640
2641    // Fetch asset Id.
2642    StringTableEntry assetId = StringTable->insert( pAssetId );
2643
2644    // Find declared asset.
2645    typeDeclaredAssetsHash::iterator declaredAssetItr = mDeclaredAssets.find( assetId );
2646
2647    // Find if we didn't find a declared asset Id.
2648    if ( declaredAssetItr == mDeclaredAssets.end() )
2649        return NULL;
2650
2651    return declaredAssetItr->value;
2652}
2653
2654//-----------------------------------------------------------------------------
2655
2656void AssetManager::addReferencedAsset( StringTableEntry assetId, StringTableEntry referenceFilePath )
2657{
2658    // Debug Profiling.
2659    PROFILE_SCOPE(AssetManager_AddReferencedAsset);
2660
2661    // Sanity!
2662    AssertFatal( assetId != NULL, "Cannot add referenced asset with NULL asset Id." );
2663    AssertFatal( referenceFilePath != NULL, "Cannot add referenced asset with NULL reference file-path." );
2664
2665    // Find referenced asset.
2666    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find( assetId );
2667
2668    // Did we find the asset?
2669    if ( referencedAssetItr == mReferencedAssets.end() )
2670    {
2671        // No, so add asset Id.
2672        mReferencedAssets.insertEqual( assetId, referenceFilePath );
2673    }
2674    else
2675    {
2676        // Yes, so add asset Id with a unique file.
2677        while( true )
2678        {
2679            // Finish if this file is already present.
2680            if ( referencedAssetItr->value == referenceFilePath )
2681                return;
2682
2683            // Move to next asset Id.
2684            referencedAssetItr++;
2685
2686            // Is this the end of referenced assets or a different asset Id?
2687            if ( referencedAssetItr == mReferencedAssets.end() ||
2688                referencedAssetItr->key != assetId )
2689            {
2690                // Yes, so add asset reference.
2691                mReferencedAssets.insertEqual( assetId, referenceFilePath );
2692                return;
2693            }
2694        };
2695    }
2696}
2697
2698//-----------------------------------------------------------------------------
2699
2700void AssetManager::renameAssetReferences( StringTableEntry assetIdFrom, StringTableEntry assetIdTo )
2701{
2702    // Debug Profiling.
2703    PROFILE_SCOPE(AssetManager_RenameAssetReferences);
2704
2705    // Sanity!
2706    AssertFatal( assetIdFrom != NULL, "Cannot rename asset references using NULL asset Id from." );
2707    AssertFatal( assetIdTo != NULL, "Cannot rename asset references using NULL asset Id to." );
2708
2709    // Finish if the asset is not referenced.
2710    if ( !mReferencedAssets.count( assetIdFrom ) )
2711        return;
2712
2713    // Setup referenced update visitor.
2714    TamlAssetReferencedUpdateVisitor assetReferencedUpdateVisitor;
2715    assetReferencedUpdateVisitor.setAssetIdFrom( assetIdFrom );
2716    assetReferencedUpdateVisitor.setAssetIdTo( assetIdTo );
2717
2718    // Find first referenced asset Id.
2719    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find( assetIdFrom );
2720
2721    // Iterate references.
2722    while( true )
2723    {
2724        // Finish if end of references.
2725        if ( referencedAssetItr == mReferencedAssets.end() || referencedAssetItr->key != assetIdFrom )
2726            return;
2727
2728        // Info.
2729        if ( mEchoInfo )
2730        {
2731            Con::printf( "Asset Manager: Renaming declared Asset Id '%s' to Asset Id '%s'.  Updating referenced file '%s'",
2732                assetIdFrom,
2733                assetIdTo,
2734                referencedAssetItr->value );
2735        }
2736
2737        // Update asset file declaration.
2738        if ( !mTaml.parse( referencedAssetItr->value, assetReferencedUpdateVisitor ) )
2739        {
2740            // No, so warn.
2741            Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as the referenced asset file could not be parsed: %s",
2742                assetIdFrom, assetIdTo, referencedAssetItr->value );
2743        }
2744
2745        // Move to next reference.
2746        referencedAssetItr++;
2747    }
2748}
2749
2750//-----------------------------------------------------------------------------
2751
2752void AssetManager::removeAssetReferences( StringTableEntry assetId )
2753{
2754    // Debug Profiling.
2755    PROFILE_SCOPE(AssetManager_RemoveAssetReferences);
2756
2757    // Sanity!
2758    AssertFatal( assetId != NULL, "Cannot rename asset references using NULL asset Id." );
2759
2760    // Finish if the asset is not referenced.
2761    if ( !mReferencedAssets.count( assetId ) )
2762        return;
2763
2764    // Setup referenced update visitor.
2765    TamlAssetReferencedUpdateVisitor assetReferencedUpdateVisitor;
2766    assetReferencedUpdateVisitor.setAssetIdFrom( assetId );
2767    assetReferencedUpdateVisitor.setAssetIdTo( StringTable->EmptyString() );
2768
2769    // Find first referenced asset Id.
2770    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find(assetId);
2771
2772    // Iterate references.
2773    while( true )
2774    {
2775        // Finish if end of references.
2776        if ( referencedAssetItr == mReferencedAssets.end() || referencedAssetItr->key != assetId )
2777            break;
2778
2779        // Info.
2780        if ( mEchoInfo )
2781        {
2782            Con::printf( "Asset Manager: Removing Asset Id '%s' references from file '%s'",
2783                assetId,
2784                referencedAssetItr->value );
2785        }
2786
2787        // Update asset file declaration.
2788        if ( !mTaml.parse( referencedAssetItr->value, assetReferencedUpdateVisitor ) )
2789        {
2790            // No, so warn.
2791            Con::warnf("Asset Manager: Cannot remove referenced asset Id '%s' as the referenced asset file could not be parsed: %s",
2792                assetId,
2793                referencedAssetItr->value );
2794        }
2795
2796        // Move to next reference.
2797        referencedAssetItr++;
2798    }
2799
2800    // Remove asset references.
2801    mReferencedAssets.erase( assetId );
2802}
2803
2804//-----------------------------------------------------------------------------
2805
2806void AssetManager::renameAssetDependencies( StringTableEntry assetIdFrom, StringTableEntry assetIdTo )
2807{
2808    // Debug Profiling.
2809    PROFILE_SCOPE(AssetManager_RenameAssetDependencies);
2810
2811    // Sanity!
2812    AssertFatal( assetIdFrom != NULL, "Cannot rename asset dependencies using NULL asset Id from." );
2813    AssertFatal( assetIdTo != NULL, "Cannot rename asset dependencies using NULL asset Id to." );
2814
2815    // Rename via depends-on...
2816    while( mAssetDependsOn.count( assetIdFrom ) > 0 )
2817    {
2818        // Find depends-on.
2819       typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(assetIdFrom);
2820
2821        // Fetch dependency asset Id.
2822        StringTableEntry dependencyAssetId = dependsOnItr->value;
2823
2824        // Find is-depends-on entry.
2825        typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find(dependencyAssetId);
2826
2827        // Sanity!
2828        AssertFatal( isDependedOnItr != mAssetIsDependedOn.end(), "Asset dependencies are corrupt!" );
2829
2830        while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value != assetIdFrom )
2831        {
2832            isDependedOnItr++;
2833        }
2834
2835        // Sanity!
2836        AssertFatal( isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value == assetIdFrom, "Asset dependencies are corrupt!" );
2837        
2838        // Remove is-depended-on.        
2839        mAssetIsDependedOn.erase( isDependedOnItr );
2840
2841        // Remove depends-on.
2842        mAssetDependsOn.erase( dependsOnItr );
2843
2844        // Insert depends-on.
2845        mAssetDependsOn.insertEqual( assetIdTo, dependencyAssetId );
2846
2847        // Insert is-depended-on.
2848        mAssetIsDependedOn.insertEqual( dependencyAssetId, assetIdTo );
2849    }
2850
2851    // Rename via is-depended-on...
2852    while( mAssetIsDependedOn.count( assetIdFrom ) > 0 )
2853    {
2854        // Find is-depended-on.
2855       typeAssetIsDependedOnHash::Iterator isdependedOnItr = mAssetIsDependedOn.find(assetIdFrom);
2856
2857        // Fetch dependency asset Id.
2858        StringTableEntry dependencyAssetId = isdependedOnItr->value;
2859
2860        // Find depends-on entry.
2861        typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(dependencyAssetId);
2862
2863        // Sanity!
2864        AssertFatal( dependsOnItr != mAssetDependsOn.end(), "Asset dependencies are corrupt!" );
2865
2866        while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == dependencyAssetId && dependsOnItr->value != assetIdFrom )
2867        {
2868            dependsOnItr++;
2869        }
2870
2871        // Sanity!
2872        AssertFatal( dependsOnItr->key == dependencyAssetId && dependsOnItr->value == assetIdFrom, "Asset dependencies are corrupt!" );
2873        
2874        // Remove is-depended-on.        
2875        mAssetIsDependedOn.erase( isdependedOnItr );
2876
2877        // Remove depends-on.
2878        mAssetDependsOn.erase( dependsOnItr );
2879
2880        // Insert depends-on.
2881        mAssetDependsOn.insertEqual( dependencyAssetId, assetIdTo );
2882
2883        // Insert is-depended-on.
2884        mAssetIsDependedOn.insertEqual( assetIdTo, dependencyAssetId );
2885    }
2886}
2887
2888//-----------------------------------------------------------------------------
2889
2890void AssetManager::removeAssetDependencies( const char* pAssetId )
2891{
2892    // Debug Profiling.
2893    PROFILE_SCOPE(AssetManager_RemvoeAsetDependencies);
2894
2895    // Sanity!
2896    AssertFatal( pAssetId != NULL, "Cannot remove asset dependencies using NULL asset Id." );
2897
2898    // Fetch asset Id.
2899    StringTableEntry assetId = StringTable->insert( pAssetId );
2900
2901    // Remove from depends-on assets.
2902    while( mAssetDependsOn.count( assetId ) > 0 )
2903    {
2904        // Find depends-on.
2905       typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(assetId);
2906
2907        // Fetch dependency asset Id.
2908        StringTableEntry dependencyAssetId = dependsOnItr->value;
2909
2910        // Find is-depends-on entry.
2911        typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find(dependencyAssetId);
2912
2913        // Sanity!
2914        AssertFatal( isDependedOnItr != mAssetIsDependedOn.end(), "Asset dependencies are corrupt!" );
2915
2916        while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value != assetId )
2917        {
2918            isDependedOnItr++;
2919        }
2920
2921        // Sanity!
2922        AssertFatal( isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value == assetId, "Asset dependencies are corrupt!" );
2923
2924        // Remove is-depended-on.        
2925        mAssetIsDependedOn.erase( isDependedOnItr );
2926
2927        // Remove depends-on.
2928        mAssetDependsOn.erase( dependsOnItr );
2929    }
2930}
2931
2932//-----------------------------------------------------------------------------
2933
2934void AssetManager::unloadAsset( AssetDefinition* pAssetDefinition )
2935{
2936    // Debug Profiling.
2937    PROFILE_SCOPE(AssetManager_UnloadAsset);
2938
2939    // Destroy the asset.
2940    pAssetDefinition->mpAssetBase->deleteObject();
2941
2942    // Increase unloaded count.
2943    pAssetDefinition->mAssetUnloadedCount++;
2944
2945    // Is the asset internal?
2946    if ( pAssetDefinition->mAssetInternal )
2947    {
2948        // Yes, so decrease internal loaded asset count.
2949        mLoadedInternalAssetsCount--;
2950    }
2951    else
2952    {
2953        // No, so decrease external loaded assets count.
2954        mLoadedExternalAssetsCount--;
2955    }
2956
2957    // Is the asset private?
2958    if ( pAssetDefinition->mAssetPrivate )
2959    {
2960        // Yes, so decrease private loaded asset count.
2961        mLoadedPrivateAssetsCount--;
2962
2963        // Remove it completely.
2964        removeDeclaredAsset( pAssetDefinition->mAssetId );
2965    }
2966}
2967
2968//-----------------------------------------------------------------------------
2969
2970void AssetManager::onModulePreLoad( ModuleDefinition* pModuleDefinition )
2971{
2972    // Debug Profiling.
2973    PROFILE_SCOPE(AssetManager_OnModulePreLoad);
2974
2975    // Add module declared assets.
2976    addModuleDeclaredAssets( pModuleDefinition );
2977
2978    // Is an asset tags manifest specified?
2979    if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString() )
2980    {
2981        // Yes, so load the asset tags manifest.
2982        loadAssetTags( pModuleDefinition );
2983    }
2984}
2985
2986//-----------------------------------------------------------------------------
2987
2988void AssetManager::onModulePreUnload( ModuleDefinition* pModuleDefinition )
2989{
2990    // Debug Profiling.
2991    PROFILE_SCOPE(AssetManager_OnModulePreUnload);
2992
2993    // Is an asset tags manifest specified?
2994    if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString() )
2995    {
2996        // Yes, so save the asset tags manifest.
2997        saveAssetTags();
2998
2999        // Do we have an asset tags manifest?
3000        if ( !mAssetTagsManifest.isNull() )
3001        {
3002            // Yes, so remove it.
3003            mAssetTagsManifest->deleteObject();
3004            mAssetTagsModuleDefinition = NULL;
3005        }
3006    }
3007}
3008
3009//-----------------------------------------------------------------------------
3010
3011void AssetManager::onModulePostUnload( ModuleDefinition* pModuleDefinition )
3012{
3013    // Debug Profiling.
3014    PROFILE_SCOPE(AssetManager_OnModulePostUnload);
3015
3016    // Remove declared assets.
3017    removeDeclaredAssets( pModuleDefinition );
3018}
3019