simManager.cpp
Engine/source/console/simManager.cpp
Namespaces:
namespace
Public Defines
define
InstantiateNamedGroup(set) g##set = ; g##set->registerObject(#set); g##set->setNameChangeAllowed(false); gRootGroup->addObject(g##set); ((*g##set))
define
InstantiateNamedSet(set) g##set = ; g##set->registerObject(#set); g##set->setNameChangeAllowed(false); gRootGroup->addObject(g##set); ((*g##set))
define
MAX_TRIES() 100
define
MAX_TRIES() 100
Public Variables
Detailed Description
Public Defines
InstantiateNamedGroup(set) g##set = ; g##set->registerObject(#set); g##set->setNameChangeAllowed(false); gRootGroup->addObject(g##set); ((*g##set))
InstantiateNamedSet(set) g##set = ; g##set->registerObject(#set); g##set->setNameChangeAllowed(false); gRootGroup->addObject(g##set); ((*g##set))
MAX_TRIES() 100
MAX_TRIES() 100
Public Variables
ExprEvalState gEvalState
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 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 "platform/platform.h" 25#include "platform/threads/mutex.h" 26#include "console/simBase.h" 27#include "console/simPersistID.h" 28#include "core/stringTable.h" 29#include "console/console.h" 30#include "core/stream/fileStream.h" 31#include "core/fileObject.h" 32#include "console/consoleInternal.h" 33#include "console/engineAPI.h" 34#include "core/idGenerator.h" 35#include "core/util/safeDelete.h" 36#include "platform/platformIntrinsics.h" 37#include "platform/profiler.h" 38#include "math/mMathFn.h" 39 40extern ExprEvalState gEvalState; 41 42//--------------------------------------------------------------------------- 43//--------------------------------------------------------------------------- 44 45// We comment out the implementation of the Con namespace when doxygenizing because 46// otherwise Doxygen decides to ignore our docs in console.h 47#ifndef DOXYGENIZING 48 49namespace Sim 50{ 51 52 53//--------------------------------------------------------------------------- 54 55//--------------------------------------------------------------------------- 56// event queue variables: 57 58SimTime gCurrentTime; 59SimTime gTargetTime; 60 61void *gEventQueueMutex; 62SimEvent *gEventQueue; 63U32 gEventSequence; 64 65//--------------------------------------------------------------------------- 66// event queue init/shutdown 67 68static void initEventQueue() 69{ 70 gCurrentTime = 0; 71 gTargetTime = 0; 72 gEventSequence = 1; 73 gEventQueue = NULL; 74 gEventQueueMutex = Mutex::createMutex(); 75} 76 77static void shutdownEventQueue() 78{ 79 // Delete all pending events 80 Mutex::lockMutex(gEventQueueMutex); 81 SimEvent *walk = gEventQueue; 82 while(walk) 83 { 84 SimEvent *temp = walk->nextEvent; 85 delete walk; 86 walk = temp; 87 } 88 Mutex::unlockMutex(gEventQueueMutex); 89 Mutex::destroyMutex(gEventQueueMutex); 90} 91 92//--------------------------------------------------------------------------- 93// event post 94 95U32 postEvent(SimObject *destObject, SimEvent* event,U32 time) 96{ 97 AssertFatal(time == -1 || time >= getCurrentTime(), 98 "Sim::postEvent() - Event time must be greater than or equal to the current time." ); 99 AssertFatal(destObject, "Sim::postEvent() - Destination object for event doesn't exist."); 100 101 Mutex::lockMutex(gEventQueueMutex); 102 103 if( time == -1 ) // FIXME: a smart compiler will remove this check. - see http://garagegames.com/community/resources/view/19785 for a fix 104 time = gCurrentTime; 105 106 event->time = time; 107 event->startTime = gCurrentTime; 108 event->destObject = destObject; 109 110 if(!destObject) 111 { 112 delete event; 113 114 Mutex::unlockMutex(gEventQueueMutex); 115 116 return InvalidEventId; 117 } 118 event->sequenceCount = gEventSequence++; 119 SimEvent **walk = &gEventQueue; 120 SimEvent *current; 121 122 while((current = *walk) != NULL && (current->time < event->time)) 123 walk = &(current->nextEvent); 124 125 // [tom, 6/24/2005] This ensures that SimEvents are dispatched in the same order that they are posted. 126 // This is needed to ensure Con::threadSafeExecute() executes script code in the correct order. 127 while((current = *walk) != NULL && (current->time == event->time)) 128 walk = &(current->nextEvent); 129 130 event->nextEvent = current; 131 *walk = event; 132 133 U32 seqCount = event->sequenceCount; 134 135 Mutex::unlockMutex(gEventQueueMutex); 136 137 return seqCount; 138} 139 140//--------------------------------------------------------------------------- 141// event cancellation 142 143void cancelEvent(U32 eventSequence) 144{ 145 Mutex::lockMutex(gEventQueueMutex); 146 147 SimEvent **walk = &gEventQueue; 148 SimEvent *current; 149 150 while((current = *walk) != NULL) 151 { 152 if(current->sequenceCount == eventSequence) 153 { 154 *walk = current->nextEvent; 155 delete current; 156 Mutex::unlockMutex(gEventQueueMutex); 157 return; 158 } 159 else 160 walk = &(current->nextEvent); 161 } 162 163 Mutex::unlockMutex(gEventQueueMutex); 164} 165 166void cancelPendingEvents(SimObject *obj) 167{ 168 Mutex::lockMutex(gEventQueueMutex); 169 170 SimEvent **walk = &gEventQueue; 171 SimEvent *current; 172 173 while((current = *walk) != NULL) 174 { 175 if(current->destObject == obj) 176 { 177 *walk = current->nextEvent; 178 delete current; 179 } 180 else 181 walk = &(current->nextEvent); 182 } 183 Mutex::unlockMutex(gEventQueueMutex); 184} 185 186//--------------------------------------------------------------------------- 187// event pending test 188 189bool isEventPending(U32 eventSequence) 190{ 191 Mutex::lockMutex(gEventQueueMutex); 192 193 for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent) 194 if(walk->sequenceCount == eventSequence) 195 { 196 Mutex::unlockMutex(gEventQueueMutex); 197 return true; 198 } 199 Mutex::unlockMutex(gEventQueueMutex); 200 return false; 201} 202 203U32 getEventTimeLeft(U32 eventSequence) 204{ 205 Mutex::lockMutex(gEventQueueMutex); 206 207 for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent) 208 if(walk->sequenceCount == eventSequence) 209 { 210 SimTime t = walk->time - getCurrentTime(); 211 Mutex::unlockMutex(gEventQueueMutex); 212 return t; 213 } 214 215 Mutex::unlockMutex(gEventQueueMutex); 216 217 return 0; 218} 219 220U32 getScheduleDuration(U32 eventSequence) 221{ 222 for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent) 223 if(walk->sequenceCount == eventSequence) 224 return (walk->time-walk->startTime); 225 return 0; 226} 227 228U32 getTimeSinceStart(U32 eventSequence) 229{ 230 for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent) 231 if(walk->sequenceCount == eventSequence) 232 return (getCurrentTime()-walk->startTime); 233 return 0; 234} 235 236//--------------------------------------------------------------------------- 237// event timing 238 239void advanceToTime(SimTime targetTime) 240{ 241 AssertFatal(targetTime >= getCurrentTime(), 242 "Sim::advanceToTime() - Target time is less than the current time." ); 243 244 Mutex::lockMutex(gEventQueueMutex); 245 246 gTargetTime = targetTime; 247 while(gEventQueue && gEventQueue->time <= targetTime) 248 { 249 SimEvent *event = gEventQueue; 250 gEventQueue = gEventQueue->nextEvent; 251 AssertFatal(event->time >= gCurrentTime, 252 "Sim::advanceToTime() - Event time is less than current time."); 253 gCurrentTime = event->time; 254 SimObject *obj = event->destObject; 255 256 if(!obj->isDeleted()) 257 event->process(obj); 258 delete event; 259 } 260 gCurrentTime = targetTime; 261 262 Mutex::unlockMutex(gEventQueueMutex); 263} 264 265void advanceTime(SimTime delta) 266{ 267 advanceToTime(getCurrentTime() + delta); 268} 269 270U32 getCurrentTime() 271{ 272 return dAtomicRead( gCurrentTime); 273} 274 275U32 getTargetTime() 276{ 277 return dAtomicRead( gTargetTime ); 278} 279 280//--------------------------------------------------------------------------- 281//--------------------------------------------------------------------------- 282 283SimGroup *gRootGroup = NULL; 284SimManagerNameDictionary *gNameDictionary; 285SimIdDictionary *gIdDictionary; 286U32 gNextObjectId; 287 288static void initRoot() 289{ 290 gIdDictionary = new SimIdDictionary; 291 gNameDictionary = new SimManagerNameDictionary; 292 293 gRootGroup = new SimGroup(); 294 gRootGroup->incRefCount(); 295 296 gRootGroup->setId(RootGroupId); 297 gRootGroup->assignName("RootGroup"); 298 gRootGroup->registerObject(); 299 300 gNextObjectId = DynamicObjectIdFirst; 301} 302 303static void shutdownRoot() 304{ 305 gRootGroup->decRefCount(); 306 if( engineAPI::gUseConsoleInterop ) 307 gRootGroup->deleteObject(); 308 gRootGroup = NULL; 309 310 SAFE_DELETE(gNameDictionary); 311 SAFE_DELETE(gIdDictionary); 312} 313 314//--------------------------------------------------------------------------- 315 316SimObject* findObject(const char* fileName, S32 declarationLine) 317{ 318 PROFILE_SCOPE(SimFindObjectByLine); 319 320 if (!fileName) 321 return NULL; 322 323 if (declarationLine < 0) 324 return NULL; 325 326 if (!gRootGroup) 327 return NULL; 328 329 return gRootGroup->findObjectByLineNumber(fileName, declarationLine, true); 330} 331 332SimObject* findObject(ConsoleValueRef &ref) 333{ 334 return findObject((const char*)ref); 335} 336 337SimObject* findObject(const char* name) 338{ 339 PROFILE_SCOPE(SimFindObject); 340 341 // Play nice with bad code - JDD 342 if( !name ) 343 return NULL; 344 345 SimObject *obj; 346 char c = *name; 347 348 if (c == '%') 349 { 350 if (gEvalState.getStackDepth()) 351 { 352 Dictionary::Entry* ent = gEvalState.getCurrentFrame().lookup(StringTable->insert(name)); 353 354 if (ent) 355 return Sim::findObject(ent->getIntValue()); 356 } 357 } 358 if(c == '/') 359 return gRootGroup->findObject(name + 1 ); 360 if(c >= '0' && c <= '9') 361 { 362 // it's an id group 363 const char* temp = name + 1; 364 for(;;) 365 { 366 c = *temp++; 367 if(!c) 368 return findObject(dAtoi(name)); 369 else if(c == '/') 370 { 371 obj = findObject(dAtoi(name)); 372 if(!obj) 373 return NULL; 374 return obj->findObject(temp); 375 } 376 else if (c < '0' || c > '9') 377 return NULL; 378 } 379 } 380 S32 len; 381 382 for(len = 0; name[len] != 0 && name[len] != '/'; len++) 383 ; 384 StringTableEntry stName = StringTable->lookupn(name, len); 385 if(!stName) 386 return NULL; 387 obj = gNameDictionary->find(stName); 388 if(!name[len]) 389 return obj; 390 if(!obj) 391 return NULL; 392 return obj->findObject(name + len + 1); 393} 394 395SimObject* findObject(SimObjectId id) 396{ 397 return gIdDictionary->find(id); 398} 399 400SimObject *spawnObject(String spawnClass, String spawnDataBlock, String spawnName, 401 String spawnProperties, String spawnScript) 402{ 403 if (spawnClass.isEmpty()) 404 { 405 Con::errorf("Unable to spawn an object without a spawnClass"); 406 return NULL; 407 } 408 409 String spawnString; 410 411 spawnString += "$SpawnObject = new " + spawnClass + "(" + spawnName + ") { "; 412 413 if (spawnDataBlock.isNotEmpty() && !spawnDataBlock.equal( "None", String::NoCase ) ) 414 spawnString += "datablock = " + spawnDataBlock + "; "; 415 416 if (spawnProperties.isNotEmpty()) 417 spawnString += spawnProperties + " "; 418 419 spawnString += "};"; 420 421 // Evaluate our spawn string 422 Con::evaluate(spawnString.c_str()); 423 424 // Get our spawnObject id 425 const char* spawnObjectId = Con::getVariable("$SpawnObject"); 426 427 // Get the actual spawnObject 428 SimObject* spawnObject = findObject(spawnObjectId); 429 430 // If we have a spawn script go ahead and execute it last 431 if (spawnScript.isNotEmpty()) 432 Con::evaluate(spawnScript.c_str(), true); 433 434 return spawnObject; 435} 436 437SimGroup *getRootGroup() 438{ 439 return gRootGroup; 440} 441 442String getUniqueName( const char *inName ) 443{ 444 String outName( inName ); 445 446 if ( outName.isEmpty() ) 447 return String::EmptyString; 448 449 SimObject *dummy; 450 451 if ( !Sim::findObject( outName, dummy ) ) 452 return outName; 453 454 S32 suffixNumb = -1; 455 String nameStr( String::GetTrailingNumber( outName, suffixNumb ) ); 456 suffixNumb = mAbs( suffixNumb ) + 1; 457 458 #define MAX_TRIES 100 459 460 for ( U32 i = 0; i < MAX_TRIES; i++ ) 461 { 462 outName = String::ToString( "%s%d", nameStr.c_str(), suffixNumb ); 463 464 if ( !Sim::findObject( outName, dummy ) ) 465 return outName; 466 467 suffixNumb++; 468 } 469 470 Con::errorf( "Sim::getUniqueName( %s ) - failed after %d attempts", inName, MAX_TRIES ); 471 return String::EmptyString; 472} 473 474String getUniqueInternalName( const char *inName, SimSet *inSet, bool searchChildren ) 475{ 476 // Since SimSet::findObjectByInternalName operates with StringTableEntry(s) 477 // we have to muck up the StringTable with our attempts. 478 // But then again, so does everywhere else. 479 480 StringTableEntry outName = StringTable->insert( inName ); 481 482 if ( !outName || !outName[0] ) 483 return String::EmptyString; 484 485 if ( !inSet->findObjectByInternalName( outName, searchChildren ) ) 486 return String(outName); 487 488 S32 suffixNumb = -1; 489 String nameStr( String::GetTrailingNumber( outName, suffixNumb ) ); 490 suffixNumb++; 491 492 static char tempStr[512]; 493 494#define MAX_TRIES 100 495 496 for ( U32 i = 0; i < MAX_TRIES; i++ ) 497 { 498 dSprintf( tempStr, 512, "%s%d", nameStr.c_str(), suffixNumb ); 499 outName = StringTable->insert( tempStr ); 500 501 if ( !inSet->findObjectByInternalName( outName, searchChildren ) ) 502 return String(outName); 503 504 suffixNumb++; 505 } 506 507 Con::errorf( "Sim::getUniqueInternalName( %s ) - failed after %d attempts", inName, MAX_TRIES ); 508 return String::EmptyString; 509} 510 511bool isValidObjectName( const char* name ) 512{ 513 if( !name || !name[ 0 ] ) 514 return true; // Anonymous object. 515 516 if( !dIsalpha( name[ 0 ] ) && name[ 0 ] != '_' ) 517 return false; 518 519 for( U32 i = 1; name[ i ]; ++ i ) 520 if( !dIsalnum( name[ i ] ) && name[ i ] != '_' ) 521 return false; 522 523 return true; 524} 525 526//--------------------------------------------------------------------------- 527//--------------------------------------------------------------------------- 528 529#define InstantiateNamedSet(set) g##set = new SimSet; g##set->registerObject(#set); g##set->setNameChangeAllowed(false); gRootGroup->addObject(g##set); SIMSET_SET_ASSOCIATION((*g##set)) 530#define InstantiateNamedGroup(set) g##set = new SimGroup; g##set->registerObject(#set); g##set->setNameChangeAllowed(false); gRootGroup->addObject(g##set); SIMSET_SET_ASSOCIATION((*g##set)) 531 532static bool sgIsShuttingDown; 533 534SimDataBlockGroup *gDataBlockGroup; 535SimDataBlockGroup *getDataBlockGroup() 536{ 537 return gDataBlockGroup; 538} 539 540 541void init() 542{ 543 initEventQueue(); 544 initRoot(); 545 546 InstantiateNamedSet(ActiveActionMapSet); 547 InstantiateNamedSet(GhostAlwaysSet); 548 InstantiateNamedSet(WayPointSet); 549 InstantiateNamedSet(fxReplicatorSet); 550 InstantiateNamedSet(fxFoliageSet); 551 InstantiateNamedSet(MaterialSet); 552 InstantiateNamedSet(SFXSourceSet); 553 InstantiateNamedSet(SFXDescriptionSet); 554 InstantiateNamedSet(SFXTrackSet); 555 InstantiateNamedSet(SFXEnvironmentSet); 556 InstantiateNamedSet(SFXStateSet); 557 InstantiateNamedSet(SFXAmbienceSet); 558 InstantiateNamedSet(TerrainMaterialSet); 559 InstantiateNamedSet(DataBlockSet); 560 InstantiateNamedGroup(ActionMapGroup); 561 InstantiateNamedGroup(ClientGroup); 562 InstantiateNamedGroup(GuiGroup); 563 InstantiateNamedGroup(GuiDataGroup); 564 InstantiateNamedGroup(TCPGroup); 565 InstantiateNamedGroup(ClientConnectionGroup); 566 InstantiateNamedGroup(SFXParameterGroup); 567 InstantiateNamedSet(BehaviorSet); 568 InstantiateNamedSet(sgMissionLightingFilterSet); 569 570 gDataBlockGroup = new SimDataBlockGroup(); 571 gDataBlockGroup->registerObject("DataBlockGroup"); 572 gRootGroup->addObject(gDataBlockGroup); 573 574 SimPersistID::init(); 575} 576 577void shutdown() 578{ 579 sgIsShuttingDown = true; 580 581 shutdownRoot(); 582 shutdownEventQueue(); 583 584 SimPersistID::shutdown(); 585} 586 587bool isShuttingDown() 588{ 589 return sgIsShuttingDown; 590} 591 592} 593 594 595#endif // DOXYGENIZING. 596 597SimDataBlockGroup::SimDataBlockGroup() 598{ 599 mLastModifiedKey = 0; 600} 601 602S32 QSORT_CALLBACK SimDataBlockGroup::compareModifiedKey(const void* a,const void* b) 603{ 604 const SimDataBlock* dba = *((const SimDataBlock**)a); 605 const SimDataBlock* dbb = *((const SimDataBlock**)b); 606 607 return dba->getModifiedKey() - dbb->getModifiedKey(); 608} 609 610 611void SimDataBlockGroup::sort() 612{ 613 if(mLastModifiedKey != SimDataBlock::getNextModifiedKey()) 614 { 615 mLastModifiedKey = SimDataBlock::getNextModifiedKey(); 616 dQsort(mObjectList.address(), mObjectList.size(),sizeof(SimObject *),compareModifiedKey); 617 } 618} 619