simObject.cpp 100 KB

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