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