fieldBrushObject.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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. // Prefix added to dynamic-fields when they're used to store any copied static-fields when peristing.
  25. #define INTERNAL_FIELD_PREFIX "_fieldBrush_"
  26. // Size of return buffers used.
  27. const U32 bufferSizes = 1024 * 4;
  28. IMPLEMENT_CONOBJECT(FieldBrushObject);
  29. ConsoleDocClass( FieldBrushObject,
  30. "@brief For static-field copying/pasting, editor use only\n\n"
  31. "@internal"
  32. );
  33. FieldBrushObject::FieldBrushObject()
  34. {
  35. // Reset Description.
  36. mDescription = StringTable->insert("");
  37. mSortName = StringTable->insert("");
  38. }
  39. //-----------------------------------------------------------------------------
  40. // Persist Fields.
  41. //-----------------------------------------------------------------------------
  42. void FieldBrushObject::initPersistFields()
  43. {
  44. // Add Fields.
  45. addProtectedField("description", TypeCaseString, Offset(mDescription, FieldBrushObject), setDescription, defaultProtectedGetFn, "");
  46. addProtectedField("sortName", TypeString, Offset(mSortName, FieldBrushObject), setSortName, defaultProtectedGetFn, "");
  47. // Call Parent.
  48. Parent::initPersistFields();
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Remove from Sim.
  52. //-----------------------------------------------------------------------------
  53. void FieldBrushObject::onRemove()
  54. {
  55. // Destroy any fields.
  56. destroyFields();
  57. // Call Parent.
  58. Parent::onRemove();
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Destroy any fields.
  62. //-----------------------------------------------------------------------------
  63. void FieldBrushObject::destroyFields()
  64. {
  65. // Fetch Dynamic-Field Dictionary.
  66. SimFieldDictionary* pFieldDictionary = getFieldDictionary();
  67. // Any Field Dictionary?
  68. if ( pFieldDictionary == NULL )
  69. {
  70. // No, so we're done.
  71. return;
  72. }
  73. // Iterate fields.
  74. for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr )
  75. {
  76. // Fetch Field Entry.
  77. SimFieldDictionary::Entry* fieldEntry = *itr;
  78. // Internal Field?
  79. if ( dStrstr( fieldEntry->slotName, INTERNAL_FIELD_PREFIX ) == fieldEntry->slotName )
  80. {
  81. // Yes, so remove it.
  82. pFieldDictionary->setFieldValue( fieldEntry->slotName, "" );
  83. }
  84. }
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Suppress Spaces.
  88. //-----------------------------------------------------------------------------
  89. static char replacebuf[1024];
  90. static char* suppressSpaces(const char* in_pname)
  91. {
  92. U32 i = 0;
  93. char chr;
  94. do
  95. {
  96. chr = in_pname[i];
  97. replacebuf[i++] = (chr != 32) ? chr : '_';
  98. } while(chr);
  99. return replacebuf;
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Query Groups.
  103. //-----------------------------------------------------------------------------
  104. ConsoleMethod(FieldBrushObject, queryGroups, const char*, 3, 3, "(simObject) Query available static-field groups for selected object./\n"
  105. "@param simObject Object to query static-field groups on.\n"
  106. "@return Space-seperated static-field group list.")
  107. {
  108. // Fetch selected object.
  109. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( argv[2] ) );
  110. // Valid object?
  111. if ( pSimObject == NULL )
  112. {
  113. // No, so warn.
  114. Con::warnf("FieldBrushObject::queryFieldGroups() - Invalid SimObject!");
  115. return NULL;
  116. }
  117. // Create Returnable Buffer.
  118. S32 maxBuffer = bufferSizes;
  119. char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
  120. char* pBuffer = pReturnBuffer;
  121. // Fetch Field List.
  122. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  123. // Iterate Fields.
  124. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  125. {
  126. // Fetch Field.
  127. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  128. // Start Group?
  129. if ( staticField.type == AbstractClassRep::StartGroupFieldType )
  130. {
  131. // Yes, so write-out group-name without spaces...
  132. char* pGroupNameNoSpaces = suppressSpaces(staticField.pGroupname);
  133. // Will the field fit?
  134. // NOTE:- We used "-1" to include the suffix space.
  135. if ( (maxBuffer - (S32)dStrlen(pGroupNameNoSpaces) - 1) >= 0 )
  136. {
  137. // Yes...
  138. // NOTE:- The group-name does not have the "_begingroup" suffix which should stay hidden.
  139. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", pGroupNameNoSpaces );
  140. pBuffer += charsWritten;
  141. maxBuffer -= charsWritten;
  142. }
  143. else
  144. {
  145. // No, so warn.
  146. Con::warnf("FieldBrushObject::queryGroups() - Couldn't fit all groups into return string!");
  147. break;
  148. }
  149. }
  150. }
  151. // Strip final space.
  152. if ( pBuffer != pReturnBuffer )
  153. {
  154. *(pBuffer-1) = 0;
  155. }
  156. // Return Buffer.
  157. return pReturnBuffer;
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Query Fields.
  161. //-----------------------------------------------------------------------------
  162. ConsoleMethod(FieldBrushObject, queryFields, const char*, 3, 4, "(simObject, [groupList]) Query available static-fields for selected object./\n"
  163. "@param simObject Object to query static-fields on.\n"
  164. "@param groupList groups to filter static-fields against.\n"
  165. "@return Space-seperated static-field list.")
  166. {
  167. // Fetch selected object.
  168. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( argv[2] ) );
  169. // Valid object?
  170. if ( pSimObject == NULL )
  171. {
  172. // No, so warn.
  173. Con::warnf("FieldBrushObject::queryFields() - Invalid SimObject!");
  174. return NULL;
  175. }
  176. // Create Returnable Buffer.
  177. S32 maxBuffer = bufferSizes;
  178. char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
  179. char* pBuffer = pReturnBuffer;
  180. // Fetch Field List.
  181. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  182. // Did we specify a groups list?
  183. if ( argc < 4 )
  184. {
  185. // No, so return all fields...
  186. // Iterate fields.
  187. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  188. {
  189. // Fetch Field.
  190. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  191. // Standard Field?
  192. if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
  193. staticField.type != AbstractClassRep::EndGroupFieldType &&
  194. staticField.type != AbstractClassRep::DeprecatedFieldType )
  195. {
  196. // Yes, so will the field fit?
  197. // NOTE:- We used "-1" to include the suffix space.
  198. if ( (maxBuffer - (S32)dStrlen(staticField.pFieldname) - 1) >= 0 )
  199. {
  200. // Yes, so write-out field-name.
  201. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", staticField.pFieldname );
  202. pBuffer += charsWritten;
  203. maxBuffer -= charsWritten;
  204. }
  205. else
  206. {
  207. // No, so warn.
  208. Con::warnf("FieldBrushObject::queryFields() - Couldn't fit all fields into return string!");
  209. break;
  210. }
  211. }
  212. }
  213. // Strip final space.
  214. if ( pBuffer != pReturnBuffer )
  215. {
  216. *(pBuffer-1) = 0;
  217. }
  218. // Return field list.
  219. return pReturnBuffer;
  220. }
  221. // Yes, so filter by groups...
  222. // Group List.
  223. Vector<StringTableEntry> groups;
  224. // Yes, so fetch group list.
  225. const char* groupList = argv[3];
  226. // Yes, so calculate group Count.
  227. const U32 groupCount = StringUnit::getUnitCount( groupList, " \t\n" );
  228. char tempBuf[256];
  229. // Iterate groups...
  230. for ( U32 groupIndex = 0; groupIndex < groupCount; ++groupIndex )
  231. {
  232. // Copy string element.
  233. dStrcpy( tempBuf, StringUnit::getUnit( groupList, groupIndex, " \t\n" ) );
  234. // Append internal name.
  235. dStrcat( tempBuf, "_begingroup" );
  236. // Store Group.
  237. groups.push_back( StringTable->insert( tempBuf ) );
  238. }
  239. // Reset Valid Group.
  240. bool validGroup = false;
  241. // Iterate fields.
  242. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  243. {
  244. // Fetch Field.
  245. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  246. // Handle Group Type.
  247. switch( staticField.type )
  248. {
  249. // Start Group.
  250. case AbstractClassRep::StartGroupFieldType:
  251. {
  252. // Is this group valid?
  253. // Iterate groups...
  254. for ( U32 groupIndex = 0; groupIndex < groups.size(); ++groupIndex )
  255. {
  256. // Group selected?
  257. if ( groups[groupIndex] == staticField.pFieldname )
  258. {
  259. // Yes, so flag as valid.
  260. validGroup = true;
  261. break;
  262. }
  263. }
  264. } break;
  265. // End Group.
  266. case AbstractClassRep::EndGroupFieldType:
  267. {
  268. // Reset Valid Group.
  269. validGroup = false;
  270. } break;
  271. // Deprecated.
  272. case AbstractClassRep::DeprecatedFieldType:
  273. {
  274. } break;
  275. // Standard.
  276. default:
  277. {
  278. // Do we have a valid group?
  279. if ( validGroup )
  280. {
  281. // Yes, so will the field fit?
  282. // NOTE:- We used "-1" to include the suffix space.
  283. if ( (maxBuffer - (S32)dStrlen(staticField.pFieldname) - 1) >= 0 )
  284. {
  285. // Yes, so write-out field-name.
  286. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", staticField.pFieldname );
  287. pBuffer += charsWritten;
  288. maxBuffer -= charsWritten;
  289. }
  290. else
  291. {
  292. // No, so warn.
  293. Con::warnf("FieldBrushObject::queryFields() - Couldn't fit all fields into return string!");
  294. // HACK: Easy way to finish iterating fields.
  295. fieldIndex = staticFields.size();
  296. break;
  297. }
  298. }
  299. } break;
  300. };
  301. }
  302. // Strip final space.
  303. if ( pBuffer != pReturnBuffer )
  304. {
  305. *(pBuffer-1) = 0;
  306. }
  307. // Return field list.
  308. return pReturnBuffer;
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Copy Fields.
  312. //-----------------------------------------------------------------------------
  313. ConsoleMethod(FieldBrushObject, copyFields, void, 3, 4, "(simObject, [fieldList]) Copy selected static-fields for selected object./\n"
  314. "@param simObject Object to copy static-fields from.\n"
  315. "@param fieldList fields to filter static-fields against.\n"
  316. "@return No return value.")
  317. {
  318. // Fetch selected object.
  319. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( argv[2] ) );
  320. // Valid object?
  321. if ( pSimObject == NULL )
  322. {
  323. // No, so warn.
  324. Con::warnf("FieldBrushObject::copyFields() - Invalid SimObject!");
  325. return;
  326. }
  327. // Fetch field list.
  328. const char* pFieldList = (argc > 3 ) ? argv[3] : NULL;
  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 ( dStrcmp(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" ) );
  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 fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex )
  383. {
  384. // Field selected?
  385. if ( staticField.pFieldname == fields[fieldIndex] )
  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. ConsoleMethod(FieldBrushObject, pasteFields, void, 3, 3, "(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( argv[2] ) );
  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 ( dStrcmp(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. // Iterate fields.
  465. for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr )
  466. {
  467. // Fetch Field Entry.
  468. SimFieldDictionary::Entry* fieldEntry = *itr;
  469. // Internal Field?
  470. char* pInternalField = dStrstr( fieldEntry->slotName, INTERNAL_FIELD_PREFIX );
  471. if ( pInternalField == fieldEntry->slotName )
  472. {
  473. // Yes, so skip the prefix.
  474. pInternalField += dStrlen(INTERNAL_FIELD_PREFIX);
  475. // Is this a static-field on the target object?
  476. // NOTE:- We're doing this so we don't end-up creating a dynamic-field if it isn't present.
  477. // Fetch Field List.
  478. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  479. // Iterate fields.
  480. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  481. {
  482. // Fetch Field.
  483. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  484. // Standard Field?
  485. if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
  486. staticField.type != AbstractClassRep::EndGroupFieldType &&
  487. staticField.type != AbstractClassRep::DeprecatedFieldType )
  488. {
  489. // Target field?
  490. if ( dStrcmp(staticField.pFieldname, pInternalField) == 0 )
  491. {
  492. // Yes, so set data.
  493. pSimObject->setDataField( staticField.pFieldname, NULL, fieldEntry->value );
  494. }
  495. }
  496. }
  497. }
  498. }
  499. }