missionMarker.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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 "T3D/missionMarker.h"
  23. #include "console/consoleTypes.h"
  24. #include "core/color.h"
  25. #include "console/engineAPI.h"
  26. #include "console/script.h"
  27. extern bool gEditingMission;
  28. IMPLEMENT_CO_DATABLOCK_V1(MissionMarkerData);
  29. ConsoleDocClass( MissionMarkerData,
  30. "@brief A very basic class containing information used by MissionMarker objects for rendering\n\n"
  31. "MissionMarkerData, is an extremely barebones class derived from ShapeBaseData. It is solely used by "
  32. "MissionMarker classes (such as SpawnSphere), so that you can see the object while editing a level.\n\n"
  33. "@tsexample\n"
  34. "datablock MissionMarkerData(SpawnSphereMarker)\n"
  35. "{\n"
  36. " category = \"Misc\";\n"
  37. " shapeFile = \"core/art/shapes/octahedron.dts\";\n"
  38. "};\n"
  39. "@endtsexample\n\n"
  40. "@see MissionMarker\n\n"
  41. "@see SpawnSphere\n\n"
  42. "@see WayPoint\n\n"
  43. "@ingroup enviroMisc\n"
  44. );
  45. //------------------------------------------------------------------------------
  46. // Class: MissionMarker
  47. //------------------------------------------------------------------------------
  48. IMPLEMENT_CO_NETOBJECT_V1(MissionMarker);
  49. ConsoleDocClass( MissionMarker,
  50. "@brief This is a base class for all \"marker\" related objets. It is a 3D representation of a point in the level.\n\n"
  51. "The main use of a MissionMarker is to represent a point in 3D space with a mesh and basic ShapeBase information. "
  52. "If you simply need to mark a spot in your level, with no overhead from additional fields, this is a useful object.\n\n"
  53. "@tsexample\n"
  54. "new MissionMarker()\n"
  55. "{\n"
  56. " dataBlock = \"WayPointMarker\";\n"
  57. " position = \"295.699 -171.817 280.124\";\n"
  58. " rotation = \"0 0 -1 13.8204\";\n"
  59. " scale = \"1 1 1\";\n"
  60. " isRenderEnabled = \"true\";\n"
  61. " canSaveDynamicFields = \"1\";\n"
  62. " enabled = \"1\";\n"
  63. "};\n"
  64. "@endtsexample\n\n"
  65. "@note MissionMarkers will not add themselves to the scene except when in the editor.\n\n"
  66. "@see MissionMarkerData\n\n"
  67. "@see SpawnSphere\n\n"
  68. "@see WayPoint\n\n"
  69. "@ingroup enviroMisc\n"
  70. );
  71. MissionMarker::MissionMarker()
  72. {
  73. mTypeMask |= StaticObjectType | MarkerObjectType;
  74. mDataBlock = 0;
  75. mAddedToScene = false;
  76. mNetFlags.set(Ghostable | ScopeAlways);
  77. }
  78. bool MissionMarker::onAdd()
  79. {
  80. if(!Parent::onAdd() || !mDataBlock)
  81. return(false);
  82. if(gEditingMission)
  83. {
  84. addToScene();
  85. mAddedToScene = true;
  86. }
  87. return(true);
  88. }
  89. void MissionMarker::onRemove()
  90. {
  91. if( mAddedToScene )
  92. {
  93. removeFromScene();
  94. mAddedToScene = false;
  95. }
  96. Parent::onRemove();
  97. }
  98. void MissionMarker::inspectPostApply()
  99. {
  100. Parent::inspectPostApply();
  101. setMaskBits(PositionMask);
  102. }
  103. void MissionMarker::onEditorEnable()
  104. {
  105. if(!mAddedToScene)
  106. {
  107. addToScene();
  108. mAddedToScene = true;
  109. }
  110. }
  111. void MissionMarker::onEditorDisable()
  112. {
  113. if(mAddedToScene)
  114. {
  115. removeFromScene();
  116. mAddedToScene = false;
  117. }
  118. }
  119. bool MissionMarker::onNewDataBlock( GameBaseData *dptr, bool reload )
  120. {
  121. mDataBlock = dynamic_cast<MissionMarkerData*>( dptr );
  122. if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
  123. return(false);
  124. scriptOnNewDataBlock(reload);
  125. return(true);
  126. }
  127. void MissionMarker::setTransform(const MatrixF& mat)
  128. {
  129. Parent::setTransform(mat);
  130. setMaskBits(PositionMask);
  131. }
  132. U32 MissionMarker::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
  133. {
  134. U32 retMask = Parent::packUpdate(con, mask, stream);
  135. if(stream->writeFlag(mask & PositionMask))
  136. {
  137. stream->writeAffineTransform(mObjToWorld);
  138. mathWrite(*stream, mObjScale);
  139. }
  140. return(retMask);
  141. }
  142. void MissionMarker::unpackUpdate(NetConnection * con, BitStream * stream)
  143. {
  144. Parent::unpackUpdate(con, stream);
  145. if(stream->readFlag())
  146. {
  147. MatrixF mat;
  148. stream->readAffineTransform(&mat);
  149. Parent::setTransform(mat);
  150. Point3F scale;
  151. mathRead(*stream, &scale);
  152. setScale(scale);
  153. }
  154. }
  155. void MissionMarker::initPersistFields()
  156. {
  157. docsURL;
  158. Parent::initPersistFields();
  159. }
  160. //------------------------------------------------------------------------------
  161. // Class: WayPoint
  162. //------------------------------------------------------------------------------
  163. IMPLEMENT_CO_NETOBJECT_V1(WayPoint);
  164. ConsoleDocClass( WayPoint,
  165. "@brief Special type of marker, distinguished by a name and team ID number\n\n"
  166. "The original Torque engines were built from a multi-player game called Tribes. "
  167. "The Tribes series featured various team based game modes, such as capture the flag. "
  168. "The WayPoint class survived the conversion from game (Tribes) to game engine (Torque).\n\n"
  169. "Essentially, this is a MissionMarker with the addition of two variables: markerName and team. "
  170. "Whenever a WayPoint is created, it is added to a unique global list called WayPointSet. "
  171. "You can iterate through this set, seeking out specific markers determined by their markerName and team ID. "
  172. "This avoids the overhead of constantly calling commandToClient and commandToServer to determine "
  173. "a WayPoint object's name, unique ID, etc.\n\n"
  174. "@note The <i>markerName<i> field was previously called <i>name</i>, but was changed "
  175. "because this conflicted with the SimObject name field. Existing scripts that relied "
  176. "on the WayPoint <i>name</i> field will need to be updated.\n\n"
  177. "@tsexample\n"
  178. "new WayPoint()\n"
  179. "{\n"
  180. " team = \"1\";\n"
  181. " dataBlock = \"WayPointMarker\";\n"
  182. " position = \"-0.0224786 1.53471 2.93219\";\n"
  183. " rotation = \"1 0 0 0\";\n"
  184. " scale = \"1 1 1\";\n"
  185. " canSave = \"1\";\n"
  186. " canSaveDynamicFields = \"1\";\n"
  187. "};\n"
  188. "@endtsexample\n\n"
  189. "@see MissionMarker\n\n"
  190. "@see MissionMarkerData\n\n"
  191. "@ingroup enviroMisc\n"
  192. );
  193. WayPoint::WayPoint()
  194. {
  195. mName = StringTable->EmptyString();
  196. }
  197. void WayPoint::setHidden(bool hidden)
  198. {
  199. // Skip ShapeBase::setHidden (only ever added to scene if in the editor)
  200. ShapeBase::Parent::setHidden( hidden );
  201. if(isServerObject())
  202. setMaskBits(UpdateHiddenMask);
  203. }
  204. bool WayPoint::onAdd()
  205. {
  206. if(!Parent::onAdd())
  207. return(false);
  208. //
  209. if(isClientObject())
  210. Sim::getWayPointSet()->addObject(this);
  211. else
  212. {
  213. setMaskBits(UpdateNameMask|UpdateTeamMask);
  214. }
  215. return(true);
  216. }
  217. void WayPoint::inspectPostApply()
  218. {
  219. Parent::inspectPostApply();
  220. if(!mName || !mName[0])
  221. mName = StringTable->EmptyString();
  222. setMaskBits(UpdateNameMask|UpdateTeamMask);
  223. }
  224. U32 WayPoint::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
  225. {
  226. U32 retMask = Parent::packUpdate(con, mask, stream);
  227. if(stream->writeFlag(mask & UpdateNameMask))
  228. stream->writeString(mName);
  229. if(stream->writeFlag(mask & UpdateHiddenMask))
  230. stream->writeFlag(isHidden());
  231. return(retMask);
  232. }
  233. void WayPoint::unpackUpdate(NetConnection * con, BitStream * stream)
  234. {
  235. Parent::unpackUpdate(con, stream);
  236. if(stream->readFlag())
  237. mName = stream->readSTString(true);
  238. if(stream->readFlag())
  239. setHidden(stream->readFlag());
  240. }
  241. void WayPoint::initPersistFields()
  242. {
  243. docsURL;
  244. addGroup("Misc");
  245. addField("markerName", TypeCaseString, Offset(mName, WayPoint), "Unique name representing this waypoint");
  246. endGroup("Misc");
  247. Parent::initPersistFields();
  248. }
  249. //------------------------------------------------------------------------------
  250. // Class: SpawnSphere
  251. //------------------------------------------------------------------------------
  252. IMPLEMENT_CO_NETOBJECT_V1(SpawnSphere);
  253. ConsoleDocClass( SpawnSphere,
  254. "@brief This class is used for creating any type of game object, assigning it a class, datablock, and other "
  255. "properties when it is spawned.\n\n"
  256. "Torque 3D uses a simple spawn system, which can be easily modified to spawn any kind of object (of any class). "
  257. "Each new level already contains at least one SpawnSphere, which is represented by a green octahedron in stock Torque 3D. "
  258. "The spawnClass field determines the object type, such as Player, AIPlayer, etc. The spawnDataBlock field applies the "
  259. "pre-defined datablock to each spawned object instance. The really powerful feature of this class is provided by "
  260. "the spawnScript field which allows you to define a simple script (multiple lines) that will be executed once the "
  261. "object has been spawned.\n\n"
  262. "@tsexample\n"
  263. "// Define an SpawnSphere that essentially performs the following each time an object is spawned\n"
  264. "//$SpawnObject = new Player()\n"
  265. "//{\n"
  266. "// dataBlock = \"DefaultPlayerData\";\n"
  267. "// name = \"Bob\";\n"
  268. "// lifeTotal = 3;\n"
  269. "//};\n"
  270. "//echo(\"Spawned a Player: \" @ $SpawnObject);\n\n"
  271. "new SpawnSphere(DefaultSpawnSphere)\n"
  272. "{\n"
  273. " spawnClass = \"Player\";\n"
  274. " spawnDatablock = \"DefaultPlayerData\";\n"
  275. " spawnScript = \"echo(\\\"Spawned a Player: \\\" @ $SpawnObject);\"; // embedded quotes must be escaped with \\ \n"
  276. " spawnProperties = \"name = \\\"Bob\\\";lifeTotal = 3;\"; // embedded quotes must be escaped with \\ \n"
  277. " autoSpawn = \"1\";\n"
  278. " dataBlock = \"SpawnSphereMarker\";\n"
  279. " position = \"-0.77266 -19.882 17.8153\";\n"
  280. " rotation = \"1 0 0 0\";\n"
  281. " scale = \"1 1 1\";\n"
  282. " canSave = \"1\";\n"
  283. " canSaveDynamicFields = \"1\";\n"
  284. "};\n\n"
  285. "// Because autoSpawn is set to true in the above example, the following lines\n"
  286. "// of code will execute AFTER the Player object has been spawned.\n"
  287. "echo(\"Object Spawned\");\n"
  288. "echo(\"Hello World\");\n\n"
  289. "@endtsexample\n\n"
  290. "@see MissionMarker\n\n"
  291. "@see MissionMarkerData\n\n"
  292. "@ingroup gameObjects\n"
  293. "@ingroup enviroMisc\n"
  294. );
  295. SpawnSphere::SpawnSphere()
  296. {
  297. mAutoSpawn = false;
  298. mSpawnTransform = false;
  299. mRadius = 100.f;
  300. mSphereWeight = 100.f;
  301. mIndoorWeight = 100.f;
  302. mOutdoorWeight = 100.f;
  303. mSpawnIf.clear();
  304. }
  305. IMPLEMENT_CALLBACK( SpawnSphere, onAdd, void, ( U32 objectId ), ( objectId ),
  306. "Called when the SpawnSphere is being created.\n"
  307. "@param objectId The unique SimObjectId generated when SpawnSphere is created (%%this in script)\n" );
  308. bool SpawnSphere::testCondition()
  309. {
  310. if (mSpawnIf.isEmpty())
  311. return true; //we've got no tests to run so just do it
  312. //test the mapper plugged in condition line
  313. String resVar = getIdString() + String(".result");
  314. Con::setBoolVariable(resVar.c_str(), false);
  315. String command = resVar + "=" + mSpawnIf + ";";
  316. Con::evaluatef(command.c_str());
  317. if (Con::getBoolVariable(resVar.c_str()) == 1)
  318. {
  319. return true;
  320. }
  321. return false;
  322. }
  323. bool SpawnSphere::onAdd()
  324. {
  325. if(!Parent::onAdd())
  326. return(false);
  327. if(!isClientObject())
  328. setMaskBits(UpdateSphereMask);
  329. if (!isGhost())
  330. {
  331. onAdd_callback( getId());
  332. if (mAutoSpawn && testCondition())
  333. spawnObject();
  334. }
  335. return true;
  336. }
  337. SimObject* SpawnSphere::spawnObject(String additionalProps)
  338. {
  339. String command = String("%this = ") + getIdString() + ";" + mSpawnScript;
  340. SimObject* spawnObject = Sim::spawnObject(mSpawnClass, mSpawnDataBlock, mSpawnName,
  341. mSpawnProperties + " " + additionalProps, command);
  342. // If we have a spawnObject add it to the MissionCleanup group
  343. if (spawnObject)
  344. {
  345. if (mSpawnTransform)
  346. {
  347. if(SceneObject *s = dynamic_cast<SceneObject*>(spawnObject))
  348. s->setTransform(getTransform());
  349. }
  350. SimObject* cleanup = Sim::findObject("MissionCleanup");
  351. if (cleanup)
  352. {
  353. SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
  354. missionCleanup->addObject(spawnObject);
  355. }
  356. }
  357. return spawnObject;
  358. }
  359. void SpawnSphere::inspectPostApply()
  360. {
  361. Parent::inspectPostApply();
  362. setMaskBits(UpdateSphereMask);
  363. }
  364. U32 SpawnSphere::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
  365. {
  366. U32 retMask = Parent::packUpdate(con, mask, stream);
  367. //
  368. if(stream->writeFlag(mask & UpdateSphereMask))
  369. {
  370. stream->writeFlag(mAutoSpawn);
  371. stream->writeFlag(mSpawnTransform);
  372. stream->write(mSpawnClass);
  373. stream->write(mSpawnDataBlock);
  374. stream->write(mSpawnName);
  375. stream->write(mSpawnProperties);
  376. stream->write(mSpawnScript);
  377. }
  378. return(retMask);
  379. }
  380. void SpawnSphere::unpackUpdate(NetConnection * con, BitStream * stream)
  381. {
  382. Parent::unpackUpdate(con, stream);
  383. if(stream->readFlag())
  384. {
  385. mAutoSpawn = stream->readFlag();
  386. mSpawnTransform = stream->readFlag();
  387. stream->read(&mSpawnClass);
  388. String oldSDB = mSpawnDataBlock;
  389. stream->read(&mSpawnDataBlock);
  390. if (oldSDB != mSpawnDataBlock)
  391. {
  392. delete mShapeInstance;
  393. ShapeBaseData *spawnedDatablock = dynamic_cast<ShapeBaseData *>(Sim::findObject(mSpawnDataBlock.c_str()));
  394. if (spawnedDatablock && spawnedDatablock->getShape())
  395. {
  396. mShapeInstance = new TSShapeInstance(spawnedDatablock->getShape());
  397. }
  398. else if (mDataBlock)
  399. {
  400. if (mDataBlock->getShape())
  401. mShapeInstance = new TSShapeInstance(mDataBlock->getShape());
  402. }
  403. }
  404. stream->read(&mSpawnName);
  405. stream->read(&mSpawnProperties);
  406. stream->read(&mSpawnScript);
  407. }
  408. }
  409. void SpawnSphere::processTick( const Move *move )
  410. {
  411. Parent::processTick( move );
  412. }
  413. void SpawnSphere::advanceTime( F32 timeDelta )
  414. {
  415. Parent::advanceTime( timeDelta );
  416. }
  417. void SpawnSphere::initPersistFields()
  418. {
  419. docsURL;
  420. addGroup( "Spawn" );
  421. addField( "spawnClass", TypeRealString, Offset(mSpawnClass, SpawnSphere),
  422. "Object class to create (eg. Player, AIPlayer, Debris etc)" );
  423. addField( "spawnDatablock", TypeRealString, Offset(mSpawnDataBlock, SpawnSphere),
  424. "Predefined datablock assigned to the object when created" );
  425. addField( "spawnProperties", TypeRealString, Offset(mSpawnProperties, SpawnSphere),
  426. "String containing semicolon (;) delimited properties to set when the object is created." );
  427. addField( "spawnScript", TypeCommand, Offset(mSpawnScript, SpawnSphere),
  428. "Command to execute immediately after spawning an object. New object id is stored in $SpawnObject. Max 255 characters." );
  429. addField( "autoSpawn", TypeBool, Offset(mAutoSpawn, SpawnSphere),
  430. "Flag to spawn object as soon as SpawnSphere is created, true to enable or false to disable." );
  431. addField("spawnIf", TypeRealString, Offset(mSpawnIf, SpawnSphere), "evaluation condition to spawn (true/false)");
  432. addField( "spawnTransform", TypeBool, Offset(mSpawnTransform, SpawnSphere),
  433. "Flag to set the spawned object's transform to the SpawnSphere's transform." );
  434. endGroup( "Spawn" );
  435. addGroup( "Dimensions" );
  436. addFieldV( "radius", TypeRangedF32, Offset(mRadius, SpawnSphere), &CommonValidators::PositiveFloat, "Deprecated" );
  437. endGroup( "Dimensions" );
  438. addGroup( "Weight" );
  439. addField( "sphereWeight", TypeF32, Offset(mSphereWeight, SpawnSphere), "Deprecated" );
  440. addField( "indoorWeight", TypeF32, Offset(mIndoorWeight, SpawnSphere), "Deprecated" );
  441. addField( "outdoorWeight", TypeF32, Offset(mOutdoorWeight, SpawnSphere), "Deprecated" );
  442. endGroup( "Weight" );
  443. Parent::initPersistFields();
  444. }
  445. ConsoleDocFragment _SpawnSpherespawnObject1(
  446. "@brief Dynamically create a new game object with a specified class, datablock, and optional properties.\n\n"
  447. "This is called on the actual SpawnSphere, not to be confused with the Sim::spawnObject() "
  448. "global function\n\n"
  449. "@param additionalProps Optional set of semiconlon delimited parameters applied to the spawn object during creation.\n\n"
  450. "@tsexample\n"
  451. "// Use the SpawnSphere::spawnObject function to create a game object\n"
  452. "// No additional properties assigned\n"
  453. "%player = DefaultSpawnSphere.spawnObject();\n\n"
  454. "@endtsexample\n\n",
  455. "SpawnSphere",
  456. "bool spawnObject(string additionalProps);"
  457. );
  458. DefineEngineMethod(SpawnSphere, spawnObject, S32, (String additionalProps), ,
  459. "([string additionalProps]) Spawns the object based on the SpawnSphere's "
  460. "class, datablock, properties, and script settings. Allows you to pass in "
  461. "extra properties."
  462. "@hide" )
  463. {
  464. //String additionalProps;
  465. //if (argc == 3)
  466. // additionalProps = String(argv[2]);
  467. SimObject* obj = object->spawnObject(additionalProps);
  468. if (obj)
  469. return obj->getId();
  470. return -1;
  471. }
  472. //------------------------------------------------------------------------------
  473. // Class: CameraBookmark
  474. //------------------------------------------------------------------------------
  475. IMPLEMENT_CO_NETOBJECT_V1(CameraBookmark);
  476. ConsoleDocClass( CameraBookmark,
  477. "@brief Special type of mission marker which allows a level editor's camera to jump to specific points.\n\n"
  478. "For Torque 3D editors only, not for actual game development\n\n"
  479. "@internal"
  480. );
  481. CameraBookmark::CameraBookmark()
  482. {
  483. mName = StringTable->EmptyString();
  484. }
  485. bool CameraBookmark::onAdd()
  486. {
  487. if(!Parent::onAdd())
  488. return(false);
  489. //
  490. if(!isClientObject())
  491. {
  492. setMaskBits(UpdateNameMask);
  493. }
  494. if( isServerObject() && isMethod("onAdd") )
  495. Con::executef( this, "onAdd" );
  496. return(true);
  497. }
  498. void CameraBookmark::onRemove()
  499. {
  500. if( isServerObject() && isMethod("onRemove") )
  501. Con::executef( this, "onRemove" );
  502. Parent::onRemove();
  503. }
  504. void CameraBookmark::onGroupAdd()
  505. {
  506. if( isServerObject() && isMethod("onGroupAdd") )
  507. Con::executef( this, "onGroupAdd" );
  508. }
  509. void CameraBookmark::onGroupRemove()
  510. {
  511. if( isServerObject() && isMethod("onGroupRemove") )
  512. Con::executef( this, "onGroupRemove" );
  513. }
  514. void CameraBookmark::inspectPostApply()
  515. {
  516. Parent::inspectPostApply();
  517. if(!mName || !mName[0])
  518. mName = StringTable->EmptyString();
  519. setMaskBits(UpdateNameMask);
  520. if( isMethod("onInspectPostApply") )
  521. Con::executef( this, "onInspectPostApply" );
  522. }
  523. U32 CameraBookmark::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
  524. {
  525. U32 retMask = Parent::packUpdate(con, mask, stream);
  526. if(stream->writeFlag(mask & UpdateNameMask))
  527. stream->writeString(mName);
  528. return(retMask);
  529. }
  530. void CameraBookmark::unpackUpdate(NetConnection * con, BitStream * stream)
  531. {
  532. Parent::unpackUpdate(con, stream);
  533. if(stream->readFlag())
  534. mName = stream->readSTString(true);
  535. }
  536. void CameraBookmark::initPersistFields()
  537. {
  538. docsURL;
  539. //addGroup("Misc");
  540. //addField("name", TypeCaseString, Offset(mName, CameraBookmark));
  541. //endGroup("Misc");
  542. Parent::initPersistFields();
  543. removeField("nameTag"); // From GameBase
  544. }