moduleManager.cpp
Engine/source/module/moduleManager.cpp
Public Variables
Public Functions
Detailed Description
Public Variables
ModuleManager ModuleDatabase
Public Functions
IMPLEMENT_CONOBJECT(ModuleManager )
moduleDefinitionVersionIdSort(const void * a, const void * b)
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 "moduleManager.h" 25 26#ifndef _MODULE_MERGE_DEFINITION_H 27#include "moduleMergeDefinition.h" 28#endif 29 30#ifndef _TAML_MODULE_ID_UPDATE_VISITOR_H_ 31#include "tamlModuleIdUpdateVisitor.h" 32#endif 33 34#ifndef _MODULE_CALLBACKS_H_ 35#include "moduleCallbacks.h" 36#endif 37 38#ifndef _CONSOLETYPES_H_ 39#include "console/consoleTypes.h" 40#endif 41 42// Script bindings. 43#include "moduleManager_ScriptBinding.h" 44 45//----------------------------------------------------------------------------- 46 47IMPLEMENT_CONOBJECT( ModuleManager ); 48 49//----------------------------------------------------------------------------- 50 51ModuleManager ModuleDatabase; 52 53//----------------------------------------------------------------------------- 54 55S32 QSORT_CALLBACK moduleDefinitionVersionIdSort( const void* a, const void* b ) 56{ 57 // Fetch module definitions. 58 ModuleDefinition* pDefinition1 = *(ModuleDefinition**)a; 59 ModuleDefinition* pDefinition2 = *(ModuleDefinition**)b; 60 61 // Fetch version Ids. 62 const U32 versionId1 = pDefinition1->getVersionId(); 63 const U32 versionId2 = pDefinition2->getVersionId(); 64 65 // We sort higher version Id first. 66 return versionId1 > versionId2 ? -1 : versionId1 < versionId2 ? 1 : 0; 67} 68 69//----------------------------------------------------------------------------- 70 71ModuleManager::ModuleManager() : 72 mEnforceDependencies(true), 73 mEchoInfo(true), 74 mDatabaseLocks( 0 ) 75{ 76 // Set module extension. 77 dStrcpy( mModuleExtension, MODULE_MANAGER_MODULE_DEFINITION_EXTENSION ); 78} 79 80//----------------------------------------------------------------------------- 81 82bool ModuleManager::onAdd() 83{ 84 if( !Parent::onAdd() ) 85 return false; 86 87 // Register listeners. 88 mNotificationListeners.registerObject(); 89 90 return true; 91} 92 93//----------------------------------------------------------------------------- 94 95void ModuleManager::onRemove() 96{ 97 // Clear database. 98 clearDatabase(); 99 100 // Unregister object. 101 mNotificationListeners.unregisterObject(); 102 103 // Call parent. 104 Parent::onRemove(); 105} 106 107//----------------------------------------------------------------------------- 108 109void ModuleManager::initPersistFields() 110{ 111 // Call parent. 112 Parent::initPersistFields(); 113 114 addField( "EnforceDependencies", TypeBool, Offset(mEnforceDependencies, ModuleManager), "Whether the module manager enforces any dependencies on module definitions it discovers or not." ); 115 addField( "EchoInfo", TypeBool, Offset(mEchoInfo, ModuleManager), "Whether the module manager echos extra information to the console or not." ); 116} 117 118//----------------------------------------------------------------------------- 119 120void ModuleManager::onDeleteNotify( SimObject *object ) 121{ 122 // Cast to a module definition. 123 ModuleDefinition* pModuleDefinition = dynamic_cast<ModuleDefinition*>( object ); 124 125 // Ignore if not appropriate. 126 if ( pModuleDefinition == NULL ) 127 return; 128 129 // Warn. 130 Con::warnf( "Module Manager::onDeleteNotify() - Notified of a module definition deletion for module Id '%s' of version Id '%d' however this should not happen and can cause module database corruption.", 131 pModuleDefinition->getModuleId(), pModuleDefinition->getVersionId() ); 132} 133 134//----------------------------------------------------------------------------- 135 136bool ModuleManager::setModuleExtension( const char* pExtension ) 137{ 138 // Sanity! 139 AssertFatal( pExtension != NULL, "Cannot set module extension with NULL extension." ); 140 141 // Did we find an extension period? 142 if ( *pExtension == '.' ) 143 { 144 // Yes, so warn. 145 Con::warnf("Module Manager: Failed to set extension as supplied extension contains an initial period: '%s'.", pExtension ); 146 return false; 147 } 148 149 // Is the extension too large? 150 if ( dStrlen( pExtension ) > sizeof( mModuleExtension ) ) 151 { 152 // Yes, so warn. 153 Con::warnf("Module Manager: Failed to set extension as supplied extension is too large: '%s'.", pExtension ); 154 return false; 155 } 156 157 // Set module extension. 158 dStrcpy( mModuleExtension, pExtension ); 159 160 return true; 161} 162 163//----------------------------------------------------------------------------- 164 165bool ModuleManager::scanModules( const char* pPath, const bool rootOnly ) 166{ 167 // Lock database. 168 LockDatabase( this ); 169 170 // Sanity! 171 AssertFatal( pPath != NULL, "Cannot scan module with NULL path." ); 172 173 // Expand module location. 174 char pathBuffer[1024]; 175 Con::expandPath( pathBuffer, sizeof(pathBuffer), pPath ); 176 177 // Info. 178 if ( mEchoInfo ) 179 { 180 Con::printSeparator(); 181 Con::printf( "Module Manager: Started scanning '%s'...", pathBuffer ); 182 } 183 184 Vector<StringTableEntry> directories; 185 186 // Find directories. 187 if ( !Platform::dumpDirectories( pathBuffer, directories, rootOnly ? 1 : -1 ) ) 188 { 189 // Failed so warn. 190 Con::warnf( "Module Manager: Failed to scan module directories in path '%s'.", pathBuffer ); 191 return false; 192 } 193 194 // Fetch extension length. 195 const U32 extensionLength = dStrlen( mModuleExtension ); 196 197 Vector<Platform::FileInfo> files; 198 199 // Iterate directories. 200 for( Vector<StringTableEntry>::iterator basePathItr = directories.begin(); basePathItr != directories.end(); ++basePathItr ) 201 { 202 // Fetch base path. 203 StringTableEntry basePath = *basePathItr; 204 205 // Skip if we're only processing the root and this is not the root. 206 if ( rootOnly && basePathItr != directories.begin() ) 207 continue; 208 209 // Find files. 210 files.clear(); 211 if ( !Platform::dumpPath( basePath, files, 0 ) ) 212 { 213 // Failed so warn. 214 Con::warnf( "Module Manager: Failed to scan modules files in directory '%s'.", basePath ); 215 return false; 216 } 217 218 // Iterate files. 219 for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr ) 220 { 221 // Fetch file info. 222 Platform::FileInfo* pFileInfo = fileItr; 223 224 // Fetch filename. 225 const char* pFilename = pFileInfo->pFileName; 226 227 // Find filename length. 228 const U32 filenameLength = dStrlen( pFilename ); 229 230 // Skip if extension is longer than filename. 231 if ( extensionLength > filenameLength ) 232 continue; 233 234 // Skip if extension not found. 235 if ( dStricmp( pFilename + filenameLength - extensionLength, mModuleExtension ) != 0 ) 236 continue; 237 238 // Register module. 239 registerModule( basePath, pFileInfo->pFileName ); 240 } 241 242 // Stop processing if we're only processing the root. 243 if ( rootOnly ) 244 break; 245 } 246 247 // Info. 248 if ( mEchoInfo ) 249 { 250 Con::printf( "Module Manager: Finished scanning '%s'.", pathBuffer ); 251 } 252 253 return true; 254} 255 256//----------------------------------------------------------------------------- 257 258bool ModuleManager::loadModuleGroup( const char* pModuleGroup ) 259{ 260 // Lock database. 261 LockDatabase( this ); 262 263 // Sanity! 264 AssertFatal( pModuleGroup != NULL, "Cannot load module group with NULL group name." ); 265 266 typeModuleLoadEntryVector moduleResolvingQueue; 267 typeModuleLoadEntryVector moduleReadyQueue; 268 269 // Fetch module group. 270 StringTableEntry moduleGroup = StringTable->insert( pModuleGroup ); 271 272 // Info. 273 if ( mEchoInfo ) 274 { 275 Con::printSeparator(); 276 Con::printf( "Module Manager: Loading group '%s':" ,moduleGroup ); 277 } 278 279 // Is the module group already loaded? 280 if ( findGroupLoaded( moduleGroup ) != NULL ) 281 { 282 // Yes, so warn. 283 Con::warnf( "Module Manager: Cannot load group '%s' as it is already loaded.", moduleGroup ); 284 return false; 285 } 286 287 // Find module group. 288 typeGroupModuleHash::iterator moduleGroupItr = mGroupModules.find( moduleGroup ); 289 290 // Did we find the module group? 291 if ( moduleGroupItr == mGroupModules.end() ) 292 { 293 // No, so info. 294 if ( mEchoInfo ) 295 { 296 Con::printf( "Module Manager: No modules found for module group '%s'.", moduleGroup ); 297 } 298 299 return true; 300 } 301 302 // Yes, so fetch the module Ids. 303 typeModuleIdVector* pModuleIds = moduleGroupItr->value; 304 305 // Iterate module groups. 306 for( typeModuleIdVector::iterator moduleIdItr = pModuleIds->begin(); moduleIdItr != pModuleIds->end(); ++moduleIdItr ) 307 { 308 // Fetch module Id. 309 StringTableEntry moduleId = *moduleIdItr; 310 311 // Finish if we could not resolve the dependencies for module Id (of any version Id). 312 if ( !resolveModuleDependencies( moduleId, 0, moduleGroup, false, moduleResolvingQueue, moduleReadyQueue ) ) 313 return false; 314 } 315 316 // Check the modules we want to load to ensure that we do not have incompatible modules loaded already. 317 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 318 { 319 // Fetch load ready module definition. 320 ModuleDefinition* pLoadReadyModuleDefinition = moduleReadyItr->mpModuleDefinition;; 321 322 // Fetch the module Id loaded entry. 323 ModuleLoadEntry* pLoadedModuleEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 324 325 // Did we find a loaded entry? 326 if ( pLoadedModuleEntry != NULL ) 327 { 328 // Yes, so is it the one we need to load? 329 if ( pLoadedModuleEntry->mpModuleDefinition != pLoadReadyModuleDefinition ) 330 { 331 // Yes, so warn. 332 Con::warnf( "Module Manager: Cannot load module group '%s' as the module Id '%s' at version Id '%d' is required but the module Id is already loaded but at version Id '%d'.", 333 moduleGroup, pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadedModuleEntry->mpModuleDefinition->getVersionId() ); 334 return false; 335 } 336 } 337 } 338 339 // Info. 340 if ( mEchoInfo ) 341 { 342 // Info. 343 Con::printf( "Module Manager: Group '%s' and its dependencies is comprised of the following '%d' module(s):", moduleGroup, moduleReadyQueue.size() ); 344 345 // Iterate the modules echoing them. 346 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 347 { 348 // Fetch the ready entry. 349 ModuleDefinition* pModuleDefinition = moduleReadyItr->mpModuleDefinition; 350 351 // Info. 352 Con::printf( "> module Id '%s' at version Id '%d':", pModuleDefinition->getModuleId(), pModuleDefinition->getVersionId() ); 353 } 354 } 355 356 // Add module group. 357 mGroupsLoaded.push_back( moduleGroup ); 358 359 // Reset modules loaded count. 360 U32 modulesLoadedCount = 0; 361 362 // Iterate the modules, executing their script files and call their create function. 363 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 364 { 365 // Fetch the ready entry. 366 ModuleLoadEntry* pReadyEntry = moduleReadyItr; 367 368 // Fetch load ready module definition. 369 ModuleDefinition* pLoadReadyModuleDefinition = pReadyEntry->mpModuleDefinition; 370 371 // Fetch any loaded entry for the module Id. 372 ModuleLoadEntry* pLoadedEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 373 374 // Is the module already loaded. 375 if ( pLoadedEntry != NULL ) 376 { 377 // Yes, so increase load count. 378 pLoadedEntry->mpModuleDefinition->increaseLoadCount(); 379 380 // Skip. 381 continue; 382 } 383 384 // No, so info. 385 if ( mEchoInfo ) 386 { 387 Con::printSeparator(); 388 Con::printf( "Module Manager: Loading group '%s' : module Id '%s' at version Id '%d' in group '%s' using the script file '%s'.", 389 moduleGroup, pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadReadyModuleDefinition->getModuleGroup(), pLoadReadyModuleDefinition->getModuleScriptFilePath() ); 390 } 391 392 // Is the module deprecated? 393 if ( pLoadReadyModuleDefinition->getDeprecated() ) 394 { 395 // Yes, so warn. 396 Con::warnf( "Module Manager: Caution: module Id '%s' at version Id '%d' in group '%s' is deprecated. You should use a newer version!", 397 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadReadyModuleDefinition->getModuleGroup() ); 398 } 399 400 // Add the path expando for module. 401 Con::addPathExpando( pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getModulePath() ); 402 403 // Create a scope set. 404 SimSet* pScopeSet = new SimSet; 405 pScopeSet->registerObject( pLoadReadyModuleDefinition->getModuleId() ); 406 pReadyEntry->mpModuleDefinition->mScopeSet = pScopeSet->getId(); 407 408 // Increase load count. 409 pReadyEntry->mpModuleDefinition->increaseLoadCount(); 410 411 // Queue module loaded. 412 mModulesLoaded.push_back( *pReadyEntry ); 413 414 // Bump modules loaded count. 415 modulesLoadedCount++; 416 417 // Raise notifications. 418 raiseModulePreLoadNotifications( pLoadReadyModuleDefinition ); 419 420 // Do we have a script file-path specified? 421 if ( pLoadReadyModuleDefinition->getModuleScriptFilePath() != StringTable->EmptyString() ) 422 { 423 // Yes, so execute the script file. 424 const bool scriptFileExecuted = dAtob( Con::executef("exec", pLoadReadyModuleDefinition->getModuleScriptFilePath() ) ); 425 426 // Did we execute the script file? 427 if ( scriptFileExecuted ) 428 { 429 // Yes, so is the create method available? 430 if ( pScopeSet->isMethod( pLoadReadyModuleDefinition->getCreateFunction() ) ) 431 { 432 // Yes, so call the create method. 433 Con::executef( pScopeSet, pLoadReadyModuleDefinition->getCreateFunction() ); 434 } 435 } 436 else 437 { 438 // No, so warn. 439 Con::errorf( "Module Manager: Cannot load module group '%s' as the module Id '%s' at version Id '%d' as it failed to have the script file '%s' loaded.", 440 moduleGroup, pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadReadyModuleDefinition->getModuleScriptFilePath() ); 441 } 442 } 443 444 // Raise notifications. 445 raiseModulePostLoadNotifications( pLoadReadyModuleDefinition ); 446 } 447 448 // Info. 449 if ( mEchoInfo ) 450 { 451 Con::printSeparator(); 452 Con::printf( "Module Manager: Finish loading '%d' module(s) for group '%s'.", modulesLoadedCount, moduleGroup ); 453 Con::printSeparator(); 454 } 455 456 return true; 457} 458 459//----------------------------------------------------------------------------- 460 461bool ModuleManager::unloadModuleGroup( const char* pModuleGroup ) 462{ 463 // Lock database. 464 LockDatabase( this ); 465 466 // Sanity! 467 AssertFatal( pModuleGroup != NULL, "Cannot unload module group with NULL group name." ); 468 469 typeModuleLoadEntryVector moduleResolvingQueue; 470 typeModuleLoadEntryVector moduleReadyQueue; 471 472 // Fetch module group. 473 StringTableEntry moduleGroup = StringTable->insert( pModuleGroup ); 474 475 // Info. 476 if ( mEchoInfo ) 477 { 478 Con::printSeparator(); 479 Con::printf( "Module Manager: Unloading group '%s':" , moduleGroup ); 480 } 481 482 // Find the group loaded iterator. 483 typeGroupVector::iterator groupLoadedItr = findGroupLoaded( moduleGroup ); 484 485 // Is the module group already unloaded? 486 if ( groupLoadedItr == NULL ) 487 { 488 // No, so warn. 489 Con::warnf( "Module Manager: Cannot unload group '%s' as it is not loaded.", moduleGroup ); 490 return false; 491 } 492 493 // Find module group. 494 typeGroupModuleHash::iterator moduleGroupItr = mGroupModules.find( moduleGroup ); 495 496 // Did we find the module group? 497 if ( moduleGroupItr == mGroupModules.end() ) 498 { 499 // No, so info. 500 if ( mEchoInfo ) 501 { 502 Con::printf( "Module Manager: No modules found for module group '%s'.", moduleGroup ); 503 return true; 504 } 505 } 506 507 // Yes, so fetch the module Ids. 508 typeModuleIdVector* pModuleIds = moduleGroupItr->value; 509 510 // Iterate module groups. 511 for( typeModuleIdVector::iterator moduleIdItr = pModuleIds->begin(); moduleIdItr != pModuleIds->end(); ++moduleIdItr ) 512 { 513 // Fetch module Id. 514 StringTableEntry moduleId = *moduleIdItr; 515 516 // Finish if we could not resolve the dependencies for module Id (of any version Id). 517 if ( !resolveModuleDependencies( moduleId, 0, moduleGroup, false, moduleResolvingQueue, moduleReadyQueue ) ) 518 return false; 519 } 520 521 // Check the modules we want to load to ensure that we do not have incompatible modules loaded already. 522 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 523 { 524 // Fetch load ready module definition. 525 ModuleDefinition* pLoadReadyModuleDefinition = moduleReadyItr->mpModuleDefinition;; 526 527 // Fetch the module Id loaded entry. 528 ModuleLoadEntry* pLoadedModuleEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 529 530 // Did we find a loaded entry? 531 if ( pLoadedModuleEntry != NULL ) 532 { 533 // Yes, so is it the one we need to load? 534 if ( pLoadedModuleEntry->mpModuleDefinition != pLoadReadyModuleDefinition ) 535 { 536 // Yes, so warn. 537 Con::warnf( "Module Manager: Cannot unload module group '%s' as the module Id '%s' at version Id '%d' is required but the module Id is loaded but at version Id '%d'.", 538 moduleGroup, pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadedModuleEntry->mpModuleDefinition->getVersionId() ); 539 return false; 540 } 541 } 542 } 543 544 // Remove module group. 545 mGroupsLoaded.erase_fast( groupLoadedItr ); 546 547 // Reset modules unloaded count. 548 U32 modulesUnloadedCount = 0; 549 550 // Iterate the modules in reverse order calling their destroy function. 551 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.end()-1; moduleReadyItr >= moduleReadyQueue.begin(); --moduleReadyItr ) 552 { 553 // Fetch the ready entry. 554 ModuleLoadEntry* pReadyEntry = moduleReadyItr; 555 556 // Fetch load ready module definition. 557 ModuleDefinition* pLoadReadyModuleDefinition = pReadyEntry->mpModuleDefinition;; 558 559 // Fetch any loaded entry for the module Id. 560 ModuleLoadEntry* pLoadedEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 561 562 // Is the module loaded. 563 if ( pLoadedEntry == NULL ) 564 { 565 // No, so warn. 566 if ( mEchoInfo ) 567 { 568 Con::printf( "Module Manager: Unloading group '%s' but could not unload module Id '%s' at version Id '%d'.", 569 moduleGroup, pLoadedEntry->mpModuleDefinition->getModuleId(), pLoadedEntry->mpModuleDefinition->getVersionId() ); 570 } 571 // Skip. 572 continue; 573 } 574 575 // Reduce load count. 576 pLoadedEntry->mpModuleDefinition->reduceLoadCount(); 577 578 // Sanity! 579 AssertFatal( pLoadedEntry->mpModuleDefinition->getLoadCount() >= 0, "ModuleManager::unloadModuleGroup() - Encountered an invalid load count." ); 580 581 // Do we need to unload? 582 if ( pLoadedEntry->mpModuleDefinition->getLoadCount() == 0 ) 583 { 584 // Yes, so info. 585 if ( mEchoInfo ) 586 { 587 Con::printSeparator(); 588 Con::printf( "Module Manager: Unload group '%s' with module Id '%s' at version Id '%d' in group '%s'.", 589 moduleGroup, pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadReadyModuleDefinition->getModuleGroup() ); 590 } 591 592 // Raise notifications. 593 raiseModulePreUnloadNotifications( pLoadReadyModuleDefinition ); 594 595 // Fetch the module Id loaded entry. 596 typeModuleLoadEntryVector::iterator moduleLoadedItr = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 597 598 // Sanity! 599 AssertFatal( moduleLoadedItr != NULL, "ModuleManager::unloadModuleGroup() - Cannot find module to unload it." ); 600 601 // Dequeue module loaded. 602 mModulesLoaded.erase_fast( moduleLoadedItr ); 603 604 // Fetch scope set. 605 SimSet* pScopeSet = dynamic_cast<SimSet*>(Sim::findObject(pLoadReadyModuleDefinition->mScopeSet)); 606 607 // Is the destroy method available? 608 if ( pScopeSet->isMethod( pLoadReadyModuleDefinition->getDestroyFunction() ) ) 609 { 610 // Yes, so call the destroy method. 611 Con::executef( pScopeSet, pLoadReadyModuleDefinition->getDestroyFunction() ); 612 } 613 614 // Remove scope set. 615 pScopeSet->deleteAllObjects(); 616 pScopeSet->unregisterObject(); 617 pLoadReadyModuleDefinition->mScopeSet = 0; 618 619 // Remove path expando for module. 620 Con::removePathExpando( pLoadReadyModuleDefinition->getModuleId() ); 621 622 // Bump modules unloaded count. 623 modulesUnloadedCount++; 624 625 // Raise notifications. 626 raiseModulePostUnloadNotifications( pLoadReadyModuleDefinition ); 627 } 628 } 629 630 // Info. 631 if ( mEchoInfo ) 632 { 633 Con::printSeparator(); 634 Con::printf( "Module Manager: Finish unloading '%d' module(s) for group '%s'.", modulesUnloadedCount, moduleGroup ); 635 Con::printSeparator(); 636 } 637 638 return true; 639} 640 641//----------------------------------------------------------------------------- 642 643bool ModuleManager::loadModuleExplicit( const char* pModuleId, const U32 versionId ) 644{ 645 // Lock database. 646 LockDatabase( this ); 647 648 // Sanity! 649 AssertFatal( pModuleId != NULL, "Cannot load explicit module Id with NULL module Id." ); 650 651 typeModuleLoadEntryVector moduleResolvingQueue; 652 typeModuleLoadEntryVector moduleReadyQueue; 653 654 // Fetch module Id. 655 StringTableEntry moduleId = StringTable->insert( pModuleId ); 656 657 // Fetch modules definitions. 658 ModuleDefinitionEntry* pDefinitions = findModuleId( moduleId ); 659 660 // Did we find the module Id? 661 if ( pDefinitions == NULL ) 662 { 663 // No, so warn. 664 Con::warnf( "Module Manager: Cannot load explicit module Id '%s' as it does not exist.", moduleId ); 665 return false; 666 } 667 668 // Fetch module group. 669 StringTableEntry moduleGroup = pDefinitions->mModuleGroup; 670 671 // Info. 672 if ( mEchoInfo ) 673 { 674 Con::printSeparator(); 675 Con::printf( "Module Manager: Loading explicit module Id '%s' at version Id '%d':", moduleId, versionId ); 676 } 677 678 // Finish if we could not resolve the dependencies for module Id (of any version Id). 679 if ( !resolveModuleDependencies( moduleId, versionId, moduleGroup, false, moduleResolvingQueue, moduleReadyQueue ) ) 680 return false; 681 682 // Check the modules we want to load to ensure that we do not have incompatible modules loaded already. 683 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 684 { 685 // Fetch load ready module definition. 686 ModuleDefinition* pLoadReadyModuleDefinition = moduleReadyItr->mpModuleDefinition; 687 688 // Fetch the module Id loaded entry. 689 ModuleLoadEntry* pLoadedModuleEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 690 691 // Did we find a loaded entry? 692 if ( pLoadedModuleEntry != NULL ) 693 { 694 // Yes, so is it the one we need to load? 695 if ( pLoadedModuleEntry->mpModuleDefinition != pLoadReadyModuleDefinition ) 696 { 697 // Yes, so warn. 698 Con::warnf( "Module Manager: Cannot load explicit module Id '%s' at version Id '%d' as the module Id is already loaded but at version Id '%d'.", 699 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadedModuleEntry->mpModuleDefinition->getVersionId() ); 700 return false; 701 } 702 } 703 } 704 705 // Info. 706 if ( mEchoInfo ) 707 { 708 // Info. 709 Con::printf( "Module Manager: Explicit load of module Id '%s' at version Id '%d' and its dependencies is comprised of the following '%d' module(s):", moduleId, versionId, moduleReadyQueue.size() ); 710 711 // Iterate the modules echoing them. 712 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 713 { 714 // Fetch the ready entry. 715 ModuleDefinition* pModuleDefinition = moduleReadyItr->mpModuleDefinition; 716 717 // Info. 718 Con::printf( "> module Id '%s' at version Id '%d'", pModuleDefinition->getModuleId(), pModuleDefinition->getVersionId() ); 719 } 720 } 721 722 // Reset modules loaded count. 723 U32 modulesLoadedCount = 0; 724 725 // Iterate the modules, executing their script files and call their create function. 726 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 727 { 728 // Fetch the ready entry. 729 ModuleLoadEntry* pReadyEntry = moduleReadyItr; 730 731 // Fetch load ready module definition. 732 ModuleDefinition* pLoadReadyModuleDefinition = pReadyEntry->mpModuleDefinition; 733 734 // Fetch any loaded entry for the module Id. 735 ModuleLoadEntry* pLoadedEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 736 737 // Is the module already loaded. 738 if ( pLoadedEntry != NULL ) 739 { 740 // Yes, so increase load count. 741 pLoadedEntry->mpModuleDefinition->increaseLoadCount(); 742 743 // Skip. 744 continue; 745 } 746 747 // No, so info. 748 if ( mEchoInfo ) 749 { 750 Con::printSeparator(); 751 Con::printf( "Module Manager: Loading explicit module Id '%s' at version Id '%d' using the script file '%s'.", 752 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadReadyModuleDefinition->getModuleScriptFilePath() ); 753 } 754 755 // Is the module deprecated? 756 if ( pLoadReadyModuleDefinition->getDeprecated() ) 757 { 758 // Yes, so warn. 759 Con::warnf( "Module Manager: Caution: module Id '%s' at version Id '%d' is deprecated, You should use a newer version!", 760 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId() ); 761 } 762 763 // Add the path expando for module. 764 Con::addPathExpando( pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getModulePath() ); 765 766 // Create a scope set. 767 SimSet* pScopeSet = new SimSet; 768 pScopeSet->registerObject( pLoadReadyModuleDefinition->getModuleId() ); 769 pReadyEntry->mpModuleDefinition->mScopeSet = pScopeSet->getId(); 770 771 // Increase load count. 772 pReadyEntry->mpModuleDefinition->increaseLoadCount(); 773 774 // Queue module loaded. 775 mModulesLoaded.push_back( *pReadyEntry ); 776 777 // Bump modules loaded count. 778 modulesLoadedCount++; 779 780 // Raise notifications. 781 raiseModulePreLoadNotifications( pLoadReadyModuleDefinition ); 782 783 // Do we have a script file-path specified? 784 if ( pLoadReadyModuleDefinition->getModuleScriptFilePath() != StringTable->EmptyString() ) 785 { 786 // Yes, so execute the script file. 787 const bool scriptFileExecuted = dAtob( Con::executef("exec", pLoadReadyModuleDefinition->getModuleScriptFilePath() ) ); 788 789 // Did we execute the script file? 790 if ( scriptFileExecuted ) 791 { 792 // Yes, so is the create method available? 793 if ( pScopeSet->isMethod( pLoadReadyModuleDefinition->getCreateFunction() ) ) 794 { 795 // Yes, so call the create method. 796 Con::executef( pScopeSet, pLoadReadyModuleDefinition->getCreateFunction() ); 797 } 798 } 799 else 800 { 801 // No, so warn. 802 Con::errorf( "Module Manager: Cannot load explicit module Id '%s' at version Id '%d' as it failed to have the script file '%s' loaded.", 803 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadReadyModuleDefinition->getModuleScriptFilePath() ); 804 } 805 } 806 807 // Raise notifications. 808 raiseModulePostLoadNotifications( pLoadReadyModuleDefinition ); 809 } 810 811 // Info. 812 if ( mEchoInfo ) 813 { 814 Con::printSeparator(); 815 Con::printf( "Module Manager: Finish loading '%d' explicit module(s).", modulesLoadedCount ); 816 Con::printSeparator(); 817 } 818 819 return true; 820} 821 822//----------------------------------------------------------------------------- 823 824bool ModuleManager::unloadModuleExplicit( const char* pModuleId ) 825{ 826 // Lock database. 827 LockDatabase( this ); 828 829 // Sanity! 830 AssertFatal( pModuleId != NULL, "Cannot unload explicit module Id with NULL module Id." ); 831 832 typeModuleLoadEntryVector moduleResolvingQueue; 833 typeModuleLoadEntryVector moduleReadyQueue; 834 835 // Fetch module Id. 836 StringTableEntry moduleId = StringTable->insert( pModuleId ); 837 838 // Fetch modules definitions. 839 ModuleDefinitionEntry* pDefinitions = findModuleId( moduleId ); 840 841 // Did we find the module Id? 842 if ( pDefinitions == NULL ) 843 { 844 // No, so warn. 845 Con::warnf( "Module Manager: Cannot unload explicit module Id '%s' as it does not exist.", moduleId ); 846 return false; 847 } 848 849 // Find if the module is actually loaded. 850 ModuleDefinition* pLoadedModule = findLoadedModule( moduleId ); 851 852 // Is the module loaded? 853 if ( pLoadedModule == NULL ) 854 { 855 // No, so warn. 856 Con::warnf( "Module Manager: Cannot unload explicit module Id '%s' as it is not loaded.", moduleId ); 857 return false; 858 } 859 860 // Fetch module group. 861 StringTableEntry moduleGroup = pDefinitions->mModuleGroup; 862 863 // Info. 864 if ( mEchoInfo ) 865 { 866 Con::printSeparator(); 867 Con::printf( "Module Manager: Unloading explicit module Id '%s':" , moduleId ); 868 } 869 870 // Finish if we could not resolve the dependencies for module Id (of any version Id). 871 if ( !resolveModuleDependencies( moduleId, pLoadedModule->getVersionId(), moduleGroup, false, moduleResolvingQueue, moduleReadyQueue ) ) 872 return false; 873 874 // Check the modules we want to unload to ensure that we do not have incompatible modules loaded already. 875 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.begin(); moduleReadyItr != moduleReadyQueue.end(); ++moduleReadyItr ) 876 { 877 // Fetch load ready module definition. 878 ModuleDefinition* pLoadReadyModuleDefinition = moduleReadyItr->mpModuleDefinition;; 879 880 // Fetch the module Id loaded entry. 881 ModuleLoadEntry* pLoadedModuleEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 882 883 // Did we find a loaded entry? 884 if ( pLoadedModuleEntry != NULL ) 885 { 886 // Yes, so is it the one we need to load? 887 if ( pLoadedModuleEntry->mpModuleDefinition != pLoadReadyModuleDefinition ) 888 { 889 // Yes, so warn. 890 Con::warnf( "Module Manager: Cannot unload explicit module Id '%s' at version Id '%d' as the module Id is loaded but at version Id '%d'.", 891 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId(), pLoadedModuleEntry->mpModuleDefinition->getVersionId() ); 892 return false; 893 } 894 } 895 } 896 897 // Reset modules unloaded count. 898 U32 modulesUnloadedCount = 0; 899 900 // Iterate the modules in reverse order calling their destroy function. 901 for ( typeModuleLoadEntryVector::iterator moduleReadyItr = moduleReadyQueue.end()-1; moduleReadyItr >= moduleReadyQueue.begin(); --moduleReadyItr ) 902 { 903 // Fetch the ready entry. 904 ModuleLoadEntry* pReadyEntry = moduleReadyItr; 905 906 // Fetch load ready module definition. 907 ModuleDefinition* pLoadReadyModuleDefinition = pReadyEntry->mpModuleDefinition;; 908 909 // Fetch any loaded entry for the module Id. 910 ModuleLoadEntry* pLoadedEntry = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 911 912 // Is the module loaded. 913 if ( pLoadedEntry == NULL ) 914 { 915 // No, so warn. 916 if ( mEchoInfo ) 917 { 918 Con::printf( "Module Manager: Unloading explicit module Id '%s' at version Id '%d' but ignoring as it is not loaded.", 919 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId() ); 920 } 921 922 // Skip. 923 continue; 924 } 925 926 // Reduce load count. 927 pLoadedEntry->mpModuleDefinition->reduceLoadCount(); 928 929 // Sanity! 930 AssertFatal( pLoadedEntry->mpModuleDefinition->getLoadCount() >= 0, "ModuleManager::unloadModuleGroup() - Encountered an invalid load count." ); 931 932 // Do we need to unload? 933 if ( pLoadedEntry->mpModuleDefinition->getLoadCount() == 0 ) 934 { 935 // Yes, so info. 936 if ( mEchoInfo ) 937 { 938 Con::printSeparator(); 939 Con::printf( "Module Manager: Unload explicit module Id '%s' at version Id '%d'.", 940 pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId() ); 941 } 942 943 // Raise notifications. 944 raiseModulePreUnloadNotifications( pLoadReadyModuleDefinition ); 945 946 // Fetch the module Id loaded entry. 947 typeModuleLoadEntryVector::iterator moduleLoadedItr = findModuleLoaded( pLoadReadyModuleDefinition->getModuleId() ); 948 949 // Sanity! 950 AssertFatal( moduleLoadedItr != NULL, "ModuleManager::unloadModuleExplicit() - Cannot find module to unload it." ); 951 952 // Dequeue module loaded. 953 mModulesLoaded.erase_fast( moduleLoadedItr ); 954 955 // Fetch scope set. 956 SimSet* pScopeSet = dynamic_cast<SimSet*>(Sim::findObject(pLoadReadyModuleDefinition->mScopeSet)); 957 958 // Is the destroy method available? 959 if ( pScopeSet->isMethod( pLoadReadyModuleDefinition->getDestroyFunction() ) ) 960 { 961 // Yes, so call the destroy method. 962 Con::executef( pScopeSet, pLoadReadyModuleDefinition->getDestroyFunction() ); 963 } 964 965 // Remove scope set. 966 pScopeSet->deleteAllObjects(); 967 pScopeSet->unregisterObject(); 968 pLoadReadyModuleDefinition->mScopeSet = 0; 969 970 // Remove path expando for module. 971 Con::removePathExpando( pLoadReadyModuleDefinition->getModuleId() ); 972 973 // Bump modules unloaded count. 974 modulesUnloadedCount++; 975 976 // Raise notifications. 977 raiseModulePostUnloadNotifications( pLoadReadyModuleDefinition ); 978 } 979 } 980 981 // Info. 982 if ( mEchoInfo ) 983 { 984 Con::printSeparator(); 985 Con::printf( "Module Manager: Finish unloading '%d' explicit module(s).", modulesUnloadedCount ); 986 Con::printSeparator(); 987 } 988 989 return true; 990} 991 992//----------------------------------------------------------------------------- 993 994ModuleDefinition* ModuleManager::findModule( const char* pModuleId, const U32 versionId ) 995{ 996 // Sanity! 997 AssertFatal( pModuleId != NULL, "Cannot find module with NULL module Id." ); 998 999 // Find module definition. 1000 ModuleDefinitionEntry::iterator moduleItr = findModuleDefinition( StringTable->insert( pModuleId ), versionId ); 1001 1002 // Finish if module was not found. 1003 if ( moduleItr == NULL ) 1004 return NULL; 1005 1006 return *moduleItr; 1007} 1008 1009//----------------------------------------------------------------------------- 1010 1011ModuleDefinition* ModuleManager::findLoadedModule( const char* pModuleId ) 1012{ 1013 // Sanity! 1014 AssertFatal( pModuleId != NULL, "Cannot find module with NULL module Id." ); 1015 1016 // Fetch module Id. 1017 StringTableEntry moduleId = StringTable->insert( pModuleId ); 1018 1019 // Iterate loaded modules. 1020 for ( typeModuleLoadEntryVector::iterator loadedModuleItr = mModulesLoaded.begin(); loadedModuleItr != mModulesLoaded.end(); ++loadedModuleItr ) 1021 { 1022 // Skip if not the module. 1023 if ( loadedModuleItr->mpModuleDefinition->getModuleId() != moduleId ) 1024 continue; 1025 1026 return loadedModuleItr->mpModuleDefinition; 1027 } 1028 1029 return NULL; 1030} 1031 1032//----------------------------------------------------------------------------- 1033 1034void ModuleManager::findModules( const bool loadedOnly, typeConstModuleDefinitionVector& moduleDefinitions ) 1035{ 1036 // Iterate module Ids. 1037 for( typeModuleIdDatabaseHash::iterator moduleIdItr = mModuleIdDatabase.begin(); moduleIdItr != mModuleIdDatabase.end(); ++moduleIdItr ) 1038 { 1039 // Fetch module definition entry. 1040 ModuleDefinitionEntry* pModuleDefinitionEntry = moduleIdItr->value; 1041 1042 // Iterate module definitions. 1043 for ( typeModuleDefinitionVector::iterator moduleDefinitionItr = pModuleDefinitionEntry->begin(); moduleDefinitionItr != pModuleDefinitionEntry->end(); ++moduleDefinitionItr ) 1044 { 1045 // Fetch module definition. 1046 ModuleDefinition* pModuleDefinition = *moduleDefinitionItr; 1047 1048 // Are we searching for loaded modules only? 1049 if ( loadedOnly ) 1050 { 1051 // Yes, so skip if the module is not loaded. 1052 if ( pModuleDefinition->getLoadCount() == 0 ) 1053 continue; 1054 1055 // Use module definition. 1056 moduleDefinitions.push_back( pModuleDefinition ); 1057 1058 // Finish iterating module definitions as only a single module in this entry can be loaded concurrently. 1059 break; 1060 } 1061 1062 // use module definition. 1063 moduleDefinitions.push_back( pModuleDefinition ); 1064 } 1065 } 1066} 1067 1068//----------------------------------------------------------------------------- 1069 1070void ModuleManager::findModuleTypes( const char* pModuleType, const bool loadedOnly, typeConstModuleDefinitionVector& moduleDefinitions ) 1071{ 1072 // Fetch module type. 1073 StringTableEntry moduleType = StringTable->insert( pModuleType ); 1074 1075 // Iterate module Ids. 1076 for( typeModuleIdDatabaseHash::iterator moduleIdItr = mModuleIdDatabase.begin(); moduleIdItr != mModuleIdDatabase.end(); ++moduleIdItr ) 1077 { 1078 // Fetch module definition entry. 1079 ModuleDefinitionEntry* pModuleDefinitionEntry = moduleIdItr->value; 1080 1081 // Skip if note the module type we're searching for. 1082 if ( pModuleDefinitionEntry->mModuleType != moduleType ) 1083 continue; 1084 1085 // Iterate module definitions. 1086 for ( typeModuleDefinitionVector::iterator moduleDefinitionItr = pModuleDefinitionEntry->begin(); moduleDefinitionItr != pModuleDefinitionEntry->end(); ++moduleDefinitionItr ) 1087 { 1088 // Fetch module definition. 1089 ModuleDefinition* pModuleDefinition = *moduleDefinitionItr; 1090 1091 // Are we searching for loaded modules only? 1092 if ( loadedOnly ) 1093 { 1094 // Yes, so skip if the module is not loaded. 1095 if ( pModuleDefinition->getLoadCount() == 0 ) 1096 continue; 1097 1098 // Use module definition. 1099 moduleDefinitions.push_back( pModuleDefinition ); 1100 1101 // Finish iterating module definitions as only a single module in this entry can be loaded concurrently. 1102 break; 1103 } 1104 1105 // use module definition. 1106 moduleDefinitions.push_back( pModuleDefinition ); 1107 } 1108 } 1109} 1110 1111//----------------------------------------------------------------------------- 1112 1113StringTableEntry ModuleManager::copyModule( ModuleDefinition* pSourceModuleDefinition, const char* pTargetModuleId, const char* pTargetPath, const bool useVersionPathing ) 1114{ 1115 // Sanity! 1116 AssertFatal( pSourceModuleDefinition != NULL, "Cannot copy module using a NULL source module definition." ); 1117 AssertFatal( pTargetModuleId != NULL, "Cannot copy module using a NULL target module Id." ); 1118 AssertFatal( pTargetPath != NULL, "Cannot copy module using a NULL target path." ); 1119 1120 // Fetch the source module Id. 1121 StringTableEntry sourceModuleId = pSourceModuleDefinition->getModuleId(); 1122 1123 // Is the source module definition registered with this module manager? 1124 if ( pSourceModuleDefinition->getModuleManager() != this ) 1125 { 1126 // No, so warn. 1127 Con::warnf("Module Manager: Cannot copy module Id '%s' as it is not registered with this module manager.", sourceModuleId ); 1128 return StringTable->EmptyString(); 1129 } 1130 1131 // Fetch the target module Id. 1132 StringTableEntry targetModuleId = StringTable->insert( pTargetModuleId ); 1133 1134 // Extend moduleId/VersionId pathing. 1135 char versionPathBuffer[1024]; 1136 1137 // Are we using version pathing? 1138 if ( useVersionPathing ) 1139 { 1140 // Yes, so format it. 1141 dSprintf( versionPathBuffer, sizeof(versionPathBuffer), "%s/%s/%d", 1142 pTargetPath, targetModuleId, pSourceModuleDefinition->getVersionId() ); 1143 } 1144 else 1145 { 1146 // No, so a straight copy. 1147 dSprintf( versionPathBuffer, sizeof(versionPathBuffer), "%s", pTargetPath ); 1148 } 1149 1150 // Expand the path. 1151 char targetPathBuffer[1024]; 1152 Con::expandPath( targetPathBuffer, sizeof(targetPathBuffer), versionPathBuffer ); 1153 pTargetPath = targetPathBuffer; 1154 1155 // Info. 1156 if ( mEchoInfo ) 1157 { 1158 Con::printf( "Module Manager: Started copying module Id '%s' to target directory '%s'.", sourceModuleId, pTargetPath ); 1159 } 1160 1161 // Is the target folder a directory? 1162 if ( !Platform::isDirectory( pTargetPath ) ) 1163 { 1164 // No, so we have to ensure that there is a trailing slash as that indicates a folder (not a file) when creating a path in the platform code. 1165 char createDirectoryBuffer[1024]; 1166 Con::expandPath( createDirectoryBuffer, sizeof(createDirectoryBuffer), pTargetPath, NULL, true ); 1167 1168 // No, so can we create it? 1169 if ( !Platform::createPath( createDirectoryBuffer ) ) 1170 { 1171 // No, so warn. 1172 Con::warnf("Module Manager: Cannot copy module Id '%s' using target directory '%s' as directory was not found and could not be created.", 1173 sourceModuleId, pTargetPath ); 1174 return StringTable->EmptyString(); 1175 } 1176 } 1177 1178 // Copy the source module to the target folder. 1179 if ( !dPathCopy( pSourceModuleDefinition->getModulePath(), pTargetPath, false ) ) 1180 { 1181 // Warn. 1182 Con::warnf("Module Manager: Cannot copy module Id '%s' using target directory '%s' as directory copy failed.", 1183 sourceModuleId, pTargetPath ); 1184 return StringTable->EmptyString(); 1185 } 1186 1187 // Format the new source module definition file-path. 1188 char newModuleDefinitionSourceFileBuffer[1024]; 1189 dSprintf( newModuleDefinitionSourceFileBuffer, sizeof(newModuleDefinitionSourceFileBuffer), "%s/%s", pTargetPath, pSourceModuleDefinition->getModuleFile() ); 1190 1191 // Finish if source/target module Ids are identical. 1192 if ( sourceModuleId == targetModuleId ) 1193 return StringTable->insert( newModuleDefinitionSourceFileBuffer ); 1194 1195 // Format the new target module definition file-path. 1196 char newModuleDefinitionTargetFileBuffer[1024]; 1197 dSprintf( newModuleDefinitionTargetFileBuffer, sizeof(newModuleDefinitionTargetFileBuffer), "%s/%s.%s", pTargetPath, targetModuleId, MODULE_MANAGER_MODULE_DEFINITION_EXTENSION ); 1198 1199 // Rename the module definition. 1200 if ( !dFileRename( newModuleDefinitionSourceFileBuffer, newModuleDefinitionTargetFileBuffer ) ) 1201 { 1202 // Warn. 1203 Con::warnf("Module Manager: Cannot copy module Id '%s' using target directory '%s' as renaming the module from '%s' to '%s' failed.", 1204 sourceModuleId, pTargetPath, newModuleDefinitionSourceFileBuffer, newModuleDefinitionTargetFileBuffer ); 1205 return StringTable->EmptyString(); 1206 } 1207 1208 Vector<StringTableEntry> directories; 1209 1210 // Find directories. 1211 if ( !Platform::dumpDirectories( pTargetPath, directories, -1 ) ) 1212 { 1213 // Warn. 1214 Con::warnf("Module Manager: Cannot copy module Id '%s' using target directory '%s' as sub-folder scanning/renaming failed.", 1215 sourceModuleId, pTargetPath ); 1216 return StringTable->EmptyString(); 1217 } 1218 1219 TamlModuleIdUpdateVisitor moduleIdUpdateVisitor; 1220 moduleIdUpdateVisitor.setModuleIdFrom( sourceModuleId ); 1221 moduleIdUpdateVisitor.setModuleIdTo( targetModuleId ); 1222 1223 Vector<Platform::FileInfo> files; 1224 1225 const char* pExtension = (const char*)"Taml"; 1226 const U32 extensionLength = dStrlen(pExtension); 1227 1228 // Iterate directories. 1229 for( Vector<StringTableEntry>::iterator basePathItr = directories.begin(); basePathItr != directories.end(); ++basePathItr ) 1230 { 1231 // Fetch base path. 1232 StringTableEntry basePath = *basePathItr; 1233 1234 // Find files. 1235 files.clear(); 1236 if ( !Platform::dumpPath( basePath, files, 0 ) ) 1237 { 1238 // Warn. 1239 Con::warnf("Module Manager: Cannot copy module Id '%s' using target directory '%s' as sub-folder scanning/renaming failed.", 1240 sourceModuleId, pTargetPath ); 1241 return StringTable->EmptyString(); 1242 } 1243 1244 // Iterate files. 1245 for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr ) 1246 { 1247 // Fetch file info. 1248 Platform::FileInfo* pFileInfo = fileItr; 1249 1250 // Fetch filename. 1251 const char* pFilename = pFileInfo->pFileName; 1252 1253 // Find filename length. 1254 const U32 filenameLength = dStrlen( pFilename ); 1255 1256 // Skip if extension is longer than filename. 1257 if ( extensionLength >= filenameLength ) 1258 continue; 1259 1260 // Skip if extension not found. 1261 if ( dStricmp( pFilename + filenameLength - extensionLength, pExtension ) != 0 ) 1262 continue; 1263 1264 char parseFileBuffer[1024]; 1265 dSprintf( parseFileBuffer, sizeof(parseFileBuffer), "%s/%s", pFileInfo->pFullPath, pFilename ); 1266 1267 // Parse file. 1268 if ( !mTaml.parse( parseFileBuffer, moduleIdUpdateVisitor ) ) 1269 { 1270 // Warn. 1271 Con::warnf("Module Manager: Failed to parse file '%s' whilst copying module Id '%s' using target directory '%s'.", 1272 parseFileBuffer, sourceModuleId, pTargetPath ); 1273 return StringTable->EmptyString(); 1274 } 1275 } 1276 } 1277 1278 // Info. 1279 if ( mEchoInfo ) 1280 { 1281 Con::printf( "Module Manager: Finished copying module Id '%s' to target directory '%s'.", sourceModuleId, pTargetPath ); 1282 } 1283 1284 return StringTable->insert( newModuleDefinitionTargetFileBuffer ); 1285} 1286 1287//----------------------------------------------------------------------------- 1288 1289bool ModuleManager::synchronizeDependencies( ModuleDefinition* pRootModuleDefinition, const char* pTargetDependencyPath ) 1290{ 1291 // Sanity! 1292 AssertFatal( pRootModuleDefinition != NULL, "Cannot synchronize dependencies with NULL root module definition." ); 1293 AssertFatal( pTargetDependencyPath != NULL, "Cannot synchronize dependencies with NULL target dependency path." ); 1294 1295 // Fetch the root module Id. 1296 StringTableEntry rootModuleId = pRootModuleDefinition->getModuleId(); 1297 1298 // Is the root module definition registered with this module manager? 1299 if ( pRootModuleDefinition->getModuleManager() != this ) 1300 { 1301 // No, so warn. 1302 Con::warnf("Cannot synchronize dependencies for module Id '%s' as it is not registered with this module manager.", rootModuleId ); 1303 return false; 1304 } 1305 1306 // Expand the path. 1307 char targetPathBuffer[1024]; 1308 Con::expandPath( targetPathBuffer, sizeof(targetPathBuffer), pTargetDependencyPath ); 1309 pTargetDependencyPath = targetPathBuffer; 1310 1311 // Is the target dependency folder a directory? 1312 if ( !Platform::isDirectory( pTargetDependencyPath ) ) 1313 { 1314 // No, so we have to ensure that there is a trailing slash as that indicates a folder (not a file) when creating a path in the platform code. 1315 char createDirectoryBuffer[1024]; 1316 Con::expandPath( createDirectoryBuffer, sizeof(createDirectoryBuffer), pTargetDependencyPath, NULL, true ); 1317 1318 // No, so can we create it? 1319 if ( !Platform::createPath( createDirectoryBuffer ) ) 1320 { 1321 // No, so warn. 1322 Con::warnf("Cannot synchronize dependencies for module Id '%s' using target directory '%s' as directory was not found and could not be created.", 1323 rootModuleId, pTargetDependencyPath ); 1324 return false; 1325 } 1326 } 1327 1328 typeModuleLoadEntryVector resolvingQueue; 1329 typeModuleLoadEntryVector sourceModulesNeeded; 1330 1331 // Could we resolve source dependencies? 1332 if ( !resolveModuleDependencies( rootModuleId, pRootModuleDefinition->getVersionId(), pRootModuleDefinition->getModuleGroup(), true, resolvingQueue, sourceModulesNeeded ) ) 1333 { 1334 // No, so warn. 1335 Con::warnf("Cannot synchronize dependencies for root module Id '%s' as its dependencies could not be resolved.", rootModuleId ); 1336 return false; 1337 } 1338 1339 // Sanity! 1340 AssertFatal( sourceModulesNeeded.size() > 0, "Cannot synchronize dependencies as no modules were returned." ); 1341 1342 // Remove the root module definition. 1343 sourceModulesNeeded.pop_back(); 1344 1345 // Initialize the target module manager and scan the target folder for modules. 1346 ModuleManager targetModuleManager; 1347 targetModuleManager.mEnforceDependencies = true; 1348 targetModuleManager.mEchoInfo = false; 1349 targetModuleManager.scanModules( pTargetDependencyPath ); 1350 1351 char targetFolderGenerateBuffer[1024]; 1352 1353 // Iterate module definitions. 1354 for ( typeModuleLoadEntryVector::iterator sourceModuleItr = sourceModulesNeeded.begin(); sourceModuleItr != sourceModulesNeeded.end(); ++sourceModuleItr ) 1355 { 1356 // Fetch module definition. 1357 ModuleDefinition* pSourceModuleDefinition = sourceModuleItr->mpModuleDefinition; 1358 1359 // Fetch the source module Id, 1360 StringTableEntry sourceModuleId = pSourceModuleDefinition->getModuleId(); 1361 1362 // Fetch the source module version Id. 1363 const U32 sourceVersionId = pSourceModuleDefinition->getVersionId(); 1364 1365 // Fetch the source module build Id. 1366 const U32 sourceBuildId = pSourceModuleDefinition->getBuildId(); 1367 1368 // Fetch module definition entry for this module Id in the target. 1369 ModuleDefinitionEntry* pDefinitions = targetModuleManager.findModuleId( sourceModuleId ); 1370 1371 // Is the module Id present in the target? 1372 if ( pDefinitions == NULL ) 1373 { 1374 // No, so format module Id folder path. 1375 dSprintf( targetFolderGenerateBuffer, sizeof(targetFolderGenerateBuffer), "%s/%s/", pTargetDependencyPath, sourceModuleId ); 1376 1377 // Create module Id folder. 1378 if ( !Platform::createPath( targetFolderGenerateBuffer ) ) 1379 { 1380 // Warn. 1381 Con::warnf("Cannot synchronize dependencies for module Id '%s' as the target directory '%s' could not be created.", sourceModuleId, targetFolderGenerateBuffer ); 1382 return false; 1383 } 1384 } 1385 else 1386 { 1387 // Yes, so fetch the module definition for this module Id and version Id in the target. 1388 ModuleDefinitionEntry::iterator definitionItr = targetModuleManager.findModuleDefinition( sourceModuleId, sourceVersionId ); 1389 1390 // Is the specific module definition present in the target? 1391 if ( definitionItr != NULL ) 1392 { 1393 // Yes, so fetch the module definition. 1394 ModuleDefinition* pTargetModuleDefinition = *definitionItr; 1395 1396 // Fetch the target module build Id. 1397 const U32 targetBuildId = pTargetModuleDefinition->getBuildId(); 1398 1399 // Fetch the target module path. 1400 StringTableEntry targetModulePath = pTargetModuleDefinition->getModulePath(); 1401 1402 // Remove the target module definition from the database. 1403 targetModuleManager.removeModuleDefinition( pTargetModuleDefinition ); 1404 1405 // Skip if the target definition is the same build Id. 1406 if ( targetBuildId == sourceBuildId ) 1407 continue; 1408 1409 // Delete the target module definition folder. 1410 if ( !Platform::deleteDirectory( targetModulePath ) ) 1411 { 1412 // Warn. 1413 Con::warnf("Cannot synchronize dependencies for module Id '%s' at version Id '%d' as the old module at '%s' could not be deleted.", 1414 sourceModuleId, sourceVersionId, targetModulePath ); 1415 return false; 1416 } 1417 } 1418 } 1419 1420 // Format source module path. 1421 char sourceFolderPath[1024]; 1422 Con::expandPath( sourceFolderPath, sizeof(sourceFolderPath), pSourceModuleDefinition->getModulePath() ); 1423 1424 // Format target module path. 1425 dSprintf( targetFolderGenerateBuffer, sizeof(targetFolderGenerateBuffer), "%s/%s/%d", pTargetDependencyPath, sourceModuleId, sourceVersionId ); 1426 1427 // Copy the source module to the target folder. 1428 if (!dPathCopy(sourceFolderPath, targetFolderGenerateBuffer, false)) 1429 { 1430 // Warn. 1431 Con::warnf("Cannot synchronize dependencies for module Id '%s' at version Id '%d' as the module could not be copied to '%s'.", 1432 sourceModuleId, sourceVersionId, targetFolderGenerateBuffer ); 1433 return false; 1434 } 1435 } 1436 1437 // Find any target modules left, These are orphaned modules not depended upon by any other module. 1438 typeConstModuleDefinitionVector orphanedTargetModules; 1439 targetModuleManager.findModules( false, orphanedTargetModules ); 1440 1441 // Iterate module definitions. 1442 for ( typeConstModuleDefinitionVector::const_iterator moduleDefinitionItr = orphanedTargetModules.begin(); moduleDefinitionItr != orphanedTargetModules.end(); ++moduleDefinitionItr ) 1443 { 1444 // Fetch orphaned module definition. 1445 const ModuleDefinition* pOrphanedModuleDefinition = *moduleDefinitionItr; 1446 1447 // Delete the target module definition folder. 1448 if ( !Platform::deleteDirectory( pOrphanedModuleDefinition->getModulePath() ) ) 1449 { 1450 // Warn. 1451 Con::warnf("Cannot delete orphaned module Id '%s' at version Id '%d' from '%s'.", 1452 pOrphanedModuleDefinition->getModuleId(), pOrphanedModuleDefinition->getVersionId(), pOrphanedModuleDefinition->getModulePath() ); 1453 } 1454 } 1455 1456 return true; 1457} 1458 1459//----------------------------------------------------------------------------- 1460 1461bool ModuleManager::canMergeModules( const char* pMergeSourcePath ) 1462{ 1463 // Sanity! 1464 AssertFatal( pMergeSourcePath != NULL, "Cannot check merge modules with NULL source path." ); 1465 1466 // Expand the source path. 1467 char sourcePathBuffer[1024]; 1468 Con::expandPath( sourcePathBuffer, sizeof(sourcePathBuffer), pMergeSourcePath ); 1469 pMergeSourcePath = sourcePathBuffer; 1470 1471 // Is the path a valid directory? 1472 if ( !Platform::isDirectory( sourcePathBuffer ) ) 1473 { 1474 // No, so warn. 1475 Con::warnf( "Cannot check merge modules as path is invalid '%s'.", sourcePathBuffer ); 1476 return false; 1477 } 1478 1479 // Initialize the source module manager and scan the source folder for modules. 1480 ModuleManager mergeModuleManager; 1481 mergeModuleManager.mEnforceDependencies = false; 1482 mergeModuleManager.mEchoInfo = false; 1483 mergeModuleManager.scanModules( pMergeSourcePath ); 1484 1485 // Find all the merge modules. 1486 typeConstModuleDefinitionVector mergeModules; 1487 mergeModuleManager.findModules( false, mergeModules ); 1488 1489 // Iterate found merge module definitions. 1490 for ( typeConstModuleDefinitionVector::const_iterator mergeModuleItr = mergeModules.begin(); mergeModuleItr != mergeModules.end(); ++mergeModuleItr ) 1491 { 1492 // Fetch module definition. 1493 const ModuleDefinition* pMergeModuleDefinition = *mergeModuleItr; 1494 1495 // Fetch module Id. 1496 StringTableEntry moduleId = pMergeModuleDefinition->getModuleId(); 1497 1498 // Fetch version Id. 1499 const U32 versionId = pMergeModuleDefinition->getVersionId(); 1500 1501 // Fetch module group. 1502 StringTableEntry moduleGroup = pMergeModuleDefinition->getModuleGroup(); 1503 1504 // Cannot merge if module already exists. 1505 if ( findModuleDefinition( moduleId, versionId ) != NULL ) 1506 return false; 1507 1508 // Cannot merge if module is part of a loaded group. 1509 if ( findGroupLoaded( moduleGroup ) != NULL ) 1510 return false; 1511 } 1512 1513 // Can merge modules. 1514 return true; 1515} 1516 1517//----------------------------------------------------------------------------- 1518 1519bool ModuleManager::mergeModules( const char* pMergeTargetPath, const bool removeMergeDefinition, const bool registerNewModules ) 1520{ 1521 // Sanity! 1522 AssertFatal( pMergeTargetPath != NULL, "Cannot merge modules with a target path of NULL." ); 1523 1524 // Is a module merge available? 1525 if ( !isModuleMergeAvailable() ) 1526 { 1527 // No, so warn. 1528 Con::warnf( "Cannot merge modules as a module merge is not available." ); 1529 return false; 1530 } 1531 1532 // Expand the target path. 1533 char targetPathBuffer[1024]; 1534 Con::expandPath( targetPathBuffer, sizeof(targetPathBuffer), pMergeTargetPath ); 1535 pMergeTargetPath = targetPathBuffer; 1536 1537 // Fetch module merge file path. 1538 StringTableEntry moduleMergeFilePath = getModuleMergeFilePath(); 1539 1540 // Read module merge definition. 1541 Taml taml; 1542 ModuleMergeDefinition* pModuleMergeDefinition = taml.read<ModuleMergeDefinition>( moduleMergeFilePath ); 1543 1544 // Do we have a module merge definition. 1545 if ( pModuleMergeDefinition == NULL ) 1546 { 1547 // No, so warn. 1548 Con::warnf( "Cannot merge modules as the module merge definition file failed to load '%s'.", moduleMergeFilePath ); 1549 return false; 1550 } 1551 1552 // Fetch the merge source path. 1553 StringTableEntry mergeSourcePath = pModuleMergeDefinition->getModuleMergePath(); 1554 1555 // Remove the module merge definition. 1556 pModuleMergeDefinition->deleteObject(); 1557 pModuleMergeDefinition = NULL; 1558 1559 // If we cannot merge the modules then we only process modules flagged as critical merge. 1560 const bool criticalMergeOnly = !canMergeModules( mergeSourcePath ); 1561 1562 // Initialize the target module manager and scan the target folder for modules. 1563 ModuleManager targetModuleManager; 1564 targetModuleManager.mEnforceDependencies = false; 1565 targetModuleManager.mEchoInfo = false; 1566 targetModuleManager.scanModules( pMergeTargetPath ); 1567 1568 // Initialize the source module manager and scan the source folder for modules. 1569 ModuleManager sourceModuleManager; 1570 sourceModuleManager.mEnforceDependencies = false; 1571 sourceModuleManager.mEchoInfo = false; 1572 sourceModuleManager.scanModules( mergeSourcePath ); 1573 1574 // Find all the source modules. 1575 typeConstModuleDefinitionVector sourceModules; 1576 sourceModuleManager.findModules( false, sourceModules ); 1577 1578 // Iterate found merge module definitions. 1579 for ( typeConstModuleDefinitionVector::const_iterator sourceModuleItr = sourceModules.begin(); sourceModuleItr != sourceModules.end(); ++sourceModuleItr ) 1580 { 1581 // Fetch the source module definition. 1582 const ModuleDefinition* pSourceModuleDefinition = *sourceModuleItr; 1583 1584 // Skip if we're performing a critical merge only and the module is not flagged as critical merge. 1585 if ( criticalMergeOnly && pSourceModuleDefinition->getCriticalMerge() ) 1586 continue; 1587 1588 // Fetch source module Id. 1589 const StringTableEntry sourceModuleId = pSourceModuleDefinition->getModuleId(); 1590 1591 // Fetch source version Id. 1592 const U32 sourceVersionId = pSourceModuleDefinition->getVersionId(); 1593 1594 // Fetch source build Id. 1595 const U32 sourceBuildId = pSourceModuleDefinition->getBuildId(); 1596 1597 // Format module Id folder path. 1598 char targetModuleIdBuffer[1024]; 1599 dSprintf( targetModuleIdBuffer, sizeof(targetModuleIdBuffer), "%s/%s/", pMergeTargetPath, sourceModuleId ); 1600 1601 // Flag to indicate if the merged module needs registering. 1602 bool shouldRegisterModule; 1603 1604 // Does the module Id exist? 1605 if ( targetModuleManager.findModuleId( sourceModuleId ) == NULL ) 1606 { 1607 // No, so create module Id folder. 1608 if ( !Platform::createPath( targetModuleIdBuffer ) ) 1609 { 1610 // Warn. 1611 Con::warnf("Cannot merge modules for module '%s' as the path '%s' could not be created.", sourceModuleId, targetModuleIdBuffer ); 1612 return false; 1613 } 1614 1615 // Module Should be registered. 1616 shouldRegisterModule = true; 1617 } 1618 else 1619 { 1620 // Yes, so find the target module definition that matches the source module definition. 1621 ModuleDefinitionEntry::iterator targetModuleDefinitionItr = targetModuleManager.findModuleDefinition( sourceModuleId, sourceVersionId ); 1622 1623 // Is there an existing target module definition entry? 1624 if ( targetModuleDefinitionItr != NULL ) 1625 { 1626 // Yes, so fetch the target module definition. 1627 const ModuleDefinition* pTargetModuleDefinition = *targetModuleDefinitionItr; 1628 1629 // Fetch target module path. 1630 StringTableEntry targetModulePath = pTargetModuleDefinition->getModulePath(); 1631 1632 // Yes, so we have to remove it first. 1633 if ( !Platform::deleteDirectory( targetModulePath ) ) 1634 { 1635 // Module was not deleted so warn. 1636 Con::warnf( "Failed to remove module folder located at '%s'. Module will be copied over.", targetModulePath ); 1637 } 1638 1639 // Is the build Id being downgraded? 1640 if ( sourceBuildId < pTargetModuleDefinition->getBuildId() ) 1641 { 1642 // Yes, so warn. 1643 Con::warnf( "Encountered a downgraded build Id for module Id '%s' at version Id '%d'.", sourceModuleId, sourceBuildId ); 1644 } 1645 1646 // Module should not be registered. 1647 shouldRegisterModule = false; 1648 } 1649 else 1650 { 1651 // Module Should be registered. 1652 shouldRegisterModule = true; 1653 } 1654 } 1655 1656 // Fetch source module path. 1657 StringTableEntry sourceModulePath = pSourceModuleDefinition->getModulePath(); 1658 1659 // Format target version Id folder path. 1660 char targetVersionIdBuffer[1024]; 1661 dSprintf( targetVersionIdBuffer, sizeof(targetVersionIdBuffer), "%s%d", targetModuleIdBuffer, sourceVersionId ); 1662 1663 // Copy module (allow overwrites as we may have failed to remove the old folder in which case this is likely to fail as well). 1664 if (!dPathCopy(sourceModulePath, targetVersionIdBuffer, false)) 1665 { 1666 // Failed to copy module. 1667 Con::warnf( "Failed to copy module folder located at '%s' to location '%s'. The modules may now be corrupted.", sourceModulePath, targetVersionIdBuffer ); 1668 } 1669 1670 // Are we registering new modules and the module needs registering? 1671 if ( registerNewModules && shouldRegisterModule ) 1672 { 1673 // Yes, so scan module. 1674 scanModules( targetVersionIdBuffer, true ); 1675 } 1676 1677 // Is the module part of a critical merge? 1678 if ( criticalMergeOnly ) 1679 { 1680 // Yes, so we need to remove the source module definition. 1681 if ( !Platform::deleteDirectory( sourceModulePath ) ) 1682 { 1683 // Module was not deleted so warn. 1684 Con::warnf( "Failed to remove CRITICAL merge module folder located at '%s'. Module will be copied over.", sourceModulePath ); 1685 } 1686 } 1687 } 1688 1689 // Do we need to remove the module merge definition file? 1690 if ( removeMergeDefinition ) 1691 { 1692 // Yes, so remove it. 1693 dFileDelete( moduleMergeFilePath ); 1694 } 1695 1696 return true; 1697} 1698 1699//----------------------------------------------------------------------------- 1700 1701void ModuleManager::addListener( SimObject* pListener ) 1702{ 1703 // Sanity! 1704 AssertFatal( pListener != NULL, "Cannot add notifications to a NULL object." ); 1705 1706 // Ignore if already added. 1707 if (mNotificationListeners.find( pListener) != mNotificationListeners.end()) 1708 return; 1709 1710 // Add as a listener. 1711 mNotificationListeners.addObject( pListener ); 1712} 1713 1714//----------------------------------------------------------------------------- 1715 1716void ModuleManager::removeListener( SimObject* pListener ) 1717{ 1718 // Sanity! 1719 AssertFatal( pListener != NULL, "Cannot remove notifications from a NULL object." ); 1720 1721 // Remove as a listener. 1722 mNotificationListeners.removeObject( pListener ); 1723} 1724 1725//----------------------------------------------------------------------------- 1726 1727void ModuleManager::clearDatabase( void ) 1728{ 1729 // Lock database. 1730 AssertFatal( mDatabaseLocks == 0, "Cannot clear database if database is locked." ); 1731 1732 // Iterate groups loaded. 1733 while ( mGroupsLoaded.size() > 0 ) 1734 { 1735 // Unload module group. 1736 unloadModuleGroup( *mGroupsLoaded.begin() ); 1737 } 1738 1739 // Iterate any other explicit modules that are loaded. 1740 while ( mModulesLoaded.size() > 0 ) 1741 { 1742 // Fetch module definition. 1743 ModuleDefinition* pModuleDefinition = mModulesLoaded.begin()->mpModuleDefinition; 1744 1745 // Unload explicit module. 1746 unloadModuleExplicit( pModuleDefinition->getModuleId() ); 1747 } 1748 1749 // Iterate modules to delete module definitions. 1750 for ( typeModuleIdDatabaseHash::iterator moduleItr = mModuleIdDatabase.begin(); moduleItr != mModuleIdDatabase.end(); ++moduleItr ) 1751 { 1752 // Fetch modules definitions. 1753 ModuleDefinitionEntry* pDefinitions = moduleItr->value; 1754 1755 // Iterate module definitions. 1756 for ( ModuleDefinitionEntry::iterator definitionItr = pDefinitions->begin(); definitionItr != pDefinitions->end(); ++definitionItr ) 1757 { 1758 // Fetch module definition. 1759 ModuleDefinition* pModuleDefinition = *definitionItr; 1760 1761 // Remove notification before we delete it. 1762 clearNotify( pModuleDefinition ); 1763 1764 // Delete module definition. 1765 pModuleDefinition->deleteObject(); 1766 } 1767 1768 // Clear definitions. 1769 delete pDefinitions; 1770 } 1771 1772 // Clear database. 1773 mModuleIdDatabase.clear(); 1774 1775 // Iterate module groups. 1776 for ( typeGroupModuleHash::iterator moduleGroupItr = mGroupModules.begin(); moduleGroupItr != mGroupModules.end(); ++moduleGroupItr ) 1777 { 1778 // Delete module group vector. 1779 delete moduleGroupItr->value; 1780 } 1781 1782 // Clear module groups. 1783 mGroupModules.clear(); 1784} 1785 1786//----------------------------------------------------------------------------- 1787 1788bool ModuleManager::removeModuleDefinition( ModuleDefinition* pModuleDefinition ) 1789{ 1790 // Sanity! 1791 AssertFatal( pModuleDefinition != NULL, "Cannot remove module definition if it is NULL." ); 1792 1793 // Fetch module Id. 1794 StringTableEntry moduleId = pModuleDefinition->getModuleId(); 1795 1796 // Is the module definition registered with this module manager? 1797 if ( pModuleDefinition->getModuleManager() != this ) 1798 { 1799 // No, so warn. 1800 Con::warnf("Cannot remove module definition '%s' as it is not registered with this module manager.", moduleId ); 1801 return false; 1802 } 1803 1804 // Is the module definition loaded? 1805 if ( pModuleDefinition->getLoadCount() > 0 ) 1806 { 1807 // No, so warn. 1808 Con::warnf("Cannot remove module definition '%s' as it is loaded.", moduleId ); 1809 return false; 1810 } 1811 1812 // Find module Id. 1813 typeModuleIdDatabaseHash::iterator moduleItr = mModuleIdDatabase.find( moduleId ); 1814 1815 // Sanity! 1816 AssertFatal( moduleItr != mModuleIdDatabase.end(), "Failed to find module definition." ); 1817 1818 // Fetch modules definitions. 1819 ModuleDefinitionEntry* pDefinitions = moduleItr->value; 1820 1821 // Fetch version Id. 1822 const U32 versionId = pModuleDefinition->getVersionId(); 1823 1824 // Iterate module definitions. 1825 for ( ModuleDefinitionEntry::iterator definitionItr = pDefinitions->begin(); definitionItr != pDefinitions->end(); ++definitionItr ) 1826 { 1827 // Skip if this isn't the version Id we're searching for. 1828 if ( versionId != (*definitionItr)->getVersionId() ) 1829 continue; 1830 1831 // Remove definition entry. 1832 pDefinitions->erase( definitionItr ); 1833 1834 // Remove notification before we delete it. 1835 clearNotify( pModuleDefinition ); 1836 1837 // Delete module definition. 1838 pModuleDefinition->deleteObject(); 1839 1840 // Are there any modules left for this module Id? 1841 if ( findModuleId( moduleId ) == NULL ) 1842 { 1843 bool moduleIdFound = false; 1844 1845 // No, so remove from groups. 1846 for( typeGroupModuleHash::iterator moduleGroupItr = mGroupModules.begin(); moduleGroupItr != mGroupModules.end(); ++moduleGroupItr ) 1847 { 1848 // Fetch module Ids. 1849 typeModuleIdVector* pModuleIds = moduleGroupItr->value; 1850 1851 // Iterate module Id. 1852 for( typeModuleIdVector::iterator moduleIdItr = pModuleIds->begin(); moduleIdItr != pModuleIds->end(); ++moduleIdItr ) 1853 { 1854 // Skip if this isn't the Id. 1855 if ( *moduleIdItr != moduleId ) 1856 continue; 1857 1858 // Remove the module Id. 1859 pModuleIds->erase( moduleIdItr ); 1860 1861 // Flag as found. 1862 moduleIdFound = true; 1863 1864 break; 1865 } 1866 1867 // Finish if found. 1868 if ( moduleIdFound ) 1869 break; 1870 } 1871 } 1872 1873 return true; 1874 } 1875 1876 // Sanity! 1877 AssertFatal( false, "Failed to find module definition." ); 1878 1879 return false; 1880} 1881 1882//----------------------------------------------------------------------------- 1883 1884bool ModuleManager::registerModule( const char* pModulePath, const char* pModuleFile ) 1885{ 1886 // Sanity! 1887 AssertFatal( pModulePath != NULL, "Cannot scan module with NULL module path." ); 1888 AssertFatal( pModuleFile != NULL, "Cannot scan module with NULL module file." ); 1889 1890 // Make the module path a full-path. 1891 char fullPathBuffer[1024]; 1892 Platform::makeFullPathName( pModulePath, fullPathBuffer, sizeof(fullPathBuffer) ); 1893 pModulePath = fullPathBuffer; 1894 1895 1896 char formatBuffer[1024]; 1897 1898 // Fetch module path trail character. 1899 char modulePathTrail = pModulePath[dStrlen(pModulePath) - 1]; 1900 1901 // Format module file-path. 1902 dSprintf( formatBuffer, sizeof(formatBuffer), modulePathTrail == '/' ? "%s%s" : "%s/%s", pModulePath, pModuleFile ); 1903 1904 // Read the module file. 1905 ModuleDefinition* pModuleDefinition = mTaml.read<ModuleDefinition>( formatBuffer ); 1906 1907 // Did we read a module definition? 1908 if ( pModuleDefinition == NULL ) 1909 { 1910 // No, so warn. 1911 Con::warnf( "Module Manager: Failed to read module definition in file '%s'.", formatBuffer ); 1912 return false; 1913 } 1914 1915 // Set the module manager. 1916 pModuleDefinition->setModuleManager( this ); 1917 1918 // Set module definition path. 1919 pModuleDefinition->setModulePath( pModulePath ); 1920 1921 // Set module file. 1922 pModuleDefinition->setModuleFile( pModuleFile ); 1923 1924 // Set module file-path. 1925 pModuleDefinition->setModuleFilePath( formatBuffer ); 1926 1927 // Fetch module Id. 1928 StringTableEntry moduleId = pModuleDefinition->getModuleId(); 1929 1930 // Fetch module version Id. 1931 const U32 versionId = pModuleDefinition->getVersionId(); 1932 1933 // Fetch module group. 1934 StringTableEntry moduleGroup = pModuleDefinition->getModuleGroup(); 1935 1936 // Fetch module type. 1937 StringTableEntry moduleType = pModuleDefinition->getModuleType(); 1938 1939 // Is the module enabled? 1940 if ( !pModuleDefinition->getEnabled() ) 1941 { 1942 // No, so warn. 1943 Con::warnf( "Module Manager: Found module: '%s' but it is disabled.", pModuleDefinition->getModuleFilePath() ); 1944 1945 // Destroy module definition and finish. 1946 pModuleDefinition->deleteObject(); 1947 return false; 1948 } 1949 1950 // Is the module Id valid? 1951 if (moduleId == StringTable->EmptyString()) 1952 { 1953 // No, so warn. 1954 Con::warnf( "Module Manager: Found module: '%s' but it has an unspecified module Id.", 1955 pModuleDefinition->getModuleFilePath() ); 1956 1957 // Destroy module definition and finish. 1958 pModuleDefinition->deleteObject(); 1959 return false; 1960 } 1961 1962 // Is the module version Id valid? 1963 if ( versionId == 0 ) 1964 { 1965 // No, so warn. 1966 Con::warnf( "Module Manager: Found Manager: Registering module: '%s' but it has an invalid Version Id of '0'.", 1967 pModuleDefinition->getModuleFilePath() ); 1968 1969 // Destroy module definition and finish. 1970 pModuleDefinition->deleteObject(); 1971 return false; 1972 } 1973 1974 // Is the module group already loaded? 1975 if ( findGroupLoaded( moduleGroup ) != NULL ) 1976 { 1977 // Yes, so warn. 1978 Con::warnf( "Module Manager: Found module: '%s' but it is in a module group '%s' which has already been loaded.", 1979 pModuleDefinition->getModuleFilePath(), 1980 moduleGroup ); 1981 1982 // Destroy module definition and finish. 1983 pModuleDefinition->deleteObject(); 1984 return false; 1985 } 1986 1987 // Was a script-file specified? 1988 if ( pModuleDefinition->getScriptFile() != StringTable->EmptyString() ) 1989 { 1990 // Yes, so format module script file-path. 1991 dSprintf( formatBuffer, sizeof(formatBuffer), modulePathTrail == '/' ? "%s%s" : "%s/%s", pModulePath, pModuleDefinition->getScriptFile() ); 1992 pModuleDefinition->setModuleScriptFilePath( formatBuffer ); 1993 } 1994 1995 // Format module signature, 1996 dSprintf( formatBuffer, sizeof(formatBuffer), "%s_%d_%d", moduleId, versionId, pModuleDefinition->getBuildId() ); 1997 pModuleDefinition->setSignature( formatBuffer ); 1998 1999 // Locked the module definition. 2000 pModuleDefinition->setLocked( true ); 2001 2002 // Fetch modules definitions. 2003 ModuleDefinitionEntry* pDefinitions = findModuleId( moduleId ); 2004 2005 // Did we find the module Id? 2006 if ( pDefinitions != NULL ) 2007 { 2008 // Yes, so find the module definition. 2009 ModuleDefinitionEntry::iterator definitionItr = findModuleDefinition( moduleId, versionId ); 2010 2011 // Does this version Id already exist? 2012 if ( definitionItr != NULL ) 2013 { 2014 // Yes, so warn. 2015 Con::warnf( "Module Manager: Found module: '%s' but it is already registered as module Id '%s' at version Id '%d'.", 2016 pModuleDefinition->getModuleFilePath(), moduleId, versionId ); 2017 2018 // Destroy module definition and finish. 2019 pModuleDefinition->deleteObject(); 2020 return false; 2021 } 2022 2023 // Is the module group the same as the module definitions we already have? 2024 if ( moduleGroup != pDefinitions->mModuleGroup ) 2025 { 2026 // No, so warn. 2027 Con::warnf( "Module Manager: Found module: '%s' but its module group '%s' is not the same as other module definitions of the same module Id.", 2028 pModuleDefinition->getModuleFilePath(), moduleGroup ); 2029 2030 // Destroy module definition and finish. 2031 pModuleDefinition->deleteObject(); 2032 return false; 2033 } 2034 2035 // Is the module type the same as the module definitions we already have? 2036 if ( moduleType != pDefinitions->mModuleType ) 2037 { 2038 // No, so warn. 2039 Con::warnf( "Module Manager: Found module: '%s' but its module type '%s' is not the same as other module definitions of the same module Id.", 2040 pModuleDefinition->getModuleFilePath(), moduleGroup ); 2041 2042 // Destroy module definition and finish. 2043 pModuleDefinition->deleteObject(); 2044 return false; 2045 } 2046 } 2047 else 2048 { 2049 // No, so create a vector of definitions. 2050 pDefinitions = new ModuleDefinitionEntry( moduleId, moduleGroup, moduleType ); 2051 2052 // Insert module Id definitions. 2053 mModuleIdDatabase.insert( moduleId, pDefinitions ); 2054 } 2055 2056 // Add module definition. 2057 pDefinitions->push_back( pModuleDefinition ); 2058 2059 // Sort module definitions by version Id so that higher versions appear first. 2060 dQsort( pDefinitions->address(), pDefinitions->size(), sizeof(ModuleDefinition*), moduleDefinitionVersionIdSort ); 2061 2062 // Find module group. 2063 typeGroupModuleHash::iterator moduleGroupItr = mGroupModules.find( moduleGroup ); 2064 2065 // Did we find the module group? 2066 if ( moduleGroupItr != mGroupModules.end() ) 2067 { 2068 // Yes, so fetch module Ids. 2069 typeModuleIdVector* pModuleIds = moduleGroupItr->value; 2070 2071 // Is the module Id already present? 2072 bool moduleIdFound = false; 2073 for( typeModuleIdVector::iterator moduleIdItr = pModuleIds->begin(); moduleIdItr != pModuleIds->end(); ++moduleIdItr ) 2074 { 2075 // Skip if this isn't the Id. 2076 if ( *moduleIdItr != moduleId ) 2077 continue; 2078 2079 // Flag as found. 2080 moduleIdFound = true; 2081 break; 2082 } 2083 2084 // Add if module Id was not found. 2085 if ( !moduleIdFound ) 2086 pModuleIds->push_back( moduleId ); 2087 } 2088 else 2089 { 2090 // No, so insert a module Id vector. 2091 moduleGroupItr = mGroupModules.insert( pModuleDefinition->getModuleGroup(), new typeModuleIdVector() ); 2092 2093 // Add module Id. 2094 moduleGroupItr->value->push_back( moduleId ); 2095 } 2096 2097 // Notify if the module definition is destroyed. 2098 deleteNotify( pModuleDefinition ); 2099 2100 // Info. 2101 if ( mEchoInfo ) 2102 { 2103#if 1 2104 Con::printf( "Module Manager: Registering: '%s' [ ID='%s', VersionId='%d', BuildId='%d', Description='%s' ].", 2105 pModuleDefinition->getModuleFilePath(), 2106 pModuleDefinition->getModuleId(), 2107 pModuleDefinition->getVersionId(), 2108 pModuleDefinition->getBuildId(), 2109 pModuleDefinition->getModuleDescription() 2110 ); 2111#else 2112 Con::printf( "Module Manager: Registering: '%s' [ ID='%s', VersionId='%d', BuildId='%d', Description='%s', Group='%s', Dependencies='%s', ScriptFile='%s', CreateFunction='%s', DestroyFunction='%s' ].", 2113 pModuleDefinition->getModuleFilePath(), 2114 pModuleDefinition->getModuleId(), 2115 pModuleDefinition->getVersionId(), 2116 pModuleDefinition->getBuildId(), 2117 pModuleDefinition->getModuleDescription(), 2118 pModuleDefinition->getModuleGroup(), 2119 pModuleDefinition->getDataField( StringTable->insert("Dependencies"), NULL ), 2120 pModuleDefinition->getScriptFile(), 2121 pModuleDefinition->getCreateFunction(), 2122 pModuleDefinition->getDestroyFunction() 2123 ); 2124#endif 2125 } 2126 2127 // Emit notifications. 2128 for( SimSet::iterator notifyItr = mNotificationListeners.begin(); notifyItr != mNotificationListeners.end(); ++notifyItr ) 2129 { 2130 Con::executef( *notifyItr, "onModuleRegister", pModuleDefinition->getIdString() ); 2131 } 2132 2133 return true; 2134} 2135 2136//----------------------------------------------------------------------------- 2137 2138bool ModuleManager::unregisterModule( const char* pModuleId, const U32 versionId ) 2139{ 2140 // Sanity! 2141 AssertFatal( pModuleId != NULL, "A module Id cannot be NULL." ); 2142 2143 // Fetch module Id. 2144 StringTableEntry moduleId = StringTable->insert( pModuleId ); 2145 2146 // Find the module definition. 2147 ModuleDefinition* pModuleDefinition = findModule( pModuleId, versionId ); 2148 2149 // Did we find the module definition? 2150 if ( pModuleDefinition == NULL ) 2151 { 2152 // No, so warn. 2153 Con::warnf( "Module Manager: Cannot unregister module Id '%s' as it is not registered.", moduleId ); 2154 return false; 2155 } 2156 2157 // Remove the module definition. 2158 return removeModuleDefinition( pModuleDefinition ); 2159} 2160 2161//----------------------------------------------------------------------------- 2162 2163void ModuleManager::raiseModulePreLoadNotifications( ModuleDefinition* pModuleDefinition ) 2164{ 2165 // Raise notifications. 2166 for( SimSet::iterator notifyItr = mNotificationListeners.begin(); notifyItr != mNotificationListeners.end(); ++notifyItr ) 2167 { 2168 // Fetch listener object. 2169 SimObject* pListener = *notifyItr; 2170 2171 // Perform object callback. 2172 ModuleCallbacks* pCallbacks = dynamic_cast<ModuleCallbacks*>( pListener ); 2173 if ( pCallbacks != NULL ) 2174 pCallbacks->onModulePreLoad( pModuleDefinition ); 2175 2176 // Perform script callback. 2177 if ( pListener->isMethod( "onModulePreLoad" ) ) 2178 Con::executef( pListener, "onModulePreLoad", pModuleDefinition->getIdString() ); 2179 } 2180} 2181 2182//----------------------------------------------------------------------------- 2183 2184void ModuleManager::raiseModulePostLoadNotifications( ModuleDefinition* pModuleDefinition ) 2185{ 2186 // Raise notifications. 2187 for( SimSet::iterator notifyItr = mNotificationListeners.begin(); notifyItr != mNotificationListeners.end(); ++notifyItr ) 2188 { 2189 // Fetch listener object. 2190 SimObject* pListener = *notifyItr; 2191 2192 // Perform object callback. 2193 ModuleCallbacks* pCallbacks = dynamic_cast<ModuleCallbacks*>( pListener ); 2194 if ( pCallbacks != NULL ) 2195 pCallbacks->onModulePostLoad( pModuleDefinition ); 2196 2197 // Perform script callback. 2198 if ( pListener->isMethod( "onModulePostLoad" ) ) 2199 Con::executef( pListener, "onModulePostLoad", pModuleDefinition->getIdString() ); 2200 } 2201} 2202 2203//----------------------------------------------------------------------------- 2204 2205void ModuleManager::raiseModulePreUnloadNotifications( ModuleDefinition* pModuleDefinition ) 2206{ 2207 // Raise notifications. 2208 for( SimSet::iterator notifyItr = mNotificationListeners.begin(); notifyItr != mNotificationListeners.end(); ++notifyItr ) 2209 { 2210 // Fetch listener object. 2211 SimObject* pListener = *notifyItr; 2212 2213 // Perform object callback. 2214 ModuleCallbacks* pCallbacks = dynamic_cast<ModuleCallbacks*>( pListener ); 2215 if ( pCallbacks != NULL ) 2216 pCallbacks->onModulePreUnload( pModuleDefinition ); 2217 2218 // Perform script callback. 2219 if ( pListener->isMethod( "onModulePreUnload" ) ) 2220 Con::executef( pListener, "onModulePreUnload", pModuleDefinition->getIdString() ); 2221 } 2222} 2223 2224//----------------------------------------------------------------------------- 2225 2226void ModuleManager::raiseModulePostUnloadNotifications( ModuleDefinition* pModuleDefinition ) 2227{ 2228 // Raise notifications. 2229 for( SimSet::iterator notifyItr = mNotificationListeners.begin(); notifyItr != mNotificationListeners.end(); ++notifyItr ) 2230 { 2231 // Fetch listener object. 2232 SimObject* pListener = *notifyItr; 2233 2234 // Perform object callback. 2235 ModuleCallbacks* pCallbacks = dynamic_cast<ModuleCallbacks*>( pListener ); 2236 if ( pCallbacks != NULL ) 2237 pCallbacks->onModulePostUnload( pModuleDefinition ); 2238 2239 // Perform script callback. 2240 if ( pListener->isMethod( "onModulePostUnload" ) ) 2241 Con::executef( pListener, "onModulePostUnload", pModuleDefinition->getIdString() ); 2242 } 2243} 2244 2245//----------------------------------------------------------------------------- 2246 2247ModuleManager::ModuleDefinitionEntry* ModuleManager::findModuleId( StringTableEntry moduleId ) 2248{ 2249 // Sanity! 2250 AssertFatal( moduleId != NULL, "A module Id cannot be NULL." ); 2251 2252 // Is the module Id valid? 2253 if ( moduleId == StringTable->EmptyString() ) 2254 { 2255 // No, so warn. 2256 Con::warnf( "Module Manager: Invalid Module Id." ); 2257 return NULL; 2258 } 2259 2260 // Find module Id. 2261 typeModuleIdDatabaseHash::iterator moduleItr = mModuleIdDatabase.find( moduleId ); 2262 2263 // Return appropriately. 2264 return moduleItr != mModuleIdDatabase.end() ? moduleItr->value : NULL; 2265} 2266 2267//----------------------------------------------------------------------------- 2268 2269ModuleManager::ModuleDefinitionEntry::iterator ModuleManager::findModuleDefinition( StringTableEntry moduleId, const U32 versionId ) 2270{ 2271 // Fetch modules definitions. 2272 ModuleDefinitionEntry* pDefinitions = findModuleId( moduleId ); 2273 2274 // Finish if no module definitions for the module Id. 2275 if ( pDefinitions == NULL ) 2276 return NULL; 2277 2278 // Iterate module definitions. 2279 for ( ModuleDefinitionEntry::iterator definitionItr = pDefinitions->begin(); definitionItr != pDefinitions->end(); ++definitionItr ) 2280 { 2281 // Skip if this isn't the version Id we're searching for. 2282 if ( versionId != (*definitionItr)->getVersionId() ) 2283 continue; 2284 2285 // Return module definition iterator. 2286 return definitionItr; 2287 } 2288 2289 // Not found. 2290 return NULL; 2291} 2292 2293//----------------------------------------------------------------------------- 2294 2295bool ModuleManager::resolveModuleDependencies( StringTableEntry moduleId, const U32 versionId, StringTableEntry moduleGroup, bool synchronizedOnly, typeModuleLoadEntryVector& moduleResolvingQueue, typeModuleLoadEntryVector& moduleReadyQueue ) 2296{ 2297 // Fetch the module Id ready entry. 2298 ModuleLoadEntry* pLoadReadyEntry = findModuleReady( moduleId, moduleReadyQueue ); 2299 2300 // Is there a load entry? 2301 if ( pLoadReadyEntry ) 2302 { 2303 // Yes, so finish if the version Id is not important, 2304 if ( versionId == 0 ) 2305 return true; 2306 2307 // Finish if the version Id are compatible. 2308 if ( versionId == pLoadReadyEntry->mpModuleDefinition->getVersionId() ) 2309 return true; 2310 2311 // Is it a strict version Id? 2312 if ( pLoadReadyEntry->mStrictVersionId ) 2313 { 2314 // Yes, so warn. 2315 Con::warnf( "Module Manager: A module dependency was detected loading module Id '%s' at version Id '%d' in group '%s' but an version Id '%d' is also required.", 2316 moduleId, versionId, pLoadReadyEntry->mpModuleDefinition->getVersionId(), moduleGroup ); 2317 return false; 2318 } 2319 2320 // No, so find the required module version Id. 2321 ModuleDefinitionEntry::iterator definitionItr = findModuleDefinition( moduleId, versionId ); 2322 2323 // Did we find the requested module definition. 2324 if ( definitionItr == NULL ) 2325 { 2326 // No, so we can safely ignore the missing dependency if we're not enforcing dependencies. 2327 if ( !mEnforceDependencies ) 2328 return true; 2329 2330 // Warn! 2331 Con::warnf( "Module Manager: A missing module dependency was detected loading module Id '%s' at version Id '%d' in group '%s'.", 2332 moduleId, versionId, moduleGroup ); 2333 return false; 2334 } 2335 2336 // Set the new module definition. 2337 pLoadReadyEntry->mpModuleDefinition = *definitionItr; 2338 2339 // Set strict version Id. 2340 pLoadReadyEntry->mStrictVersionId = true; 2341 2342 return true; 2343 } 2344 2345 // Is the module Id load resolving? 2346 if ( findModuleResolving( moduleId, moduleResolvingQueue ) != NULL ) 2347 { 2348 // Yes, so a cycle has been detected so warn. 2349 Con::warnf( "Module Manager: A cyclic dependency was detected resolving module Id '%s' at version Id '%d' in group '%s'.", 2350 moduleId, versionId, moduleGroup ); 2351 return false; 2352 } 2353 2354 // Reset selected module definition. 2355 ModuleDefinition* pSelectedModuleDefinition = NULL; 2356 2357 // Do we want the latest version Id? 2358 if ( versionId == 0 ) 2359 { 2360 // Yes, so find the module Id. 2361 typeModuleIdDatabaseHash::iterator moduleIdItr = mModuleIdDatabase.find( moduleId ); 2362 2363 // Did we find the module Id? 2364 if ( moduleIdItr == mModuleIdDatabase.end() ) 2365 { 2366 // No, so we can safely ignore the missing dependency if we're not enforcing dependencies. 2367 if ( !mEnforceDependencies ) 2368 return true; 2369 2370 // Warn! 2371 Con::warnf( "Module Manager: A missing module dependency was detected loading module Id '%s' at version Id '%d' in group '%s'.", 2372 moduleId, versionId, moduleGroup ); 2373 return false; 2374 } 2375 2376 // Fetch first module definition which should be the highest version Id. 2377 pSelectedModuleDefinition = (*moduleIdItr->value)[0]; 2378 } 2379 else 2380 { 2381 // No, so find the module Id at the specific version Id. 2382 ModuleDefinitionEntry::iterator definitionItr = findModuleDefinition( moduleId, versionId ); 2383 2384 // Did we find the module definition? 2385 if ( definitionItr == NULL ) 2386 { 2387 // No, so we can safely ignore the missing dependency if we're not enforcing dependencies. 2388 if ( !mEnforceDependencies ) 2389 return true; 2390 2391 // Warn! 2392 Con::warnf( "Module Manager: A missing module dependency was detected loading module Id '%s' at version Id '%d' in group '%s'.", 2393 moduleId, versionId, moduleGroup ); 2394 return false; 2395 } 2396 2397 // Select the module definition. 2398 pSelectedModuleDefinition = *definitionItr; 2399 } 2400 2401 // If we're only resolving synchronized modules and the module is not synchronized then finish. 2402 if ( synchronizedOnly && !pSelectedModuleDefinition->getSynchronized() ) 2403 return true; 2404 2405 // Create a load entry. 2406 ModuleLoadEntry loadEntry( pSelectedModuleDefinition, false ); 2407 2408 // Fetch module dependencies. 2409 const ModuleDefinition::typeModuleDependencyVector& moduleDependencies = pSelectedModuleDefinition->getDependencies(); 2410 2411 // Do we have any module dependencies? 2412 if ( moduleDependencies.size() > 0 ) 2413 { 2414 // Yes, so queue this module as resolving. 2415 moduleResolvingQueue.push_back( loadEntry ); 2416 2417 // Iterate module dependencies. 2418 for( ModuleDefinition::typeModuleDependencyVector::const_iterator dependencyItr = moduleDependencies.begin(); dependencyItr != moduleDependencies.end(); ++dependencyItr ) 2419 { 2420 // Finish if we could not the dependent module Id at the version Id. 2421 if ( !resolveModuleDependencies( dependencyItr->mModuleId, dependencyItr->mVersionId, moduleGroup, synchronizedOnly, moduleResolvingQueue, moduleReadyQueue ) ) 2422 return false; 2423 } 2424 2425 // Remove module as resolving. 2426 moduleResolvingQueue.pop_back(); 2427 } 2428 2429 // Queue module as ready. 2430 moduleReadyQueue.push_back( loadEntry ); 2431 2432 return true; 2433} 2434 2435//----------------------------------------------------------------------------- 2436 2437ModuleManager::ModuleLoadEntry* ModuleManager::findModuleResolving( StringTableEntry moduleId, typeModuleLoadEntryVector& moduleResolvingQueue ) 2438{ 2439 // Iterate module load resolving queue. 2440 for( typeModuleLoadEntryVector::iterator loadEntryItr = moduleResolvingQueue.begin(); loadEntryItr != moduleResolvingQueue.end(); ++loadEntryItr ) 2441 { 2442 // Finish if found. 2443 if ( moduleId == loadEntryItr->mpModuleDefinition->getModuleId() ) 2444 return loadEntryItr; 2445 } 2446 2447 // Not found. 2448 return NULL; 2449} 2450 2451//----------------------------------------------------------------------------- 2452 2453ModuleManager::ModuleLoadEntry* ModuleManager::findModuleReady( StringTableEntry moduleId, typeModuleLoadEntryVector& moduleReadyQueue ) 2454{ 2455 // Iterate module load ready queue. 2456 for( typeModuleLoadEntryVector::iterator loadEntryItr = moduleReadyQueue.begin(); loadEntryItr != moduleReadyQueue.end(); ++loadEntryItr ) 2457 { 2458 // Finish if found. 2459 if ( moduleId == loadEntryItr->mpModuleDefinition->getModuleId() ) 2460 return loadEntryItr; 2461 } 2462 2463 // Not found. 2464 return NULL; 2465} 2466 2467//----------------------------------------------------------------------------- 2468 2469ModuleManager::typeModuleLoadEntryVector::iterator ModuleManager::findModuleLoaded( StringTableEntry moduleId, const U32 versionId ) 2470{ 2471 // Iterate module loaded queue. 2472 for( typeModuleLoadEntryVector::iterator loadEntryItr = mModulesLoaded.begin(); loadEntryItr != mModulesLoaded.end(); ++loadEntryItr ) 2473 { 2474 // Skip if not the module Id we're looking for. 2475 if ( moduleId != loadEntryItr->mpModuleDefinition->getModuleId() ) 2476 continue; 2477 2478 // Skip if we are searching for a specific version and it does not match. 2479 if ( versionId != 0 && versionId != loadEntryItr->mpModuleDefinition->getVersionId() ) 2480 continue; 2481 2482 return loadEntryItr; 2483 } 2484 2485 // Not found. 2486 return NULL; 2487} 2488 2489//----------------------------------------------------------------------------- 2490 2491ModuleManager::typeGroupVector::iterator ModuleManager::findGroupLoaded( StringTableEntry moduleGroup ) 2492{ 2493 // Iterate groups loaded queue. 2494 for( typeGroupVector::iterator groupsLoadedItr = mGroupsLoaded.begin(); groupsLoadedItr != mGroupsLoaded.end(); ++groupsLoadedItr ) 2495 { 2496 // Finish if found. 2497 if ( moduleGroup == *groupsLoadedItr ) 2498 return groupsLoadedItr; 2499 } 2500 2501 // Not found. 2502 return NULL; 2503} 2504 2505//----------------------------------------------------------------------------- 2506 2507StringTableEntry ModuleManager::getModuleMergeFilePath( void ) const 2508{ 2509 // Format merge file path. 2510 char filePathBuffer[1024]; 2511 dSprintf( filePathBuffer, sizeof(filePathBuffer), "%s/%s", Platform::getExecutablePath(), MODULE_MANAGER_MERGE_FILE ); 2512 2513 return StringTable->insert( filePathBuffer ); 2514} 2515
