simSet.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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 "sim/simBase.h"
  24. #include "string/stringTable.h"
  25. #include "console/console.h"
  26. #include "io/fileStream.h"
  27. #include "input/actionMap.h"
  28. #include "io/resource/resourceManager.h"
  29. #include "io/fileObject.h"
  30. #include "console/consoleInternal.h"
  31. #include "debug/profiler.h"
  32. #include "console/ConsoleTypeValidators.h"
  33. #include "memory/frameAllocator.h"
  34. #include "simSet_ScriptBinding.h"
  35. //////////////////////////////////////////////////////////////////////////
  36. // Sim Set
  37. //////////////////////////////////////////////////////////////////////////
  38. void SimSet::addObject(SimObject* obj)
  39. {
  40. lock();
  41. objectList.pushBack(obj);
  42. deleteNotify(obj);
  43. unlock();
  44. }
  45. void SimSet::removeObject(SimObject* obj)
  46. {
  47. lock();
  48. objectList.remove(obj);
  49. clearNotify(obj);
  50. unlock();
  51. }
  52. void SimSet::pushObject(SimObject* pObj)
  53. {
  54. lock();
  55. objectList.pushBackForce(pObj);
  56. deleteNotify(pObj);
  57. unlock();
  58. }
  59. void SimSet::popObject()
  60. {
  61. MutexHandle handle;
  62. handle.lock(mMutex);
  63. if (objectList.size() == 0)
  64. {
  65. AssertWarn(false, "Stack underflow in SimSet::popObject");
  66. return;
  67. }
  68. SimObject* pObject = objectList[objectList.size() - 1];
  69. objectList.removeStable(pObject);
  70. clearNotify(pObject);
  71. }
  72. //-----------------------------------------------------------------------------
  73. void SimSet::callOnChildren( const char * method, S32 argc, const char *argv[], bool executeOnChildGroups )
  74. {
  75. // Prep the arguments for the console exec...
  76. // Make sure and leave args[1] empty.
  77. const char* args[21];
  78. args[0] = method;
  79. for (S32 i = 0; i < argc; i++)
  80. args[i + 2] = argv[i];
  81. for( iterator i = begin(); i != end(); i++ )
  82. {
  83. SimObject *childObj = static_cast<SimObject*>(*i);
  84. if( childObj->isMethod( method ) )
  85. Con::execute(childObj, argc + 2, args);
  86. if( executeOnChildGroups )
  87. {
  88. SimSet* childSet = dynamic_cast<SimSet*>(*i);
  89. if ( childSet )
  90. childSet->callOnChildren( method, argc, argv, executeOnChildGroups );
  91. }
  92. }
  93. }
  94. bool SimSet::reOrder( SimObject *obj, SimObject *target )
  95. {
  96. MutexHandle handle;
  97. handle.lock(mMutex);
  98. iterator itrS, itrD;
  99. if ( (itrS = find(begin(),end(),obj)) == end() )
  100. {
  101. return false; // object must be in list
  102. }
  103. if ( obj == target )
  104. {
  105. return true; // don't reorder same object but don't indicate error
  106. }
  107. if ( !target ) // if no target, then put to back of list
  108. {
  109. if ( itrS != (end()-1) ) // don't move if already last object
  110. {
  111. objectList.erase(itrS); // remove object from its current location
  112. objectList.push_back(obj); // push it to the back of the list
  113. }
  114. }
  115. else // if target, insert object in front of target
  116. {
  117. if ( (itrD = find(begin(),end(),target)) == end() )
  118. return false; // target must be in list
  119. objectList.erase(itrS);
  120. //Tinman - once itrS has been erased, itrD won't be pointing at the same place anymore - re-find...
  121. itrD = find(begin(),end(),target);
  122. objectList.insert(itrD,obj);
  123. }
  124. return true;
  125. }
  126. void SimSet::onDeleteNotify(SimObject *object)
  127. {
  128. removeObject(object);
  129. Parent::onDeleteNotify(object);
  130. }
  131. void SimSet::onRemove()
  132. {
  133. MutexHandle handle;
  134. handle.lock(mMutex);
  135. objectList.sortId();
  136. if (objectList.size())
  137. {
  138. // This backwards iterator loop doesn't work if the
  139. // list is empty, check the size first.
  140. for (SimObjectList::iterator ptr = objectList.end() - 1;
  141. ptr >= objectList.begin(); ptr--)
  142. {
  143. clearNotify(*ptr);
  144. }
  145. }
  146. handle.unlock();
  147. Parent::onRemove();
  148. }
  149. void SimSet::write(Stream &stream, U32 tabStop, U32 flags)
  150. {
  151. MutexHandle handle;
  152. handle.lock(mMutex);
  153. // export selected only?
  154. if((flags & SelectedOnly) && !isSelected())
  155. {
  156. for(U32 i = 0; i < (U32)size(); i++)
  157. (*this)[i]->write(stream, tabStop, flags);
  158. return;
  159. }
  160. stream.writeTabs(tabStop);
  161. char buffer[1024];
  162. dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : "");
  163. stream.write(dStrlen(buffer), buffer);
  164. writeFields(stream, tabStop + 1);
  165. if(size())
  166. {
  167. stream.write(2, "\r\n");
  168. for(U32 i = 0; i < (U32)size(); i++)
  169. (*this)[i]->write(stream, tabStop + 1, flags);
  170. }
  171. stream.writeTabs(tabStop);
  172. stream.write(4, "};\r\n");
  173. }
  174. void SimSet::deleteObjects( void )
  175. {
  176. lock();
  177. while(size() > 0 )
  178. {
  179. objectList[0]->deleteObject();
  180. }
  181. unlock();
  182. }
  183. void SimSet::clear()
  184. {
  185. lock();
  186. while (size() > 0)
  187. removeObject(objectList.last());
  188. unlock();
  189. }
  190. SimObject* SimSet::findObjectByInternalName(const char* internalName, bool searchChildren)
  191. {
  192. iterator i;
  193. for (i = begin(); i != end(); i++)
  194. {
  195. SimObject *childObj = static_cast<SimObject*>(*i);
  196. if(childObj->getInternalName() == internalName)
  197. return childObj;
  198. else if (searchChildren)
  199. {
  200. SimSet* childSet = dynamic_cast<SimSet*>(*i);
  201. if (childSet)
  202. {
  203. SimObject* found = childSet->findObjectByInternalName(internalName, searchChildren);
  204. if (found) return found;
  205. }
  206. }
  207. }
  208. return NULL;
  209. }
  210. //////////////////////////////////////////////////////////////////////////
  211. IMPLEMENT_CONOBJECT_CHILDREN(SimSet);
  212. inline void SimSetIterator::Stack::push_back(SimSet* set)
  213. {
  214. increment();
  215. last().set = set;
  216. last().itr = set->begin();
  217. }
  218. //-----------------------------------------------------------------------------
  219. SimSetIterator::SimSetIterator(SimSet* set)
  220. {
  221. VECTOR_SET_ASSOCIATION(stack);
  222. if (!set->empty())
  223. stack.push_back(set);
  224. }
  225. //-----------------------------------------------------------------------------
  226. SimObject* SimSetIterator::operator++()
  227. {
  228. SimSet* set;
  229. if ((set = dynamic_cast<SimSet*>(*stack.last().itr)) != 0)
  230. {
  231. if (!set->empty())
  232. {
  233. stack.push_back(set);
  234. return *stack.last().itr;
  235. }
  236. }
  237. while (++stack.last().itr == stack.last().set->end())
  238. {
  239. stack.pop_back();
  240. if (stack.empty())
  241. return 0;
  242. }
  243. return *stack.last().itr;
  244. }
  245. SimObject* SimGroupIterator::operator++()
  246. {
  247. SimGroup* set;
  248. if ((set = dynamic_cast<SimGroup*>(*stack.last().itr)) != 0)
  249. {
  250. if (!set->empty())
  251. {
  252. stack.push_back(set);
  253. return *stack.last().itr;
  254. }
  255. }
  256. while (++stack.last().itr == stack.last().set->end())
  257. {
  258. stack.pop_back();
  259. if (stack.empty())
  260. return 0;
  261. }
  262. return *stack.last().itr;
  263. }
  264. //////////////////////////////////////////////////////////////////////////
  265. // SimGroup
  266. //////////////////////////////////////////////////////////////////////////
  267. SimGroup::~SimGroup()
  268. {
  269. lock();
  270. for (iterator itr = begin(); itr != end(); itr++)
  271. nameDictionary.remove(*itr);
  272. // XXX Move this later into Group Class
  273. // If we have any objects at this point, they should
  274. // already have been removed from the manager, so we
  275. // can just delete them directly.
  276. objectList.sortId();
  277. while (!objectList.empty())
  278. {
  279. delete objectList.last();
  280. objectList.decrement();
  281. }
  282. unlock();
  283. }
  284. //////////////////////////////////////////////////////////////////////////
  285. void SimGroup::addObject(SimObject* obj)
  286. {
  287. lock();
  288. // Make sure we aren't adding ourself. This isn't the most robust check
  289. // but it should be good enough to prevent some self-foot-shooting.
  290. if(obj == this)
  291. {
  292. Con::errorf("SimGroup::addObject - (%d) can't add self!", getIdString());
  293. unlock();
  294. return;
  295. }
  296. if (obj->mGroup != this)
  297. {
  298. if (obj->mGroup)
  299. obj->mGroup->removeObject(obj);
  300. nameDictionary.insert(obj);
  301. obj->mGroup = this;
  302. objectList.push_back(obj); // force it into the object list
  303. // doesn't get a delete notify
  304. obj->onGroupAdd();
  305. }
  306. unlock();
  307. }
  308. void SimGroup::removeObject(SimObject* obj)
  309. {
  310. lock();
  311. if (obj->mGroup == this)
  312. {
  313. obj->onGroupRemove();
  314. nameDictionary.remove(obj);
  315. objectList.remove(obj);
  316. obj->mGroup = 0;
  317. }
  318. unlock();
  319. }
  320. //////////////////////////////////////////////////////////////////////////
  321. void SimGroup::onRemove()
  322. {
  323. lock();
  324. objectList.sortId();
  325. if (objectList.size())
  326. {
  327. // This backwards iterator loop doesn't work if the
  328. // list is empty, check the size first.
  329. for (SimObjectList::iterator ptr = objectList.end() - 1;
  330. ptr >= objectList.begin(); ptr--)
  331. {
  332. if ( (*ptr)->isProperlyAdded() )
  333. {
  334. (*ptr)->onGroupRemove();
  335. (*ptr)->mGroup = NULL;
  336. (*ptr)->unregisterObject();
  337. (*ptr)->mGroup = this;
  338. }
  339. }
  340. }
  341. SimObject::onRemove();
  342. unlock();
  343. }
  344. //////////////////////////////////////////////////////////////////////////
  345. SimObject *SimGroup::findObject(const char *namePath)
  346. {
  347. // find the end of the object name
  348. S32 len;
  349. for(len = 0; namePath[len] != 0 && namePath[len] != '/'; len++)
  350. ;
  351. StringTableEntry stName = StringTable->lookupn(namePath, len);
  352. if(!stName)
  353. return NULL;
  354. SimObject *root = nameDictionary.find(stName);
  355. if(!root)
  356. return NULL;
  357. if(namePath[len] == 0)
  358. return root;
  359. return root->findObject(namePath + len + 1);
  360. }
  361. SimObject *SimSet::findObject(const char *namePath)
  362. {
  363. // find the end of the object name
  364. S32 len;
  365. for(len = 0; namePath[len] != 0 && namePath[len] != '/'; len++)
  366. ;
  367. StringTableEntry stName = StringTable->lookupn(namePath, len);
  368. if(!stName)
  369. return NULL;
  370. lock();
  371. for(SimSet::iterator i = begin(); i != end(); i++)
  372. {
  373. if((*i)->getName() == stName)
  374. {
  375. unlock();
  376. if(namePath[len] == 0)
  377. return *i;
  378. return (*i)->findObject(namePath + len + 1);
  379. }
  380. }
  381. unlock();
  382. return NULL;
  383. }
  384. SimObject* SimObject::findObject(const char* )
  385. {
  386. return NULL;
  387. }
  388. //////////////////////////////////////////////////////////////////////////
  389. bool SimGroup::processArguments(S32, const char **)
  390. {
  391. return true;
  392. }
  393. //////////////////////////////////////////////////////////////////////////
  394. IMPLEMENT_CONOBJECT(SimGroup);