fieldBrushObject.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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. // Add Fields.
  46. addProtectedField("description", TypeCaseString, Offset(mDescription, FieldBrushObject), setDescription, defaultProtectedGetFn, "");
  47. addProtectedField("sortName", TypeString, Offset(mSortName, FieldBrushObject), setSortName, defaultProtectedGetFn, "");
  48. // Call Parent.
  49. Parent::initPersistFields();
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Remove from Sim.
  53. //-----------------------------------------------------------------------------
  54. void FieldBrushObject::onRemove()
  55. {
  56. // Destroy any fields.
  57. destroyFields();
  58. // Call Parent.
  59. Parent::onRemove();
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Destroy any fields.
  63. //-----------------------------------------------------------------------------
  64. void FieldBrushObject::destroyFields()
  65. {
  66. // Fetch Dynamic-Field Dictionary.
  67. SimFieldDictionary* pFieldDictionary = getFieldDictionary();
  68. // Any Field Dictionary?
  69. if ( pFieldDictionary == NULL )
  70. {
  71. // No, so we're done.
  72. return;
  73. }
  74. // Iterate fields.
  75. for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr )
  76. {
  77. // Fetch Field Entry.
  78. SimFieldDictionary::Entry* fieldEntry = *itr;
  79. // Internal Field?
  80. if ( dStrstr( fieldEntry->slotName, INTERNAL_FIELD_PREFIX ) == fieldEntry->slotName )
  81. {
  82. // Yes, so remove it.
  83. pFieldDictionary->setFieldValue( fieldEntry->slotName, "" );
  84. }
  85. }
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Suppress Spaces.
  89. //-----------------------------------------------------------------------------
  90. static char replacebuf[1024];
  91. static char* suppressSpaces(const char* in_pname)
  92. {
  93. U32 i = 0;
  94. char chr;
  95. do
  96. {
  97. chr = in_pname[i];
  98. replacebuf[i++] = (chr != 32) ? chr : '_';
  99. } while(chr);
  100. return replacebuf;
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Query Groups.
  104. //-----------------------------------------------------------------------------
  105. DefineEngineMethod(FieldBrushObject, queryGroups, const char*, (const char* simObjName), , "(simObject) Query available static-field groups for selected object./\n"
  106. "@param simObject Object to query static-field groups on.\n"
  107. "@return Space-seperated static-field group list.")
  108. {
  109. // Fetch selected object.
  110. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
  111. // Valid object?
  112. if ( pSimObject == NULL )
  113. {
  114. // No, so warn.
  115. Con::warnf("FieldBrushObject::queryFieldGroups() - Invalid SimObject!");
  116. return NULL;
  117. }
  118. // Create Returnable Buffer.
  119. S32 maxBuffer = bufferSizes;
  120. char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
  121. char* pBuffer = pReturnBuffer;
  122. // Fetch Field List.
  123. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  124. // Iterate Fields.
  125. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  126. {
  127. // Fetch Field.
  128. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  129. // Start Group?
  130. if ( staticField.type == AbstractClassRep::StartGroupFieldType )
  131. {
  132. // Yes, so write-out group-name without spaces...
  133. char* pGroupNameNoSpaces = suppressSpaces(staticField.pGroupname);
  134. // Will the field fit?
  135. // NOTE:- We used "-1" to include the suffix space.
  136. if ( (maxBuffer - (S32)dStrlen(pGroupNameNoSpaces) - 1) >= 0 )
  137. {
  138. // Yes...
  139. // NOTE:- The group-name does not have the "_begingroup" suffix which should stay hidden.
  140. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", pGroupNameNoSpaces );
  141. pBuffer += charsWritten;
  142. maxBuffer -= charsWritten;
  143. }
  144. else
  145. {
  146. // No, so warn.
  147. Con::warnf("FieldBrushObject::queryGroups() - Couldn't fit all groups into return string!");
  148. break;
  149. }
  150. }
  151. }
  152. // Strip final space.
  153. if ( pBuffer != pReturnBuffer )
  154. {
  155. *(pBuffer-1) = 0;
  156. }
  157. // Return Buffer.
  158. return pReturnBuffer;
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Query Fields.
  162. //-----------------------------------------------------------------------------
  163. DefineEngineMethod(FieldBrushObject, queryFields, const char*, (const char* simObjName, const char* groupList), (""), "(simObject, [groupList]) Query available static-fields for selected object./\n"
  164. "@param simObject Object to query static-fields on.\n"
  165. "@param groupList groups to filter static-fields against.\n"
  166. "@return Space-seperated static-field list.")
  167. {
  168. // Fetch selected object.
  169. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
  170. // Valid object?
  171. if ( pSimObject == NULL )
  172. {
  173. // No, so warn.
  174. Con::warnf("FieldBrushObject::queryFields() - Invalid SimObject!");
  175. return NULL;
  176. }
  177. // Create Returnable Buffer.
  178. S32 maxBuffer = bufferSizes;
  179. char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
  180. char* pBuffer = pReturnBuffer;
  181. // Fetch Field List.
  182. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  183. // Did we specify a groups list?
  184. if ( String::isEmpty(groupList) )
  185. {
  186. // No, so return all fields...
  187. // Iterate fields.
  188. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  189. {
  190. // Fetch Field.
  191. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  192. // Standard Field?
  193. if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
  194. staticField.type != AbstractClassRep::EndGroupFieldType &&
  195. staticField.type != AbstractClassRep::DeprecatedFieldType )
  196. {
  197. // Yes, so will the field fit?
  198. // NOTE:- We used "-1" to include the suffix space.
  199. if ( (maxBuffer - (S32)dStrlen(staticField.pFieldname) - 1) >= 0 )
  200. {
  201. // Yes, so write-out field-name.
  202. S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", staticField.pFieldname );
  203. pBuffer += charsWritten;
  204. maxBuffer -= charsWritten;
  205. }
  206. else
  207. {
  208. // No, so warn.
  209. Con::warnf("FieldBrushObject::queryFields() - Couldn't fit all fields into return string!");
  210. break;
  211. }
  212. }
  213. }
  214. // Strip final space.
  215. if ( pBuffer != pReturnBuffer )
  216. {
  217. *(pBuffer-1) = 0;
  218. }
  219. // Return field list.
  220. return pReturnBuffer;
  221. }
  222. // Yes, so filter by groups...
  223. // Group List.
  224. Vector<StringTableEntry> groups;
  225. // Yes, so fetch group list.
  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" ), 256 );
  234. // Append internal name.
  235. dStrcat( tempBuf, "_begingroup", 256 );
  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. DefineEngineMethod(FieldBrushObject, copyFields, void, (const char* simObjName, const char* pFieldList), (""), "(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( simObjName ) );
  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. // Copy Fields.
  329. object->copyFields( pSimObject, pFieldList );
  330. }
  331. // Copy Fields.
  332. void FieldBrushObject::copyFields( SimObject* pSimObject, const char* fieldList )
  333. {
  334. // FieldBrushObject class?
  335. if ( String::compare(pSimObject->getClassName(), getClassName()) == 0 )
  336. {
  337. // Yes, so warn.
  338. Con::warnf("FieldBrushObject::copyFields() - Cannot copy FieldBrushObject objects!");
  339. return;
  340. }
  341. char tempBuf[bufferSizes];
  342. // Field List.
  343. Vector<StringTableEntry> fields;
  344. // Fetch valid field-list flag.
  345. bool validFieldList = ( fieldList != NULL );
  346. // Did we specify a fields list?
  347. if ( validFieldList )
  348. {
  349. // Yes, so calculate field Count.
  350. const U32 fieldCount = StringUnit::getUnitCount( fieldList, " \t\n" );
  351. // Iterate fields...
  352. for ( U32 fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
  353. {
  354. // Copy string element.
  355. dStrcpy( tempBuf, StringUnit::getUnit( fieldList, fieldIndex, " \t\n" ), bufferSizes );
  356. // Store field.
  357. fields.push_back( StringTable->insert( tempBuf ) );
  358. }
  359. }
  360. // Destroy Fields.
  361. destroyFields();
  362. // Fetch Field List.
  363. const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
  364. // Iterate fields.
  365. for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
  366. {
  367. // Fetch Field.
  368. const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
  369. // Standard Field?
  370. if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
  371. staticField.type != AbstractClassRep::EndGroupFieldType &&
  372. staticField.type != AbstractClassRep::DeprecatedFieldType )
  373. {
  374. // Set field-specified flag.
  375. bool fieldSpecified = !validFieldList;
  376. // Did we specify a fields list?
  377. if ( validFieldList )
  378. {
  379. // Yes, so is this field name selected?
  380. // Iterate fields...
  381. for ( U32 findFieldIDx = 0; findFieldIDx < fields.size(); ++findFieldIDx)
  382. {
  383. // Field selected?
  384. if ( staticField.pFieldname == fields[findFieldIDx] )
  385. {
  386. // Yes, so flag as such.
  387. fieldSpecified = true;
  388. break;
  389. }
  390. }
  391. }
  392. // Field specified?
  393. if ( fieldSpecified )
  394. {
  395. if ( staticField.elementCount <= 1 )
  396. {
  397. for( U32 fieldElement = 0; S32(fieldElement) < staticField.elementCount; ++fieldElement )
  398. {
  399. // Fetch Field Value.
  400. const char* fieldValue = (staticField.getDataFn)( pSimObject, Con::getData(staticField.type, (void *) (((const char *)pSimObject) + staticField.offset), fieldElement, staticField.table, staticField.flag) );
  401. // Field Value?
  402. if ( fieldValue )
  403. {
  404. // Yes.
  405. dSprintf( tempBuf, sizeof(tempBuf), INTERNAL_FIELD_PREFIX"%s", staticField.pFieldname );
  406. // Fetch Dynamic-Field Dictionary.
  407. SimFieldDictionary* pFieldDictionary = getFieldDictionary();
  408. // Set field value.
  409. if ( !pFieldDictionary )
  410. {
  411. setDataField( StringTable->insert( tempBuf ), NULL, fieldValue );
  412. }
  413. else
  414. {
  415. pFieldDictionary->setFieldValue( StringTable->insert( tempBuf ), fieldValue );
  416. }
  417. }
  418. }
  419. }
  420. }
  421. }
  422. }
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Paste Fields.
  426. //-----------------------------------------------------------------------------
  427. DefineEngineMethod(FieldBrushObject, pasteFields, void, (const char* simObjName), , "(simObject) Paste copied static-fields to selected object./\n"
  428. "@param simObject Object to paste static-fields to.\n"
  429. "@return No return value.")
  430. {
  431. // Fetch selected object.
  432. SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
  433. // Valid object?
  434. if ( pSimObject == NULL )
  435. {
  436. // No, so warn.
  437. Con::warnf("FieldBrushObject::pasteFields() - Invalid SimObject!");
  438. return;
  439. }
  440. // Paste Fields.
  441. object->pasteFields( pSimObject );
  442. }
  443. // Paste Fields.
  444. void FieldBrushObject::pasteFields( SimObject* pSimObject )
  445. {
  446. // FieldBrushObject class?
  447. if ( String::compare(pSimObject->getClassName(), getClassName()) == 0 )
  448. {
  449. // Yes, so warn.
  450. Con::warnf("FieldBrushObject::pasteFields() - Cannot paste FieldBrushObject objects!");
  451. return;
  452. }
  453. // Fetch Dynamic-Field Dictionary.
  454. SimFieldDictionary* pFieldDictionary = getFieldDictionary();
  455. // Any Field Dictionary?
  456. if ( pFieldDictionary == NULL )
  457. {
  458. // No, so we're done.
  459. return;
  460. }
  461. // Force modification of static-fields on target object!
  462. pSimObject->setModStaticFields( true );
  463. S32 prefixLength = dStrlen(INTERNAL_FIELD_PREFIX);
  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 += prefixLength;
  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 ( String::compare(staticField.pFieldname, pInternalField) == 0 )
  491. {
  492. // Yes, so set data.
  493. pSimObject->setDataField( staticField.pFieldname, NULL, fieldEntry->value );
  494. }
  495. }
  496. }
  497. }
  498. }
  499. }