simManager.cpp

Engine/source/console/simManager.cpp

More...

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