gameBase.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  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 "platform/platform.h"
  23. #include "T3D/gameBase/gameBase.h"
  24. #include "console/consoleTypes.h"
  25. #include "console/engineAPI.h"
  26. #include "console/consoleInternal.h"
  27. #include "core/stream/bitStream.h"
  28. #include "sim/netConnection.h"
  29. #include "T3D/gameBase/gameConnection.h"
  30. #include "math/mathIO.h"
  31. #include "T3D/gameBase/moveManager.h"
  32. #include "T3D/gameBase/gameProcess.h"
  33. #ifdef TORQUE_DEBUG_NET_MOVES
  34. #include "T3D/aiConnection.h"
  35. #endif
  36. //----------------------------------------------------------------------------
  37. // Ghost update relative priority values
  38. static F32 sUpFov = 1.0;
  39. static F32 sUpDistance = 0.4f;
  40. static F32 sUpVelocity = 0.4f;
  41. static F32 sUpSkips = 0.2f;
  42. static F32 sUpInterest = 0.2f;
  43. //----------------------------------------------------------------------------
  44. IMPLEMENT_CO_DATABLOCK_V1(GameBaseData);
  45. ConsoleDocClass( GameBaseData,
  46. "@brief Scriptable, demo-able datablock. Used by GameBase objects.\n\n"
  47. "@see GameBase\n"
  48. "@ingroup gameObjects\n"
  49. );
  50. IMPLEMENT_CALLBACK( GameBaseData, onAdd, void, ( GameBase* obj ), ( obj ),
  51. "@brief Called when the object is added to the scene.\n\n"
  52. "@param obj the GameBase object\n\n"
  53. "@tsexample\n"
  54. "datablock GameBaseData(MyObjectData)\n"
  55. "{\n"
  56. " category = \"Misc\";\n"
  57. "};\n\n"
  58. "function MyObjectData::onAdd( %this, %obj )\n"
  59. "{\n"
  60. " echo( \"Added \" @ %obj.getName() @ \" to the scene.\" );\n"
  61. "}\n\n"
  62. "function MyObjectData::onNewDataBlock( %this, %obj )\n"
  63. "{\n"
  64. " echo( \"Assign \" @ %this.getName() @ \" datablock to \" %obj.getName() );\n"
  65. "}\n\n"
  66. "function MyObjectData::onRemove( %this, %obj )\n"
  67. "{\n"
  68. " echo( \"Removed \" @ %obj.getName() @ \" to the scene.\" );\n"
  69. "}\n\n"
  70. "function MyObjectData::onMount( %this, %obj, %mountObj, %node )\n"
  71. "{\n"
  72. " echo( %obj.getName() @ \" mounted to \" @ %mountObj.getName() );\n"
  73. "}\n\n"
  74. "function MyObjectData::onUnmount( %this, %obj, %mountObj, %node )\n"
  75. "{\n"
  76. " echo( %obj.getName() @ \" unmounted from \" @ %mountObj.getName() );\n"
  77. "}\n\n"
  78. "@endtsexample\n" );
  79. IMPLEMENT_CALLBACK( GameBaseData, onNewDataBlock, void, ( GameBase* obj ), ( obj ),
  80. "@brief Called when the object has a new datablock assigned.\n\n"
  81. "@param obj the GameBase object\n\n"
  82. "@see onAdd for an example\n" );
  83. IMPLEMENT_CALLBACK( GameBaseData, onRemove, void, ( GameBase* obj ), ( obj ),
  84. "@brief Called when the object is removed from the scene.\n\n"
  85. "@param obj the GameBase object\n\n"
  86. "@see onAdd for an example\n" );
  87. IMPLEMENT_CALLBACK( GameBaseData, onMount, void, ( GameBase* obj, SceneObject* mountObj, S32 node ), ( obj, mountObj, node ),
  88. "@brief Called when the object is mounted to another object in the scene.\n\n"
  89. "@param obj the GameBase object being mounted\n"
  90. "@param mountObj the object we are mounted to\n"
  91. "@param node the mountObj node we are mounted to\n\n"
  92. "@see onAdd for an example\n" );
  93. IMPLEMENT_CALLBACK( GameBaseData, onUnmount, void, ( GameBase* obj, SceneObject* mountObj, S32 node ), ( obj, mountObj, node ),
  94. "@brief Called when the object is unmounted from another object in the scene.\n\n"
  95. "@param obj the GameBase object being unmounted\n"
  96. "@param mountObj the object we are unmounted from\n"
  97. "@param node the mountObj node we are unmounted from\n\n"
  98. "@see onAdd for an example\n" );
  99. IMPLEMENT_CALLBACK( GameBase, setControl, void, ( bool controlled ), ( controlled ),
  100. "@brief Called when the client controlling the object changes.\n\n"
  101. "@param controlled true if a client now controls this object, false if no "
  102. "client controls this object.\n" );
  103. GameBaseData::GameBaseData()
  104. {
  105. category = "";
  106. packed = false;
  107. }
  108. void GameBaseData::inspectPostApply()
  109. {
  110. Parent::inspectPostApply();
  111. // Tell interested parties ( like objects referencing this datablock )
  112. // that we have been modified and they might want to rebuild...
  113. mReloadSignal.trigger();
  114. }
  115. bool GameBaseData::onAdd()
  116. {
  117. if (!Parent::onAdd())
  118. return false;
  119. return true;
  120. }
  121. void GameBaseData::initPersistFields()
  122. {
  123. addGroup("Scripting");
  124. addField( "category", TypeCaseString, Offset( category, GameBaseData ),
  125. "The group that this datablock will show up in under the \"Scripted\" "
  126. "tab in the World Editor Library." );
  127. endGroup("Scripting");
  128. Parent::initPersistFields();
  129. }
  130. bool GameBaseData::preload(bool server, String &errorStr)
  131. {
  132. if (!Parent::preload(server, errorStr))
  133. return false;
  134. packed = false;
  135. return true;
  136. }
  137. void GameBaseData::unpackData(BitStream* stream)
  138. {
  139. Parent::unpackData(stream);
  140. packed = true;
  141. }
  142. //----------------------------------------------------------------------------
  143. bool UNPACK_DB_ID(BitStream * stream, U32 & id)
  144. {
  145. if (stream->readFlag())
  146. {
  147. id = stream->readRangedU32(DataBlockObjectIdFirst,DataBlockObjectIdLast);
  148. return true;
  149. }
  150. return false;
  151. }
  152. bool PACK_DB_ID(BitStream * stream, U32 id)
  153. {
  154. if (stream->writeFlag(id))
  155. {
  156. stream->writeRangedU32(id,DataBlockObjectIdFirst,DataBlockObjectIdLast);
  157. return true;
  158. }
  159. return false;
  160. }
  161. bool PRELOAD_DB(U32 & id, SimDataBlock ** data, bool server, const char * clientMissing, const char * serverMissing)
  162. {
  163. if (server)
  164. {
  165. if (*data)
  166. id = (*data)->getId();
  167. else if (server && serverMissing)
  168. {
  169. Con::errorf(ConsoleLogEntry::General,serverMissing);
  170. return false;
  171. }
  172. }
  173. else
  174. {
  175. if (id && !Sim::findObject(id,*data) && clientMissing)
  176. {
  177. Con::errorf(ConsoleLogEntry::General,clientMissing);
  178. return false;
  179. }
  180. }
  181. return true;
  182. }
  183. //----------------------------------------------------------------------------
  184. bool GameBase::gShowBoundingBox = false;
  185. //----------------------------------------------------------------------------
  186. IMPLEMENT_CO_NETOBJECT_V1(GameBase);
  187. ConsoleDocClass( GameBase,
  188. "@brief Base class for game objects which use datablocks, networking, are "
  189. "editable, and need to process ticks.\n\n"
  190. "@ingroup gameObjects\n"
  191. );
  192. GameBase::GameBase()
  193. : mDataBlock( NULL ),
  194. mControllingClient( NULL ),
  195. mCurrentWaterObject( NULL )
  196. {
  197. mNetFlags.set(Ghostable);
  198. mTypeMask |= GameBaseObjectType;
  199. mProcessTag = 0;
  200. // From ProcessObject
  201. mIsGameBase = true;
  202. #ifdef TORQUE_DEBUG_NET_MOVES
  203. mLastMoveId = 0;
  204. mTicksSinceLastMove = 0;
  205. mIsAiControlled = false;
  206. #endif
  207. }
  208. GameBase::~GameBase()
  209. {
  210. }
  211. //----------------------------------------------------------------------------
  212. bool GameBase::onAdd()
  213. {
  214. if ( !Parent::onAdd() )
  215. return false;
  216. // Datablock must be initialized on the server.
  217. // Client datablock are initialized by the initial update.
  218. if ( isServerObject() && mDataBlock && !onNewDataBlock( mDataBlock, false ) )
  219. return false;
  220. setProcessTick( true );
  221. return true;
  222. }
  223. void GameBase::onRemove()
  224. {
  225. // EDITOR FEATURE: Remove us from the reload signal of our datablock.
  226. if ( mDataBlock )
  227. mDataBlock->mReloadSignal.remove( this, &GameBase::_onDatablockModified );
  228. Parent::onRemove();
  229. }
  230. bool GameBase::onNewDataBlock( GameBaseData *dptr, bool reload )
  231. {
  232. // EDITOR FEATURE: Remove us from old datablock's reload signal and
  233. // add us to the new one.
  234. if ( !reload )
  235. {
  236. if ( mDataBlock )
  237. mDataBlock->mReloadSignal.remove( this, &GameBase::_onDatablockModified );
  238. if ( dptr )
  239. dptr->mReloadSignal.notify( this, &GameBase::_onDatablockModified );
  240. }
  241. mDataBlock = dptr;
  242. if ( !mDataBlock )
  243. return false;
  244. setMaskBits(DataBlockMask);
  245. return true;
  246. }
  247. void GameBase::_onDatablockModified()
  248. {
  249. AssertFatal( mDataBlock, "GameBase::onDatablockModified - mDataBlock is NULL." );
  250. onNewDataBlock( mDataBlock, true );
  251. }
  252. void GameBase::inspectPostApply()
  253. {
  254. Parent::inspectPostApply();
  255. setMaskBits(ExtendedInfoMask);
  256. }
  257. //----------------------------------------------------------------------------
  258. void GameBase::processTick(const Move * move)
  259. {
  260. #ifdef TORQUE_DEBUG_NET_MOVES
  261. if (!move)
  262. mTicksSinceLastMove++;
  263. const char * srv = isClientObject() ? "client" : "server";
  264. const char * who = "";
  265. if (isClientObject())
  266. {
  267. if (this == (GameBase*)GameConnection::getConnectionToServer()->getControlObject())
  268. who = " player";
  269. else
  270. who = " ghost";
  271. if (mIsAiControlled)
  272. who = " ai";
  273. }
  274. if (isServerObject())
  275. {
  276. if (dynamic_cast<AIConnection*>(getControllingClient()))
  277. {
  278. who = " ai";
  279. mIsAiControlled = true;
  280. }
  281. else if (getControllingClient())
  282. {
  283. who = " player";
  284. mIsAiControlled = false;
  285. }
  286. else
  287. {
  288. who = "";
  289. mIsAiControlled = false;
  290. }
  291. }
  292. U32 moveid = mLastMoveId+mTicksSinceLastMove;
  293. if (move)
  294. moveid = move->id;
  295. if (getTypeMask() & GameBaseHiFiObjectType)
  296. {
  297. if (move)
  298. Con::printf("Processing (%s%s id %i) move %i",srv,who,getId(), move->id);
  299. else
  300. Con::printf("Processing (%s%s id %i) move %i (%i)",srv,who,getId(),mLastMoveId+mTicksSinceLastMove,mTicksSinceLastMove);
  301. }
  302. if (move)
  303. {
  304. mLastMoveId = move->id;
  305. mTicksSinceLastMove=0;
  306. }
  307. #endif
  308. }
  309. //----------------------------------------------------------------------------
  310. F32 GameBase::getUpdatePriority(CameraScopeQuery *camInfo, U32 updateMask, S32 updateSkips)
  311. {
  312. TORQUE_UNUSED(updateMask);
  313. // Calculate a priority used to decide if this object
  314. // will be updated on the client. All the weights
  315. // are calculated 0 -> 1 Then weighted together at the
  316. // end to produce a priority.
  317. Point3F pos;
  318. getWorldBox().getCenter(&pos);
  319. pos -= camInfo->pos;
  320. F32 dist = pos.len();
  321. if (dist == 0.0f) dist = 0.001f;
  322. pos *= 1.0f / dist;
  323. // Weight based on linear distance, the basic stuff.
  324. F32 wDistance = (dist < camInfo->visibleDistance)?
  325. 1.0f - (dist / camInfo->visibleDistance): 0.0f;
  326. // Weight by field of view, objects directly in front
  327. // will be weighted 1, objects behind will be 0
  328. F32 dot = mDot(pos,camInfo->orientation);
  329. #ifdef GHOSTSCOPING
  330. bool inFov = dot > camInfo->cosFov*1.5f;
  331. #else
  332. bool inFov = dot > camInfo->cosFov;
  333. #endif
  334. F32 wFov = inFov? 1.0f: 0;
  335. // Weight by linear velocity parallel to the viewing plane
  336. // (if it's the field of view, 0 if it's not).
  337. F32 wVelocity = 0.0f;
  338. if (inFov)
  339. {
  340. Point3F vec;
  341. mCross(camInfo->orientation,getVelocity(),&vec);
  342. wVelocity = (vec.len() * camInfo->fov) /
  343. (camInfo->fov * camInfo->visibleDistance);
  344. if (wVelocity > 1.0f)
  345. wVelocity = 1.0f;
  346. }
  347. // Weight by interest.
  348. F32 wInterest;
  349. #ifdef GHOSTSCOPING
  350. if (getTypeMask() & (PlayerObjectType || VehicleObjectType ))
  351. #else
  352. if (getTypeMask() & PlayerObjectType)
  353. #endif
  354. wInterest = 0.75f;
  355. else if (getTypeMask() & ProjectileObjectType)
  356. {
  357. // Projectiles are more interesting if they
  358. // are heading for us.
  359. wInterest = 0.30f;
  360. F32 dot = -mDot(pos,getVelocity());
  361. if (dot > 0.0f)
  362. wInterest += 0.20 * dot;
  363. }
  364. else
  365. {
  366. if (getTypeMask() & ItemObjectType)
  367. wInterest = 0.25f;
  368. else
  369. // Everything else is less interesting.
  370. wInterest = 0.0f;
  371. }
  372. // Weight by updateSkips
  373. F32 wSkips = updateSkips * 0.5;
  374. // Calculate final priority, should total to about 1.0f
  375. //
  376. return
  377. wFov * sUpFov +
  378. wDistance * sUpDistance +
  379. wVelocity * sUpVelocity +
  380. wSkips * sUpSkips +
  381. wInterest * sUpInterest;
  382. }
  383. //----------------------------------------------------------------------------
  384. bool GameBase::setDataBlock(GameBaseData* dptr)
  385. {
  386. if (isGhost() || isProperlyAdded()) {
  387. if (mDataBlock != dptr)
  388. return onNewDataBlock(dptr,false);
  389. }
  390. else
  391. mDataBlock = dptr;
  392. return true;
  393. }
  394. //--------------------------------------------------------------------------
  395. void GameBase::scriptOnAdd()
  396. {
  397. // Script onAdd() must be called by the leaf class after
  398. // everything is ready.
  399. if (mDataBlock && !isGhost())
  400. mDataBlock->onAdd_callback( this );
  401. }
  402. void GameBase::scriptOnNewDataBlock()
  403. {
  404. // Script onNewDataBlock() must be called by the leaf class
  405. // after everything is loaded.
  406. if (mDataBlock && !isGhost())
  407. mDataBlock->onNewDataBlock_callback( this );
  408. }
  409. void GameBase::scriptOnRemove()
  410. {
  411. // Script onRemove() must be called by leaf class while
  412. // the object state is still valid.
  413. if (!isGhost() && mDataBlock)
  414. mDataBlock->onRemove_callback( this );
  415. }
  416. //----------------------------------------------------------------------------
  417. void GameBase::setControllingClient(GameConnection* client)
  418. {
  419. if (isClientObject())
  420. {
  421. if (mControllingClient)
  422. setControl_callback( 0 );
  423. if (client)
  424. setControl_callback( 1 );
  425. }
  426. mControllingClient = client;
  427. }
  428. U32 GameBase::getPacketDataChecksum(GameConnection * connection)
  429. {
  430. // just write the packet data into a buffer
  431. // then we can CRC the buffer. This should always let us
  432. // know when there is a checksum problem.
  433. static U8 buffer[1500] = { 0, };
  434. BitStream stream(buffer, sizeof(buffer));
  435. writePacketData(connection, &stream);
  436. U32 byteCount = stream.getPosition();
  437. U32 ret = CRC::calculateCRC(buffer, byteCount, 0xFFFFFFFF);
  438. dMemset(buffer, 0, byteCount);
  439. return ret;
  440. }
  441. void GameBase::writePacketData(GameConnection*, BitStream*)
  442. {
  443. }
  444. void GameBase::readPacketData(GameConnection*, BitStream*)
  445. {
  446. }
  447. U32 GameBase::packUpdate( NetConnection *connection, U32 mask, BitStream *stream )
  448. {
  449. U32 retMask = Parent::packUpdate( connection, mask, stream );
  450. if ( stream->writeFlag( mask & ScaleMask ) )
  451. {
  452. // Only write one bit if the scale is one.
  453. if ( stream->writeFlag( mObjScale != Point3F::One ) )
  454. mathWrite( *stream, mObjScale );
  455. }
  456. if ( stream->writeFlag( ( mask & DataBlockMask ) && mDataBlock != NULL ) )
  457. {
  458. stream->writeRangedU32( mDataBlock->getId(),
  459. DataBlockObjectIdFirst,
  460. DataBlockObjectIdLast );
  461. if ( stream->writeFlag( mNetFlags.test( NetOrdered ) ) )
  462. stream->writeInt( mOrderGUID, 16 );
  463. }
  464. #ifdef TORQUE_DEBUG_NET_MOVES
  465. stream->write(mLastMoveId);
  466. stream->writeFlag(mIsAiControlled);
  467. #endif
  468. return retMask;
  469. }
  470. void GameBase::unpackUpdate(NetConnection *con, BitStream *stream)
  471. {
  472. Parent::unpackUpdate( con, stream );
  473. // ScaleMask
  474. if ( stream->readFlag() )
  475. {
  476. if ( stream->readFlag() )
  477. {
  478. VectorF scale;
  479. mathRead( *stream, &scale );
  480. setScale( scale );
  481. }
  482. else
  483. setScale( Point3F::One );
  484. }
  485. // DataBlockMask
  486. if ( stream->readFlag() )
  487. {
  488. GameBaseData *dptr = 0;
  489. SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst,
  490. DataBlockObjectIdLast );
  491. if ( stream->readFlag() )
  492. mOrderGUID = stream->readInt( 16 );
  493. if ( !Sim::findObject( id, dptr ) || !setDataBlock( dptr ) )
  494. con->setLastError( "Invalid packet GameBase::unpackUpdate()" );
  495. }
  496. #ifdef TORQUE_DEBUG_NET_MOVES
  497. stream->read(&mLastMoveId);
  498. mTicksSinceLastMove = 0;
  499. mIsAiControlled = stream->readFlag();
  500. #endif
  501. }
  502. void GameBase::onMount( SceneObject *obj, S32 node )
  503. {
  504. deleteNotify( obj );
  505. // Are we mounting to a GameBase object?
  506. GameBase *gbaseObj = dynamic_cast<GameBase*>( obj );
  507. if ( gbaseObj && gbaseObj->getControlObject() != this )
  508. processAfter( gbaseObj );
  509. if (!isGhost()) {
  510. setMaskBits(MountedMask);
  511. mDataBlock->onMount_callback( this, obj, node );
  512. }
  513. }
  514. void GameBase::onUnmount( SceneObject *obj, S32 node )
  515. {
  516. clearNotify(obj);
  517. GameBase *gbaseObj = dynamic_cast<GameBase*>( obj );
  518. if ( gbaseObj && gbaseObj->getControlObject() != this )
  519. clearProcessAfter();
  520. if (!isGhost()) {
  521. setMaskBits(MountedMask);
  522. mDataBlock->onUnmount_callback( this, obj, node );
  523. }
  524. }
  525. bool GameBase::setDataBlockProperty( void *obj, const char *index, const char *db)
  526. {
  527. if( db == NULL || !db[ 0 ] )
  528. {
  529. Con::errorf( "GameBase::setDataBlockProperty - Can't unset datablock on GameBase objects" );
  530. return false;
  531. }
  532. GameBase* object = static_cast< GameBase* >( obj );
  533. GameBaseData* data;
  534. if( Sim::findObject( db, data ) )
  535. return object->setDataBlock( data );
  536. Con::errorf( "GameBase::setDatablockProperty - Could not find data block \"%s\"", db );
  537. return false;
  538. }
  539. MoveList* GameBase::getMoveList()
  540. {
  541. return mControllingClient ? mControllingClient->mMoveList : NULL;
  542. }
  543. //----------------------------------------------------------------------------
  544. DefineEngineMethod( GameBase, getDataBlock, S32, (),,
  545. "@brief Get the datablock used by this object.\n\n"
  546. "@return the datablock this GameBase is using."
  547. "@see setDataBlock()\n")
  548. {
  549. return object->getDataBlock()? object->getDataBlock()->getId(): 0;
  550. }
  551. //----------------------------------------------------------------------------
  552. DefineEngineMethod( GameBase, setDataBlock, bool, ( GameBaseData* data ),,
  553. "@brief Assign this GameBase to use the specified datablock.\n\n"
  554. "@param data new datablock to use\n"
  555. "@return true if successful, false if failed."
  556. "@see getDataBlock()\n")
  557. {
  558. return ( data && object->setDataBlock(data) );
  559. }
  560. //----------------------------------------------------------------------------
  561. void GameBase::initPersistFields()
  562. {
  563. addGroup( "Game" );
  564. addProtectedField( "dataBlock", TYPEID< GameBaseData >(), Offset(mDataBlock, GameBase),
  565. &setDataBlockProperty, &defaultProtectedGetFn,
  566. "Script datablock used for game objects." );
  567. endGroup( "Game" );
  568. Parent::initPersistFields();
  569. }
  570. void GameBase::consoleInit()
  571. {
  572. #ifdef TORQUE_DEBUG
  573. Con::addVariable( "GameBase::boundingBox", TypeBool, &gShowBoundingBox,
  574. "@brief Toggles on the rendering of the bounding boxes for certain types of objects in scene.\n\n"
  575. "@ingroup GameBase" );
  576. #endif
  577. }
  578. DefineEngineMethod( GameBase, applyImpulse, bool, ( Point3F pos, VectorF vel ),,
  579. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  580. "@param pos impulse world position\n"
  581. "@param vel impulse velocity (impulse force F = m * v)\n"
  582. "@return Always true\n"
  583. "@note Not all objects that derrive from GameBase have this defined.\n")
  584. {
  585. object->applyImpulse(pos,vel);
  586. return true;
  587. }
  588. DefineEngineMethod( GameBase, applyRadialImpulse, void, ( Point3F origin, F32 radius, F32 magnitude ),,
  589. "@brief Applies a radial impulse to the object using the given origin and force.\n\n"
  590. "@param origin World point of origin of the radial impulse.\n"
  591. "@param radius The radius of the impulse area.\n"
  592. "@param magnitude The strength of the impulse.\n"
  593. "@note Not all objects that derrive from GameBase have this defined.\n")
  594. {
  595. object->applyRadialImpulse( origin, radius, magnitude );
  596. }