simSet_ScriptBinding.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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. /*! @class SimSet
  23. A container for a sequence of unique SimObjects.
  24. @par Overview
  25. A SimSet is a specized container: an ordered set of references to SimObjects.
  26. As the name "set" implies, a SimObject can appear no more than once within a particular SimSet.
  27. Attempting to add an object multiple times will not change the SimSet not does it (nor should it) warn you.
  28. A SimSet keeps its items ordered, however, so it is more than a mathematical "set." You can reorder the
  29. objects.
  30. A Simset only *references* SimObjects. The deletion of a SimSet will not delete the objects in it.
  31. Likewise, removing an object from a SimSet does not delete that object.
  32. Note that a SimObject can be a member of any number of SimSets.
  33. When a SimObject is deleted, it will be automatically removed from any SimSets it is in.
  34. This is one of a SimSets most powerful features. There can be no invalid references to objects
  35. because you can not insert a non-existent reference, and references to SimObjects are automatically removed
  36. when those objects are deleted.
  37. *Due to its many capabilities, a SimSet is usually the appropriate structure for keeping Collections in Torque2D.*
  38. Note that only SimObjects can be held in SimSets. Strings, for instance, can not.
  39. But, because SimObject is the base class for almost all script classes, you can add almost any script class to a SimSet.
  40. The SimSet's member objects are stored initially in the order of insertion (add()),
  41. and can be removed (remove()), retrieved (getObject()), and queried (isMember()).
  42. The SimSet can have all its members counted (getCount()), printed (listObjects()), and removed (clear()).
  43. A member can be reordered via bringToFront() and pushToBack(), or re-ordered relative to another via reorderChild().
  44. @par Examples
  45. **Creating and Adding**
  46. We create the SimSet, then create objects to put in it, then we add them all in.
  47. @code
  48. new SimSet(Fruit);
  49. echo(Fruit.getCount());
  50. > 0
  51. // Apple, Pear, etc will be SimObjects
  52. new SimObject(Apple);
  53. new SimObject(Pear);
  54. new SimObject(Orange);
  55. new SimObject(Fig);
  56. new SimObject(Persimmon);
  57. // add our fruit to the SimSet named Fruit
  58. Fruit.add(Apple);
  59. Fruit.add(Pear);
  60. Fruit.add(Orange);
  61. Fruit.add(Fig);
  62. Fruit.add(Persimmon);
  63. echo(Fruit.getCount());
  64. > 5
  65. @endcode
  66. **Uniqueness**
  67. Continuing the above example, each member of the SimSet appears exactly once: the SimSet is a mathematically proper set.
  68. @code
  69. // Apple is already added.
  70. Fruit.add(Apple);
  71. echo(Fruit.getCount());
  72. > 5
  73. @endcode
  74. **Re-ordering**
  75. The members of a SimSet are well ordered. Let us move a different object to the front.
  76. @code
  77. echo(Fruit.getObject(0).getName());
  78. > Apple
  79. Fruit.bringToFront(Persimmon);
  80. echo(Fruit.getObject(0).getName());
  81. > Persimmon
  82. @endcode
  83. Now we move a different member to the back.
  84. @code
  85. Fruit.pushToBack(Apple);
  86. echo(Fruit.getObject(4).getName());
  87. > Apple
  88. @endcode
  89. Finally, we move the Fig member to precede Pear. Note that all of the other members retain their relative order.
  90. @code
  91. Fruit.listObjects();
  92. > 2887,"Persimmon": SimObject
  93. > 2884,"Pear": SimObject
  94. > 2885,"Orange": SimObject
  95. > 2886,"Fig": SimObject
  96. > 2883,"Apple": SimObject
  97. Fruit.reorderChild(Fig, Pear);
  98. Fruit.listObjects();
  99. > 2887,"Persimmon": SimObject
  100. > 2886,"Fig": SimObject
  101. > 2885,"Orange": SimObject
  102. > 2884,"Pear": SimObject
  103. > 2883,"Apple": SimObject
  104. @endcode
  105. **Removing**
  106. @code
  107. echo(Fruit.isMember(Apple));
  108. > 1
  109. Fruit.remove(Apple);
  110. echo(Fruit.isMember(Apple));
  111. > 0
  112. // Apple was not deleted
  113. echo(isObject(Apple));
  114. > 1
  115. Fruit.clear();
  116. echo(Fruit.getCount());
  117. > 0
  118. // The fruit SimObjects are not deleted by clear() either. For example...
  119. echo(isObject(Persimmon));
  120. > 1
  121. @endcode
  122. @par caveat
  123. Suppose you want to delete the items in a SimSet. Remember that, as you delete each one, it is automatically
  124. removed from the SimSet, which in turn changes the index of any items that came after the one you just deleted!
  125. @code
  126. // DO NOT DO THIS! this may lead to tears!
  127. for (%i = 0; %i < %mySet.getCount(); %i++)
  128. {
  129. %object = %mySet.getObject(%i);
  130. %object.delete();
  131. }
  132. @endcode
  133. The problem is that you delete the object at index 0. This, in turn, moves the objects down one index so
  134. that what was at index 1 is not at index 0. But your loop will not try index 0 again, where there is a fresh
  135. object. Instead it will skip to index 1. You will only delete half the items.
  136. @code
  137. // fixed it
  138. while (%mySet.getCount() > 0)
  139. {
  140. %object = %mySet.getObject(0);
  141. %object.delete();
  142. }
  143. // or this will work too. see why?
  144. for (%i = %mySet.getCount() - 1; %i >= 0; %i--)
  145. {
  146. %object = %mySet.getObject(%i);
  147. %object.delete();
  148. }
  149. @endcode
  150. */
  151. ConsoleMethodGroupBeginWithDocs(SimSet, SimObject)
  152. /*! Prints the object data within the set
  153. @return No return value
  154. */
  155. ConsoleMethodWithDocs(SimSet, listObjects, ConsoleVoid, 2, 2, ())
  156. {
  157. object->lock();
  158. SimSet::iterator itr;
  159. for(itr = object->begin(); itr != object->end(); itr++)
  160. {
  161. SimObject *obj = *itr;
  162. bool isSet = dynamic_cast<SimSet *>(obj) != 0;
  163. const char *name = obj->getName();
  164. if(name)
  165. Con::printf(" %d,\"%s\": %s %s", obj->getId(), name,
  166. obj->getClassName(), isSet ? "(g)":"");
  167. else
  168. Con::printf(" %d: %s %s", obj->getId(), obj->getClassName(),
  169. isSet ? "(g)" : "");
  170. }
  171. object->unlock();
  172. }
  173. /*! Appends given SimObject (or list of SimObjects) to the SimSet.
  174. @param obj_1..obj_n list of SimObjects to add
  175. @return No return value
  176. */
  177. ConsoleMethodWithDocs(SimSet, add, ConsoleVoid, 3, 0, (obj1, [obj2]*))
  178. {
  179. for(S32 i = 2; i < argc; i++)
  180. {
  181. SimObject *obj = Sim::findObject(argv[i]);
  182. if(obj)
  183. object->addObject(obj);
  184. else
  185. Con::printf("Set::add: Object \"%s\" doesn't exist", argv[i]);
  186. }
  187. }
  188. /*! Removes given SimObject (or list of SimObjects) from the SimSet.
  189. @param obj_1..obj_n list of SimObjects to remove
  190. The SimObjects are not deleted. An attempt to remove a SimObject that is not present
  191. in the SimSet will print a warning and continue.
  192. @return No return value
  193. */
  194. ConsoleMethodWithDocs(SimSet, remove, ConsoleVoid, 3, 0, (obj1, [obj2]*))
  195. {
  196. for(S32 i = 2; i < argc; i++)
  197. {
  198. SimObject *obj = Sim::findObject(argv[i]);
  199. object->lock();
  200. if(obj && object->find(object->begin(),object->end(),obj) != object->end())
  201. object->removeObject(obj);
  202. else
  203. Con::printf("Set::remove: Object \"%s\" does not exist in set", argv[i]);
  204. object->unlock();
  205. }
  206. }
  207. /*! Removes given SimObject (or list of SimObjects) from the SimSet with no warning.
  208. @param obj_1..obj_n list of SimObjects to remove
  209. The SimObjects are not deleted. An attempt to remove a SimObject that is not present
  210. in the SimSet will silently fail.
  211. @return No return value
  212. */
  213. ConsoleMethodWithDocs(SimSet, removeIfMember, ConsoleVoid, 3, 0, (obj1, [obj2] *))
  214. {
  215. for (S32 i = 2; i < argc; i++)
  216. {
  217. SimObject* obj = Sim::findObject(argv[i]);
  218. object->lock();
  219. if (obj && object->find(object->begin(), object->end(), obj) != object->end())
  220. object->removeObject(obj);
  221. object->unlock();
  222. }
  223. }
  224. //-----------------------------------------------------------------------------
  225. /*! Deletes all the objects in the SimSet.
  226. @return No return value
  227. */
  228. ConsoleMethodWithDocs(SimSet, deleteObjects, ConsoleVoid, 2, 2, ())
  229. {
  230. object->deleteObjects();
  231. }
  232. //-----------------------------------------------------------------------------
  233. /*! Clears the Simset
  234. This does not delete the cleared SimObjects.
  235. @return No return value
  236. */
  237. ConsoleMethodWithDocs(SimSet, clear, ConsoleVoid, 2, 2, ())
  238. {
  239. object->clear();
  240. }
  241. //-----------------------------------------------------------------------------
  242. /*! Call a method on all objects contained in the set.
  243. @param method The name of the method to call.
  244. @param args The arguments to the method.
  245. @note This method recurses into all SimSets that are children to the set.
  246. @see callOnChildrenNoRecurse" )
  247. */
  248. ConsoleMethodWithDocs(SimSet, callOnChildren, void, 3, 0, ( string method, [string args]* ))
  249. {
  250. object->callOnChildren( argv[2], argc - 3, argv + 3 );
  251. }
  252. //-----------------------------------------------------------------------------
  253. /*! Call a method on all objects contained in the set.
  254. @param method The name of the method to call.
  255. @param args The arguments to the method.
  256. @note This method does not recursively call into all SimSets that are children to the set.
  257. @see callOnChildren" )
  258. */
  259. ConsoleMethodWithDocs(SimSet, callOnChildrenNoRecurse, void, 3, 0, (string method, [string args] *))
  260. {
  261. object->callOnChildren(argv[2], argc - 3, argv + 3, false);
  262. }
  263. //////////////////////////////////////////////////////////////////////////-
  264. // Make Sure Child 1 is Ordered Just Under Child 2.
  265. //////////////////////////////////////////////////////////////////////////-
  266. /*! Bring child 1 before child 2
  267. Both SimObjects must already be child objects. If not, the operation silently fails.
  268. @param child1 The child you wish to set first
  269. @param child2 The child you wish to set after child1
  270. @return No return value.
  271. */
  272. ConsoleMethodWithDocs(SimSet, reorderChild, ConsoleVoid, 4,4, (SimObject child1, SimObject child2))
  273. {
  274. SimObject* pObject = Sim::findObject(argv[2]);
  275. SimObject* pTarget = Sim::findObject(argv[3]);
  276. if(pObject && pTarget)
  277. {
  278. object->reOrder(pObject,pTarget);
  279. }
  280. }
  281. /*! @return Returns the number of objects in the SimSet
  282. */
  283. ConsoleMethodWithDocs(SimSet, getCount, ConsoleInt, 2, 2, ())
  284. {
  285. return object->size();
  286. }
  287. /*! Returns a member SimObject of the SimSet
  288. @param index into this ordered collection (zero-based).
  289. @return Returns the ID of the desired object or -1 on failure
  290. */
  291. ConsoleMethodWithDocs(SimSet, getObject, ConsoleInt, 3, 3, (index))
  292. {
  293. S32 objectIndex = dAtoi(argv[2]);
  294. if(objectIndex < 0 || objectIndex >= S32(object->size()))
  295. {
  296. Con::printf("Set::getObject index out of range.");
  297. return -1;
  298. }
  299. return ((*object)[objectIndex])->getId();
  300. }
  301. /*! @return Returns true if specified object is a member of the set, and false otherwise
  302. */
  303. ConsoleMethodWithDocs(SimSet, isMember, ConsoleBool, 3, 3, (object))
  304. {
  305. SimObject *testObject = Sim::findObject(argv[2]);
  306. if(!testObject)
  307. {
  308. Con::printf("SimSet::isMember: %s is not an object.", argv[2]);
  309. return false;
  310. }
  311. return object->isMember(testObject);
  312. }
  313. /*! Returns the object with given internal name
  314. @param name The internal name of the object you wish to find
  315. @param searchChildren Set this true if you wish to search all children as well.
  316. @return Returns the ID of the object.
  317. */
  318. ConsoleMethodWithDocs( SimSet, findObjectByInternalName, ConsoleInt, 3, 4, (string name, [bool searchChildren]?))
  319. {
  320. StringTableEntry pcName = StringTable->insert(argv[2]);
  321. bool searchChildren = false;
  322. if (argc > 3)
  323. searchChildren = dAtob(argv[3]);
  324. SimObject* child = object->findObjectByInternalName(pcName, searchChildren);
  325. if(child)
  326. return child->getId();
  327. return 0;
  328. }
  329. /*! Brings SimObject to front of set.
  330. If the SimObject is not in the set, do nothing.
  331. @return No return value.
  332. */
  333. ConsoleMethodWithDocs(SimSet, bringToFront, ConsoleVoid, 3, 3, (object))
  334. {
  335. SimObject *obj = Sim::findObject(argv[2]);
  336. if(!obj)
  337. return;
  338. object->bringObjectToFront(obj);
  339. }
  340. /*! Sends item to back of set.
  341. If the SimObject is not in the set, do nothing.
  342. @return No return value.
  343. */
  344. ConsoleMethodWithDocs(SimSet, pushToBack, ConsoleVoid, 3, 3, (object))
  345. {
  346. SimObject *obj = Sim::findObject(argv[2]);
  347. if(!obj)
  348. return;
  349. object->pushObjectToBack(obj);
  350. }
  351. ConsoleMethodGroupEndWithDocs(SimSet)