simObject.cpp 96 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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/platformMemory.h"
  24. #include "console/simObject.h"
  25. #include "console/console.h"
  26. #include "console/consoleInternal.h"
  27. #include "console/engineAPI.h"
  28. #include "console/simFieldDictionary.h"
  29. #include "console/simPersistID.h"
  30. #include "console/typeValidators.h"
  31. #include "console/arrayObject.h"
  32. #include "console/codeBlock.h"
  33. #include "core/frameAllocator.h"
  34. #include "core/stream/fileStream.h"
  35. #include "core/fileObject.h"
  36. #include "persistence/taml/tamlCustom.h"
  37. IMPLEMENT_CONOBJECT( SimObject );
  38. // See full description in the new CHM manual
  39. ConsoleDocClass( SimObject,
  40. "@brief Base class for almost all objects involved in the simulation.\n\n"
  41. "@ingroup Console\n"
  42. );
  43. bool SimObject::smForceId = false;
  44. SimObjectId SimObject::smForcedId = 0;
  45. namespace Sim
  46. {
  47. // Defined in simManager.cpp
  48. extern SimGroup *gRootGroup;
  49. extern SimManagerNameDictionary *gNameDictionary;
  50. extern SimIdDictionary *gIdDictionary;
  51. extern U32 gNextObjectId;
  52. }
  53. //-----------------------------------------------------------------------------
  54. SimObject::SimObject()
  55. {
  56. objectName = NULL;
  57. mOriginalName = NULL;
  58. mInternalName = NULL;
  59. nextNameObject = (SimObject*)-1;
  60. nextManagerNameObject = (SimObject*)-1;
  61. nextIdObject = NULL;
  62. mFilename = NULL;
  63. mDeclarationLine = -1;
  64. mId = 0;
  65. mIdString[ 0 ] = '\0';
  66. mGroup = 0;
  67. mNameSpace = NULL;
  68. mNotifyList = NULL;
  69. mFlags.set( ModStaticFields | ModDynamicFields );
  70. mFieldDictionary = NULL;
  71. mCanSaveFieldDictionary = true;
  72. mClassName = NULL;
  73. mSuperClassName = NULL;
  74. mCopySource = NULL;
  75. mPersistentId = NULL;
  76. }
  77. //-----------------------------------------------------------------------------
  78. SimObject::~SimObject()
  79. {
  80. if( mFieldDictionary )
  81. {
  82. delete mFieldDictionary;
  83. mFieldDictionary = NULL;
  84. }
  85. // Release persistent ID.
  86. if( mPersistentId )
  87. {
  88. mPersistentId->unresolve();
  89. mPersistentId->decRefCount();
  90. mPersistentId = NULL;
  91. }
  92. if( mCopySource )
  93. mCopySource->unregisterReference( &mCopySource );
  94. AssertFatal(nextNameObject == (SimObject*)-1,avar(
  95. "SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
  96. objectName, mId));
  97. AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
  98. "SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
  99. objectName,mId));
  100. AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
  101. "missing call to SimObject::onRemove");
  102. }
  103. //-----------------------------------------------------------------------------
  104. bool SimObject::processArguments(S32 argc, ConsoleValueRef *argv)
  105. {
  106. return argc == 0;
  107. }
  108. //-----------------------------------------------------------------------------
  109. void SimObject::initPersistFields()
  110. {
  111. addGroup( "Ungrouped" );
  112. addProtectedField( "name", TypeName, Offset(objectName, SimObject), &setProtectedName, &defaultProtectedGetFn,
  113. "Optional global name of this object." );
  114. endGroup( "Ungrouped" );
  115. addGroup( "Object" );
  116. addField( "internalName", TypeString, Offset(mInternalName, SimObject),
  117. "Optional name that may be used to lookup this object within a SimSet.");
  118. addProtectedField( "parentGroup", TYPEID< SimObject >(), Offset(mGroup, SimObject), &setProtectedParent, &defaultProtectedGetFn,
  119. "Group hierarchy parent of the object." );
  120. addProtectedField( "class", TypeString, Offset(mClassName, SimObject), &setClass, &defaultProtectedGetFn,
  121. "Script class of object." );
  122. addProtectedField( "superClass", TypeString, Offset(mSuperClassName, SimObject), &setSuperClass, &defaultProtectedGetFn,
  123. "Script super-class of object." );
  124. // For legacy support
  125. addProtectedField( "className", TypeString, Offset(mClassName, SimObject), &setClass, &defaultProtectedGetFn,
  126. "Script class of object.", AbstractClassRep::FIELD_HideInInspectors );
  127. endGroup( "Object" );
  128. addGroup( "Editing" );
  129. addProtectedField( "hidden", TypeBool, NULL,
  130. &_setHidden, &_getHidden,
  131. "Whether the object is visible." );
  132. addProtectedField( "locked", TypeBool, NULL,
  133. &_setLocked, &_getLocked,
  134. "Whether the object can be edited." );
  135. endGroup( "Editing" );
  136. addGroup( "Persistence" );
  137. addProtectedField( "canSave", TypeBool, Offset( mFlags, SimObject ),
  138. &_setCanSave, &_getCanSave,
  139. "Whether the object can be saved out. If false, the object is purely transient in nature." );
  140. addField( "canSaveDynamicFields", TypeBool, Offset(mCanSaveFieldDictionary, SimObject),
  141. "True if dynamic fields (added at runtime) should be saved. Defaults to true." );
  142. addProtectedField( "persistentId", TypePID, Offset( mPersistentId, SimObject ),
  143. &_setPersistentID, &defaultProtectedGetFn,
  144. "The universally unique identifier for the object." );
  145. endGroup( "Persistence" );
  146. Parent::initPersistFields();
  147. }
  148. //-----------------------------------------------------------------------------
  149. String SimObject::describeSelf() const
  150. {
  151. String desc = Parent::describeSelf();
  152. if( mId != 0 )
  153. desc = avar( "%s|id: %i", desc.c_str(), mId );
  154. if( objectName )
  155. desc = avar( "%s|name: %s", desc.c_str(), objectName );
  156. if( mInternalName )
  157. desc = avar( "%s|internal: %s", desc.c_str(), mInternalName );
  158. if( mNameSpace )
  159. desc = avar( "%s|nspace: %s", desc.c_str(), mNameSpace->mName );
  160. if( mGroup )
  161. desc = avar( "%s|group: %s", desc.c_str(), mGroup->getName() );
  162. if( mCopySource )
  163. desc = avar( "%s|copy: %s", desc.c_str(), mCopySource->getName() );
  164. if( mPersistentId )
  165. desc = avar( "%s|pid: %s", desc.c_str(), mPersistentId->getUUID().toString().c_str() );
  166. return desc;
  167. }
  168. //=============================================================================
  169. // Persistence.
  170. //=============================================================================
  171. // MARK: ---- Persistence ----
  172. //-----------------------------------------------------------------------------
  173. bool SimObject::writeField(StringTableEntry fieldname, const char* value)
  174. {
  175. // Don't write empty fields.
  176. if (!value || !*value)
  177. return false;
  178. // Don't write owner field for components
  179. static StringTableEntry sOwner = StringTable->insert( "owner" );
  180. if( fieldname == sOwner )
  181. return false;
  182. // Don't write ParentGroup
  183. static StringTableEntry sParentGroup = StringTable->insert( "parentGroup" );
  184. if( fieldname == sParentGroup )
  185. return false;
  186. // Don't write name, is within the parenthesis already
  187. static StringTableEntry sName = StringTable->insert( "name" );
  188. if( fieldname == sName )
  189. return false;
  190. // Don't write className, it is read for legacy support but we
  191. // write it out as class.
  192. static StringTableEntry sClassName = StringTable->insert( "className" );
  193. if( fieldname == sClassName )
  194. return false;
  195. // Write persistent ID only if present.
  196. static StringTableEntry sPersistentId = StringTable->insert( "persistentId" );
  197. if( fieldname == sPersistentId && ( !value || !value[ 0 ] ) )
  198. return false;
  199. // Don't write hidden and locked flags if they are at their default value.
  200. static StringTableEntry sHidden = StringTable->insert( "hidden" );
  201. static StringTableEntry sLocked = StringTable->insert( "locked" );
  202. if( fieldname == sHidden && !dAtob( value ) )
  203. return false;
  204. if( fieldname == sLocked && !dAtob( value ) )
  205. return false;
  206. return true;
  207. }
  208. //-----------------------------------------------------------------------------
  209. void SimObject::writeFields(Stream &stream, U32 tabStop)
  210. {
  211. // Write static fields.
  212. const AbstractClassRep::FieldList &list = getFieldList();
  213. for(U32 i = 0; i < list.size(); i++)
  214. {
  215. const AbstractClassRep::Field* f = &list[i];
  216. // Skip the special field types.
  217. if ( f->type >= AbstractClassRep::ARCFirstCustomField )
  218. continue;
  219. for(U32 j = 0; S32(j) < f->elementCount; j++)
  220. {
  221. char array[8];
  222. dSprintf( array, 8, "%d", j );
  223. const char *val = getDataField(StringTable->insert( f->pFieldname ), array );
  224. // Make a copy for the field check.
  225. if (!val)
  226. continue;
  227. U32 nBufferSize = dStrlen( val ) + 1;
  228. FrameTemp<char> valCopy( nBufferSize );
  229. dStrcpy( (char *)valCopy, val );
  230. if (!writeField(f->pFieldname, valCopy))
  231. continue;
  232. val = valCopy;
  233. U32 expandedBufferSize = ( nBufferSize * 2 ) + dStrlen(f->pFieldname) + 32;
  234. FrameTemp<char> expandedBuffer( expandedBufferSize );
  235. if(f->elementCount == 1)
  236. dSprintf(expandedBuffer, expandedBufferSize, "%s = \"", f->pFieldname);
  237. else
  238. dSprintf(expandedBuffer, expandedBufferSize, "%s[%d] = \"", f->pFieldname, j);
  239. // detect and collapse relative path information
  240. char fnBuf[1024];
  241. if (f->type == TypeFilename ||
  242. f->type == TypeStringFilename ||
  243. f->type == TypeImageFilename ||
  244. f->type == TypePrefabFilename ||
  245. f->type == TypeShapeFilename)
  246. {
  247. Con::collapseScriptFilename(fnBuf, 1024, val);
  248. val = fnBuf;
  249. }
  250. expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), val);
  251. dStrcat(expandedBuffer, "\";\r\n");
  252. stream.writeTabs(tabStop);
  253. stream.write(dStrlen(expandedBuffer),expandedBuffer);
  254. }
  255. }
  256. // Write dynamic fields, if enabled.
  257. if(mFieldDictionary && mCanSaveFieldDictionary)
  258. mFieldDictionary->writeFields(this, stream, tabStop);
  259. }
  260. //-----------------------------------------------------------------------------
  261. void SimObject::write(Stream &stream, U32 tabStop, U32 flags)
  262. {
  263. if( !getCanSave() && !( flags & IgnoreCanSave ) )
  264. return;
  265. // Only output selected objects if they want that.
  266. if((flags & SelectedOnly) && !isSelected())
  267. return;
  268. stream.writeTabs(tabStop);
  269. char buffer[1024];
  270. dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() && !(flags & NoName) ? getName() : "");
  271. stream.write(dStrlen(buffer), buffer);
  272. writeFields(stream, tabStop + 1);
  273. stream.writeTabs(tabStop);
  274. stream.write(4, "};\r\n");
  275. }
  276. //-----------------------------------------------------------------------------
  277. bool SimObject::save(const char *pcFileName, bool bOnlySelected, const char *preappend)
  278. {
  279. static const char *beginMessage = "//--- OBJECT WRITE BEGIN ---";
  280. static const char *endMessage = "//--- OBJECT WRITE END ---";
  281. FileStream *stream;
  282. FileObject f;
  283. f.readMemory(pcFileName);
  284. // check for flags <selected, ...>
  285. U32 writeFlags = 0;
  286. if(bOnlySelected)
  287. writeFlags |= SimObject::SelectedOnly;
  288. if((stream = FileStream::createAndOpen( pcFileName, Torque::FS::File::Write )) == NULL)
  289. return false;
  290. char docRoot[256];
  291. char modRoot[256];
  292. dStrcpy(docRoot, pcFileName);
  293. char *p = dStrrchr(docRoot, '/');
  294. if (p) *++p = '\0';
  295. else docRoot[0] = '\0';
  296. dStrcpy(modRoot, pcFileName);
  297. p = dStrchr(modRoot, '/');
  298. if (p) *++p = '\0';
  299. else modRoot[0] = '\0';
  300. Con::setVariable("$DocRoot", docRoot);
  301. Con::setVariable("$ModRoot", modRoot);
  302. const char *buffer;
  303. while(!f.isEOF())
  304. {
  305. buffer = (const char *) f.readLine();
  306. if(!dStrcmp(buffer, beginMessage))
  307. break;
  308. stream->write(dStrlen(buffer), buffer);
  309. stream->write(2, "\r\n");
  310. }
  311. stream->write(dStrlen(beginMessage), beginMessage);
  312. stream->write(2, "\r\n");
  313. if ( preappend != NULL )
  314. stream->write(dStrlen(preappend),preappend);
  315. write(*stream, 0, writeFlags);
  316. stream->write(dStrlen(endMessage), endMessage);
  317. stream->write(2, "\r\n");
  318. while(!f.isEOF())
  319. {
  320. buffer = (const char *) f.readLine();
  321. if(!dStrcmp(buffer, endMessage))
  322. break;
  323. }
  324. while(!f.isEOF())
  325. {
  326. buffer = (const char *) f.readLine();
  327. stream->write(dStrlen(buffer), buffer);
  328. stream->write(2, "\r\n");
  329. }
  330. Con::setVariable("$DocRoot", NULL);
  331. Con::setVariable("$ModRoot", NULL);
  332. delete stream;
  333. return true;
  334. }
  335. //-----------------------------------------------------------------------------
  336. SimPersistID* SimObject::getOrCreatePersistentId()
  337. {
  338. if( !mPersistentId )
  339. {
  340. mPersistentId = SimPersistID::create( this );
  341. mPersistentId->incRefCount();
  342. }
  343. return mPersistentId;
  344. }
  345. void SimObject::onTamlCustomRead(TamlCustomNodes const& customNodes)
  346. {
  347. // Debug Profiling.
  348. //PROFILE_SCOPE(SimObject_OnTamlCustomRead);
  349. // Fetch field list.
  350. const AbstractClassRep::FieldList& fieldList = getFieldList();
  351. const U32 fieldCount = fieldList.size();
  352. for (U32 index = 0; index < fieldCount; ++index)
  353. {
  354. // Fetch field.
  355. const AbstractClassRep::Field* pField = &fieldList[index];
  356. // Ignore if field not appropriate.
  357. if (pField->type == AbstractClassRep::StartArrayFieldType || pField->elementCount > 1)
  358. {
  359. // Find cell custom node.
  360. const TamlCustomNode* pCustomCellNodes = NULL;
  361. if (pField->pGroupname != NULL)
  362. pCustomCellNodes = customNodes.findNode(pField->pGroupname);
  363. if (!pCustomCellNodes)
  364. {
  365. char* niceFieldName = const_cast<char *>(pField->pFieldname);
  366. niceFieldName[0] = dToupper(niceFieldName[0]);
  367. String str_niceFieldName = String(niceFieldName);
  368. pCustomCellNodes = customNodes.findNode(str_niceFieldName + "s");
  369. }
  370. // Continue if we have explicit cells.
  371. if (pCustomCellNodes != NULL)
  372. {
  373. // Fetch children cell nodes.
  374. const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
  375. U8 idx = 0;
  376. // Iterate cells.
  377. for (TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr)
  378. {
  379. char buf[5];
  380. dSprintf(buf, 5, "%d", idx);
  381. // Fetch cell node.
  382. TamlCustomNode* pCellNode = *cellNodeItr;
  383. // Fetch node name.
  384. StringTableEntry nodeName = pCellNode->getNodeName();
  385. // Is this a valid alias?
  386. if (nodeName != pField->pFieldname)
  387. {
  388. // No, so warn.
  389. Con::warnf("SimObject::onTamlCustomRead() - Encountered an unknown custom name of '%s'. Only '%s' is valid.", nodeName, pField->pFieldname);
  390. continue;
  391. }
  392. // Fetch fields.
  393. const TamlCustomFieldVector& fields = pCellNode->getFields();
  394. // Iterate property fields.
  395. for (TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr)
  396. {
  397. // Fetch field.
  398. const TamlCustomField* pField = *fieldItr;
  399. // Fetch field name.
  400. StringTableEntry fieldName = pField->getFieldName();
  401. const AbstractClassRep::Field* field = findField(fieldName);
  402. // Check common fields.
  403. if (field)
  404. {
  405. setDataField(fieldName, buf, pField->getFieldValue());
  406. }
  407. else
  408. {
  409. // Unknown name so warn.
  410. Con::warnf("SimObject::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName);
  411. continue;
  412. }
  413. }
  414. idx++;
  415. }
  416. }
  417. }
  418. }
  419. }
  420. //-----------------------------------------------------------------------------
  421. bool SimObject::_setPersistentID( void* object, const char* index, const char* data )
  422. {
  423. SimObject* simObject = reinterpret_cast< SimObject* >( object );
  424. // Make sure we don't already have a PID.
  425. if( simObject->getPersistentId() )
  426. {
  427. Con::errorf( "SimObject::_setPersistentID - cannot set a persistent ID on an object that already has a persistent ID assigned." );
  428. return false;
  429. }
  430. SimPersistID* pid;
  431. Con::setData( TypePID, &pid, 0, 1, &data );
  432. if ( !pid )
  433. return false;
  434. // Make sure it's not already bound to an object.
  435. if( pid->getObject() )
  436. {
  437. AssertWarn( pid->getObject() != simObject, "Sim::_setPersistentID - PID is bound to this object yet not assigned to it!" );
  438. SimObject* otherObj = pid->getObject();
  439. Con::errorf( "SimObject::_setPersistentID - UUID is already used by another object: '%s' -> %i:%s (%s)",
  440. data, otherObj->getId(), otherObj->getClassName(), otherObj->getName() );
  441. return false;
  442. }
  443. pid->resolve( simObject );
  444. pid->incRefCount();
  445. simObject->mPersistentId = pid;
  446. return false;
  447. }
  448. //-----------------------------------------------------------------------------
  449. void SimObject::setFilename( const char* file )
  450. {
  451. if( file )
  452. mFilename = StringTable->insert( file );
  453. else
  454. mFilename = StringTable->EmptyString();
  455. }
  456. //-----------------------------------------------------------------------------
  457. void SimObject::setDeclarationLine(U32 lineNumber)
  458. {
  459. mDeclarationLine = lineNumber;
  460. }
  461. //=============================================================================
  462. // Management.
  463. //=============================================================================
  464. // MARK: ---- Management ----
  465. //-----------------------------------------------------------------------------
  466. bool SimObject::registerObject()
  467. {
  468. AssertFatal( !mFlags.test( Added ), "reigsterObject - Object already registered!");
  469. mFlags.clear(Deleted | Removed);
  470. if(smForceId)
  471. {
  472. setId(smForcedId);
  473. smForceId = false;
  474. }
  475. if( !mId )
  476. {
  477. mId = Sim::gNextObjectId++;
  478. dSprintf( mIdString, sizeof( mIdString ), "%u", mId );
  479. }
  480. AssertFatal(Sim::gIdDictionary && Sim::gNameDictionary,
  481. "SimObject::registerObject - tried to register an object before Sim::init()!");
  482. Sim::gIdDictionary->insert(this);
  483. Sim::gNameDictionary->insert(this);
  484. // Notify object
  485. bool ret = onAdd();
  486. if(!ret)
  487. unregisterObject();
  488. AssertFatal(!ret || isProperlyAdded(), "Object did not call SimObject::onAdd()");
  489. return ret;
  490. }
  491. //-----------------------------------------------------------------------------
  492. void SimObject::unregisterObject()
  493. {
  494. mFlags.set(Removed);
  495. // Notify object first
  496. onRemove();
  497. // Clear out any pending notifications before
  498. // we call our own, just in case they delete
  499. // something that we have referenced.
  500. clearAllNotifications();
  501. // Notify all objects that are waiting for delete
  502. // messages
  503. if (getGroup())
  504. getGroup()->removeObject(this);
  505. processDeleteNotifies();
  506. // Do removals from the Sim.
  507. Sim::gNameDictionary->remove(this);
  508. Sim::gIdDictionary->remove(this);
  509. Sim::cancelPendingEvents(this);
  510. }
  511. //-----------------------------------------------------------------------------
  512. void SimObject::deleteObject()
  513. {
  514. Parent::destroySelf();
  515. }
  516. //-----------------------------------------------------------------------------
  517. void SimObject::_destroySelf()
  518. {
  519. AssertFatal( !isDeleted(), "SimObject::destroySelf - Object has already been deleted" );
  520. AssertFatal( !isRemoved(), "SimObject::destroySelf - Object in the process of being removed" );
  521. mFlags.set( Deleted );
  522. if( mFlags.test( Added ) )
  523. unregisterObject();
  524. Parent::_destroySelf();
  525. }
  526. //-----------------------------------------------------------------------------
  527. void SimObject::destroySelf()
  528. {
  529. // When using the legacy console interop, we don't delete objects
  530. // when their reference count drops to zero but rather defer their
  531. // deletion until deleteObject() is called.
  532. if( engineAPI::gUseConsoleInterop )
  533. return;
  534. Parent::destroySelf();
  535. }
  536. //-----------------------------------------------------------------------------
  537. class SimObjectDeleteEvent : public SimEvent
  538. {
  539. public:
  540. void process(SimObject *object)
  541. {
  542. object->deleteObject();
  543. }
  544. };
  545. void SimObject::safeDeleteObject()
  546. {
  547. Sim::postEvent( this, new SimObjectDeleteEvent, Sim::getCurrentTime() + 1 );
  548. }
  549. //-----------------------------------------------------------------------------
  550. void SimObject::setId(SimObjectId newId)
  551. {
  552. if(!mFlags.test(Added))
  553. mId = newId;
  554. else
  555. {
  556. // get this object out of the id dictionary if it's in it
  557. Sim::gIdDictionary->remove(this);
  558. // Free current Id.
  559. // Assign new one.
  560. mId = newId ? newId : Sim::gNextObjectId++;
  561. Sim::gIdDictionary->insert(this);
  562. }
  563. dSprintf( mIdString, sizeof( mIdString ), "%u", mId );
  564. }
  565. //-----------------------------------------------------------------------------
  566. void SimObject::assignName(const char *name)
  567. {
  568. if( objectName && !isNameChangeAllowed() )
  569. {
  570. Con::errorf( "SimObject::assignName - not allowed to change name of object '%s'", objectName );
  571. return;
  572. }
  573. // Added this assert 3/30/2007 because it is dumb to try to name
  574. // a SimObject the same thing as it's class name -patw
  575. //AssertFatal( dStricmp( getClassName(), name ), "Attempted to assign a name to a SimObject which matches it's type name." );
  576. if( dStricmp( getClassName(), name ) == 0 )
  577. Con::errorf( "SimObject::assignName - Assigning name '%s' to instance of object with type '%s'."
  578. " This can cause namespace linking issues.", getClassName(), name );
  579. StringTableEntry newName = NULL;
  580. if(name[0])
  581. newName = StringTable->insert(name);
  582. onNameChange( newName );
  583. if( mGroup )
  584. mGroup->mNameDictionary.remove( this );
  585. if( isProperlyAdded() )
  586. {
  587. unlinkNamespaces();
  588. Sim::gNameDictionary->remove( this );
  589. }
  590. objectName = newName;
  591. if( mGroup )
  592. mGroup->mNameDictionary.insert( this );
  593. if( isProperlyAdded() )
  594. {
  595. Sim::gNameDictionary->insert( this );
  596. linkNamespaces();
  597. }
  598. }
  599. //-----------------------------------------------------------------------------
  600. bool SimObject::registerObject(U32 id)
  601. {
  602. setId(id);
  603. return registerObject();
  604. }
  605. //-----------------------------------------------------------------------------
  606. bool SimObject::registerObject(const char *name)
  607. {
  608. assignName(name);
  609. return registerObject();
  610. }
  611. //-----------------------------------------------------------------------------
  612. bool SimObject::registerObject(const char *name, U32 id)
  613. {
  614. setId(id);
  615. assignName(name);
  616. return registerObject();
  617. }
  618. //=============================================================================
  619. // Introspection.
  620. //=============================================================================
  621. // MARK: ---- Introspection ----
  622. //-----------------------------------------------------------------------------
  623. bool SimObject::isMethod( const char* methodName )
  624. {
  625. if( !methodName || !methodName[0] )
  626. return false;
  627. StringTableEntry stname = StringTable->insert( methodName );
  628. if( getNamespace() )
  629. return ( getNamespace()->lookup( stname ) != NULL );
  630. return false;
  631. }
  632. //-----------------------------------------------------------------------------
  633. bool SimObject::isField( const char* fieldName, bool includeStatic, bool includeDynamic )
  634. {
  635. const char* strFieldName = StringTable->insert( fieldName );
  636. if( includeStatic && getClassRep()->findField( strFieldName ) )
  637. return true;
  638. if( includeDynamic && getFieldDictionary() && getFieldDictionary()->findDynamicField( strFieldName ) )
  639. return true;
  640. return false;
  641. }
  642. //-----------------------------------------------------------------------------
  643. void SimObject::assignDynamicFieldsFrom(SimObject* parent)
  644. {
  645. if(parent->mFieldDictionary)
  646. {
  647. if( mFieldDictionary == NULL )
  648. mFieldDictionary = new SimFieldDictionary;
  649. mFieldDictionary->assignFrom(parent->mFieldDictionary);
  650. }
  651. }
  652. //-----------------------------------------------------------------------------
  653. void SimObject::assignFieldsFrom(SimObject *parent)
  654. {
  655. // Only allow field assigns from objects of the same class or
  656. // a superclass.
  657. if( getClassRep()->isClass( parent->getClassRep() ) )
  658. {
  659. const AbstractClassRep::FieldList &list = parent->getFieldList();
  660. // copy out all the fields:
  661. for(U32 i = 0; i < list.size(); i++)
  662. {
  663. const AbstractClassRep::Field* f = &list[i];
  664. // Skip the special field types.
  665. if ( f->type >= AbstractClassRep::ARCFirstCustomField )
  666. continue;
  667. // Skip certain fields that we don't want to see copied so we don't
  668. // get error messages from their setters.
  669. static StringTableEntry sName = StringTable->insert( "name" );
  670. static StringTableEntry sPersistentId = StringTable->insert( "persistentId" );
  671. if( f->pFieldname == sName || f->pFieldname == sPersistentId )
  672. continue;
  673. S32 lastField = f->elementCount - 1;
  674. for(S32 j = 0; j <= lastField; j++)
  675. {
  676. const char* fieldVal = (*f->getDataFn)( parent, Con::getData(f->type, (void *) (((const char *)parent) + f->offset), j, f->table, f->flag));
  677. // Don't assign the field is the pointer is null or if
  678. // the field is not empty and writing it was disallowed.
  679. if ( !fieldVal || ( fieldVal[0] && !writeField( f->pFieldname, fieldVal ) ) )
  680. continue;
  681. // code copied from SimObject::setDataField().
  682. // TODO: paxorr: abstract this into a better setData / getData that considers prot fields.
  683. FrameTemp<char> buffer(2048);
  684. FrameTemp<char> bufferSecure(2048); // This buffer is used to make a copy of the data
  685. ConsoleBaseType *cbt = ConsoleBaseType::getType( f->type );
  686. const char* szBuffer = cbt->prepData( fieldVal, buffer, 2048 );
  687. dMemset( bufferSecure, 0, 2048 );
  688. dMemcpy( bufferSecure, szBuffer, dStrlen( szBuffer ) );
  689. if((*f->setDataFn)( this, NULL, bufferSecure ) )
  690. Con::setData(f->type, (void *) (((const char *)this) + f->offset), j, 1, &fieldVal, f->table);
  691. }
  692. }
  693. }
  694. else
  695. {
  696. Con::errorf( "SimObject::assignFieldsFrom() - cannot assigned fields from object of type '%s' to object of type '%s'",
  697. parent->getClassName(), getClassName()
  698. );
  699. }
  700. assignDynamicFieldsFrom(parent);
  701. }
  702. //-----------------------------------------------------------------------------
  703. void SimObject::setDataField(StringTableEntry slotName, const char *array, const char *value)
  704. {
  705. // first search the static fields if enabled
  706. if(mFlags.test(ModStaticFields))
  707. {
  708. const AbstractClassRep::Field *fld = findField(slotName);
  709. if(fld)
  710. {
  711. // Skip the special field types as they are not data.
  712. if ( fld->type >= AbstractClassRep::ARCFirstCustomField )
  713. return;
  714. S32 array1 = array ? dAtoi(array) : 0;
  715. if(array1 >= 0 && array1 < fld->elementCount && fld->elementCount >= 1)
  716. {
  717. // If the set data notify callback returns true, then go ahead and
  718. // set the data, otherwise, assume the set notify callback has either
  719. // already set the data, or has deemed that the data should not
  720. // be set at all.
  721. FrameTemp<char> buffer(2048);
  722. FrameTemp<char> bufferSecure(2048); // This buffer is used to make a copy of the data
  723. // so that if the prep functions or any other functions use the string stack, the data
  724. // is not corrupted.
  725. ConsoleBaseType *cbt = ConsoleBaseType::getType( fld->type );
  726. AssertFatal( cbt != NULL, "Could not resolve Type Id." );
  727. const char* szBuffer = cbt->prepData( value, buffer, 2048 );
  728. dMemset( bufferSecure, 0, 2048 );
  729. dMemcpy( bufferSecure, szBuffer, dStrlen( szBuffer ) );
  730. if( (*fld->setDataFn)( this, array, bufferSecure ) )
  731. Con::setData(fld->type, (void *) (((const char *)this) + fld->offset), array1, 1, &value, fld->table);
  732. if(fld->validator)
  733. fld->validator->validateType(this, (void *) (((const char *)this) + fld->offset));
  734. onStaticModified( slotName, value );
  735. return;
  736. }
  737. if(fld->validator)
  738. fld->validator->validateType(this, (void *) (((const char *)this) + fld->offset));
  739. onStaticModified( slotName, value );
  740. return;
  741. }
  742. }
  743. if(mFlags.test(ModDynamicFields))
  744. {
  745. if(!mFieldDictionary)
  746. mFieldDictionary = new SimFieldDictionary;
  747. if(!array)
  748. {
  749. mFieldDictionary->setFieldValue(slotName, value);
  750. onDynamicModified( slotName, value );
  751. }
  752. else
  753. {
  754. char buf[256];
  755. dStrcpy(buf, slotName);
  756. dStrcat(buf, array);
  757. StringTableEntry permanentSlotName = StringTable->insert(buf);
  758. mFieldDictionary->setFieldValue(permanentSlotName, value);
  759. onDynamicModified( permanentSlotName, value );
  760. }
  761. }
  762. }
  763. //-----------------------------------------------------------------------------
  764. const char *SimObject::getDataField(StringTableEntry slotName, const char *array)
  765. {
  766. if(mFlags.test(ModStaticFields))
  767. {
  768. S32 array1 = array ? dAtoi(array) : -1;
  769. const AbstractClassRep::Field *fld = findField(slotName);
  770. if(fld)
  771. {
  772. if(array1 == -1 && fld->elementCount == 1)
  773. return (*fld->getDataFn)( this, Con::getData(fld->type, (void *) (((const char *)this) + fld->offset), 0, fld->table, fld->flag) );
  774. if(array1 >= 0 && array1 < fld->elementCount)
  775. return (*fld->getDataFn)( this, Con::getData(fld->type, (void *) (((const char *)this) + fld->offset), array1, fld->table, fld->flag) );// + typeSizes[fld.type] * array1));
  776. return "";
  777. }
  778. }
  779. if(mFlags.test(ModDynamicFields))
  780. {
  781. if(!mFieldDictionary)
  782. return "";
  783. if(!array)
  784. {
  785. if (const char* val = mFieldDictionary->getFieldValue(slotName))
  786. return val;
  787. }
  788. else
  789. {
  790. static char buf[256];
  791. dStrcpy(buf, slotName);
  792. dStrcat(buf, array);
  793. if (const char* val = mFieldDictionary->getFieldValue(StringTable->insert(buf)))
  794. return val;
  795. }
  796. }
  797. return "";
  798. }
  799. const char *SimObject::getPrefixedDataField(StringTableEntry fieldName, const char *array)
  800. {
  801. // Sanity!
  802. AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
  803. // Fetch field value.
  804. const char* pFieldValue = getDataField(fieldName, array);
  805. // Sanity.
  806. //AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
  807. if (!pFieldValue)
  808. return NULL;
  809. // Return without the prefix if there's no value.
  810. if (*pFieldValue == 0)
  811. return StringTable->EmptyString();
  812. // Fetch the field prefix.
  813. StringTableEntry fieldPrefix = getDataFieldPrefix(fieldName);
  814. // Sanity!
  815. AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
  816. // Calculate a buffer size including prefix.
  817. const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
  818. // Fetch a buffer.
  819. char* pValueBuffer = Con::getReturnBuffer(valueBufferSize);
  820. // Format the value buffer.
  821. dSprintf(pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue);
  822. return pValueBuffer;
  823. }
  824. //-----------------------------------------------------------------------------
  825. void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value)
  826. {
  827. // Sanity!
  828. AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
  829. AssertFatal(value != NULL, "Field value cannot be NULL.");
  830. // Set value without prefix if there's no value.
  831. if (*value == 0)
  832. {
  833. setDataField(fieldName, NULL, value);
  834. return;
  835. }
  836. // Fetch the field prefix.
  837. StringTableEntry fieldPrefix = getDataFieldPrefix(fieldName);
  838. // Sanity.
  839. AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
  840. // Do we have a field prefix?
  841. if (fieldPrefix == StringTable->EmptyString())
  842. {
  843. // No, so set the data field in the usual way.
  844. setDataField(fieldName, NULL, value);
  845. return;
  846. }
  847. // Yes, so fetch the length of the field prefix.
  848. const U32 fieldPrefixLength = dStrlen(fieldPrefix);
  849. // Yes, so does it start with the object field prefix?
  850. if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
  851. {
  852. // No, so set the data field in the usual way.
  853. setDataField(fieldName, NULL, value);
  854. return;
  855. }
  856. // Yes, so set the data excluding the prefix.
  857. setDataField(fieldName, NULL, value + fieldPrefixLength);
  858. }
  859. //-----------------------------------------------------------------------------
  860. const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType)
  861. {
  862. // Sanity!
  863. AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
  864. // Fetch field value.
  865. const char* pFieldValue = getDataField(fieldName, array);
  866. // Sanity.
  867. AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
  868. // Return the field if no field type is specified.
  869. if (fieldType == -1)
  870. return pFieldValue;
  871. // Return without the prefix if there's no value.
  872. if (*pFieldValue == 0)
  873. return StringTable->EmptyString();
  874. // Fetch the console base type.
  875. ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(fieldType);
  876. // Did we find the console base type?
  877. if (pConsoleBaseType == NULL)
  878. {
  879. // No, so warn.
  880. Con::warnf("getPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
  881. fieldType, fieldName, pFieldValue);
  882. }
  883. // Fetch the field prefix.
  884. StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
  885. // Sanity!
  886. AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
  887. // Calculate a buffer size including prefix.
  888. const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
  889. // Fetch a buffer.
  890. char* pValueBuffer = Con::getReturnBuffer(valueBufferSize);
  891. // Format the value buffer.
  892. dSprintf(pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue);
  893. return pValueBuffer;
  894. }
  895. //-----------------------------------------------------------------------------
  896. void SimObject::setPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const char *value, const S32 fieldType)
  897. {
  898. // Sanity!
  899. AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
  900. AssertFatal(value != NULL, "Field value cannot be NULL.");
  901. // Set value without prefix if no field type was specified.
  902. if (fieldType == -1)
  903. {
  904. setDataField(fieldName, NULL, value);
  905. return;
  906. }
  907. // Fetch the console base type.
  908. ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(fieldType);
  909. // Did we find the console base type?
  910. if (pConsoleBaseType == NULL)
  911. {
  912. // No, so warn.
  913. Con::warnf("setPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
  914. fieldType, fieldName, value);
  915. }
  916. // Set value without prefix if there's no value or we didn't find the console base type.
  917. if (*value == 0 || pConsoleBaseType == NULL)
  918. {
  919. setDataField(fieldName, NULL, value);
  920. return;
  921. }
  922. // Fetch the field prefix.
  923. StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
  924. // Sanity.
  925. AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
  926. // Do we have a field prefix?
  927. if (fieldPrefix == StringTable->EmptyString())
  928. {
  929. // No, so set the data field in the usual way.
  930. setDataField(fieldName, NULL, value);
  931. return;
  932. }
  933. // Yes, so fetch the length of the field prefix.
  934. const U32 fieldPrefixLength = dStrlen(fieldPrefix);
  935. // Yes, so does it start with the object field prefix?
  936. if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
  937. {
  938. // No, so set the data field in the usual way.
  939. setDataField(fieldName, NULL, value);
  940. return;
  941. }
  942. // Yes, so set the data excluding the prefix.
  943. setDataField(fieldName, NULL, value + fieldPrefixLength);
  944. }
  945. //-----------------------------------------------------------------------------
  946. StringTableEntry SimObject::getDataFieldPrefix(StringTableEntry fieldName)
  947. {
  948. // Sanity!
  949. AssertFatal(fieldName != NULL, "Cannot get field prefix with NULL field name.");
  950. // Find the field.
  951. const AbstractClassRep::Field* pField = findField(fieldName);
  952. // Return nothing if field was not found.
  953. if (pField == NULL)
  954. return StringTable->EmptyString();
  955. // Yes, so fetch the console base type.
  956. ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(pField->type);
  957. // Fetch the type prefix.
  958. return pConsoleBaseType->getTypePrefix();
  959. }
  960. //-----------------------------------------------------------------------------
  961. U32 SimObject::getDataFieldType( StringTableEntry slotName, const char* array )
  962. {
  963. const AbstractClassRep::Field* field = findField( slotName );
  964. if(field)
  965. return field->type;
  966. // Check dynamic fields
  967. if(!mFieldDictionary)
  968. return 0;
  969. if(array == NULL || *array == 0)
  970. return mFieldDictionary->getFieldType( slotName );
  971. else
  972. {
  973. static char buf[256];
  974. dStrcpy( buf, slotName );
  975. dStrcat( buf, array );
  976. return mFieldDictionary->getFieldType( StringTable->insert( buf ) );
  977. }
  978. }
  979. //-----------------------------------------------------------------------------
  980. void SimObject::setDataFieldType(const U32 fieldTypeId, StringTableEntry slotName, const char *array)
  981. {
  982. // This only works on dynamic fields, bail if we have no field dictionary
  983. if(!mFieldDictionary)
  984. return;
  985. if(array == NULL || *array == 0)
  986. {
  987. mFieldDictionary->setFieldType( slotName, fieldTypeId );
  988. onDynamicModified( slotName, mFieldDictionary->getFieldValue(slotName) );
  989. }
  990. else
  991. {
  992. static char buf[256];
  993. dStrcpy( buf, slotName );
  994. dStrcat( buf, array );
  995. mFieldDictionary->setFieldType( StringTable->insert( buf ), fieldTypeId );
  996. onDynamicModified( slotName, mFieldDictionary->getFieldValue(slotName) );
  997. }
  998. }
  999. //-----------------------------------------------------------------------------
  1000. void SimObject::setDataFieldType(const char *typeName, StringTableEntry slotName, const char *array)
  1001. {
  1002. // This only works on dynamic fields, bail if we have no field dictionary
  1003. if(!mFieldDictionary)
  1004. return;
  1005. if(array == NULL || *array == 0)
  1006. mFieldDictionary->setFieldType( slotName, typeName );
  1007. else
  1008. {
  1009. static char buf[256];
  1010. dStrcpy( buf, slotName );
  1011. dStrcat( buf, array );
  1012. StringTableEntry permanentSlotName = StringTable->insert(buf);
  1013. mFieldDictionary->setFieldType( permanentSlotName, typeName );
  1014. onDynamicModified( permanentSlotName, mFieldDictionary->getFieldValue(permanentSlotName) );
  1015. }
  1016. }
  1017. //-----------------------------------------------------------------------------
  1018. void SimObject::dumpClassHierarchy()
  1019. {
  1020. AbstractClassRep* pRep = getClassRep();
  1021. while(pRep)
  1022. {
  1023. Con::warnf("%s ->", pRep->getClassName());
  1024. pRep = pRep->getParentClass();
  1025. }
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. SimObject* SimObject::clone()
  1029. {
  1030. if( !getClassRep() )
  1031. return NULL;
  1032. ConsoleObject* conObject = getClassRep()->create();
  1033. if( !conObject )
  1034. return NULL;
  1035. SimObject* simObject = dynamic_cast< SimObject* >( conObject );
  1036. if( !simObject )
  1037. {
  1038. delete conObject;
  1039. return NULL;
  1040. }
  1041. simObject->assignFieldsFrom( this );
  1042. String name = Sim::getUniqueName( getName() );
  1043. if( !simObject->registerObject( name ) )
  1044. {
  1045. delete simObject;
  1046. return NULL;
  1047. }
  1048. if( getGroup() )
  1049. getGroup()->addObject( simObject );
  1050. return simObject;
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. SimObject* SimObject::deepClone()
  1054. {
  1055. return clone();
  1056. }
  1057. //=============================================================================
  1058. // Grouping.
  1059. //=============================================================================
  1060. // MARK: ---- Grouping ----
  1061. //-----------------------------------------------------------------------------
  1062. SimObject* SimObject::findObject( const char* )
  1063. {
  1064. return NULL;
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. bool SimObject::isChildOfGroup(SimGroup* pGroup)
  1068. {
  1069. if(!pGroup)
  1070. return false;
  1071. //if we *are* the group in question,
  1072. //return true:
  1073. if(pGroup == dynamic_cast<SimGroup*>(this))
  1074. return true;
  1075. SimGroup* temp = mGroup;
  1076. while(temp)
  1077. {
  1078. if(temp == pGroup)
  1079. return true;
  1080. temp = temp->mGroup;
  1081. }
  1082. return false;
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. bool SimObject::addToSet(SimObjectId spid)
  1086. {
  1087. if (mFlags.test(Added) == false)
  1088. return false;
  1089. SimObject* ptr = Sim::findObject(spid);
  1090. if (ptr)
  1091. {
  1092. SimSet* sp = dynamic_cast<SimSet*>(ptr);
  1093. AssertFatal(sp != 0,
  1094. "SimObject::addToSet: "
  1095. "ObjectId does not refer to a set object");
  1096. sp->addObject(this);
  1097. return true;
  1098. }
  1099. return false;
  1100. }
  1101. //-----------------------------------------------------------------------------
  1102. bool SimObject::addToSet(const char *ObjectName)
  1103. {
  1104. if (mFlags.test(Added) == false)
  1105. return false;
  1106. SimObject* ptr = Sim::findObject(ObjectName);
  1107. if (ptr)
  1108. {
  1109. SimSet* sp = dynamic_cast<SimSet*>(ptr);
  1110. AssertFatal(sp != 0,
  1111. "SimObject::addToSet: "
  1112. "ObjectName does not refer to a set object");
  1113. sp->addObject(this);
  1114. return true;
  1115. }
  1116. return false;
  1117. }
  1118. //-----------------------------------------------------------------------------
  1119. bool SimObject::removeFromSet(SimObjectId sid)
  1120. {
  1121. if (mFlags.test(Added) == false)
  1122. return false;
  1123. SimSet *set;
  1124. if(Sim::findObject(sid, set))
  1125. {
  1126. set->removeObject(this);
  1127. return true;
  1128. }
  1129. return false;
  1130. }
  1131. //-----------------------------------------------------------------------------
  1132. bool SimObject::removeFromSet(const char *objectName)
  1133. {
  1134. if (mFlags.test(Added) == false)
  1135. return false;
  1136. SimSet *set;
  1137. if(Sim::findObject(objectName, set))
  1138. {
  1139. set->removeObject(this);
  1140. return true;
  1141. }
  1142. return false;
  1143. }
  1144. //-----------------------------------------------------------------------------
  1145. void SimObject::dumpGroupHierarchy()
  1146. {
  1147. String className( getClassName() );
  1148. String objectName( getName() );
  1149. Con::warnf( "[%i] %s - %s ->", getId(), className.c_str(), objectName.c_str() );
  1150. if ( mGroup )
  1151. mGroup->dumpGroupHierarchy();
  1152. }
  1153. //=============================================================================
  1154. // Events.
  1155. //=============================================================================
  1156. // MARK: ---- Events ----
  1157. //-----------------------------------------------------------------------------
  1158. bool SimObject::onAdd()
  1159. {
  1160. mFlags.set(Added);
  1161. linkNamespaces();
  1162. return true;
  1163. }
  1164. //-----------------------------------------------------------------------------
  1165. void SimObject::onRemove()
  1166. {
  1167. mFlags.clear(Added);
  1168. unlinkNamespaces();
  1169. }
  1170. //-----------------------------------------------------------------------------
  1171. void SimObject::onGroupAdd()
  1172. {
  1173. }
  1174. //-----------------------------------------------------------------------------
  1175. void SimObject::onGroupRemove()
  1176. {
  1177. }
  1178. //-----------------------------------------------------------------------------
  1179. void SimObject::onDeleteNotify(SimObject*)
  1180. {
  1181. }
  1182. //-----------------------------------------------------------------------------
  1183. void SimObject::onNameChange(const char*)
  1184. {
  1185. }
  1186. //-----------------------------------------------------------------------------
  1187. void SimObject::onStaticModified(const char* slotName, const char* newValue)
  1188. {
  1189. }
  1190. //-----------------------------------------------------------------------------
  1191. void SimObject::onDynamicModified(const char* slotName, const char* newValue)
  1192. {
  1193. }
  1194. //=============================================================================
  1195. // Notifications.
  1196. //=============================================================================
  1197. // MARK: ---- Notifications ----
  1198. static Chunker<SimObject::Notify> notifyChunker(128000);
  1199. SimObject::Notify *SimObject::mNotifyFreeList = NULL;
  1200. //-----------------------------------------------------------------------------
  1201. SimObject::Notify *SimObject::allocNotify()
  1202. {
  1203. if(mNotifyFreeList)
  1204. {
  1205. SimObject::Notify *ret = mNotifyFreeList;
  1206. mNotifyFreeList = ret->next;
  1207. return ret;
  1208. }
  1209. return notifyChunker.alloc();
  1210. }
  1211. //-----------------------------------------------------------------------------
  1212. void SimObject::freeNotify(SimObject::Notify* note)
  1213. {
  1214. AssertFatal(note->type != SimObject::Notify::Invalid, "Invalid notify");
  1215. note->type = SimObject::Notify::Invalid;
  1216. note->next = mNotifyFreeList;
  1217. mNotifyFreeList = note;
  1218. }
  1219. //-----------------------------------------------------------------------------
  1220. SimObject::Notify* SimObject::removeNotify(void *ptr, SimObject::Notify::Type type)
  1221. {
  1222. Notify **list = &mNotifyList;
  1223. while(*list)
  1224. {
  1225. if((*list)->ptr == ptr && (*list)->type == type)
  1226. {
  1227. SimObject::Notify *ret = *list;
  1228. *list = ret->next;
  1229. return ret;
  1230. }
  1231. list = &((*list)->next);
  1232. }
  1233. return NULL;
  1234. }
  1235. //-----------------------------------------------------------------------------
  1236. void SimObject::deleteNotify(SimObject* obj)
  1237. {
  1238. AssertFatal(!obj->isDeleted(),
  1239. "SimManager::deleteNotify: Object is being deleted");
  1240. Notify *note = allocNotify();
  1241. note->ptr = (void *) this;
  1242. note->next = obj->mNotifyList;
  1243. note->type = Notify::DeleteNotify;
  1244. obj->mNotifyList = note;
  1245. note = allocNotify();
  1246. note->ptr = (void *) obj;
  1247. note->next = mNotifyList;
  1248. note->type = Notify::ClearNotify;
  1249. mNotifyList = note;
  1250. //obj->deleteNotifyList.pushBack(this);
  1251. //clearNotifyList.pushBack(obj);
  1252. }
  1253. //-----------------------------------------------------------------------------
  1254. void SimObject::registerReference(SimObject **ptr)
  1255. {
  1256. Notify *note = allocNotify();
  1257. note->ptr = (void *) ptr;
  1258. note->next = mNotifyList;
  1259. note->type = Notify::ObjectRef;
  1260. mNotifyList = note;
  1261. }
  1262. //-----------------------------------------------------------------------------
  1263. void SimObject::unregisterReference(SimObject **ptr)
  1264. {
  1265. Notify *note = removeNotify((void *) ptr, Notify::ObjectRef);
  1266. if(note)
  1267. {
  1268. freeNotify(note);
  1269. if( mFlags.test( AutoDelete ) )
  1270. {
  1271. for( Notify* n = mNotifyList; n != NULL; n = n->next )
  1272. if( n->type == Notify::ObjectRef )
  1273. return;
  1274. deleteObject();
  1275. }
  1276. }
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. void SimObject::clearNotify(SimObject* obj)
  1280. {
  1281. Notify *note = obj->removeNotify((void *) this, Notify::DeleteNotify);
  1282. if(note)
  1283. freeNotify(note);
  1284. note = removeNotify((void *) obj, Notify::ClearNotify);
  1285. if(note)
  1286. freeNotify(note);
  1287. }
  1288. //-----------------------------------------------------------------------------
  1289. void SimObject::processDeleteNotifies()
  1290. {
  1291. // clear out any delete notifies and
  1292. // object refs.
  1293. while(mNotifyList)
  1294. {
  1295. Notify *note = mNotifyList;
  1296. mNotifyList = note->next;
  1297. AssertFatal(note->type != Notify::ClearNotify, "Clear notes should be all gone.");
  1298. if(note->type == Notify::DeleteNotify)
  1299. {
  1300. SimObject *obj = (SimObject *) note->ptr;
  1301. Notify *cnote = obj->removeNotify((void *)this, Notify::ClearNotify);
  1302. obj->onDeleteNotify(this);
  1303. freeNotify(cnote);
  1304. }
  1305. else
  1306. {
  1307. // it must be an object ref - a pointer refs this object
  1308. *((SimObject **) note->ptr) = NULL;
  1309. }
  1310. freeNotify(note);
  1311. }
  1312. }
  1313. //-----------------------------------------------------------------------------
  1314. void SimObject::clearAllNotifications()
  1315. {
  1316. for(Notify **cnote = &mNotifyList; *cnote; )
  1317. {
  1318. Notify *temp = *cnote;
  1319. if(temp->type == Notify::ClearNotify)
  1320. {
  1321. *cnote = temp->next;
  1322. Notify *note = ((SimObject *) temp->ptr)->removeNotify((void *) this, Notify::DeleteNotify);
  1323. freeNotify(temp);
  1324. if ( note )
  1325. freeNotify(note);
  1326. }
  1327. else
  1328. cnote = &(temp->next);
  1329. }
  1330. }
  1331. //=============================================================================
  1332. // Namespaces.
  1333. //=============================================================================
  1334. // MARK: ---- Namespaces ----
  1335. //-----------------------------------------------------------------------------
  1336. void SimObject::linkNamespaces()
  1337. {
  1338. // Don't link if we already have a namespace linkage in place.
  1339. // If you want to change namespace linking, first call unlinkNamespaces()
  1340. // while still having the class namespace fields matching the current
  1341. // setup.
  1342. if (mNameSpace)
  1343. {
  1344. Con::warnf("SimObject::linkNamespaces -- Namespace linkage already in place %s", mNameSpace->getName());
  1345. return;
  1346. }
  1347. // Get the namespace for the C++ class.
  1348. Namespace* cppNamespace = getClassRep()->getNameSpace();
  1349. // Parent namespace defaults to namespace of C++ class.
  1350. Namespace* parentNamespace = cppNamespace;
  1351. // Perform superclass linking, if requested.
  1352. if( mSuperClassName && mSuperClassName[ 0 ] )
  1353. {
  1354. // Look up the superclass namespace.
  1355. Namespace* superClassNamespace = Con::lookupNamespace( mSuperClassName );
  1356. // If packages are active and adding to the superclass namespace, then we will
  1357. // have multiple packages in a parent chain that all have the same name.
  1358. // Con::lookupNamespace returns the bottom-most package in the chain to us so
  1359. // in order to properly link namespace here without conflicting with the package
  1360. // mechanism, we need to properly link child namespaces to the bottom-most namespace
  1361. // while linking parent namespaces to the topmost namespace. To find the latter
  1362. // one, we walk up the hierarchy here.
  1363. Namespace* superClassNamespacePackageRoot = superClassNamespace->getPackageRoot();
  1364. // Link the superclass namespace to the C++ class namespace.
  1365. if( superClassNamespacePackageRoot->getParent() == NULL )
  1366. {
  1367. // The superclass namespace isn't linked yet so we just
  1368. // link it to the C++ class namespace and make that our parent.
  1369. // No increasing parent reference counts is needed in this case.
  1370. bool ok = superClassNamespacePackageRoot->classLinkTo( cppNamespace );
  1371. AssertFatal( ok, "SimObject::linkNamespaces - failed to link new namespace to c++ class name" );
  1372. parentNamespace = superClassNamespace;
  1373. }
  1374. else
  1375. {
  1376. // In debug builds, make sure the namespace hierarchy that's been
  1377. // put into place actually makes sense and leads back to the C++
  1378. // class namespace.
  1379. #ifdef TORQUE_DEBUG
  1380. bool foundClassNameNS = false;
  1381. for( Namespace* linkWalk = superClassNamespacePackageRoot->getParent(); linkWalk != NULL;
  1382. linkWalk = linkWalk->getParent() )
  1383. {
  1384. if( linkWalk == cppNamespace )
  1385. {
  1386. foundClassNameNS = true;
  1387. break;
  1388. }
  1389. }
  1390. if( !foundClassNameNS )
  1391. {
  1392. // C++ class namespace not in parent link chain. Warn about it.
  1393. Con::errorf(
  1394. "SimObject::linkNamespaces - cannot link object to superclass %s because c++ class %s is not in the parent namespace chain. Linking object to c++ class.",
  1395. mSuperClassName,
  1396. getClassName()
  1397. );
  1398. // Clear out superclass name so we don't come across it during
  1399. // unlinking.
  1400. mSuperClassName = NULL;
  1401. }
  1402. else
  1403. #endif
  1404. {
  1405. // Super link is ok.
  1406. parentNamespace = superClassNamespace;
  1407. // Now increase the reference count of all namespaces in the parent hierarchy
  1408. // (up to the C++ class).
  1409. for( Namespace* linkWalk = parentNamespace;
  1410. linkWalk != NULL && linkWalk != cppNamespace && linkWalk->getParent() != NULL;
  1411. linkWalk = linkWalk->getParent() )
  1412. {
  1413. // Skip namespaces coming from packages.
  1414. if( linkWalk->getPackage() != NULL )
  1415. continue;
  1416. linkWalk->incRefCountToParent();
  1417. }
  1418. }
  1419. }
  1420. }
  1421. // If class name is set, link it in as the new parent
  1422. // which itself inherits from the current parent.
  1423. if( mClassName && mClassName[ 0 ] )
  1424. {
  1425. Namespace* classNamespace = Con::lookupNamespace( mClassName );
  1426. if( classNamespace && classNamespace->classLinkTo( parentNamespace ) )
  1427. {
  1428. parentNamespace = classNamespace;
  1429. }
  1430. else
  1431. {
  1432. // Clear out class name so we don't perform a bogus unlink
  1433. // in unlinkNamespaces().
  1434. mClassName = NULL;
  1435. }
  1436. }
  1437. // Finally, if we have an object name, link its namespace
  1438. // as the child to the current parent namespace and let it
  1439. // become the final namespace of this object.
  1440. StringTableEntry objectName = getName();
  1441. if( objectName && objectName[ 0 ] )
  1442. {
  1443. Namespace* objectNamespace = Con::lookupNamespace( objectName );
  1444. if( objectNamespace && objectNamespace->classLinkTo( parentNamespace ) )
  1445. {
  1446. parentNamespace = objectNamespace;
  1447. }
  1448. }
  1449. // Store our namespace.
  1450. mNameSpace = parentNamespace;
  1451. }
  1452. //-----------------------------------------------------------------------------
  1453. void SimObject::unlinkNamespaces()
  1454. {
  1455. if( !mNameSpace )
  1456. return;
  1457. Namespace* cppNamespace = getClassRep()->getNameSpace();
  1458. Namespace* parentNamespace = cppNamespace;
  1459. // Handle superclass.
  1460. if( mSuperClassName && mSuperClassName[ 0 ] )
  1461. {
  1462. // Get the superclass namespace.
  1463. Namespace* superClassNamespace = Con::lookupNamespace( mSuperClassName );
  1464. // Make it the parent namespace.
  1465. parentNamespace = superClassNamespace;
  1466. // Decrease parent refcounts on the superclass hierarchy.
  1467. for( Namespace* linkWalk = superClassNamespace;
  1468. linkWalk != NULL && linkWalk != cppNamespace && linkWalk->getParent() != NULL; )
  1469. {
  1470. // Store the parent link since it may disappear once we
  1471. // decrease the reference count.
  1472. Namespace* parent = linkWalk->getParent();
  1473. // Decrease the refcount.
  1474. if( linkWalk->getPackage() == NULL ) // Skip namespaces coming from packages.
  1475. linkWalk->decRefCountToParent();
  1476. // Walk up.
  1477. linkWalk = parent;
  1478. }
  1479. }
  1480. // Handle class.
  1481. if( mClassName && mClassName[ 0 ] )
  1482. {
  1483. Namespace* classNamespace = Con::lookupNamespace( mClassName );
  1484. if( classNamespace )
  1485. {
  1486. classNamespace->decRefCountToParent();
  1487. parentNamespace = classNamespace;
  1488. }
  1489. }
  1490. // Handle object name.
  1491. StringTableEntry objectName = getName();
  1492. if( objectName && objectName[ 0 ] )
  1493. mNameSpace->decRefCountToParent();
  1494. mNameSpace = NULL;
  1495. }
  1496. //-----------------------------------------------------------------------------
  1497. void SimObject::setClassNamespace( const char *classNamespace )
  1498. {
  1499. StringTableEntry oldClassNamespace = mClassName;
  1500. StringTableEntry newClassNamespace = StringTable->insert( classNamespace );
  1501. if( oldClassNamespace == newClassNamespace )
  1502. return;
  1503. if( isProperlyAdded() )
  1504. unlinkNamespaces();
  1505. mClassName = newClassNamespace;
  1506. if( isProperlyAdded() )
  1507. {
  1508. linkNamespaces();
  1509. // Restore old namespace setup if linkage failed.
  1510. if( mClassName != newClassNamespace )
  1511. {
  1512. mClassName = oldClassNamespace;
  1513. linkNamespaces();
  1514. }
  1515. }
  1516. }
  1517. //-----------------------------------------------------------------------------
  1518. void SimObject::setSuperClassNamespace( const char *superClassNamespace )
  1519. {
  1520. StringTableEntry oldSuperClassNamespace = mSuperClassName;
  1521. StringTableEntry newSuperClassNamespace = StringTable->insert( superClassNamespace );
  1522. if( oldSuperClassNamespace == newSuperClassNamespace )
  1523. return;
  1524. if( isProperlyAdded() )
  1525. unlinkNamespaces();
  1526. mSuperClassName = newSuperClassNamespace;
  1527. if( isProperlyAdded() )
  1528. {
  1529. linkNamespaces();
  1530. // Restore old setup if linkage failed.
  1531. if( mSuperClassName != newSuperClassNamespace )
  1532. {
  1533. mSuperClassName = oldSuperClassNamespace;
  1534. linkNamespaces();
  1535. }
  1536. }
  1537. }
  1538. //=============================================================================
  1539. // Misc.
  1540. //=============================================================================
  1541. // MARK: ---- Misc ----
  1542. //-----------------------------------------------------------------------------
  1543. void SimObject::setInternalName( const char* newname )
  1544. {
  1545. if( newname )
  1546. mInternalName = StringTable->insert( newname );
  1547. else
  1548. mInternalName = StringTable->EmptyString();
  1549. }
  1550. //-----------------------------------------------------------------------------
  1551. void SimObject::setOriginalName( const char* originalName )
  1552. {
  1553. if( originalName )
  1554. mOriginalName = StringTable->insert( originalName );
  1555. else
  1556. mOriginalName = StringTable->EmptyString();
  1557. }
  1558. //-----------------------------------------------------------------------------
  1559. const char *SimObject::tabComplete(const char *prevText, S32 baseLen, bool fForward)
  1560. {
  1561. return mNameSpace->tabComplete(prevText, baseLen, fForward);
  1562. }
  1563. //-----------------------------------------------------------------------------
  1564. void SimObject::setSelected( bool sel )
  1565. {
  1566. if( mFlags.test( Selected ) == sel )
  1567. return; // No change.
  1568. if( sel )
  1569. {
  1570. mFlags.set( Selected );
  1571. _onSelected();
  1572. }
  1573. else
  1574. {
  1575. mFlags.clear( Selected );
  1576. _onUnselected();
  1577. }
  1578. }
  1579. //-----------------------------------------------------------------------------
  1580. bool SimObject::isSelectedRecursive() const
  1581. {
  1582. const SimObject *walk = this;
  1583. while ( walk )
  1584. {
  1585. if ( walk->isSelected() )
  1586. return true;
  1587. walk = walk->getGroup();
  1588. }
  1589. return false;
  1590. }
  1591. //-----------------------------------------------------------------------------
  1592. void SimObject::setLocked( bool b )
  1593. {
  1594. if( b )
  1595. mFlags.set( Locked );
  1596. else
  1597. mFlags.clear( Locked );
  1598. }
  1599. //-----------------------------------------------------------------------------
  1600. void SimObject::setHidden( bool b )
  1601. {
  1602. if( b )
  1603. mFlags.set( Hidden );
  1604. else
  1605. mFlags.clear( Hidden );
  1606. }
  1607. //-----------------------------------------------------------------------------
  1608. void SimObject::setCopySource( SimObject* object )
  1609. {
  1610. if( mCopySource )
  1611. mCopySource->unregisterReference( &mCopySource );
  1612. mCopySource = object;
  1613. if( mCopySource )
  1614. mCopySource->registerReference( &mCopySource );
  1615. }
  1616. //---------------------------------------------------------------------------
  1617. bool SimObject::_setCanSave( void* object, const char* index, const char* data )
  1618. {
  1619. SimObject* obj = reinterpret_cast< SimObject* >( object );
  1620. obj->setCanSave( dAtob( data ) );
  1621. return false;
  1622. }
  1623. //-----------------------------------------------------------------------------
  1624. const char* SimObject::_getCanSave( void* object, const char* data )
  1625. {
  1626. SimObject* obj = reinterpret_cast< SimObject* >( object );
  1627. if( obj->getCanSave() )
  1628. return "1";
  1629. else
  1630. return "0";
  1631. }
  1632. //---------------------------------------------------------------------------
  1633. // Copy SimObject to another SimObject (Originally designed for T2D).
  1634. void SimObject::copyTo( SimObject* object )
  1635. {
  1636. object->mClassName = mClassName;
  1637. object->mSuperClassName = mSuperClassName;
  1638. linkNamespaces();
  1639. }
  1640. //-----------------------------------------------------------------------------
  1641. bool SimObject::setProtectedParent( void *obj, const char *index, const char *data )
  1642. {
  1643. SimGroup *parent = NULL;
  1644. SimObject *object = static_cast<SimObject*>(obj);
  1645. if(Sim::findObject(data, parent))
  1646. parent->addObject(object);
  1647. // always return false, because we've set mGroup when we called addObject
  1648. return false;
  1649. }
  1650. //-----------------------------------------------------------------------------
  1651. bool SimObject::setProtectedName(void *obj, const char *index, const char *data)
  1652. {
  1653. SimObject *object = static_cast<SimObject*>(obj);
  1654. if ( object->isProperlyAdded() )
  1655. object->assignName( data );
  1656. // always return false because we assign the name here
  1657. return false;
  1658. }
  1659. //-----------------------------------------------------------------------------
  1660. void SimObject::inspectPreApply()
  1661. {
  1662. }
  1663. //-----------------------------------------------------------------------------
  1664. void SimObject::inspectPostApply()
  1665. {
  1666. }
  1667. //-----------------------------------------------------------------------------
  1668. String SimObject::_getLogMessage(const char* fmt, va_list args) const
  1669. {
  1670. String objClass = "UnknownClass";
  1671. if(getClassRep())
  1672. objClass = getClassRep()->getClassName();
  1673. String objName = getName();
  1674. if(objName.isEmpty())
  1675. objName = "Unnamed";
  1676. String formattedMessage = String::VToString(fmt, args);
  1677. return String::ToString("%s - %s(%i) - %s",
  1678. objClass.c_str(), objName.c_str(), getId(), formattedMessage.c_str());
  1679. }
  1680. //=============================================================================
  1681. // API.
  1682. //=============================================================================
  1683. // MARK: ---- API ----
  1684. //-----------------------------------------------------------------------------
  1685. DefineEngineMethod( SimObject, dumpGroupHierarchy, void, (),,
  1686. "Dump the hierarchy of this object up to RootGroup to the console." )
  1687. {
  1688. object->dumpGroupHierarchy();
  1689. }
  1690. //-----------------------------------------------------------------------------
  1691. DefineConsoleMethod( SimObject, isMethod, bool, ( const char* methodName ),,
  1692. "Test whether the given method is defined on this object.\n"
  1693. "@param The name of the method.\n"
  1694. "@return True if the object implements the given method." )
  1695. {
  1696. return object->isMethod( methodName );
  1697. }
  1698. //-----------------------------------------------------------------------------
  1699. DefineEngineMethod( SimObject, isChildOfGroup, bool, ( SimGroup* group ),,
  1700. "Test whether the object belongs directly or indirectly to the given group.\n"
  1701. "@param group The SimGroup object.\n"
  1702. "@return True if the object is a child of the given group or a child of a group that the given group is directly or indirectly a child to." )
  1703. {
  1704. return object->isChildOfGroup( group );
  1705. }
  1706. //-----------------------------------------------------------------------------
  1707. DefineConsoleMethod( SimObject, getClassNamespace, const char*, (),,
  1708. "Get the name of the class namespace assigned to this object.\n"
  1709. "@return The name of the 'class' namespace." )
  1710. {
  1711. return object->getClassNamespace();
  1712. }
  1713. //-----------------------------------------------------------------------------
  1714. DefineConsoleMethod( SimObject, getSuperClassNamespace, const char*, (),,
  1715. "Get the name of the superclass namespace assigned to this object.\n"
  1716. "@return The name of the 'superClass' namespace." )
  1717. {
  1718. return object->getSuperClassNamespace();
  1719. }
  1720. //-----------------------------------------------------------------------------
  1721. DefineConsoleMethod( SimObject, setClassNamespace, void, ( const char* name ),,
  1722. "Assign a class namespace to this object.\n"
  1723. "@param name The name of the 'class' namespace for this object." )
  1724. {
  1725. object->setClassNamespace( name );
  1726. }
  1727. //-----------------------------------------------------------------------------
  1728. DefineConsoleMethod( SimObject, setSuperClassNamespace, void, ( const char* name ),,
  1729. "Assign a superclass namespace to this object.\n"
  1730. "@param name The name of the 'superClass' namespace for this object." )
  1731. {
  1732. object->setSuperClassNamespace( name );
  1733. }
  1734. //-----------------------------------------------------------------------------
  1735. DefineEngineMethod( SimObject, isSelected, bool, (),,
  1736. "Get whether the object has been marked as selected. (in editor)\n"
  1737. "@return True if the object is currently selected." )
  1738. {
  1739. return object->isSelected();
  1740. }
  1741. //-----------------------------------------------------------------------------
  1742. DefineEngineMethod( SimObject, setIsSelected, void, ( bool state ), ( true ),
  1743. "Set whether the object has been marked as selected. (in editor)\n"
  1744. "@param state True if object is to be marked selected; false if not." )
  1745. {
  1746. object->setSelected( state );
  1747. }
  1748. //-----------------------------------------------------------------------------
  1749. DefineConsoleMethod( SimObject, isExpanded, bool, (),,
  1750. "Get whether the object has been marked as expanded. (in editor)\n"
  1751. "@return True if the object is marked expanded." )
  1752. {
  1753. return object->isExpanded();
  1754. }
  1755. //-----------------------------------------------------------------------------
  1756. DefineConsoleMethod( SimObject, setIsExpanded, void, ( bool state ), ( true ),
  1757. "Set whether the object has been marked as expanded. (in editor)\n"
  1758. "@param state True if the object is to be marked expanded; false if not." )
  1759. {
  1760. object->setExpanded( state );
  1761. }
  1762. //-----------------------------------------------------------------------------
  1763. DefineConsoleMethod( SimObject, getFilename, const char*, (),,
  1764. "Returns the filename the object is attached to.\n"
  1765. "@return The name of the file the object is associated with; usually the file the object was loaded from." )
  1766. {
  1767. return object->getFilename();
  1768. }
  1769. //-----------------------------------------------------------------------------
  1770. DefineConsoleMethod( SimObject, setFilename, void, ( const char* fileName ),,
  1771. "Sets the object's file name and path\n"
  1772. "@param fileName The name of the file to associate this object with." )
  1773. {
  1774. return object->setFilename( fileName );
  1775. }
  1776. //-----------------------------------------------------------------------------
  1777. DefineConsoleMethod( SimObject, getDeclarationLine, S32, (),,
  1778. "Get the line number at which the object is defined in its file.\n\n"
  1779. "@return The line number of the object's definition in script.\n"
  1780. "@see getFilename()")
  1781. {
  1782. return object->getDeclarationLine();
  1783. }
  1784. //-----------------------------------------------------------------------------
  1785. #ifdef TORQUE_DEBUG
  1786. static const char* sEnumCallbackFunction;
  1787. static void sEnumCallback( EngineObject* object )
  1788. {
  1789. SimObject* simObject = dynamic_cast< SimObject* >( object );
  1790. if( !simObject )
  1791. return;
  1792. Con::evaluatef( "%s( %i );", sEnumCallbackFunction, simObject->getId() );
  1793. }
  1794. DefineEngineFunction( debugEnumInstances, void, ( const char* className, const char* functionName ),,
  1795. "Call the given function for each instance of the given class.\n"
  1796. "@param className Name of the class for which to enumerate instances.\n"
  1797. "@param functionName Name of function to call and pass each instance of the given class.\n"
  1798. "@note This function is only available in debug builds and primarily meant as an aid in debugging."
  1799. "@ingroup Console")
  1800. {
  1801. sEnumCallbackFunction = functionName;
  1802. ConsoleObject::debugEnumInstances( className, sEnumCallback );
  1803. }
  1804. #endif
  1805. //-----------------------------------------------------------------------------
  1806. DefineConsoleMethod( SimObject, assignFieldsFrom, void, ( SimObject* fromObject ),,
  1807. "Copy fields from another object onto this one. The objects must "
  1808. "be of same type. Everything from the object will overwrite what's "
  1809. "in this object; extra fields in this object will remain. This "
  1810. "includes dynamic fields.\n"
  1811. "@param fromObject The object from which to copy fields." )
  1812. {
  1813. if( fromObject )
  1814. object->assignFieldsFrom( fromObject );
  1815. }
  1816. //-----------------------------------------------------------------------------
  1817. DefineEngineMethod( SimObject, assignPersistentId, void, (),,
  1818. "Assign a persistent ID to the object if it does not already have one." )
  1819. {
  1820. object->getOrCreatePersistentId();
  1821. }
  1822. //-----------------------------------------------------------------------------
  1823. DefineConsoleMethod( SimObject, getCanSave, bool, (),,
  1824. "Get whether the object will be included in saves.\n"
  1825. "@return True if the object will be saved; false otherwise." )
  1826. {
  1827. return object->getCanSave();
  1828. }
  1829. //-----------------------------------------------------------------------------
  1830. DefineConsoleMethod( SimObject, setCanSave, void, ( bool value ), ( true ),
  1831. "Set whether the object will be included in saves.\n"
  1832. "@param value If true, the object will be included in saves; if false, it will be excluded." )
  1833. {
  1834. object->setCanSave( value );
  1835. }
  1836. //-----------------------------------------------------------------------------
  1837. DefineEngineMethod( SimObject, isEditorOnly, bool, (),,
  1838. "Return true if the object is only used by the editor.\n"
  1839. "@return True if this object exists only for the sake of editing." )
  1840. {
  1841. return object->isEditorOnly();
  1842. }
  1843. //-----------------------------------------------------------------------------
  1844. DefineEngineMethod( SimObject, setEditorOnly, void, ( bool value ), ( true ),
  1845. "Set/clear the editor-only flag on this object.\n"
  1846. "@param value If true, the object is marked as existing only for the editor." )
  1847. {
  1848. object->setEditorOnly( value );
  1849. }
  1850. //-----------------------------------------------------------------------------
  1851. DefineEngineMethod( SimObject, isNameChangeAllowed, bool, (),,
  1852. "Get whether this object may be renamed.\n"
  1853. "@return True if this object can be renamed; false otherwise." )
  1854. {
  1855. return object->isNameChangeAllowed();
  1856. }
  1857. //-----------------------------------------------------------------------------
  1858. DefineEngineMethod( SimObject, setNameChangeAllowed, void, ( bool value ), ( true ),
  1859. "Set whether this object can be renamed from its first name.\n"
  1860. "@param value If true, renaming is allowed for this object; if false, trying to change the name of the object will generate a console error." )
  1861. {
  1862. object->setNameChangeAllowed( value );
  1863. }
  1864. //-----------------------------------------------------------------------------
  1865. DefineEngineMethod( SimObject, clone, SimObject*, (),,
  1866. "Create a copy of this object.\n"
  1867. "@return An exact duplicate of this object." )
  1868. {
  1869. return object->clone();
  1870. }
  1871. //-----------------------------------------------------------------------------
  1872. DefineEngineMethod( SimObject, deepClone, SimObject*, (),,
  1873. "Create a copy of this object and all its subobjects.\n"
  1874. "@return An exact duplicate of this object and all objects it references." )
  1875. {
  1876. return object->deepClone();
  1877. }
  1878. //-----------------------------------------------------------------------------
  1879. DefineEngineMethod( SimObject, setLocked, void, ( bool value ), ( true ),
  1880. "Lock/unlock the object in the editor.\n"
  1881. "@param value If true, the object will be locked; if false, the object will be unlocked." )
  1882. {
  1883. object->setLocked( value );
  1884. }
  1885. //-----------------------------------------------------------------------------
  1886. DefineEngineMethod( SimObject, setHidden, void, ( bool value ), ( true ),
  1887. "Hide/unhide the object.\n"
  1888. "@param value If true, the object will be hidden; if false, the object will be unhidden." )
  1889. {
  1890. object->setHidden( value );
  1891. }
  1892. //-----------------------------------------------------------------------------
  1893. DefineConsoleMethod( SimObject, dumpMethods, ArrayObject*, (),,
  1894. "List the methods defined on this object.\n\n"
  1895. "Each description is a newline-separated vector with the following elements:\n"
  1896. "- Minimum number of arguments.\n"
  1897. "- Maximum number of arguments.\n"
  1898. "- Prototype string.\n"
  1899. "- Full script file path (if script method).\n"
  1900. "- Line number of method definition in script (if script method).\n\n"
  1901. "- Documentation string (not including prototype). This takes up the remainder of the vector.\n"
  1902. "@return An ArrayObject populated with (name,description) pairs of all methods defined on the object." )
  1903. {
  1904. Namespace *ns = object->getNamespace();
  1905. if( !ns )
  1906. return 0;
  1907. ArrayObject* dictionary = new ArrayObject();
  1908. dictionary->registerObject();
  1909. VectorPtr<Namespace::Entry *> vec(__FILE__, __LINE__);
  1910. ns->getEntryList(&vec);
  1911. for(Vector< Namespace::Entry* >::iterator j = vec.begin(); j != vec.end(); j++)
  1912. {
  1913. Namespace::Entry* e = *j;
  1914. if( e->mType < 0 )
  1915. continue;
  1916. StringBuilder str;
  1917. str.append( String::ToString( e->mMinArgs ) );
  1918. str.append( '\n' );
  1919. str.append( String::ToString( e->mMaxArgs ) );
  1920. str.append( '\n' );
  1921. str.append( e->getPrototypeString() );
  1922. str.append( '\n' );
  1923. if( e->mCode && e->mCode->fullPath )
  1924. str.append( e->mCode->fullPath );
  1925. str.append( '\n' );
  1926. if( e->mCode )
  1927. str.append( String::ToString( e->mFunctionLineNumber ) );
  1928. str.append( '\n' );
  1929. String docs = e->getDocString();
  1930. if( !docs.isEmpty() )
  1931. str.append( docs );
  1932. dictionary->push_back( e->mFunctionName, str.end() );
  1933. }
  1934. return dictionary;
  1935. }
  1936. //-----------------------------------------------------------------------------
  1937. namespace {
  1938. S32 QSORT_CALLBACK compareFields( const void* a,const void* b )
  1939. {
  1940. const AbstractClassRep::Field* fa = *((const AbstractClassRep::Field**)a);
  1941. const AbstractClassRep::Field* fb = *((const AbstractClassRep::Field**)b);
  1942. return dStricmp(fa->pFieldname, fb->pFieldname);
  1943. }
  1944. struct DocString
  1945. {
  1946. char mPadding[ 8 ];
  1947. String mPrototype;
  1948. String mDescription;
  1949. const char* mReturnType;
  1950. DocString( Namespace::Entry* entry )
  1951. : mPrototype( entry->getArgumentsString() ),
  1952. mDescription( entry->getBriefDescription() )
  1953. {
  1954. mReturnType = " ";
  1955. mPadding[ 0 ] = 0;
  1956. if( entry->mType == -4 )
  1957. {
  1958. //TODO: need to have script callbacks set up proper return type info
  1959. }
  1960. else
  1961. {
  1962. switch( entry->mType )
  1963. {
  1964. case Namespace::Entry::StringCallbackType:
  1965. mReturnType = "string";
  1966. mPadding[ 0 ] = ' ';
  1967. mPadding[ 1 ] = ' ';
  1968. mPadding[ 2 ] = 0;
  1969. break;
  1970. case Namespace::Entry::IntCallbackType:
  1971. mReturnType = "int";
  1972. mPadding[ 0 ] = ' ';
  1973. mPadding[ 1 ] = ' ';
  1974. mPadding[ 2 ] = ' ';
  1975. mPadding[ 3 ] = ' ';
  1976. mPadding[ 4 ] = ' ';
  1977. mPadding[ 5 ] = 0;
  1978. break;
  1979. case Namespace::Entry::FloatCallbackType:
  1980. mReturnType = "float";
  1981. mPadding[ 0 ] = ' ';
  1982. mPadding[ 1 ] = ' ';
  1983. mPadding[ 2 ] = ' ';
  1984. mPadding[ 3 ] = 0;
  1985. break;
  1986. case Namespace::Entry::VoidCallbackType:
  1987. mReturnType = "void";
  1988. mPadding[ 0 ] = ' ';
  1989. mPadding[ 1 ] = ' ';
  1990. mPadding[ 2 ] = ' ';
  1991. mPadding[ 3 ] = ' ';
  1992. mPadding[ 4 ] = 0;
  1993. break;
  1994. case Namespace::Entry::BoolCallbackType:
  1995. mReturnType = "bool";
  1996. mPadding[ 0 ] = ' ';
  1997. mPadding[ 1 ] = ' ';
  1998. mPadding[ 2 ] = ' ';
  1999. mPadding[ 3 ] = ' ';
  2000. mPadding[ 4 ] = 0;
  2001. break;
  2002. }
  2003. }
  2004. }
  2005. };
  2006. }
  2007. DefineEngineMethod( SimObject, dump, void, ( bool detailed ), ( false ),
  2008. "Dump a description of all fields and methods defined on this object to the console.\n"
  2009. "@param detailed Whether to print detailed information about members." )
  2010. {
  2011. Con::printf( "Class: %s", object->getClassName() );
  2012. const AbstractClassRep::FieldList &list = object->getFieldList();
  2013. char expandedBuffer[4096];
  2014. Con::printf( "Static Fields:" );
  2015. Vector<const AbstractClassRep::Field *> flist(__FILE__, __LINE__);
  2016. for(U32 i = 0; i < list.size(); i++)
  2017. flist.push_back(&list[i]);
  2018. dQsort(flist.address(),flist.size(),sizeof(AbstractClassRep::Field *),compareFields);
  2019. for(Vector<const AbstractClassRep::Field *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
  2020. {
  2021. const AbstractClassRep::Field* f = *itr;
  2022. // The special field types can be skipped.
  2023. if ( f->type >= AbstractClassRep::ARCFirstCustomField )
  2024. continue;
  2025. for(U32 j = 0; S32(j) < f->elementCount; j++)
  2026. {
  2027. // [neo, 07/05/2007 - #3000]
  2028. // Some objects use dummy vars and projected fields so make sure we call the get functions
  2029. //const char *val = Con::getData(f->type, (void *) (((const char *)object) + f->offset), j, f->table, f->flag);
  2030. const char *val = (*f->getDataFn)( object, Con::getData(f->type, (void *) (((const char *)object) + f->offset), j, f->table, f->flag) );// + typeSizes[fld.type] * array1));
  2031. ConsoleBaseType* conType = ConsoleBaseType::getType( f->type );
  2032. const char* conTypeName = "<unknown>";
  2033. if( conType )
  2034. conTypeName = conType->getTypeClassName();
  2035. if( !val /*|| !*val*/ )
  2036. continue;
  2037. if( f->elementCount == 1 )
  2038. dSprintf( expandedBuffer, sizeof( expandedBuffer ), " %s %s = \"", conTypeName, f->pFieldname );
  2039. else
  2040. dSprintf( expandedBuffer, sizeof( expandedBuffer ), " %s %s[ %d ] = \"", conTypeName, f->pFieldname, j );
  2041. expandEscape( expandedBuffer + dStrlen(expandedBuffer), val);
  2042. Con::printf( "%s\"", expandedBuffer );
  2043. if( detailed && f->pFieldDocs && f->pFieldDocs[ 0 ] )
  2044. Con::printf( " %s", f->pFieldDocs );
  2045. }
  2046. }
  2047. Con::printf( "Dynamic Fields:" );
  2048. if(object->getFieldDictionary())
  2049. object->getFieldDictionary()->printFields(object);
  2050. Con::printf( "Methods:" );
  2051. Namespace *ns = object->getNamespace();
  2052. VectorPtr<Namespace::Entry *> vec(__FILE__, __LINE__);
  2053. if(ns)
  2054. ns->getEntryList(&vec);
  2055. bool sawCBs = false;
  2056. for(Vector<Namespace::Entry *>::iterator j = vec.begin(); j != vec.end(); j++)
  2057. {
  2058. Namespace::Entry *e = *j;
  2059. if(e->mType == Namespace::Entry::ScriptCallbackType)
  2060. sawCBs = true;
  2061. if(e->mType < 0)
  2062. continue;
  2063. DocString doc( e );
  2064. Con::printf( " %s%s%s%s", doc.mReturnType, doc.mPadding, e->mFunctionName, doc.mPrototype.c_str() );
  2065. if( detailed && !doc.mDescription.isEmpty() )
  2066. Con::printf( " %s", doc.mDescription.c_str() );
  2067. }
  2068. if( sawCBs )
  2069. {
  2070. Con::printf( "Callbacks:" );
  2071. for(Vector<Namespace::Entry *>::iterator j = vec.begin(); j != vec.end(); j++)
  2072. {
  2073. Namespace::Entry *e = *j;
  2074. if(e->mType != Namespace::Entry::ScriptCallbackType)
  2075. continue;
  2076. DocString doc( e );
  2077. Con::printf( " %s%s%s%s", doc.mReturnType, doc.mPadding, e->cb.mCallbackName, doc.mPrototype.c_str() );
  2078. if( detailed && !doc.mDescription.isEmpty() )
  2079. Con::printf( " %s", doc.mDescription.c_str() );
  2080. }
  2081. }
  2082. }
  2083. //-----------------------------------------------------------------------------
  2084. DefineConsoleMethod( SimObject, save, bool, ( const char* fileName, bool selectedOnly, const char* preAppendString ), ( false, "" ),
  2085. "Save out the object to the given file.\n"
  2086. "@param fileName The name of the file to save to."
  2087. "@param selectedOnly If true, only objects marked as selected will be saved out.\n"
  2088. "@param preAppendString Text which will be preprended directly to the object serialization.\n"
  2089. "@param True on success, false on failure." )
  2090. {
  2091. return object->save( fileName, selectedOnly, preAppendString );
  2092. }
  2093. //-----------------------------------------------------------------------------
  2094. DefineEngineMethod( SimObject, setName, void, ( const char* newName ),,
  2095. "Set the global name of the object.\n"
  2096. "@param newName The new global name to assign to the object.\n"
  2097. "@note If name changing is disallowed on the object, the method will fail with a console error." )
  2098. {
  2099. object->assignName( newName );
  2100. }
  2101. //-----------------------------------------------------------------------------
  2102. DefineEngineMethod( SimObject, getName, const char*, (),,
  2103. "Get the global name of the object.\n"
  2104. "@return The global name assigned to the object." )
  2105. {
  2106. const char *ret = object->getName();
  2107. return ret ? ret : "";
  2108. }
  2109. //-----------------------------------------------------------------------------
  2110. DefineConsoleMethod( SimObject, getClassName, const char*, (),,
  2111. "Get the name of the C++ class which the object is an instance of.\n"
  2112. "@return The name of the C++ class of the object." )
  2113. {
  2114. const char *ret = object->getClassName();
  2115. return ret ? ret : "";
  2116. }
  2117. //-----------------------------------------------------------------------------
  2118. DefineConsoleMethod( SimObject, isField, bool, ( const char* fieldName ),,
  2119. "Test whether the given field is defined on this object.\n"
  2120. "@param fieldName The name of the field.\n"
  2121. "@return True if the object implements the given field." )
  2122. {
  2123. return object->isField( fieldName );
  2124. }
  2125. //-----------------------------------------------------------------------------
  2126. DefineConsoleMethod( SimObject, getFieldValue, const char*, ( const char* fieldName, S32 index ), ( -1 ),
  2127. "Return the value of the given field on this object.\n"
  2128. "@param fieldName The name of the field. If it includes a field index, the index is parsed out.\n"
  2129. "@param index Optional parameter to specify the index of an array field separately.\n"
  2130. "@return The value of the given field or \"\" if undefined." )
  2131. {
  2132. char fieldNameBuffer[ 1024 ];
  2133. char arrayIndexBuffer[ 64 ];
  2134. // Parse out index if the field is given in the form of 'name[index]'.
  2135. const char* arrayIndex = NULL;
  2136. const U32 nameLen = dStrlen( fieldName );
  2137. if( fieldName[ nameLen - 1 ] == ']' )
  2138. {
  2139. const char* leftBracket = dStrchr( fieldName, '[' );
  2140. const char* rightBracket = &fieldName[ nameLen - 1 ];
  2141. const U32 fieldNameLen = getMin( U32( leftBracket - fieldName ), sizeof( fieldNameBuffer ) - 1 );
  2142. const U32 arrayIndexLen = getMin( U32( rightBracket - leftBracket - 1 ), sizeof( arrayIndexBuffer ) - 1 );
  2143. dMemcpy( fieldNameBuffer, fieldName, fieldNameLen );
  2144. dMemcpy( arrayIndexBuffer, leftBracket + 1, arrayIndexLen );
  2145. fieldNameBuffer[ fieldNameLen ] = '\0';
  2146. arrayIndexBuffer[ arrayIndexLen ] = '\0';
  2147. fieldName = fieldNameBuffer;
  2148. arrayIndex = arrayIndexBuffer;
  2149. }
  2150. fieldName = StringTable->insert( fieldName );
  2151. if( index != -1 )
  2152. {
  2153. dSprintf( arrayIndexBuffer, sizeof( arrayIndexBuffer ), "%i", index );
  2154. arrayIndex = arrayIndexBuffer;
  2155. }
  2156. return object->getDataField( fieldName, arrayIndex );
  2157. }
  2158. //-----------------------------------------------------------------------------
  2159. DefineConsoleMethod( SimObject, setFieldValue, bool, ( const char* fieldName, const char* value, S32 index ), ( -1 ),
  2160. "Set the value of the given field on this object.\n"
  2161. "@param fieldName The name of the field to assign to. If it includes an array index, the index will be parsed out.\n"
  2162. "@param value The new value to assign to the field.\n"
  2163. "@param index Optional argument to specify an index for an array field.\n"
  2164. "@return True." )
  2165. {
  2166. char fieldNameBuffer[ 1024 ];
  2167. char arrayIndexBuffer[ 64 ];
  2168. // Parse out index if the field is given in the form of 'name[index]'.
  2169. const char* arrayIndex = NULL;
  2170. const U32 nameLen = dStrlen( fieldName );
  2171. if( fieldName[ nameLen - 1 ] == ']' )
  2172. {
  2173. const char* leftBracket = dStrchr( fieldName, '[' );
  2174. const char* rightBracket = &fieldName[ nameLen - 1 ];
  2175. const U32 fieldNameLen = getMin( U32( leftBracket - fieldName ), sizeof( fieldNameBuffer ) - 1 );
  2176. const U32 arrayIndexLen = getMin( U32( rightBracket - leftBracket - 1 ), sizeof( arrayIndexBuffer ) - 1 );
  2177. dMemcpy( fieldNameBuffer, fieldName, fieldNameLen );
  2178. dMemcpy( arrayIndexBuffer, leftBracket + 1, arrayIndexLen );
  2179. fieldNameBuffer[ fieldNameLen ] = '\0';
  2180. arrayIndexBuffer[ arrayIndexLen ] = '\0';
  2181. fieldName = fieldNameBuffer;
  2182. arrayIndex = arrayIndexBuffer;
  2183. }
  2184. fieldName = StringTable->insert( fieldName );
  2185. if( index != -1 )
  2186. {
  2187. dSprintf( arrayIndexBuffer, sizeof( arrayIndexBuffer ), "%i", index );
  2188. arrayIndex = arrayIndexBuffer;
  2189. }
  2190. object->setDataField( fieldName, arrayIndex, value );
  2191. return true;
  2192. }
  2193. //-----------------------------------------------------------------------------
  2194. DefineConsoleMethod( SimObject, getFieldType, const char*, ( const char* fieldName ),,
  2195. "Get the console type code of the given field.\n"
  2196. "@return The numeric type code for the underlying console type of the given field." )
  2197. {
  2198. U32 typeID = object->getDataFieldType( StringTable->insert( fieldName ), NULL );
  2199. ConsoleBaseType* type = ConsoleBaseType::getType( typeID );
  2200. if( type )
  2201. return type->getTypeName();
  2202. return "";
  2203. }
  2204. //-----------------------------------------------------------------------------
  2205. DefineConsoleMethod( SimObject, setFieldType, void, ( const char* fieldName, const char* type ),,
  2206. "Set the console type code for the given field.\n"
  2207. "@param fieldName The name of the dynamic field to change to type for.\n"
  2208. "@param type The name of the console type.\n"
  2209. "@note This only works for dynamic fields. Types of static fields cannot be changed." )
  2210. {
  2211. object->setDataFieldType( type, StringTable->insert( fieldName ), NULL );
  2212. }
  2213. //-----------------------------------------------------------------------------
  2214. ConsoleMethod( SimObject, call, const char*, 3, 0, "( string method, string args... ) Dynamically call a method on an object.\n"
  2215. "@param method Name of method to call.\n"
  2216. "@param args Zero or more arguments for the method.\n"
  2217. "@return The result of the method call." )
  2218. {
  2219. argv[1] = argv[2];
  2220. return Con::execute( object, argc - 1, argv + 1 );
  2221. }
  2222. //-----------------------------------------------------------------------------
  2223. DefineEngineMethod( SimObject, setInternalName, void, ( const char* newInternalName ),,
  2224. "Set the internal name of the object.\n"
  2225. "@param newInternalName The new internal name for the object." )
  2226. {
  2227. object->setInternalName( newInternalName );
  2228. }
  2229. //-----------------------------------------------------------------------------
  2230. DefineEngineMethod( SimObject, getInternalName, const char*, (),,
  2231. "Get the internal name of the object.\n"
  2232. "@return The internal name of the object." )
  2233. {
  2234. return object->getInternalName();
  2235. }
  2236. //-----------------------------------------------------------------------------
  2237. DefineConsoleMethod( SimObject, dumpClassHierarchy, void, (),,
  2238. "Dump the native C++ class hierarchy of this object's C++ class to the console." )
  2239. {
  2240. object->dumpClassHierarchy();
  2241. }
  2242. //-----------------------------------------------------------------------------
  2243. DefineConsoleMethod( SimObject, isMemberOfClass, bool, ( const char* className ),,
  2244. "Test whether this object is a member of the specified class.\n"
  2245. "@param className Name of a native C++ class.\n"
  2246. "@return True if this object is an instance of the given C++ class or any of its super classes." )
  2247. {
  2248. AbstractClassRep* pRep = object->getClassRep();
  2249. while(pRep)
  2250. {
  2251. if( !dStricmp(pRep->getClassName(), className ) )
  2252. {
  2253. //matches
  2254. return true;
  2255. }
  2256. pRep = pRep->getParentClass();
  2257. }
  2258. return false;
  2259. }
  2260. //-----------------------------------------------------------------------------
  2261. DefineConsoleMethod( SimObject, isInNamespaceHierarchy, bool, ( const char* name ),,
  2262. "Test whether the namespace of this object is a direct or indirect child to the given namespace.\n"
  2263. "@param name The name of a namespace.\n"
  2264. "@return True if the given namespace name is within the namespace hierarchy of this object." )
  2265. {
  2266. Namespace* nspace = object->getNamespace();
  2267. while( nspace && dStricmp( nspace->mName, name ) != 0 )
  2268. nspace = nspace->mParent;
  2269. return ( nspace != NULL );
  2270. }
  2271. //-----------------------------------------------------------------------------
  2272. DefineEngineMethod( SimObject, getId, S32, (),,
  2273. "Get the underlying unique numeric ID of the object.\n"
  2274. "@note Object IDs are unique only during single engine runs.\n"
  2275. "@return The unique numeric ID of the object." )
  2276. {
  2277. return object->getId();
  2278. }
  2279. //-----------------------------------------------------------------------------
  2280. DefineEngineMethod( SimObject, getGroup, SimGroup*, (),,
  2281. "Get the group that this object is contained in.\n"
  2282. "@note If not assigned to particular SimGroup, an object belongs to RootGroup.\n"
  2283. "@return The SimGroup object to which the object belongs." )
  2284. {
  2285. return object->getGroup();
  2286. }
  2287. //-----------------------------------------------------------------------------
  2288. DefineConsoleMethod( SimObject, delete, void, (),,
  2289. "Delete and remove the object." )
  2290. {
  2291. object->deleteObject();
  2292. }
  2293. //-----------------------------------------------------------------------------
  2294. ConsoleMethod( SimObject,schedule, S32, 4, 0, "( float time, string method, string args... ) Delay an invocation of a method.\n"
  2295. "@param time The number of milliseconds after which to invoke the method. This is a soft limit.\n"
  2296. "@param method The method to call.\n"
  2297. "@param args The arguments with which to call the method.\n"
  2298. "@return The numeric ID of the created schedule. Can be used to cancel the call.\n" )
  2299. {
  2300. U32 timeDelta = U32(dAtof(argv[2]));
  2301. argv[2] = argv[3];
  2302. argv[3] = argv[1];
  2303. SimConsoleEvent *evt = new SimConsoleEvent(argc - 2, argv + 2, true);
  2304. S32 ret = Sim::postEvent(object, evt, Sim::getCurrentTime() + timeDelta);
  2305. // #ifdef DEBUG
  2306. // Con::printf("obj %s schedule(%s) = %d", argv[3], argv[2], ret);
  2307. // Con::executef( "backtrace");
  2308. // #endif
  2309. return ret;
  2310. }
  2311. //-----------------------------------------------------------------------------
  2312. DefineConsoleMethod( SimObject, getDynamicFieldCount, S32, (),,
  2313. "Get the number of dynamic fields defined on the object.\n"
  2314. "@return The number of dynamic fields defined on the object." )
  2315. {
  2316. S32 count = 0;
  2317. SimFieldDictionary* fieldDictionary = object->getFieldDictionary();
  2318. for (SimFieldDictionaryIterator itr(fieldDictionary); *itr; ++itr)
  2319. count++;
  2320. return count;
  2321. }
  2322. //-----------------------------------------------------------------------------
  2323. DefineConsoleMethod( SimObject, getDynamicField, const char*, ( S32 index ),,
  2324. "Get a value of a dynamic field by index.\n"
  2325. "@param index The index of the dynamic field.\n"
  2326. "@return The value of the dynamic field at the given index or \"\"." )
  2327. {
  2328. SimFieldDictionary* fieldDictionary = object->getFieldDictionary();
  2329. SimFieldDictionaryIterator itr(fieldDictionary);
  2330. for (S32 i = 0; i < index; i++)
  2331. {
  2332. if (!(*itr))
  2333. {
  2334. Con::warnf("Invalid dynamic field index passed to SimObject::getDynamicField!");
  2335. return NULL;
  2336. }
  2337. ++itr;
  2338. }
  2339. static const U32 bufSize = 256;
  2340. char* buffer = Con::getReturnBuffer(bufSize);
  2341. if (*itr)
  2342. {
  2343. SimFieldDictionary::Entry* entry = *itr;
  2344. dSprintf(buffer, bufSize, "%s\t%s", entry->slotName, entry->value);
  2345. return buffer;
  2346. }
  2347. Con::warnf("Invalid dynamic field index passed to SimObject::getDynamicField!");
  2348. return NULL;
  2349. }
  2350. //-----------------------------------------------------------------------------
  2351. DefineConsoleMethod( SimObject, getFieldCount, S32, (),,
  2352. "Get the number of static fields on the object.\n"
  2353. "@return The number of static fields defined on the object." )
  2354. {
  2355. const AbstractClassRep::FieldList &list = object->getFieldList();
  2356. const AbstractClassRep::Field* f;
  2357. U32 numDummyEntries = 0;
  2358. for(S32 i = 0; i < list.size(); i++)
  2359. {
  2360. f = &list[i];
  2361. // The special field types do not need to be counted.
  2362. if ( f->type >= AbstractClassRep::ARCFirstCustomField )
  2363. numDummyEntries++;
  2364. }
  2365. return list.size() - numDummyEntries;
  2366. }
  2367. //-----------------------------------------------------------------------------
  2368. DefineConsoleMethod( SimObject, getField, const char*, ( S32 index ),,
  2369. "Retrieve the value of a static field by index.\n"
  2370. "@param index The index of the static field.\n"
  2371. "@return The value of the static field with the given index or \"\"." )
  2372. {
  2373. const AbstractClassRep::FieldList &list = object->getFieldList();
  2374. if( ( index < 0 ) || ( index >= list.size() ) )
  2375. return "";
  2376. const AbstractClassRep::Field* f;
  2377. S32 currentField = 0;
  2378. for ( U32 i = 0; i < list.size() && currentField <= index; i++ )
  2379. {
  2380. f = &list[i];
  2381. // The special field types can be skipped.
  2382. if ( f->type >= AbstractClassRep::ARCFirstCustomField )
  2383. continue;
  2384. if(currentField == index)
  2385. return f->pFieldname;
  2386. currentField++;
  2387. }
  2388. // if we found nada, return nada.
  2389. return "";
  2390. }
  2391. //-----------------------------------------------------------------------------
  2392. #ifdef TORQUE_DEBUG
  2393. DefineEngineMethod( SimObject, getDebugInfo, ArrayObject*, (),,
  2394. "Return some behind-the-scenes information on the object.\n"
  2395. "@return An ArrayObject filled with internal information about the object." )
  2396. {
  2397. ArrayObject* array = new ArrayObject();
  2398. array->registerObject();
  2399. array->push_back( "C++|Address", String::ToString( "0x%x", object ) );
  2400. array->push_back( "C++|Size", String::ToString( object->getClassRep()->getSizeof() ) );
  2401. array->push_back( "Object|Description", object->describeSelf() );
  2402. array->push_back( "Object|FileName", object->getFilename() );
  2403. array->push_back( "Object|DeclarationLine", String::ToString( object->getDeclarationLine() ) );
  2404. array->push_back( "Object|CopySource", object->getCopySource() ?
  2405. String::ToString( "%i:%s (%s)", object->getCopySource()->getId(), object->getCopySource()->getClassName(), object->getCopySource()->getName() ) : "" );
  2406. array->push_back( "Flag|EditorOnly", object->isEditorOnly() ? "true" : "false" );
  2407. array->push_back( "Flag|NameChangeAllowed", object->isNameChangeAllowed() ? "true" : "false" );
  2408. array->push_back( "Flag|AutoDelete", object->isAutoDeleted() ? "true" : "false" );
  2409. array->push_back( "Flag|Selected", object->isSelected() ? "true" : "false" );
  2410. array->push_back( "Flag|Expanded", object->isExpanded() ? "true" : "false" );
  2411. array->push_back( "Flag|ModStaticFields", object->canModStaticFields() ? "true" : "false" );
  2412. array->push_back( "Flag|ModDynamicFields", object->canModDynamicFields() ? "true" : "false" );
  2413. array->push_back( "Flag|CanSave", object->getCanSave() ? "true" : "false" );
  2414. #ifndef TORQUE_DISABLE_MEMORY_MANAGER
  2415. Memory::Info memInfo;
  2416. Memory::getMemoryInfo( object, memInfo );
  2417. array->push_back( "Memory|AllocNumber", String::ToString( memInfo.mAllocNumber ) );
  2418. array->push_back( "Memory|AllocSize", String::ToString( memInfo.mAllocSize ) );
  2419. array->push_back( "Memory|AllocFile", memInfo.mFileName );
  2420. array->push_back( "Memory|AllocLine", String::ToString( memInfo.mLineNumber ) );
  2421. array->push_back( "Memory|IsGlobal", memInfo.mIsGlobal ? "true" : "false" );
  2422. array->push_back( "Memory|IsStatic", memInfo.mIsStatic ? "true" : "false" );
  2423. #endif
  2424. return array;
  2425. }
  2426. #endif