fieldBrushObject.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "core/strings/stringUnit.h"
  23. #include "console/fieldBrushObject.h"
  24. #include "console/engineAPI.h"
  25. // Prefix added to dynamic-fields when they're used to store any copied static-fields when peristing.
  26. #define INTERNAL_FIELD_PREFIX "_fieldBrush_"
  27. // Size of return buffers used.
  28. const U32 bufferSizes = 1024 * 4;
  29. IMPLEMENT_CONOBJECT(FieldBrushObject);
  30. ConsoleDocClass( FieldBrushObject,
  31. "@brief For static-field copying/pasting, editor use only\n\n"
  32. "@internal"
  33. );
  34. FieldBrushObject::FieldBrushObject()
  35. {
  36. // Reset Description.
  37. mDescription = StringTable->EmptyString();
  38. mSortName = StringTable->EmptyString();
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Persist Fields.
  42. //-----------------------------------------------------------------------------
  43. void FieldBrushObject::initPersistFields()
  44. {
  45. docsURL;
  46. // Add Fields.
  47. addProtectedField("description", TypeCaseString, Offset(mDescription, FieldBrushObject), setDescription, defaultProtectedGetFn, "");
  48. addProtectedField("sortName", TypeString, Offset(mSortName, FieldBrushObject), setSortName, defaultProtectedGetFn, "");
  49. // Call Parent.
  50. Parent::initPersistFields();
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Remove from Sim.
  54. //-----------------------------------------------------------------------------
  55. void FieldBrushObject::onRemove()
  56. {
  57. // Destroy any fields.
  58. destroyFields();
  59. // Call Parent.
  60. Parent::onRemove();
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Destroy any fields.
  64. //-----------------------------------------------------------------------------
  65. void FieldBrushObject::destroyFields()
  66. {
  67. // Fetch Dynamic-Field Dictionary.
  68. SimFieldDictionary* pFieldDictionary = getFieldDictionary();
  69. // Any Field Dictionary?
  70. if ( pFieldDictionary == NULL )
  71. {
  72. // No, so we're done.
  73. return;
  74. }
  75. // Iterate fields.
  76. for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr )
  77. {
  78. // Fetch Field Entry.
  79. SimFieldDictionary::Entry* fieldEntry = *itr;
  80. // Internal Field?
  81. if ( dStrstr( fieldEntry->slotName, INTERNAL_FIELD_PREFIX ) == fieldEntry->slotName )
  82. {
  83. // Yes, so remove it.
  84. pFieldDictionary->setFieldValue( fieldEntry->slotName, "" );
  85. }
  86. }
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Suppress Spaces.
  90. //-----------------------------------------------------------------------------
  91. static char replacebuf[1024];
  92. static char* suppressSpaces(const char* in_pname)
  93. {
  94. U32 i = 0;
  95. char chr;
  96. do
  97. {
  98. chr = in_pname[i];
  99. replacebuf[i++] = (chr != 32) ? chr : '_';
  100. } while(chr);
  101. return replacebuf;
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Query Groups.
  105. //-----------------------------------------------------------------------------
  106. DefineEngineMethod(FieldBrushObject, queryGroups, const char*, (const char* simObjName), , "(simObject) Query available static-field groups for selected object./\n"
  107. "@param simObject Object to query static-field groups on.\n"
  108. "@return Space-seperated static-field group list.")
  109. {
  110. // Fetch selected object.
  111. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
  112. // Valid object?
  113. if ( pSimObject == NULL )
  114. {
  115. // No, so warn.
  116. Con::warnf("FieldBrushObject::queryFieldGroups() - Invalid SimObject!");
  117. return NULL;
  118. }
  119. // Create Returnable Buffer.
  120. S32 maxBuffer = bufferSizes;
  121. char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
  122. char* pBuffer = pReturnBuffer;
  123. // Fetch Field List.
  124. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  125. // Iterate Fields.
  126. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  127. {
  128. // Fetch Field.
  129. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  130. // Start Group?
  131. if ( staticField.type == AbstractClassRep::StartGroupFieldType )
  132. {
  133. // Yes, so write-out group-name without spaces...
  134. char* pGroupNameNoSpaces = suppressSpaces(staticField.pGroupname);
  135. // Will the field fit?
  136. // NOTE:- We used "-1" to include the suffix space.
  137. if ( (maxBuffer - (S32)dStrlen(pGroupNameNoSpaces) - 1) >= 0 )
  138. {
  139. // Yes...
  140. // NOTE:- The group-name does not have the "_begingroup" suffix which should stay hidden.
  141. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", pGroupNameNoSpaces );
  142. pBuffer += charsWritten;
  143. maxBuffer -= charsWritten;
  144. }
  145. else
  146. {
  147. // No, so warn.
  148. Con::warnf("FieldBrushObject::queryGroups() - Couldn't fit all groups into return string!");
  149. break;
  150. }
  151. }
  152. }
  153. // Strip final space.
  154. if ( pBuffer != pReturnBuffer )
  155. {
  156. *(pBuffer-1) = 0;
  157. }
  158. // Return Buffer.
  159. return pReturnBuffer;
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Query Fields.
  163. //-----------------------------------------------------------------------------
  164. DefineEngineMethod(FieldBrushObject, queryFields, const char*, (const char* simObjName, const char* groupList), (""), "(simObject, [groupList]) Query available static-fields for selected object./\n"
  165. "@param simObject Object to query static-fields on.\n"
  166. "@param groupList groups to filter static-fields against.\n"
  167. "@return Space-seperated static-field list.")
  168. {
  169. // Fetch selected object.
  170. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
  171. // Valid object?
  172. if ( pSimObject == NULL )
  173. {
  174. // No, so warn.
  175. Con::warnf("FieldBrushObject::queryFields() - Invalid SimObject!");
  176. return NULL;
  177. }
  178. // Create Returnable Buffer.
  179. S32 maxBuffer = bufferSizes;
  180. char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
  181. char* pBuffer = pReturnBuffer;
  182. // Fetch Field List.
  183. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  184. // Did we specify a groups list?
  185. if ( String::isEmpty(groupList) )
  186. {
  187. // No, so return all fields...
  188. // Iterate fields.
  189. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  190. {
  191. // Fetch Field.
  192. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  193. // Standard Field?
  194. if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
  195. staticField.type != AbstractClassRep::EndGroupFieldType &&
  196. staticField.type != AbstractClassRep::DeprecatedFieldType )
  197. {
  198. // Yes, so will the field fit?
  199. // NOTE:- We used "-1" to include the suffix space.
  200. if ( (maxBuffer - (S32)dStrlen(staticField.pFieldname) - 1) >= 0 )
  201. {
  202. // Yes, so write-out field-name.
  203. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", staticField.pFieldname );
  204. pBuffer += charsWritten;
  205. maxBuffer -= charsWritten;
  206. }
  207. else
  208. {
  209. // No, so warn.
  210. Con::warnf("FieldBrushObject::queryFields() - Couldn't fit all fields into return string!");
  211. break;
  212. }
  213. }
  214. }
  215. // Strip final space.
  216. if ( pBuffer != pReturnBuffer )
  217. {
  218. *(pBuffer-1) = 0;
  219. }
  220. // Return field list.
  221. return pReturnBuffer;
  222. }
  223. // Yes, so filter by groups...
  224. // Group List.
  225. Vector<StringTableEntry> groups;
  226. // Yes, so fetch group list.
  227. // Yes, so calculate group Count.
  228. const U32 groupCount = StringUnit::getUnitCount( groupList, " \t\n" );
  229. char tempBuf[256];
  230. // Iterate groups...
  231. for ( U32 groupIndex = 0; groupIndex < groupCount; ++groupIndex )
  232. {
  233. // Copy string element.
  234. dStrcpy( tempBuf, StringUnit::getUnit( groupList, groupIndex, " \t\n" ), 256 );
  235. // Append internal name.
  236. dStrcat( tempBuf, "_begingroup", 256 );
  237. // Store Group.
  238. groups.push_back( StringTable->insert( tempBuf ) );
  239. }
  240. // Reset Valid Group.
  241. bool validGroup = false;
  242. // Iterate fields.
  243. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  244. {
  245. // Fetch Field.
  246. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  247. // Handle Group Type.
  248. switch( staticField.type )
  249. {
  250. // Start Group.
  251. case AbstractClassRep::StartGroupFieldType:
  252. {
  253. // Is this group valid?
  254. // Iterate groups...
  255. for ( U32 groupIndex = 0; groupIndex < groups.size(); ++groupIndex )
  256. {
  257. // Group selected?
  258. if ( groups[groupIndex] == staticField.pFieldname )
  259. {
  260. // Yes, so flag as valid.
  261. validGroup = true;
  262. break;
  263. }
  264. }
  265. } break;
  266. // End Group.
  267. case AbstractClassRep::EndGroupFieldType:
  268. {
  269. // Reset Valid Group.
  270. validGroup = false;
  271. } break;
  272. // Deprecated.
  273. case AbstractClassRep::DeprecatedFieldType:
  274. {
  275. } break;
  276. // Standard.
  277. default:
  278. {
  279. // Do we have a valid group?
  280. if ( validGroup )
  281. {
  282. // Yes, so will the field fit?
  283. // NOTE:- We used "-1" to include the suffix space.
  284. if ( (maxBuffer - (S32)dStrlen(staticField.pFieldname) - 1) >= 0 )
  285. {
  286. // Yes, so write-out field-name.
  287. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", staticField.pFieldname );
  288. pBuffer += charsWritten;
  289. maxBuffer -= charsWritten;
  290. }
  291. else
  292. {
  293. // No, so warn.
  294. Con::warnf("FieldBrushObject::queryFields() - Couldn't fit all fields into return string!");
  295. // HACK: Easy way to finish iterating fields.
  296. fieldIndex = staticFields.size();
  297. break;
  298. }
  299. }
  300. } break;
  301. };
  302. }
  303. // Strip final space.
  304. if ( pBuffer != pReturnBuffer )
  305. {
  306. *(pBuffer-1) = 0;
  307. }
  308. // Return field list.
  309. return pReturnBuffer;
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Copy Fields.
  313. //-----------------------------------------------------------------------------
  314. DefineEngineMethod(FieldBrushObject, copyFields, void, (const char* simObjName, const char* pFieldList), (""), "(simObject, [fieldList]) Copy selected static-fields for selected object./\n"
  315. "@param simObject Object to copy static-fields from.\n"
  316. "@param fieldList fields to filter static-fields against.\n"
  317. "@return No return value.")
  318. {
  319. // Fetch selected object.
  320. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
  321. // Valid object?
  322. if ( pSimObject == NULL )
  323. {
  324. // No, so warn.
  325. Con::warnf("FieldBrushObject::copyFields() - Invalid SimObject!");
  326. return;
  327. }
  328. // Fetch field list.
  329. // Copy Fields.
  330. object->copyFields( pSimObject, pFieldList );
  331. }
  332. // Copy Fields.
  333. void FieldBrushObject::copyFields( SimObject* pSimObject, const char* fieldList )
  334. {
  335. // FieldBrushObject class?
  336. if ( String::compare(pSimObject->getClassName(), getClassName()) == 0 )
  337. {
  338. // Yes, so warn.
  339. Con::warnf("FieldBrushObject::copyFields() - Cannot copy FieldBrushObject objects!");
  340. return;
  341. }
  342. char tempBuf[bufferSizes];
  343. // Field List.
  344. Vector<StringTableEntry> fields;
  345. // Fetch valid field-list flag.
  346. bool validFieldList = ( fieldList != NULL );
  347. // Did we specify a fields list?
  348. if ( validFieldList )
  349. {
  350. // Yes, so calculate field Count.
  351. const U32 fieldCount = StringUnit::getUnitCount( fieldList, " \t\n" );
  352. // Iterate fields...
  353. for ( U32 fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
  354. {
  355. // Copy string element.
  356. dStrcpy( tempBuf, StringUnit::getUnit( fieldList, fieldIndex, " \t\n" ), bufferSizes );
  357. // Store field.
  358. fields.push_back( StringTable->insert( tempBuf ) );
  359. }
  360. }
  361. // Destroy Fields.
  362. destroyFields();
  363. // Fetch Field List.
  364. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  365. // Iterate fields.
  366. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  367. {
  368. // Fetch Field.
  369. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  370. // Standard Field?
  371. if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
  372. staticField.type != AbstractClassRep::EndGroupFieldType &&
  373. staticField.type != AbstractClassRep::DeprecatedFieldType )
  374. {
  375. // Set field-specified flag.
  376. bool fieldSpecified = !validFieldList;
  377. // Did we specify a fields list?
  378. if ( validFieldList )
  379. {
  380. // Yes, so is this field name selected?
  381. // Iterate fields...
  382. for ( U32 findFieldIDx = 0; findFieldIDx < fields.size(); ++findFieldIDx)
  383. {
  384. // Field selected?
  385. if ( staticField.pFieldname == fields[findFieldIDx] )
  386. {
  387. // Yes, so flag as such.
  388. fieldSpecified = true;
  389. break;
  390. }
  391. }
  392. }
  393. // Field specified?
  394. if ( fieldSpecified )
  395. {
  396. if ( staticField.elementCount <= 1 )
  397. {
  398. for( U32 fieldElement = 0; S32(fieldElement) < staticField.elementCount; ++fieldElement )
  399. {
  400. // Fetch Field Value.
  401. const char* fieldValue = (staticField.getDataFn)( pSimObject, Con::getData(staticField.type, (void *) (((const char *)pSimObject) + staticField.offset), fieldElement, staticField.table, staticField.flag) );
  402. // Field Value?
  403. if ( fieldValue )
  404. {
  405. // Yes.
  406. dSprintf( tempBuf, sizeof(tempBuf), INTERNAL_FIELD_PREFIX"%s", staticField.pFieldname );
  407. // Fetch Dynamic-Field Dictionary.
  408. SimFieldDictionary* pFieldDictionary = getFieldDictionary();
  409. // Set field value.
  410. if ( !pFieldDictionary )
  411. {
  412. setDataField( StringTable->insert( tempBuf ), NULL, fieldValue );
  413. }
  414. else
  415. {
  416. pFieldDictionary->setFieldValue( StringTable->insert( tempBuf ), fieldValue );
  417. }
  418. }
  419. }
  420. }
  421. }
  422. }
  423. }
  424. }
  425. //-----------------------------------------------------------------------------
  426. // Paste Fields.
  427. //-----------------------------------------------------------------------------
  428. DefineEngineMethod(FieldBrushObject, pasteFields, void, (const char* simObjName), , "(simObject) Paste copied static-fields to selected object./\n"
  429. "@param simObject Object to paste static-fields to.\n"
  430. "@return No return value.")
  431. {
  432. // Fetch selected object.
  433. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
  434. // Valid object?
  435. if ( pSimObject == NULL )
  436. {
  437. // No, so warn.
  438. Con::warnf("FieldBrushObject::pasteFields() - Invalid SimObject!");
  439. return;
  440. }
  441. // Paste Fields.
  442. object->pasteFields( pSimObject );
  443. }
  444. // Paste Fields.
  445. void FieldBrushObject::pasteFields( SimObject* pSimObject )
  446. {
  447. // FieldBrushObject class?
  448. if ( String::compare(pSimObject->getClassName(), getClassName()) == 0 )
  449. {
  450. // Yes, so warn.
  451. Con::warnf("FieldBrushObject::pasteFields() - Cannot paste FieldBrushObject objects!");
  452. return;
  453. }
  454. // Fetch Dynamic-Field Dictionary.
  455. SimFieldDictionary* pFieldDictionary = getFieldDictionary();
  456. // Any Field Dictionary?
  457. if ( pFieldDictionary == NULL )
  458. {
  459. // No, so we're done.
  460. return;
  461. }
  462. // Force modification of static-fields on target object!
  463. pSimObject->setModStaticFields( true );
  464. S32 prefixLength = dStrlen(INTERNAL_FIELD_PREFIX);
  465. // Iterate fields.
  466. for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr )
  467. {
  468. // Fetch Field Entry.
  469. SimFieldDictionary::Entry* fieldEntry = *itr;
  470. // Internal Field?
  471. char* pInternalField = dStrstr( fieldEntry->slotName, INTERNAL_FIELD_PREFIX );
  472. if ( pInternalField == fieldEntry->slotName )
  473. {
  474. // Yes, so skip the prefix.
  475. pInternalField += prefixLength;
  476. // Is this a static-field on the target object?
  477. // NOTE:- We're doing this so we don't end-up creating a dynamic-field if it isn't present.
  478. // Fetch Field List.
  479. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  480. // Iterate fields.
  481. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  482. {
  483. // Fetch Field.
  484. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  485. // Standard Field?
  486. if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
  487. staticField.type != AbstractClassRep::EndGroupFieldType &&
  488. staticField.type != AbstractClassRep::DeprecatedFieldType )
  489. {
  490. // Target field?
  491. if ( String::compare(staticField.pFieldname, pInternalField) == 0 )
  492. {
  493. // Yes, so set data.
  494. pSimObject->setDataField( staticField.pFieldname, NULL, fieldEntry->value );
  495. }
  496. }
  497. }
  498. }
  499. }
  500. }