2
0

simManager.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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. // We comment out the implementation of the Con namespace when doxygenizing because
  34. // otherwise Doxygen decides to ignore our docs in console.h
  35. #ifndef DOXYGENIZING
  36. namespace Sim
  37. {
  38. //---------------------------------------------------------------------------
  39. //---------------------------------------------------------------------------
  40. // event queue variables:
  41. SimTime gCurrentTime;
  42. SimTime gTargetTime;
  43. void *gEventQueueMutex;
  44. SimEvent *gEventQueue;
  45. U32 gEventSequence;
  46. //---------------------------------------------------------------------------
  47. // event queue init/shutdown
  48. void initEventQueue()
  49. {
  50. gCurrentTime = 0;
  51. gTargetTime = 0;
  52. gEventSequence = 1;
  53. gEventQueue = NULL;
  54. gEventQueueMutex = Mutex::createMutex();
  55. }
  56. void shutdownEventQueue()
  57. {
  58. // Delete all pending events
  59. Mutex::lockMutex(gEventQueueMutex);
  60. SimEvent *walk = gEventQueue;
  61. while(walk)
  62. {
  63. SimEvent *temp = walk->nextEvent;
  64. delete walk;
  65. walk = temp;
  66. }
  67. Mutex::unlockMutex(gEventQueueMutex);
  68. Mutex::destroyMutex(gEventQueueMutex);
  69. }
  70. //---------------------------------------------------------------------------
  71. // event post
  72. U32 postEvent(SimObject *destObject, SimEvent* event,U32 time)
  73. {
  74. AssertFatal(time == -1 || time >= getCurrentTime(),
  75. "Sim::postEvent: Cannot go back in time. (flux capacitor unavailable -- BJG)");
  76. AssertFatal(destObject, "Destination object for event doesn't exist.");
  77. Mutex::lockMutex(gEventQueueMutex);
  78. if( time == -1 )
  79. time = gCurrentTime;
  80. event->time = time;
  81. event->startTime = gCurrentTime;
  82. event->destObject = destObject;
  83. if(!destObject)
  84. {
  85. delete event;
  86. Mutex::unlockMutex(gEventQueueMutex);
  87. return InvalidEventId;
  88. }
  89. event->sequenceCount = gEventSequence++;
  90. SimEvent **walk = &gEventQueue;
  91. SimEvent *current;
  92. while((current = *walk) != NULL && (current->time < event->time))
  93. walk = &(current->nextEvent);
  94. // [tom, 6/24/2005] This ensures that SimEvents are dispatched in the same order that they are posted.
  95. // This is needed to ensure Con::threadSafeExecute() executes script code in the correct order.
  96. while((current = *walk) != NULL && (current->time == event->time))
  97. walk = &(current->nextEvent);
  98. event->nextEvent = current;
  99. *walk = event;
  100. U32 seqCount = event->sequenceCount;
  101. Mutex::unlockMutex(gEventQueueMutex);
  102. return seqCount;
  103. }
  104. //---------------------------------------------------------------------------
  105. // event cancellation
  106. void cancelEvent(U32 eventSequence)
  107. {
  108. Mutex::lockMutex(gEventQueueMutex);
  109. SimEvent **walk = &gEventQueue;
  110. SimEvent *current;
  111. while((current = *walk) != NULL)
  112. {
  113. if(current->sequenceCount == eventSequence)
  114. {
  115. *walk = current->nextEvent;
  116. delete current;
  117. Mutex::unlockMutex(gEventQueueMutex);
  118. return;
  119. }
  120. else
  121. walk = &(current->nextEvent);
  122. }
  123. Mutex::unlockMutex(gEventQueueMutex);
  124. }
  125. void cancelPendingEvents(SimObject *obj)
  126. {
  127. Mutex::lockMutex(gEventQueueMutex);
  128. SimEvent **walk = &gEventQueue;
  129. SimEvent *current;
  130. while((current = *walk) != NULL)
  131. {
  132. if(current->destObject == obj)
  133. {
  134. *walk = current->nextEvent;
  135. delete current;
  136. }
  137. else
  138. walk = &(current->nextEvent);
  139. }
  140. Mutex::unlockMutex(gEventQueueMutex);
  141. }
  142. //---------------------------------------------------------------------------
  143. // event pending test
  144. bool isEventPending(U32 eventSequence)
  145. {
  146. Mutex::lockMutex(gEventQueueMutex);
  147. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  148. if(walk->sequenceCount == eventSequence)
  149. {
  150. Mutex::unlockMutex(gEventQueueMutex);
  151. return true;
  152. }
  153. Mutex::unlockMutex(gEventQueueMutex);
  154. return false;
  155. }
  156. U32 getEventTimeLeft(U32 eventSequence)
  157. {
  158. Mutex::lockMutex(gEventQueueMutex);
  159. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  160. if(walk->sequenceCount == eventSequence)
  161. {
  162. SimTime t = walk->time - getCurrentTime();
  163. Mutex::unlockMutex(gEventQueueMutex);
  164. return t;
  165. }
  166. Mutex::unlockMutex(gEventQueueMutex);
  167. return 0;
  168. }
  169. U32 getScheduleDuration(U32 eventSequence)
  170. {
  171. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  172. if(walk->sequenceCount == eventSequence)
  173. return (walk->time-walk->startTime);
  174. return 0;
  175. }
  176. U32 getTimeSinceStart(U32 eventSequence)
  177. {
  178. for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
  179. if(walk->sequenceCount == eventSequence)
  180. return (getCurrentTime()-walk->startTime);
  181. return 0;
  182. }
  183. //---------------------------------------------------------------------------
  184. // event timing
  185. void advanceToTime(SimTime targetTime)
  186. {
  187. AssertFatal(targetTime >= getCurrentTime(), "EventQueue::process: cannot advance to time in the past.");
  188. Mutex::lockMutex(gEventQueueMutex);
  189. gTargetTime = targetTime;
  190. while(gEventQueue && gEventQueue->time <= targetTime)
  191. {
  192. SimEvent *event = gEventQueue;
  193. gEventQueue = gEventQueue->nextEvent;
  194. AssertFatal(event->time >= gCurrentTime,
  195. "SimEventQueue::pop: Cannot go back in time (flux capacitor not installed - BJG).");
  196. gCurrentTime = event->time;
  197. SimObject *obj = event->destObject;
  198. if(!obj->isDeleted())
  199. event->process(obj);
  200. delete event;
  201. }
  202. gCurrentTime = targetTime;
  203. Mutex::unlockMutex(gEventQueueMutex);
  204. }
  205. void advanceTime(SimTime delta)
  206. {
  207. advanceToTime(getCurrentTime() + delta);
  208. }
  209. U32 getCurrentTime()
  210. {
  211. if(gEventQueueMutex)
  212. Mutex::lockMutex(gEventQueueMutex);
  213. SimTime t = gCurrentTime;
  214. if(gEventQueueMutex)
  215. Mutex::unlockMutex(gEventQueueMutex);
  216. return t;
  217. }
  218. U32 getTargetTime()
  219. {
  220. return gTargetTime;
  221. }
  222. //---------------------------------------------------------------------------
  223. //---------------------------------------------------------------------------
  224. SimGroup *gRootGroup = NULL;
  225. SimManagerNameDictionary *gNameDictionary;
  226. SimIdDictionary *gIdDictionary;
  227. U32 gNextObjectId;
  228. void initRoot()
  229. {
  230. gIdDictionary = new SimIdDictionary;
  231. gNameDictionary = new SimManagerNameDictionary;
  232. gRootGroup = new SimGroup();
  233. gRootGroup->setId(RootGroupId);
  234. gRootGroup->assignName("RootGroup");
  235. gRootGroup->registerObject();
  236. gNextObjectId = DynamicObjectIdFirst;
  237. }
  238. void shutdownRoot()
  239. {
  240. gRootGroup->deleteObject();
  241. SAFE_DELETE(gNameDictionary);
  242. SAFE_DELETE(gIdDictionary);
  243. }
  244. //---------------------------------------------------------------------------
  245. SimObject* findObject(const char* name)
  246. {
  247. // Play nice with bad code - JDD
  248. if( !name )
  249. return NULL;
  250. SimObject *obj;
  251. char c = *name;
  252. if(c == '/')
  253. return gRootGroup->findObject(name + 1 );
  254. if(c >= '0' && c <= '9')
  255. {
  256. // it's an id group
  257. const char* temp = name + 1;
  258. for(;;)
  259. {
  260. c = *temp++;
  261. if(!c)
  262. return findObject(dAtoi(name));
  263. else if(c == '/')
  264. {
  265. obj = findObject(dAtoi(name));
  266. if(!obj)
  267. return NULL;
  268. return obj->findObject(temp);
  269. }
  270. }
  271. }
  272. S32 len;
  273. //-Mat ensure > 0, instead of just != 0 (prevent running through bogus memory on non-NULL-terminated strings)
  274. for(len = 0; name[len] > 0 && name[len] != '/'; len++)
  275. ;
  276. StringTableEntry stName = StringTable->lookupn(name, len);
  277. if(!stName)
  278. return NULL;
  279. obj = gNameDictionary->find(stName);
  280. if(!name[len])
  281. return obj;
  282. if(!obj)
  283. return NULL;
  284. return obj->findObject(name + len + 1);
  285. }
  286. SimObject* findObject(SimObjectId id)
  287. {
  288. return gIdDictionary->find(id);
  289. }
  290. SimGroup *getRootGroup()
  291. {
  292. return gRootGroup;
  293. }
  294. //---------------------------------------------------------------------------
  295. //---------------------------------------------------------------------------
  296. #define InstantiateNamedSet(set) g##set = new SimSet; g##set->registerObject(#set); gRootGroup->addObject(g##set); SIMSET_SET_ASSOCIATION((*g##set))
  297. #define InstantiateNamedGroup(set) g##set = new SimGroup; g##set->registerObject(#set); gRootGroup->addObject(g##set); SIMSET_SET_ASSOCIATION((*g##set))
  298. SimDataBlockGroup *gDataBlockGroup;
  299. SimDataBlockGroup *getDataBlockGroup()
  300. {
  301. return gDataBlockGroup;
  302. }
  303. void init()
  304. {
  305. initEventQueue();
  306. initRoot();
  307. InstantiateNamedSet(ActiveActionMapSet);
  308. InstantiateNamedSet(GhostAlwaysSet);
  309. InstantiateNamedGroup(ActionMapGroup);
  310. InstantiateNamedGroup(ClientGroup);
  311. InstantiateNamedGroup(GuiGroup);
  312. InstantiateNamedGroup(GuiDataGroup);
  313. InstantiateNamedGroup(TCPGroup);
  314. InstantiateNamedGroup(ClientConnectionGroup);
  315. InstantiateNamedGroup(ChunkFileGroup);
  316. InstantiateNamedSet(BehaviorSet);
  317. InstantiateNamedSet(AchievementSet);
  318. gDataBlockGroup = new SimDataBlockGroup();
  319. gDataBlockGroup->registerObject("DataBlockGroup");
  320. gRootGroup->addObject(gDataBlockGroup);
  321. }
  322. void shutdown()
  323. {
  324. shutdownRoot();
  325. shutdownEventQueue();
  326. }
  327. } // Sim Namespace.
  328. #endif // DOXYGENIZING.
  329. SimDataBlockGroup::SimDataBlockGroup()
  330. {
  331. mLastModifiedKey = 0;
  332. }
  333. S32 QSORT_CALLBACK SimDataBlockGroup::compareModifiedKey(const void* a,const void* b)
  334. {
  335. return (reinterpret_cast<const SimDataBlock* >(a))->getModifiedKey() -
  336. (reinterpret_cast<const SimDataBlock*>(b))->getModifiedKey();
  337. }
  338. void SimDataBlockGroup::sort()
  339. {
  340. if(mLastModifiedKey != SimDataBlock::getNextModifiedKey())
  341. {
  342. mLastModifiedKey = SimDataBlock::getNextModifiedKey();
  343. dQsort(objectList.address(),objectList.size(),sizeof(SimObject *),compareModifiedKey);
  344. }
  345. }