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