simManager.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "platform/threads/mutex.h"
  24. #include "sim/simBase.h"
  25. #include "string/stringTable.h"
  26. #include "console/console.h"
  27. #include "io/fileStream.h"
  28. #include "io/resource/resourceManager.h"
  29. #include "io/fileObject.h"
  30. #include "console/consoleInternal.h"
  31. #include "memory/safeDelete.h"
  32. //---------------------------------------------------------------------------
  33. namespace Sim
  34. {
  35. //---------------------------------------------------------------------------
  36. //---------------------------------------------------------------------------
  37. // event queue variables:
  38. SimTime gCurrentTime;
  39. SimTime gTargetTime;
  40. void *gEventQueueMutex;
  41. SimEvent *gEventQueue;
  42. U32 gEventSequence;
  43. //---------------------------------------------------------------------------
  44. // event queue init/shutdown
  45. void initEventQueue()
  46. {
  47. gCurrentTime = 0;
  48. gTargetTime = 0;
  49. gEventSequence = 1;
  50. gEventQueue = NULL;
  51. gEventQueueMutex = Mutex::createMutex();
  52. }
  53. void shutdownEventQueue()
  54. {
  55. // Delete all pending events
  56. Mutex::lockMutex(gEventQueueMutex);
  57. SimEvent *walk = gEventQueue;
  58. while(walk)
  59. {
  60. SimEvent *temp = walk->nextEvent;
  61. delete walk;
  62. walk = temp;
  63. }
  64. Mutex::unlockMutex(gEventQueueMutex);
  65. Mutex::destroyMutex(gEventQueueMutex);
  66. }
  67. //---------------------------------------------------------------------------
  68. // event post
  69. U32 postEvent(SimObject *destObject, SimEvent* event,U32 time)
  70. {
  71. AssertFatal(time == -1 || time >= getCurrentTime(),
  72. "Sim::postEvent: Cannot go back in time. (flux capacitor unavailable -- BJG)");
  73. AssertFatal(destObject, "Destination object for event doesn't exist.");
  74. Mutex::lockMutex(gEventQueueMutex);
  75. if( time == -1 )
  76. time = gCurrentTime;
  77. event->time = time;
  78. event->startTime = gCurrentTime;
  79. event->destObject = destObject;
  80. if(!destObject)
  81. {
  82. delete event;
  83. Mutex::unlockMutex(gEventQueueMutex);
  84. return InvalidEventId;
  85. }
  86. event->sequenceCount = gEventSequence++;
  87. SimEvent **walk = &gEventQueue;
  88. SimEvent *current;
  89. while((current = *walk) != NULL && (current->time < event->time))
  90. walk = &(current->nextEvent);
  91. // [tom, 6/24/2005] This ensures that SimEvents are dispatched in the same order that they are posted.
  92. // This is needed to ensure Con::threadSafeExecute() executes script code in the correct order.
  93. while((current = *walk) != NULL && (current->time == event->time))
  94. walk = &(current->nextEvent);
  95. event->nextEvent = current;
  96. *walk = event;
  97. U32 seqCount = event->sequenceCount;
  98. Mutex::unlockMutex(gEventQueueMutex);
  99. return seqCount;
  100. }
  101. //---------------------------------------------------------------------------
  102. // event cancellation
  103. /*! cancel a previously scheduled event.
  104. @param eventSequence The numeric ID of a previously scheduled event.
  105. @return No return value.
  106. @sa getEventTimeLeft, getScheduleDuration, getTimeSinceStart, isEventPending, schedule, obj.schedule
  107. */
  108. void cancelEvent(U32 eventSequence)
  109. {
  110. Mutex::lockMutex(gEventQueueMutex);
  111. SimEvent **walk = &gEventQueue;
  112. SimEvent *current;
  113. while((current = *walk) != NULL)
  114. {
  115. if(current->sequenceCount == eventSequence)
  116. {
  117. *walk = current->nextEvent;
  118. delete current;
  119. Mutex::unlockMutex(gEventQueueMutex);
  120. return;
  121. }
  122. else
  123. walk = &(current->nextEvent);
  124. }
  125. Mutex::unlockMutex(gEventQueueMutex);
  126. }
  127. void cancelPendingEvents(SimObject *obj)
  128. {
  129. Mutex::lockMutex(gEventQueueMutex);
  130. SimEvent **walk = &gEventQueue;
  131. SimEvent *current;
  132. while((current = *walk) != NULL)
  133. {
  134. if(current->destObject == obj)
  135. {
  136. *walk = current->nextEvent;
  137. delete current;
  138. }
  139. else
  140. walk = &(current->nextEvent);
  141. }
  142. Mutex::unlockMutex(gEventQueueMutex);
  143. }
  144. //---------------------------------------------------------------------------
  145. // event pending test
  146. /*! see if the event associated with eventID is still pending.
  147. When an event passes, the eventID is removed from the event queue, becoming invalid, so there is no discernable difference between a completed event and a bad event ID.
  148. @param eventID The numeric ID of a previously scheduled event.
  149. @return true if this event is still outstanding and false if it has passed or eventID is invalid.
  150. @sa cancel, getEventTimeLeft, getScheduleDuration, getTimeSinceStart, schedule, obj.schedule
  151. */
  152. bool isEventPending(U32 eventSequence)
  153. {
  154. Mutex::lockMutex(gEventQueueMutex);
  155. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  156. if(walk->sequenceCount == eventSequence)
  157. {
  158. Mutex::unlockMutex(gEventQueueMutex);
  159. return true;
  160. }
  161. Mutex::unlockMutex(gEventQueueMutex);
  162. return false;
  163. }
  164. /*!
  165. determines how much time remains until the event specified by eventID occurs.
  166. @param eventID The numeric ID of a previously scheduled event.
  167. @return a non-zero integer value equal to the milliseconds until the event specified by eventID will occur. However, if eventID is invalid, or the event has passed, this function will return zero.
  168. @sa cancel, getScheduleDuration, getTimeSinceStart, isEventPending, schedule, SimObject::schedule
  169. */
  170. U32 getEventTimeLeft(U32 eventSequence)
  171. {
  172. Mutex::lockMutex(gEventQueueMutex);
  173. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  174. if(walk->sequenceCount == eventSequence)
  175. {
  176. SimTime t = walk->time - getCurrentTime();
  177. Mutex::unlockMutex(gEventQueueMutex);
  178. return t;
  179. }
  180. Mutex::unlockMutex(gEventQueueMutex);
  181. return 0;
  182. }
  183. /*!
  184. Determines how long the event associated with eventID was scheduled for.
  185. @param eventID The numeric ID of a previously scheduled event.
  186. @return a non-zero integer value equal to the milliseconds used in the schedule call that created this event. However, if eventID is invalid, this function will return zero.
  187. @sa cancel, getEventTimeLeft, getTimeSinceStart, isEventPending, schedule, SimObject::schedule
  188. */
  189. U32 getScheduleDuration(U32 eventSequence)
  190. {
  191. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  192. if(walk->sequenceCount == eventSequence)
  193. return (walk->time-walk->startTime);
  194. return 0;
  195. }
  196. /*!
  197. Determines how much time has passed since the event specified by eventID was scheduled.
  198. @param eventID The numeric ID of a previously scheduled event.
  199. @return a non-zero integer value equal to the milliseconds that have passed since this event was scheduled. However, if eventID is invalid, or the event has passed, this function will return zero.
  200. @sa cancel, getEventTimeLeft, getScheduleDuration, isEventPending, schedule, SimObject::schedule
  201. */
  202. U32 getTimeSinceStart(U32 eventSequence)
  203. {
  204. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  205. if(walk->sequenceCount == eventSequence)
  206. return (getCurrentTime()-walk->startTime);
  207. return 0;
  208. }
  209. //---------------------------------------------------------------------------
  210. // event timing
  211. void advanceToTime(SimTime targetTime)
  212. {
  213. AssertFatal(targetTime >= getCurrentTime(), "EventQueue::process: cannot advance to time in the past.");
  214. Mutex::lockMutex(gEventQueueMutex);
  215. gTargetTime = targetTime;
  216. while(gEventQueue && gEventQueue->time <= targetTime)
  217. {
  218. SimEvent *event = gEventQueue;
  219. gEventQueue = gEventQueue->nextEvent;
  220. AssertFatal(event->time >= gCurrentTime,
  221. "SimEventQueue::pop: Cannot go back in time (flux capacitor not installed - BJG).");
  222. gCurrentTime = event->time;
  223. SimObject *obj = event->destObject;
  224. if(!obj->isDeleted())
  225. event->process(obj);
  226. delete event;
  227. }
  228. gCurrentTime = targetTime;
  229. Mutex::unlockMutex(gEventQueueMutex);
  230. }
  231. void advanceTime(SimTime delta)
  232. {
  233. advanceToTime(getCurrentTime() + delta);
  234. }
  235. /*! get the time, in ticks, that has elapsed since the engine started executing.
  236. @return the time in ticks since the engine was started.
  237. @sa getRealTime
  238. */
  239. U32 getCurrentTime()
  240. {
  241. if(gEventQueueMutex)
  242. Mutex::lockMutex(gEventQueueMutex);
  243. SimTime t = gCurrentTime;
  244. if(gEventQueueMutex)
  245. Mutex::unlockMutex(gEventQueueMutex);
  246. return t;
  247. }
  248. U32 getTargetTime()
  249. {
  250. return gTargetTime;
  251. }
  252. //---------------------------------------------------------------------------
  253. //---------------------------------------------------------------------------
  254. SimGroup *gRootGroup = NULL;
  255. SimManagerNameDictionary *gNameDictionary;
  256. SimIdDictionary *gIdDictionary;
  257. U32 gNextObjectId;
  258. void initRoot()
  259. {
  260. gIdDictionary = new SimIdDictionary;
  261. gNameDictionary = new SimManagerNameDictionary;
  262. gRootGroup = new SimGroup();
  263. gRootGroup->setId(RootGroupId);
  264. gRootGroup->assignName("RootGroup");
  265. gRootGroup->registerObject();
  266. gNextObjectId = DynamicObjectIdFirst;
  267. }
  268. void shutdownRoot()
  269. {
  270. gRootGroup->deleteObject();
  271. SAFE_DELETE(gNameDictionary);
  272. SAFE_DELETE(gIdDictionary);
  273. }
  274. //---------------------------------------------------------------------------
  275. SimObject* findObject(const char* name)
  276. {
  277. // Play nice with bad code - JDD
  278. if( !name )
  279. return NULL;
  280. SimObject *obj;
  281. char c = *name;
  282. if(c == '/')
  283. return gRootGroup->findObject(name + 1 );
  284. if(c >= '0' && c <= '9')
  285. {
  286. // it's an id group
  287. const char* temp = name + 1;
  288. for(;;)
  289. {
  290. c = *temp++;
  291. if(!c)
  292. return findObject(dAtoi(name));
  293. else if(c == '/')
  294. {
  295. obj = findObject(dAtoi(name));
  296. if(!obj)
  297. return NULL;
  298. return obj->findObject(temp);
  299. }
  300. }
  301. }
  302. S32 len;
  303. //-Mat ensure > 0, instead of just != 0 (prevent running through bogus memory on non-NULL-terminated strings)
  304. for(len = 0; name[len] > 0 && name[len] != '/'; len++)
  305. ;
  306. StringTableEntry stName = StringTable->lookupn(name, len);
  307. if(!stName)
  308. return NULL;
  309. obj = gNameDictionary->find(stName);
  310. if(!name[len])
  311. return obj;
  312. if(!obj)
  313. return NULL;
  314. return obj->findObject(name + len + 1);
  315. }
  316. SimObject* findObject(SimObjectId id)
  317. {
  318. return gIdDictionary->find(id);
  319. }
  320. SimGroup *getRootGroup()
  321. {
  322. return gRootGroup;
  323. }
  324. //---------------------------------------------------------------------------
  325. //---------------------------------------------------------------------------
  326. #define InstantiateNamedSet(set) g##set = new SimSet; g##set->registerObject(#set); gRootGroup->addObject(g##set); SIMSET_SET_ASSOCIATION((*g##set))
  327. #define InstantiateNamedGroup(set) g##set = new SimGroup; g##set->registerObject(#set); gRootGroup->addObject(g##set); SIMSET_SET_ASSOCIATION((*g##set))
  328. SimDataBlockGroup *gDataBlockGroup;
  329. SimDataBlockGroup *getDataBlockGroup()
  330. {
  331. return gDataBlockGroup;
  332. }
  333. void init()
  334. {
  335. initEventQueue();
  336. initRoot();
  337. InstantiateNamedSet(ActiveActionMapSet);
  338. InstantiateNamedSet(GhostAlwaysSet);
  339. InstantiateNamedGroup(ActionMapGroup);
  340. InstantiateNamedGroup(ClientGroup);
  341. InstantiateNamedGroup(GuiGroup);
  342. InstantiateNamedGroup(GuiDataGroup);
  343. InstantiateNamedGroup(TCPGroup);
  344. InstantiateNamedGroup(ClientConnectionGroup);
  345. InstantiateNamedGroup(ChunkFileGroup);
  346. InstantiateNamedSet(BehaviorSet);
  347. InstantiateNamedSet(AchievementSet);
  348. gDataBlockGroup = new SimDataBlockGroup();
  349. gDataBlockGroup->registerObject("DataBlockGroup");
  350. gRootGroup->addObject(gDataBlockGroup);
  351. }
  352. void shutdown()
  353. {
  354. shutdownRoot();
  355. shutdownEventQueue();
  356. }
  357. } // Sim Namespace.
  358. SimDataBlockGroup::SimDataBlockGroup()
  359. {
  360. mLastModifiedKey = 0;
  361. }
  362. S32 QSORT_CALLBACK SimDataBlockGroup::compareModifiedKey(const void* a,const void* b)
  363. {
  364. return (reinterpret_cast<const SimDataBlock* >(a))->getModifiedKey() -
  365. (reinterpret_cast<const SimDataBlock*>(b))->getModifiedKey();
  366. }
  367. void SimDataBlockGroup::sort()
  368. {
  369. if(mLastModifiedKey != SimDataBlock::getNextModifiedKey())
  370. {
  371. mLastModifiedKey = SimDataBlock::getNextModifiedKey();
  372. dQsort(objectList.address(),objectList.size(),sizeof(SimObject *),compareModifiedKey);
  373. }
  374. }