simObject_ScriptBinding.h 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177
  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. ConsoleMethodRootGroupBeginWithDocs(SimObject)
  23. /*! @class SimObject
  24. SimObject is the base class for all other scripted classes.
  25. This means that all other "simulation" classes -- be they SceneObjects, Scenes, or plain-old SimObjects
  26. -- can use the methods and fields of SimObject.
  27. @par Identity
  28. When we create a SimObject with `::new`, it is given a unique id which is returned by `::new`.
  29. We usually save the id in our own variables. Alternatively, we can give the SimObject a name which we can
  30. use to directly manipulate it. This name can be set with the `::new` operator or it can be added later.
  31. If we give an object a name, then we can write script methods that are "scoped" to run on this object only.
  32. For instance, if we have a SimObject named `MyObject`, and if we call `MyObject.myMethod()`, then this
  33. call will be handled by a method we named `MyObject::myMethod` if one exists.
  34. See getId(), getName(), setName()
  35. @par Static and Dynamic Fields
  36. Each subclass of SimObject will provide important fields. For instance, a SceneObject will have a position,
  37. scale, etc. These are known as "static" or "built-in" fields. Additionally, you can add any number of your
  38. own fields, for example `myField` or `hitPoints`. These are known as "dynamic" or "add-on" fields.
  39. To do so only requires you to set the field directly with `%%myObject.myField = myValue;`. Attempting to
  40. retrieve a field that does not exist (yet) returns nothing. There is no error or warning.
  41. Note that static fields exist for every object of a class, while dynamic fields are unique to any one instance. Adding
  42. `myField` to one SceneObject does not add it to all SceneObjects.
  43. For working with fields more programmatically, see *Reflection* below.
  44. @par Script Namespace
  45. We can attach a `Namespace` to an object. Then calls to this object
  46. will be handled by the script functions in that Namespace. For instance, if we set `%%myObject.class = MyScope` then
  47. the call `%%myObject.myMethod` will be handled with a method named `MyScope::myMethod()`. (If we also named the object `MyObject`, then
  48. if there is a `MyObject::myMethod()` it will run. Otherwise, Torque2D will look for `MyScope::myMethod()` and run that
  49. if found.)
  50. Finally there is also a *secondary* `Namespace` that will receive the call if neither the `Name` nor the *primary* `Namespace`
  51. had a method to handle the call.
  52. Unfortunately, these `Namespaces` are called `Classes` in this context. You set the `class` or `superclass`. But this
  53. should not be confused with the SimObject's "real" class which is SimObject or Scene as examples.
  54. See getClassNamespace(), setClassNamespace(), getSuperClassNamespace(), setSuperClassNamespace()
  55. @par Reflection
  56. SimObject supports "reflection" -- the run-time inspection of an object's methods, fields, etc. For instance,
  57. we can ask an object what class it instantiates, what dynamic fields it has, etc. We can also use this feature to
  58. call a method on an object even if we only know the string name of the method.
  59. See getClassName(), isMemberOfClass(), isMethod(), dump(), dumpClassHierarchy(), call()
  60. See getFieldValue(), setFieldValue(), getFieldCount(), getField(), getDynamicFieldCount(), getDynamicField()
  61. @par Scheduling Callbacks
  62. We can set a SimObject to regularly call its own onTimer() callback. Additionally, we can schedule a single call to
  63. any method at any time in the future.
  64. See startTimer(), stopTimer(), isTimerActive(), schedule()
  65. @par Groups
  66. TBD
  67. @par Persistence
  68. canSaveDynamicFields bool = "1" - Whether a save() shall save the object's Dynamic Fields (member fields created by TorqueScript)
  69. */
  70. /*! @name Identity
  71. Reference an object
  72. @{
  73. */
  74. /*! get the unique numeric ID -- or "handle" -- of this object.
  75. @return Returns the numeric ID.
  76. The id is provided for you by the simulator upon object creation. You can not change it
  77. and it likely will not be reused by any other object after this object is deleted.
  78. @par Example
  79. @code
  80. new SimObject(example);
  81. echo(example.getId());
  82. > 1752
  83. @endcode
  84. @par Caveat
  85. You can not access the id directly. That is, you can not access `%%object.id`.
  86. If you do set `%%object.id` you will only succeed in creating a dynamic field named
  87. `id` -- an unrelated field to the actual object's id.
  88. @par Example
  89. @code
  90. %example = SimObject();
  91. echo(%example.getId());
  92. > 1753
  93. // warning! this will fail to change the id!
  94. // it will also not warn you as it is legal syntax
  95. %example.id = 50;
  96. echo(%example.getId());
  97. > 1753
  98. echo(%example.id);
  99. > 50
  100. @endcode
  101. @sa getName, setName
  102. */
  103. ConsoleMethodWithDocs(SimObject, getId, ConsoleInt, 2, 2, ())
  104. {
  105. return object->getId();
  106. }
  107. /*! Set the objects name field.
  108. @param newName name for objects
  109. @return no return value
  110. Now the object can be invoked by this name.
  111. This is different than tracking an object by a variable, such as `%%myObject` or `$myObject`.
  112. Only one object can have a specific name. Setting a second object
  113. with this name will remove the name from the former object.
  114. Note not to confuse this with the `internalName` which is a name for grouping purposes.
  115. @par Example
  116. @code
  117. %obj = new SimObject();
  118. %obj.setName("MyName");
  119. // these are now equivalent
  120. %obj.save();
  121. MyName.save();
  122. @endcode
  123. @par Caveat
  124. You can not access the name directly. That is, you can not access `%%object.name`.
  125. If you do set `%%object.name` you will only succeed in creating a dynamic field named
  126. `name` -- an unrelated field to the actual object's name.
  127. @par Example
  128. @code
  129. SimObject("example");
  130. echo(example.getName());
  131. > example
  132. // warning! the field `name` does not exist yet
  133. echo(example.name);
  134. >
  135. // warning! this will fail to change the name!
  136. // it will also not warn you as it is legal syntax
  137. %example.name = "newExample";
  138. echo(%example.getName());
  139. > example
  140. echo(%example.name);
  141. > newExample
  142. @endcode
  143. @see setName, getId
  144. */
  145. ConsoleMethodWithDocs(SimObject, setName, ConsoleVoid, 3, 3, (newName))
  146. {
  147. object->assignName(argv[2]);
  148. }
  149. /*! Returns the name of the object
  150. @return the "global" name
  151. See setName() for a description of the name field.
  152. Note not to confuse this with the `internalName` which is a name for grouping purposes.
  153. @par Example
  154. @code
  155. %example = new SimObject();
  156. %example.setName("myObject");
  157. // now we can reference our object with variables and with its name
  158. %example.getId();
  159. > 160
  160. myObject.getId();
  161. > 160
  162. @endcode
  163. @Caveats
  164. See setName() for caveats.
  165. @see setName, getId
  166. */
  167. ConsoleMethodWithDocs(SimObject, getName, ConsoleString, 2, 2, ())
  168. {
  169. const char *ret = object->getName();
  170. return ret ? ret : "";
  171. }
  172. /*! @} */ // member group Identity
  173. /*! @name Scoping
  174. Manipulate the object's script-defined `Namespace`
  175. @{
  176. */
  177. /*! Returns the `Namespace` of this object as set by the user.
  178. @return The Namespace as set in the object's `class` field.
  179. The class namespace is a a scripting concept that provides a "namespace" in which the engine looks
  180. to find user-defined scripting functions. It can be set, and reset, by the user
  181. by using setClassNamespace(). Alternatively, it can be set directly using the `class` field of the object.
  182. Note that this can easily be confused with getClassName(), which is unrelated, and returns the "true"
  183. engine class name of an object, such as `SimObject`.
  184. See setClassNamespace() for examples.
  185. @see setClassNamespace
  186. */
  187. ConsoleMethodWithDocs(SimObject, getClassNamespace, ConsoleString, 2, 2, ())
  188. {
  189. return object->getClassNamespace();
  190. }
  191. /*! Return the superclass `Namespace` of this object as set by the user.
  192. An object can have a primary and secondary `Namespace` also known as its
  193. `class` and `superclass`. If a user-defined function is not found in the `class`
  194. then the `superclass` is searched.
  195. @see getClassNamespace
  196. */
  197. ConsoleMethodWithDocs(SimObject, getSuperClassNamespace, ConsoleString, 2, 2, ())
  198. {
  199. return object->getSuperClassNamespace();
  200. }
  201. /*! Sets the `Namespace` of this object.
  202. @return no return value
  203. The class namespace is a a scripting concept that provides a "namespace" in which the engine looks
  204. to find user-defined scripting functions. It can be set, and reset, by the user using setClassNamespace().
  205. Alternatively, it can be set directly using the `class` field of the object.
  206. The `Namespace` or `class` can then be returned with getClassNamespace(). Note that this can easily be
  207. confused with getClassName(), which is unrelated, and returns the "true" engine class name of an object,
  208. such as `SimObject`.
  209. @par Example
  210. @code
  211. %example = new SimObject()
  212. {
  213. class = MyScope;
  214. };
  215. echo(%example.class);
  216. > MyScope
  217. // set the namespace using setNamespace()
  218. %example.setClassNamespace(DifferentScope);
  219. echo(%example.class);
  220. > DifferentScope
  221. // set the namespace directly using the field 'class'
  222. %example.class = YetAnotherScope;
  223. echo(%example.getClassNamespace());
  224. > YetAnotherScope
  225. @endcode
  226. @see getClassNamespace
  227. */
  228. ConsoleMethodWithDocs(SimObject, setClassNamespace, ConsoleVoid, 2, 3, (nameSpace))
  229. {
  230. object->setClassNamespace(argv[2]);
  231. }
  232. /*! Sets the superclass `Namespace` of this object.
  233. An object can have a primary and secondary `Namespace` also known as its
  234. `class` and `superclass`. If a user-defined function is not found in the `class`
  235. then the `superclass` is searched.
  236. @see setClassNamespace
  237. */
  238. ConsoleMethodWithDocs(SimObject, setSuperClassNamespace, ConsoleVoid, 2, 3, ())
  239. {
  240. object->setSuperClassNamespace(argv[2]);
  241. }
  242. /*! @} */ // member group Scoping
  243. /*! @name Reflection
  244. Methods to query and manipulate the object's class, methods, and fields.
  245. @{
  246. */
  247. /*! Returns wether the method exists for this object.
  248. @returns true if the method exists; false otherwise
  249. The method must be a "built-in" method, or one that is not user-defined in script.
  250. It must also be a direct method on the object, and not a behavior defined in a Behavior.
  251. */
  252. ConsoleMethodWithDocs(SimObject, isMethod, ConsoleBool, 3, 3, (string methodName))
  253. {
  254. return object->isMethod( argv[2] );
  255. }
  256. /*! Dynamically call a method by a string name
  257. Normally you would call a method in the form `%object.myMethod(param1, param2)`.
  258. Alternatively, you can use `%object.call(myMethod, param1, param2)`. This can be
  259. useful if, for instance, you don't know which method to call in advance.
  260. @par Example
  261. @code
  262. %method = "setClassNamespace";
  263. %newNamespace = "myNamespace";
  264. %object.call(%method, %newNamespace);
  265. @endcode
  266. */
  267. ConsoleMethodWithDocs( SimObject, call, ConsoleString, 2, 0, ( methodName, [args]* ))
  268. {
  269. argv[1] = argv[2];
  270. return Con::execute( object, argc - 1, argv + 1 );
  271. }
  272. /*! Write the class hierarchy of an object to the console.
  273. @return no return value
  274. @par Example
  275. @code
  276. new SimGroup(sg);
  277. echo(sg.dumpClassHierarchy());
  278. > SimGroup ->
  279. > SimSet ->
  280. > SimObject
  281. @endcode
  282. */
  283. ConsoleMethodWithDocs(SimObject, dumpClassHierarchy, ConsoleVoid, 2, 2, ())
  284. {
  285. object->dumpClassHierarchy();
  286. }
  287. /*! dump the object to the console.
  288. Use the dump method to display the following information about this object:
  289. + All static and dynamic fields that are non-null
  290. + All engine and script-registered console methods (including superclass methods) for this object
  291. @return No return value
  292. */
  293. ConsoleMethodWithDocs(SimObject,dump, ConsoleVoid, 2, 2, ())
  294. {
  295. object->dump();
  296. }
  297. /*! returns true if this object is of the specified class or a subclass of the specified class
  298. @return true if a class or subclass of the given class
  299. @par Example
  300. @code
  301. %example = new SceneObject();
  302. echo(%example.isMemberOfClass(SimObject);
  303. > 1
  304. echo(%example.isMemberOfClass(SimSet);
  305. > 0
  306. @endcode
  307. */
  308. ConsoleMethodWithDocs(SimObject, isMemberOfClass, ConsoleBool, 3, 3, (string classname))
  309. {
  310. AbstractClassRep* pRep = object->getClassRep();
  311. while(pRep)
  312. {
  313. if(!dStricmp(pRep->getClassName(), argv[2]))
  314. {
  315. //matches
  316. return true;
  317. }
  318. pRep = pRep->getParentClass();
  319. }
  320. return false;
  321. }
  322. /*! Returns the engine class of this object such as `SimObject` or `SceneObject`
  323. @return class name
  324. Note that this method is defined in SimObject but is inherited by subclasses of SimObject.
  325. Subclasses will return the correct subclass name.
  326. Note also, getClassName() is not related to an object's `class` field! The `class` field
  327. is a scripting concept that provides a "namespace" to look for user-defined functions (see getClassNamespace()).
  328. @par Example
  329. @code
  330. %example = new SimObject()
  331. {
  332. class = MyScope;
  333. };
  334. echo(%example.getClassName());
  335. > SimObject
  336. echo(%example.class);
  337. > MyScope
  338. @endcode
  339. */
  340. ConsoleMethodWithDocs(SimObject, getClassName, ConsoleString, 2, 2, ())
  341. {
  342. const char *ret = object->getClassName();
  343. return ret ? ret : "";
  344. }
  345. /*! Return the value of any field.
  346. This can be a static ("built-in") field or a dynamic ("add-on") field.
  347. Normally, you would get a field directly as `%%object.field`.
  348. However, in some cases you may want to use getFieldValue(). For instance,
  349. suppose you allow the field name to be passed into a function. You can still
  350. get that field with `%%object.getFieldValue(%%field)`.
  351. @param fieldName the name of the field
  352. @return the value of the field
  353. @par Example
  354. @code
  355. // create a SimObject and set its 'class' field for our example
  356. %example = new SimObject()
  357. {
  358. class = "MyClass";
  359. }
  360. // 'class' is a static "built-in" field. retrieve it directly and with getFieldValue()
  361. echo(%example.class);
  362. > MyClass
  363. echo(%example.getFieldValue(class));
  364. > MyClass
  365. // set a dynamic "add-on" field
  366. %example.myField = "myValue";
  367. echo(%example.myField);
  368. > myValue
  369. echo(%example.getFieldValue(myField));
  370. > myValue
  371. @endcode
  372. */
  373. ConsoleMethodWithDocs(SimObject, getFieldValue, ConsoleString, 3, 3, (fieldName))
  374. {
  375. const char *fieldName = StringTable->insert( argv[2] );
  376. return object->getDataField( fieldName, NULL );
  377. }
  378. /*! Set the value of any field.
  379. This can be a static ("built-in") field or a dynamic ("add-on") field.
  380. Normally, you would set a field directly as `%%object.field = value`.
  381. However, in some cases you may want to use setFieldValue(). For instance,
  382. suppose you allow the field name to be passed into a function. You can still
  383. set that field with `%%object.setFieldValue(%field, "myValue")`.
  384. @param fieldName the name of the field to set
  385. @param value the value to set
  386. @return always returns true
  387. @par Example
  388. @code
  389. // create a SimObject
  390. %example = new SimObject();
  391. // 'class' is a static "built-in" field. set it directly and with setFieldValue()
  392. echo(%example.class);
  393. >
  394. %example.class = "MyClass";
  395. echo(%example.class);
  396. > MyClass
  397. %example.setFieldValue(class, "AnotherClass");
  398. echo(%example.class);
  399. > AnotherClass
  400. // set a dynamic "add-on" field
  401. echo(%example.myField);
  402. >
  403. %example.myField = "myValue";
  404. echo(%example.myField);
  405. > myValue
  406. %example.setFieldValue(anotherField, "anotherValue");
  407. echo(%example.anotherField);
  408. > anotherValue
  409. @endcode
  410. */
  411. ConsoleMethodWithDocs(SimObject, setFieldValue, ConsoleBool, 4, 4, (fieldName,value))
  412. {
  413. const char *fieldName = StringTable->insert(argv[2]);
  414. const char *value = argv[3];
  415. object->setDataField( fieldName, NULL, value );
  416. return true;
  417. }
  418. ConsoleMethodWithDocs(SimObject, setEditFieldValue, ConsoleBool, 4, 4, (fieldName, value))
  419. {
  420. const char *fieldName = StringTable->insert(argv[2]);
  421. const char *value = argv[3];
  422. object->inspectPreApply();
  423. object->setDataField(fieldName, NULL, value);
  424. object->inspectPostApply();
  425. return true;
  426. }
  427. /*! return the number of dynamic ("add-on") fields.
  428. @return the number of dynamic fields
  429. Note that static (or "built-in") fields are not counted. For instance,
  430. `SimObject.class` will not count.
  431. See getDynamicField() for an explanation and examples.
  432. @see getDynamicField, getField, getFieldCount
  433. */
  434. ConsoleMethodWithDocs(SimObject, getDynamicFieldCount, ConsoleInt, 2, 2, ())
  435. {
  436. S32 count = 0;
  437. SimFieldDictionary* fieldDictionary = object->getFieldDictionary();
  438. for (SimFieldDictionaryIterator itr(fieldDictionary); *itr; ++itr)
  439. count++;
  440. return count;
  441. }
  442. /*! Return the field name of a specific dynamic ("add-on") field by index.
  443. @param index the dynamic field for which to retrieve the name
  444. @return the name of the field
  445. You would normally access dynamic fields directly `%%object.field` or
  446. indirectly `%%object.getFieldValue(%%field)`. However, you may not know the
  447. field's names or otherwise need to iterate over the fields. Use getDynamicFieldCount()
  448. to get the number of dynamic fields, and then iterate over them with this function.
  449. Note that only dynamic ("add-on") fields will be surfaced. Static ("built-in") fields
  450. like `SimSet.class` will not be counted or listed.
  451. While static and dynamic fields have separate functions to get their counts and names, they
  452. share getFieldValue() and setFieldValue() to read and set any field by name.
  453. Also note that the order of the fields by an index has no meaning. It is not alphabetical,
  454. the order created, or otherwise.
  455. @par Example
  456. @code
  457. %count = %example.getDynamicFieldCount();
  458. for (%i = 0; %i < %count; %i++)
  459. {
  460. %fieldName = %example.getDynamicField(%i);
  461. %fieldValue = %example.getFieldValue(%fieldName);
  462. echo(%fieldName @ " = " @ %fieldValue);
  463. }
  464. @endcode
  465. @see getDynamicFieldCount, getField, getFieldCount
  466. */
  467. ConsoleMethodWithDocs(SimObject, getDynamicField, ConsoleString, 3, 3, (index))
  468. {
  469. SimFieldDictionary* fieldDictionary = object->getFieldDictionary();
  470. SimFieldDictionaryIterator itr(fieldDictionary);
  471. S32 index = dAtoi(argv[2]);
  472. for (S32 i = 0; i < index; i++)
  473. {
  474. if (!(*itr))
  475. {
  476. Con::warnf("Invalid dynamic field index passed to SimObject::getDynamicField!");
  477. return NULL;
  478. }
  479. ++itr;
  480. }
  481. char* buffer = Con::getReturnBuffer(256);
  482. if (*itr)
  483. {
  484. SimFieldDictionary::Entry* entry = *itr;
  485. dSprintf(buffer, 256, "%s", entry->slotName);
  486. return buffer;
  487. }
  488. Con::warnf("Invalid dynamic field index passed to SimObject::getDynamicField!");
  489. return NULL;
  490. }
  491. /*! return the number of static ("built-in") fields.
  492. @return the number of dynamic fields
  493. Note that dynamic (or "add-on") fields are not counted. For instance,
  494. `%%object.class` will count, but `%%object.myField` will not.
  495. See getField() for an explanation and examples.
  496. @see getDynamicField, getDynamicFieldCount, getField
  497. */
  498. ConsoleMethodWithDocs( SimObject, getFieldCount, ConsoleInt, 2, 2, ())
  499. {
  500. const AbstractClassRep::FieldList &list = object->getFieldList();
  501. const AbstractClassRep::Field* f;
  502. U32 numDummyEntries = 0;
  503. for(int i = 0; i < list.size(); i++)
  504. {
  505. f = &list[i];
  506. if( f->type == AbstractClassRep::DepricatedFieldType ||
  507. f->type == AbstractClassRep::StartGroupFieldType ||
  508. f->type == AbstractClassRep::EndGroupFieldType )
  509. {
  510. numDummyEntries++;
  511. }
  512. }
  513. return list.size() - numDummyEntries;
  514. }
  515. /*! Return the field name of a specific static ("built-in") field by index.
  516. @param index the static field for which to retrieve the name
  517. @return the name of the field
  518. You would normally access static fields directly `%%object.class` or
  519. indirectly `%%object.getFieldValue(%%field)`. However, you may not know the
  520. field's names or otherwise need to iterate over the fields. Use getFieldCount()
  521. to get the number of static fields, and then iterate over them with this function.
  522. Note that only static ("built-in") fields will be surfaced. Dynamic ("add-on") fields
  523. like `%%SimSet.myField` will not be counted or listed.
  524. While static and dynamic fields have separate functions to get their counts and names, they
  525. share getFieldValue() and setFieldValue() to read and set any field by name.
  526. Also note that the order of the fields by an index has no meaning. It is not alphabetical,
  527. the order created, or otherwise.
  528. @par Example
  529. @code
  530. %count = %example.getFieldCount();
  531. for (%i = 0; %i < %count; %i++)
  532. {
  533. %fieldName = %example.getField(%i);
  534. %fieldValue = %example.getFieldValue(%fieldName);
  535. echo(%fieldName @ " = " @ %fieldValue);
  536. }
  537. @endcode
  538. @see getDynamicField, getDynamicFieldCount, getFieldCount
  539. */
  540. ConsoleMethodWithDocs( SimObject, getField, ConsoleString, 3, 3, (int index))
  541. {
  542. S32 index = dAtoi( argv[2] );
  543. const AbstractClassRep::FieldList &list = object->getFieldList();
  544. if( ( index < 0 ) || ( index >= list.size() ) )
  545. return "";
  546. const AbstractClassRep::Field* f;
  547. S32 currentField = 0;
  548. for(int i = 0; i < list.size() && currentField <= index; i++)
  549. {
  550. f = &list[i];
  551. // skip any dummy fields
  552. if(f->type == AbstractClassRep::DepricatedFieldType ||
  553. f->type == AbstractClassRep::StartGroupFieldType ||
  554. f->type == AbstractClassRep::EndGroupFieldType)
  555. {
  556. continue;
  557. }
  558. if(currentField == index)
  559. return f->pFieldname;
  560. currentField++;
  561. }
  562. // if we found nada, return nada.
  563. return "";
  564. }
  565. /*! Sets the progenitor file responsible for this instances creation.
  566. @param file The progenitor file responsible for this instances creation.
  567. @return No return value.
  568. */
  569. ConsoleMethodWithDocs(SimObject, setProgenitorFile, ConsoleVoid, 3, 3, (file))
  570. {
  571. object->setProgenitorFile( argv[2] );
  572. }
  573. //-----------------------------------------------------------------------------
  574. /*! Gets the progenitor file responsible for this instances creation.
  575. @return The progenitor file responsible for this instances creation.
  576. */
  577. ConsoleMethodWithDocs(SimObject, getProgenitorFile, ConsoleString, 2, 2, ())
  578. {
  579. return object->getProgenitorFile();
  580. }
  581. /*! Use the getType method to get the type for this object.
  582. @return Returns a bit mask containing one or more set bits.
  583. This is here for legacy purposes.
  584. This type is an integer value composed of bitmasks. For simplicity, these bitmasks
  585. are defined in the engine and exposed for our use as global variables.
  586. To simplify the writing of scripts, a set of globals has been provided containing
  587. the bit setting for each class corresponding to a particular type.
  588. @sa getClassName
  589. */
  590. ConsoleMethodWithDocs(SimObject, getType, ConsoleInt, 2, 2, ())
  591. {
  592. return((S32)object->getType());
  593. }
  594. /*! return the type of a field, such as "int" for an Integer
  595. @param fieldName field of the object to get the type of
  596. @return string name of the type; or nothing if the field isn't found
  597. No warning will be shown if the field isn't found.
  598. @par Example
  599. @code
  600. new sprite(s);
  601. echo(s.getFieldType(frame));
  602. > int
  603. echo(s.getFieldType(blendcolor));
  604. > ColorF
  605. echo(s.getFieldType(angle));
  606. > float
  607. echo(s.getFieldType(position));
  608. > Vector2
  609. echo(s.getFieldType(class));
  610. > string
  611. echo(s.getFieldType(notAField));
  612. >
  613. @endcode
  614. */
  615. ConsoleMethodWithDocs(SimObject, getFieldType, ConsoleString, 3, 3, (fieldName))
  616. {
  617. const char *fieldName = StringTable->insert( argv[2] );
  618. U32 typeID = object->getDataFieldType( fieldName, NULL );
  619. ConsoleBaseType* type = ConsoleBaseType::getType( typeID );
  620. if( type )
  621. return type->getTypeClassName();
  622. return "";
  623. }
  624. /*! @} */ // member group Reflection
  625. /*! @name Grouping
  626. Manipulate the (singular) group for this object.
  627. @{
  628. */
  629. //-----------------------------------------------------------------------------
  630. // Set the internal name, can be used to find child objects
  631. // in a meaningful way, usually from script, while keeping
  632. // common script functionality together using the controls "Name" field.
  633. //-----------------------------------------------------------------------------
  634. /*! sets the objects "internal" name
  635. @param internalName the name used for group access
  636. @return nothing returned
  637. Not to be confused with the object's `Name`, the internal name is used to
  638. find this object within a group. Each object may be in one group, ultimately
  639. forming a tree (usually for GUI related classes). See SimGroup for more information.
  640. @see SimGroup, getInternalName, isChildOfGroup, getGroup
  641. */
  642. ConsoleMethodWithDocs( SimObject, setInternalName, ConsoleVoid, 3, 3, (string InternalName))
  643. {
  644. object->setInternalName(argv[2]);
  645. }
  646. /*! returns the objects "internal" name
  647. @return the internalName used for group access
  648. Not to be confused with the object's `Name`, the internal name is used to
  649. find this object within a group. Each object may be in one group, ultimately
  650. forming a tree (usually for GUI related classes). See SimGroup for more information.
  651. @see SimGroup, setInternalName, isChildOfGroup, getGroup
  652. */
  653. ConsoleMethodWithDocs( SimObject, getInternalName, ConsoleString, 2, 2, ())
  654. {
  655. return object->getInternalName();
  656. }
  657. /*! test if this object is in a specified group (or subgroup of it)
  658. @param groupID the ID of the group being tested
  659. @returns true if we are in the specified simgroup or a subgroup of it; false otherwise
  660. @see SimGroup, getInternalName, setInternalName, getGroup
  661. */
  662. ConsoleMethodWithDocs(SimObject, isChildOfGroup, ConsoleBool, 3,3, (groupID))
  663. {
  664. SimGroup* pGroup = dynamic_cast<SimGroup*>(Sim::findObject(dAtoi(argv[2])));
  665. if(pGroup)
  666. {
  667. return object->isChildOfGroup(pGroup);
  668. }
  669. return false;
  670. }
  671. /*! determines if this object is contained in a SimGroup and if so, which one.
  672. @return Returns the ID of the SimGroup this shape is in or zero if the shape is not contained in a SimGroup
  673. @see SimGroup, getInternalName, setInternalName, isChildOfGroup
  674. */
  675. ConsoleMethodWithDocs(SimObject, getGroup, ConsoleInt, 2, 2, ())
  676. {
  677. SimGroup *grp = object->getGroup();
  678. if(!grp)
  679. return -1;
  680. return grp->getId();
  681. }
  682. /*! @} */ // member group Grouping
  683. /*! Use the delete method to delete this object.
  684. When an object is deleted, it automatically
  685. + Unregisters its ID and name (if it has one) with the engine.
  686. + Removes itself from any SimGroup or SimSet it may be a member of.
  687. + (eventually) returns the memory associated with itself and its non-dynamic members.
  688. + Cancels all pending %obj.schedule() events.
  689. For objects in the GameBase, ScriptObject, or GUIControl hierarchies, an object will first: Call the onRemove() method for the object's namespace
  690. @return No return value.
  691. */
  692. ConsoleMethodWithDocs(SimObject, delete, ConsoleVoid, 2, 2, ())
  693. {
  694. object->deleteObject();
  695. }
  696. /*! Clones the object.
  697. @param copyDynamicFields Whether the dynamic fields should be copied to the cloned object or not. Optional: Defaults to false.
  698. @return (newObjectID) The newly cloned object's id if successful, otherwise a 0.
  699. */
  700. ConsoleMethodWithDocs(SimObject, clone, ConsoleInt, 2, 3, ([copyDynamicFields = false]?))
  701. {
  702. // Fetch copy dynamic fields flag.
  703. const bool copyDynamicFields = ( argc >= 3 ) ? dAtob( argv[2] ) : false;
  704. // Clone Object.
  705. SimObject* pClonedObject = object->clone( copyDynamicFields );
  706. // Finish if object was not cloned.
  707. if ( pClonedObject == NULL )
  708. return 0;
  709. return pClonedObject->getId();
  710. }
  711. /*! Takes all values from one object and puts them into anther object of the same class. This includes dynamic fields.
  712. @return No return value.
  713. */
  714. ConsoleMethodWithDocs(SimObject, assignFieldsFrom, ConsoleVoid, 3, 3, (SimObject))
  715. {
  716. // Find the specified object.
  717. SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
  718. // Did we find the object?
  719. if (!pSimObject)
  720. {
  721. // No, so warn.
  722. Con::warnf("SimObject::assignFieldsFrom() - Could not find the source object '%s'.", argv[2]);
  723. return;
  724. }
  725. // Do the objects have the same class?
  726. if (object->getClassRep() != pSimObject->getClassRep())
  727. {
  728. // No, so warn.
  729. Con::warnf("SimObject::assignFieldsFrom() - target object and source object must have the same class.");
  730. return;
  731. }
  732. object->assignFieldsFrom(pSimObject);
  733. }
  734. /*! @name Timer/Scheduled Events
  735. Perform timed callbacks on the object.
  736. @{
  737. */
  738. /*! Starts a periodic timer for this object.
  739. Sets a timer on the object that, when it expires, will cause the object to execute the given callback function.
  740. The timer event will continue to occur at regular intervals until stopTimer() is called or the timer expires.
  741. @param callbackFunction The name of the callback function to call for each timer repetition.
  742. @param timePeriod The period of time (in milliseconds) between each callback.
  743. @param repeat The number of times the timer should repeat. If not specified or zero then it will run infinitely.
  744. @return No return Value.
  745. */
  746. ConsoleMethodWithDocs(SimObject, startTimer, ConsoleBool, 4, 5, (callbackFunction, float timePeriod, [repeat]?))
  747. {
  748. // Is the periodic timer running?
  749. if ( object->getPeriodicTimerID() != 0 )
  750. {
  751. // Yes, so cancel it.
  752. Sim::cancelEvent( object->getPeriodicTimerID() );
  753. // Reset Timer ID.
  754. object->setPeriodicTimerID( 0 );
  755. }
  756. // Fetch the callback function.
  757. StringTableEntry callbackFunction = StringTable->insert( argv[2] );
  758. // Does the function exist?
  759. if ( !object->isMethod( callbackFunction ) )
  760. {
  761. // No, so warn.
  762. Con::warnf("SimObject::startTimer() - The callback function of '%s' does not exist.", callbackFunction );
  763. return false;
  764. }
  765. // Fetch the time period.
  766. const S32 timePeriod = dAtoi(argv[3]);
  767. // Is the time period valid?
  768. if ( timePeriod < 1 )
  769. {
  770. // No, so warn.
  771. Con::warnf("SimObject::startTimer() - The time period of '%d' is invalid.", timePeriod );
  772. return false;
  773. }
  774. // Fetch the repeat count.
  775. const S32 repeat = argc >= 5 ? dAtoi(argv[4]) : 0;
  776. // Create Timer Event.
  777. SimObjectTimerEvent* pEvent = new SimObjectTimerEvent( callbackFunction, (U32)timePeriod, (U32)repeat );
  778. // Post Event.
  779. object->setPeriodicTimerID( Sim::postEvent( object, pEvent, Sim::getCurrentTime() + timePeriod ) );
  780. return true;
  781. }
  782. //-----------------------------------------------------------------------------
  783. /*! Stops the periodic timer for this object.
  784. @return No return Value.
  785. */
  786. ConsoleMethodWithDocs(SimObject, stopTimer, ConsoleVoid, 2, 2, ())
  787. {
  788. // Finish if the periodic timer isn't running.
  789. if ( object->getPeriodicTimerID() == 0 )
  790. return;
  791. // Cancel It.
  792. Sim::cancelEvent( object->getPeriodicTimerID() );
  793. // Reset Timer ID.
  794. object->setPeriodicTimerID( 0 );
  795. }
  796. //-----------------------------------------------------------------------------
  797. /*! Checks whether the periodic timer is active for this object or not.
  798. @return Whether the periodic timer is active for this object or not.
  799. */
  800. ConsoleMethodWithDocs(SimObject, isTimerActive, ConsoleBool, 2, 2, ())
  801. {
  802. return object->isPeriodicTimerActive();
  803. }
  804. /*! schedule an action to be executed upon this object in the future.
  805. @param time Time in milliseconds till action is scheduled to occur.
  806. @param command Name of the command to execute. This command must be scoped to this object
  807. (i.e. It must exist in the namespace of the object), otherwise the schedule call will fail.
  808. @param arg1...argN These are optional arguments which will be passed to the command.
  809. This version of schedule automatically passes the ID of %obj as arg0 to command.
  810. @return Returns an integer schedule ID.
  811. The major difference between this and the ::schedule() console function is that if this object is deleted prior
  812. to the scheduled event, the event is automatically canceled. Times should not be treated as exact since some
  813. 'simulation delay' is to be expected. The minimum resolution for a scheduled event is 32 ms, or one tick.
  814. The existence of command is not validated. If you pass an invalid console method name, the
  815. schedule() method will still return a schedule ID, but the subsequent event will fail silently.
  816. To manipulate the scheduled event, use the id returned with the system schedule functions.
  817. @see ::schedule
  818. */
  819. ConsoleMethodWithDocs(SimObject,schedule, ConsoleInt, 4, 0, (time , command , [arg]* ))
  820. {
  821. U32 timeDelta = U32(dAtof(argv[2]));
  822. argv[2] = argv[3];
  823. argv[3] = argv[1];
  824. SimConsoleEvent *evt = new SimConsoleEvent(argc - 2, argv + 2, true);
  825. S32 ret = Sim::postEvent(object, evt, Sim::getCurrentTime() + timeDelta);
  826. // #ifdef DEBUG
  827. // Con::printf("obj %s schedule(%s) = %d", argv[3], argv[2], ret);
  828. // Con::executef(1, "backtrace");
  829. // #endif
  830. return ret;
  831. }
  832. /*! @} */ // member group Timer Events
  833. /*! @name member group Object to Object Events
  834. Raise events for listening objects to consume.
  835. @{
  836. */
  837. /*! Starts listening to another object.
  838. @param SimObject The object that will be posting events.
  839. @return No return value.
  840. */
  841. ConsoleMethodWithDocs(SimObject, startListening, ConsoleVoid, 3, 3, (SimObject))
  842. {
  843. // Find the specified object.
  844. SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
  845. // Did we find the object?
  846. if (!pSimObject)
  847. {
  848. // No, so warn.
  849. Con::warnf("SimObject::startListening() - Could not find the specified object '%s'.", argv[2]);
  850. return;
  851. }
  852. // Start Listening
  853. pSimObject->addListener(object->getIdString());
  854. }
  855. /*! Stops listening to another object.
  856. @param SimObject The object that will be posting events.
  857. @return No return value.
  858. */
  859. ConsoleMethodWithDocs(SimObject, stopListening, ConsoleVoid, 3, 3, (SimObject))
  860. {
  861. // Find the specified object.
  862. SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
  863. // Did we find the object?
  864. if (!pSimObject)
  865. {
  866. // No, so warn.
  867. Con::warnf("SimObject::stopListening() - Could not find the specified object '%s'.", argv[2]);
  868. return;
  869. }
  870. // Stop Listening
  871. pSimObject->removeListener(object->getIdString());
  872. }
  873. /*! Adds an object so that it receives events from this object.
  874. @param SimObject The object that will be listening to events.
  875. @return No return value.
  876. */
  877. ConsoleMethodWithDocs(SimObject, addListener, ConsoleVoid, 3, 3, (SimObject))
  878. {
  879. // Find the specified object.
  880. SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
  881. // Did we find the object?
  882. if (!pSimObject)
  883. {
  884. // No, so warn.
  885. Con::warnf("SimObject::addListener() - Could not find the specified object '%s'.", argv[2]);
  886. return;
  887. }
  888. // Start Listening
  889. object->addListener(pSimObject->getIdString());
  890. }
  891. /*! Removes an object so that it no longer receives events from this object.
  892. @param SimObject The object that will stop listening to events.
  893. @return No return value.
  894. */
  895. ConsoleMethodWithDocs(SimObject, removeListener, ConsoleVoid, 3, 3, (SimObject))
  896. {
  897. // Find the specified object.
  898. SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
  899. // Did we find the object?
  900. if (!pSimObject)
  901. {
  902. // No, so warn.
  903. Con::warnf("SimObject::removeListener() - Could not find the specified object '%s'.", argv[2]);
  904. return;
  905. }
  906. // Start Listening
  907. object->removeListener(pSimObject->getIdString());
  908. }
  909. /*! Removes all listeners from this object.
  910. @return No return value.
  911. */
  912. ConsoleMethodWithDocs(SimObject, removeAllListeners, ConsoleVoid, 2, 2, ())
  913. {
  914. // Start Listening
  915. object->removeAllListeners();
  916. }
  917. /*! Raises an event on all listening objects.
  918. @param eventName The name of the event to raise. The actual function called on listeners will begin with "on" followed by the event name.
  919. @param data Any data that should be passed on to the listeners.
  920. @return No return value.
  921. */
  922. ConsoleMethodWithDocs(SimObject, postEvent, ConsoleVoid, 3, 4, (String eventName, String data))
  923. {
  924. if (argc < 3)
  925. {
  926. Con::warnf("SimObject::postEvent() - Invalid number of parameters. You must include an Event Name.");
  927. return;
  928. }
  929. // Start Listening
  930. object->postEvent(argv[2], argc > 3 ? argv[3] : "");
  931. }
  932. /*! @} */ // member group Object to Object Events
  933. ConsoleMethodRootGroupEndWithDocs(SimObject)