123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
- // Copyright (C) 2015 Faust Logic, Inc.
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- #include "platform/platform.h"
- #include "T3D/gameBase/gameBase.h"
- #include "console/consoleTypes.h"
- #include "console/engineAPI.h"
- #include "console/consoleInternal.h"
- #include "core/stream/bitStream.h"
- #include "sim/netConnection.h"
- #include "T3D/gameBase/gameConnection.h"
- #include "math/mathIO.h"
- #include "T3D/gameBase/moveManager.h"
- #include "T3D/gameBase/gameProcess.h"
- #ifdef TORQUE_DEBUG_NET_MOVES
- #include "T3D/aiConnection.h"
- #endif
- #ifdef TORQUE_AFX_ENABLED
- #include "afx/arcaneFX.h"
- #endif
- //----------------------------------------------------------------------------
- // Ghost update relative priority values
- static F32 sUpFov = 1.0;
- static F32 sUpDistance = 0.4f;
- static F32 sUpVelocity = 0.4f;
- static F32 sUpSkips = 0.2f;
- static F32 sUpInterest = 0.2f;
- //----------------------------------------------------------------------------
- IMPLEMENT_CO_DATABLOCK_V1(GameBaseData);
- ConsoleDocClass( GameBaseData,
- "@brief Scriptable, demo-able datablock. Used by GameBase objects.\n\n"
- "@see GameBase\n"
- "@ingroup gameObjects\n"
- );
- IMPLEMENT_CALLBACK( GameBaseData, onAdd, void, ( GameBase* obj ), ( obj ),
- "@brief Called when the object is added to the scene.\n\n"
- "@param obj the GameBase object\n\n"
- "@tsexample\n"
- "datablock GameBaseData(MyObjectData)\n"
- "{\n"
- " category = \"Misc\";\n"
- "};\n\n"
- "function MyObjectData::onAdd( %this, %obj )\n"
- "{\n"
- " echo( \"Added \" @ %obj.getName() @ \" to the scene.\" );\n"
- "}\n\n"
- "function MyObjectData::onNewDataBlock( %this, %obj )\n"
- "{\n"
- " echo( \"Assign \" @ %this.getName() @ \" datablock to \" %obj.getName() );\n"
- "}\n\n"
- "function MyObjectData::onRemove( %this, %obj )\n"
- "{\n"
- " echo( \"Removed \" @ %obj.getName() @ \" to the scene.\" );\n"
- "}\n\n"
- "function MyObjectData::onMount( %this, %obj, %mountObj, %node )\n"
- "{\n"
- " echo( %obj.getName() @ \" mounted to \" @ %mountObj.getName() );\n"
- "}\n\n"
- "function MyObjectData::onUnmount( %this, %obj, %mountObj, %node )\n"
- "{\n"
- " echo( %obj.getName() @ \" unmounted from \" @ %mountObj.getName() );\n"
- "}\n\n"
- "@endtsexample\n" );
- IMPLEMENT_CALLBACK( GameBaseData, onNewDataBlock, void, ( GameBase* obj ), ( obj ),
- "@brief Called when the object has a new datablock assigned.\n\n"
- "@param obj the GameBase object\n\n"
- "@see onAdd for an example\n" );
- IMPLEMENT_CALLBACK( GameBaseData, onRemove, void, ( GameBase* obj ), ( obj ),
- "@brief Called when the object is removed from the scene.\n\n"
- "@param obj the GameBase object\n\n"
- "@see onAdd for an example\n" );
- IMPLEMENT_CALLBACK( GameBaseData, onMount, void, ( SceneObject* obj, SceneObject* mountObj, S32 node ), ( obj, mountObj, node ),
- "@brief Called when the object is mounted to another object in the scene.\n\n"
- "@param obj the GameBase object being mounted\n"
- "@param mountObj the object we are mounted to\n"
- "@param node the mountObj node we are mounted to\n\n"
- "@see onAdd for an example\n" );
- IMPLEMENT_CALLBACK( GameBaseData, onUnmount, void, ( SceneObject* obj, SceneObject* mountObj, S32 node ), ( obj, mountObj, node ),
- "@brief Called when the object is unmounted from another object in the scene.\n\n"
- "@param obj the GameBase object being unmounted\n"
- "@param mountObj the object we are unmounted from\n"
- "@param node the mountObj node we are unmounted from\n\n"
- "@see onAdd for an example\n" );
- IMPLEMENT_CALLBACK( GameBase, setControl, void, ( bool controlled ), ( controlled ),
- "@brief Called when the client controlling the object changes.\n\n"
- "@param controlled true if a client now controls this object, false if no "
- "client controls this object.\n" );
- GameBaseData::GameBaseData()
- {
- mCategory = "";
- mPacked = false;
- }
- GameBaseData::GameBaseData(const GameBaseData& other, bool temp_clone) : SimDataBlock(other, temp_clone)
- {
- mPacked = other.mPacked;
- mCategory = other.mCategory;
- //mReloadSignal = other.mReloadSignal; // DO NOT copy the mReloadSignal member.
- }
- void GameBaseData::inspectPostApply()
- {
- Parent::inspectPostApply();
- // Tell interested parties ( like objects referencing this datablock )
- // that we have been modified and they might want to rebuild...
- mReloadSignal.trigger();
- }
- bool GameBaseData::onAdd()
- {
- if (!Parent::onAdd())
- return false;
- return true;
- }
- void GameBaseData::initPersistFields()
- {
- addGroup("Scripting");
- addField( "category", TypeCaseString, Offset(mCategory, GameBaseData ),
- "The group that this datablock will show up in under the \"Scripted\" "
- "tab in the World Editor Library." );
- endGroup("Scripting");
- Parent::initPersistFields();
- }
- bool GameBaseData::preload(bool server, String &errorStr)
- {
- if (!Parent::preload(server, errorStr))
- return false;
- mPacked = false;
- return true;
- }
- void GameBaseData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- mPacked = true;
- }
- //----------------------------------------------------------------------------
- bool UNPACK_DB_ID(BitStream * stream, U32 & id)
- {
- if (stream->readFlag())
- {
- id = stream->readRangedU32(DataBlockObjectIdFirst,DataBlockObjectIdLast);
- return true;
- }
- return false;
- }
- bool PACK_DB_ID(BitStream * stream, U32 id)
- {
- if (stream->writeFlag(id))
- {
- stream->writeRangedU32(id,DataBlockObjectIdFirst,DataBlockObjectIdLast);
- return true;
- }
- return false;
- }
- bool PRELOAD_DB(U32 & id, SimDataBlock ** data, bool server, const char * clientMissing, const char * serverMissing)
- {
- if (server)
- {
- if (*data)
- id = (*data)->getId();
- else if (server && serverMissing)
- {
- Con::errorf(ConsoleLogEntry::General,serverMissing);
- return false;
- }
- }
- else
- {
- if (id && !Sim::findObject(id,*data) && clientMissing)
- {
- Con::errorf(ConsoleLogEntry::General,clientMissing);
- return false;
- }
- }
- return true;
- }
- //----------------------------------------------------------------------------
- bool GameBase::gShowBoundingBox = false;
- //----------------------------------------------------------------------------
- IMPLEMENT_CO_NETOBJECT_V1(GameBase);
- ConsoleDocClass( GameBase,
- "@brief Base class for game objects which use datablocks, networking, are "
- "editable, and need to process ticks.\n\n"
- "@ingroup gameObjects\n"
- );
- GameBase::GameBase()
- : mDataBlock( NULL ),
- mControllingClient( NULL ),
- mCurrentWaterObject( NULL )
- {
- mNetFlags.set(Ghostable);
- mTypeMask |= GameBaseObjectType;
- mProcessTag = 0;
- // From ProcessObject
- mIsGameBase = true;
-
- #ifdef TORQUE_DEBUG_NET_MOVES
- mLastMoveId = 0;
- mTicksSinceLastMove = 0;
- mIsAiControlled = false;
- #endif
- mCameraFov = 90.f;
- }
- GameBase::~GameBase()
- {
- #ifdef TORQUE_AFX_ENABLED
- if (mScope_registered)
- arcaneFX::unregisterScopedObject(this);
- #endif
- }
- //----------------------------------------------------------------------------
- bool GameBase::onAdd()
- {
- if ( !Parent::onAdd() )
- return false;
- // Datablock must be initialized on the server.
- // Client datablock are initialized by the initial update.
- #ifdef TORQUE_AFX_ENABLED
- if (isClientObject())
- {
- if (mScope_id > 0 && !mScope_registered)
- arcaneFX::registerScopedObject(this);
- }
- else
- {
- if ( mDataBlock && !onNewDataBlock( mDataBlock, false ) )
- return false;
- }
- #else
- if ( isServerObject() && mDataBlock && !onNewDataBlock( mDataBlock, false ) )
- return false;
- #endif
- setProcessTick( true );
- return true;
- }
- void GameBase::onRemove()
- {
- #ifdef TORQUE_AFX_ENABLED
- if (mScope_registered)
- arcaneFX::unregisterScopedObject(this);
- #endif
- // EDITOR FEATURE: Remove us from the reload signal of our datablock.
- if ( mDataBlock )
- mDataBlock->mReloadSignal.remove( this, &GameBase::_onDatablockModified );
- Parent::onRemove();
- }
- bool GameBase::onNewDataBlock( GameBaseData *dptr, bool reload )
- {
- // EDITOR FEATURE: Remove us from old datablock's reload signal and
- // add us to the new one.
- if ( !reload )
- {
- if ( mDataBlock )
- mDataBlock->mReloadSignal.remove( this, &GameBase::_onDatablockModified );
- if ( dptr )
- dptr->mReloadSignal.notify( this, &GameBase::_onDatablockModified );
- }
-
- mDataBlock = dptr;
- if ( !mDataBlock )
- return false;
- #ifdef TORQUE_AFX_ENABLED
- // Don't set mask when new datablock is a temp-clone.
- if (mDataBlock->isTempClone())
- return true;
- #endif
- setMaskBits(DataBlockMask);
- return true;
- }
- void GameBase::_onDatablockModified()
- {
- AssertFatal( mDataBlock, "GameBase::onDatablockModified - mDataBlock is NULL." );
- onNewDataBlock( mDataBlock, true );
- }
- void GameBase::inspectPostApply()
- {
- Parent::inspectPostApply();
- setMaskBits(ExtendedInfoMask);
- }
- //----------------------------------------------------------------------------
- void GameBase::processTick(const Move * move)
- {
- #ifdef TORQUE_DEBUG_NET_MOVES
- if (!move)
- mTicksSinceLastMove++;
- const char * srv = isClientObject() ? "client" : "server";
- const char * who = "";
- if (isClientObject())
- {
- if (this == (GameBase*)GameConnection::getConnectionToServer()->getControlObject())
- who = " player";
- else
- who = " ghost";
- if (mIsAiControlled)
- who = " ai";
- }
- if (isServerObject())
- {
- if (dynamic_cast<AIConnection*>(getControllingClient()))
- {
- who = " ai";
- mIsAiControlled = true;
- }
- else if (getControllingClient())
- {
- who = " player";
- mIsAiControlled = false;
- }
- else
- {
- who = "";
- mIsAiControlled = false;
- }
- }
- U32 moveid = mLastMoveId+mTicksSinceLastMove;
- if (move)
- moveid = move->id;
- if (getTypeMask() & GameBaseHiFiObjectType)
- {
- if (move)
- Con::printf("Processing (%s%s id %i) move %i",srv,who,getId(), move->id);
- else
- Con::printf("Processing (%s%s id %i) move %i (%i)",srv,who,getId(),mLastMoveId+mTicksSinceLastMove,mTicksSinceLastMove);
- }
- if (move)
- {
- mLastMoveId = move->id;
- mTicksSinceLastMove=0;
- }
- #endif
- }
- void GameBase::interpolateTick(F32 dt)
- {
- // PATHSHAPE
- updateRenderChangesByParent();
- // PATHSHAPE END
- }
- //----------------------------------------------------------------------------
- F32 GameBase::getUpdatePriority(CameraScopeQuery *camInfo, U32 updateMask, S32 updateSkips)
- {
- TORQUE_UNUSED(updateMask);
- // Calculate a priority used to decide if this object
- // will be updated on the client. All the weights
- // are calculated 0 -> 1 Then weighted together at the
- // end to produce a priority.
- Point3F pos;
- getWorldBox().getCenter(&pos);
- pos -= camInfo->pos;
- F32 dist = pos.len();
- if (dist == 0.0f) dist = 0.001f;
- pos *= 1.0f / dist;
- // Weight based on linear distance, the basic stuff.
- F32 wDistance = (dist < camInfo->visibleDistance)?
- 1.0f - (dist / camInfo->visibleDistance): 0.0f;
- // Weight by field of view, objects directly in front
- // will be weighted 1, objects behind will be 0
- F32 dot = mDot(pos,camInfo->orientation);
- bool inFov = dot > camInfo->cosFov * 1.5f;
- F32 wFov = inFov? 1.0f: 0;
- // Weight by linear velocity parallel to the viewing plane
- // (if it's the field of view, 0 if it's not).
- F32 wVelocity = 0.0f;
- if (inFov)
- {
- Point3F vec;
- mCross(camInfo->orientation,getVelocity(),&vec);
- wVelocity = (vec.len() * camInfo->fov) /
- (camInfo->fov * camInfo->visibleDistance);
- if (wVelocity > 1.0f)
- wVelocity = 1.0f;
- }
- // Weight by interest.
- F32 wInterest;
- if (getTypeMask() & (PlayerObjectType || VehicleObjectType ))
- wInterest = 0.75f;
- else if (getTypeMask() & ProjectileObjectType)
- {
- // Projectiles are more interesting if they
- // are heading for us.
- wInterest = 0.30f;
- dot = -mDot(pos,getVelocity());
- if (dot > 0.0f)
- wInterest += 0.20 * dot;
- }
- else
- {
- if (getTypeMask() & ItemObjectType)
- wInterest = 0.25f;
- else
- // Everything else is less interesting.
- wInterest = 0.0f;
- }
- // Weight by updateSkips
- F32 wSkips = updateSkips * 0.5;
- // Calculate final priority, should total to about 1.0f (plus children)
- //
- return
- wFov * sUpFov +
- wDistance * sUpDistance +
- wVelocity * sUpVelocity +
- wSkips * sUpSkips +
- wInterest * sUpInterest +
- getNumChildren();
- }
- //----------------------------------------------------------------------------
- bool GameBase::setDataBlock(GameBaseData* dptr)
- {
- if (isGhost() || isProperlyAdded()) {
- if (mDataBlock != dptr)
- return onNewDataBlock(dptr,false);
- }
- else
- mDataBlock = dptr;
- return true;
- }
- //--------------------------------------------------------------------------
- void GameBase::scriptOnAdd()
- {
- // Script onAdd() must be called by the leaf class after
- // everything is ready.
- if (mDataBlock && !isGhost())
- mDataBlock->onAdd_callback( this );
- }
- void GameBase::scriptOnNewDataBlock()
- {
- // Script onNewDataBlock() must be called by the leaf class
- // after everything is loaded.
- if (mDataBlock && !isGhost())
- mDataBlock->onNewDataBlock_callback( this );
- }
- void GameBase::scriptOnRemove()
- {
- // Script onRemove() must be called by leaf class while
- // the object state is still valid.
- if (!isGhost() && mDataBlock)
- mDataBlock->onRemove_callback( this );
- }
- //----------------------------------------------------------------------------
- void GameBase::setControllingClient(GameConnection* client)
- {
- if (isClientObject())
- {
- if (mControllingClient)
- setControl_callback( 0 );
- if (client)
- setControl_callback( 1 );
- }
- mControllingClient = client;
- }
- U32 GameBase::getPacketDataChecksum(GameConnection * connection)
- {
- // just write the packet data into a buffer
- // then we can CRC the buffer. This should always let us
- // know when there is a checksum problem.
- static U8 buffer[1500] = { 0, };
- BitStream stream(buffer, sizeof(buffer));
- writePacketData(connection, &stream);
- U32 byteCount = stream.getPosition();
- U32 ret = CRC::calculateCRC(buffer, byteCount, 0xFFFFFFFF);
- dMemset(buffer, 0, byteCount);
- return ret;
- }
- void GameBase::writePacketData(GameConnection*, BitStream*)
- {
- }
- void GameBase::readPacketData(GameConnection*, BitStream*)
- {
- }
- U32 GameBase::packUpdate( NetConnection *connection, U32 mask, BitStream *stream )
- {
- U32 retMask = Parent::packUpdate( connection, mask, stream );
-
- if ( stream->writeFlag( mask & ScaleMask ) )
- {
- // Only write one bit if the scale is one.
- if ( stream->writeFlag( mObjScale != Point3F::One ) )
- mathWrite( *stream, mObjScale );
- }
- if ( stream->writeFlag( ( mask & DataBlockMask ) && mDataBlock != NULL ) )
- {
- stream->writeRangedU32( mDataBlock->getId(),
- DataBlockObjectIdFirst,
- DataBlockObjectIdLast );
- if ( stream->writeFlag( mNetFlags.test( NetOrdered ) ) )
- stream->writeInt( mOrderGUID, 16 );
- }
- #ifdef TORQUE_DEBUG_NET_MOVES
- stream->write(mLastMoveId);
- stream->writeFlag(mIsAiControlled);
- #endif
- #ifdef TORQUE_AFX_ENABLED
- if (stream->writeFlag(mask & ScopeIdMask))
- {
- if (stream->writeFlag(mScope_refs > 0))
- stream->writeInt(mScope_id, SCOPE_ID_BITS);
- }
- #endif
- return retMask;
- }
- void GameBase::unpackUpdate(NetConnection *con, BitStream *stream)
- {
- Parent::unpackUpdate( con, stream );
-
- // ScaleMask
- if ( stream->readFlag() )
- {
- if ( stream->readFlag() )
- {
- VectorF scale;
- mathRead( *stream, &scale );
- setScale( scale );
- }
- else
- setScale( Point3F::One );
- }
- // DataBlockMask
- if ( stream->readFlag() )
- {
- GameBaseData *dptr = 0;
- SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst,
- DataBlockObjectIdLast );
- if ( stream->readFlag() )
- mOrderGUID = stream->readInt( 16 );
- if ( !Sim::findObject( id, dptr ) || !setDataBlock( dptr ) )
- con->setLastError( "Invalid packet GameBase::unpackUpdate()" );
- }
- #ifdef TORQUE_DEBUG_NET_MOVES
- stream->read(&mLastMoveId);
- mTicksSinceLastMove = 0;
- mIsAiControlled = stream->readFlag();
- #endif
- #ifdef TORQUE_AFX_ENABLED
- if (stream->readFlag())
- {
- mScope_id = (stream->readFlag()) ? (U16) stream->readInt(SCOPE_ID_BITS) : 0;
- mScope_refs = 0;
- }
- #endif
- }
- void GameBase::onMount( SceneObject *obj, S32 node )
- {
- deleteNotify( obj );
- // Are we mounting to a GameBase object?
- GameBase *gbaseObj = dynamic_cast<GameBase*>( obj );
- if ( gbaseObj && gbaseObj->getControlObject() != this && gbaseObj->getControllingObject() != this)
- processAfter( gbaseObj );
- if (!isGhost()) {
- setMaskBits(MountedMask);
- mDataBlock->onMount_callback( this, obj, node );
- }
- }
- void GameBase::onUnmount( SceneObject *obj, S32 node )
- {
- clearNotify(obj);
- GameBase *gbaseObj = dynamic_cast<GameBase*>( obj );
- if ( gbaseObj && gbaseObj->getControlObject() != this )
- clearProcessAfter();
- if (!isGhost()) {
- setMaskBits(MountedMask);
- mDataBlock->onUnmount_callback( this, obj, node );
- }
- }
- bool GameBase::setDataBlockProperty( void *obj, const char *index, const char *db)
- {
- if( db == NULL || !db[ 0 ] )
- {
- Con::errorf( "GameBase::setDataBlockProperty - Can't unset datablock on GameBase objects" );
- return false;
- }
-
- GameBase* object = static_cast< GameBase* >( obj );
- GameBaseData* data;
- if( Sim::findObject( db, data ) )
- return object->setDataBlock( data );
-
- Con::errorf( "GameBase::setDatablockProperty - Could not find data block \"%s\"", db );
- return false;
- }
- MoveList* GameBase::getMoveList()
- {
- return mControllingClient ? mControllingClient->mMoveList : NULL;
- }
- //----------------------------------------------------------------------------
- DefineEngineMethod( GameBase, getDataBlock, S32, (),,
- "@brief Get the datablock used by this object.\n\n"
- "@return the datablock this GameBase is using."
- "@see setDataBlock()\n")
- {
- return object->getDataBlock()? object->getDataBlock()->getId(): 0;
- }
- //----------------------------------------------------------------------------
- DefineEngineMethod( GameBase, setDataBlock, bool, ( GameBaseData* data ),,
- "@brief Assign this GameBase to use the specified datablock.\n\n"
- "@param data new datablock to use\n"
- "@return true if successful, false if failed."
- "@see getDataBlock()\n")
- {
- return ( data && object->setDataBlock(data) );
- }
- //----------------------------------------------------------------------------
- void GameBase::initPersistFields()
- {
- addGroup( "Game" );
- addProtectedField( "dataBlock", TYPEID< GameBaseData >(), Offset(mDataBlock, GameBase),
- &setDataBlockProperty, &defaultProtectedGetFn,
- "Script datablock used for game objects." );
- endGroup( "Game" );
- Parent::initPersistFields();
- }
- void GameBase::consoleInit()
- {
- #ifdef TORQUE_DEBUG
- Con::addVariable( "GameBase::boundingBox", TypeBool, &gShowBoundingBox,
- "@brief Toggles on the rendering of the bounding boxes for certain types of objects in scene.\n\n"
- "@ingroup GameBase" );
- #endif
- }
- DefineEngineMethod( GameBase, applyImpulse, bool, ( Point3F pos, VectorF vel ),,
- "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
- "@param pos impulse world position\n"
- "@param vel impulse velocity (impulse force F = m * v)\n"
- "@return Always true\n"
- "@note Not all objects that derrive from GameBase have this defined.\n")
- {
- object->applyImpulse(pos,vel);
- return true;
- }
- DefineEngineMethod( GameBase, applyRadialImpulse, void, ( Point3F origin, F32 radius, F32 magnitude ),,
- "@brief Applies a radial impulse to the object using the given origin and force.\n\n"
- "@param origin World point of origin of the radial impulse.\n"
- "@param radius The radius of the impulse area.\n"
- "@param magnitude The strength of the impulse.\n"
-
- "@note Not all objects that derrive from GameBase have this defined.\n")
- {
- object->applyRadialImpulse( origin, radius, magnitude );
- }
- // PATHSHAPE
- // Console Methods for attach children. can't put them in sceneobject because //
- // we want the processafter functions////////////////////////////////////////////
- DefineEngineMethod(GameBase, attachChild, bool, (GameBase* _subObject), (nullAsType<GameBase*>()), "(SceneObject subObject)"
- "attach an object to this one, preserving its present transform.")
- {
- if (_subObject != nullptr)
- {
- if (_subObject->getParent() != object){
- Con::errorf("Object is (%d)", _subObject->getId());
- _subObject->clearProcessAfter();
- _subObject->processAfter(object);
- return object->attachChild(_subObject);
- }
- else
- return false;
- }
- else
- {
- Con::errorf("Couldn't addObject()!");
- return false;
- }
- }
- DefineEngineMethod(GameBase, detachChild, bool, (GameBase* _subObject), (nullAsType<GameBase*>()), "(SceneObject subObject)"
- "attach an object to this one, preserving its present transform.")
- {
- if (_subObject != nullptr)
- {
- _subObject->clearProcessAfter();
- return _subObject->attachToParent(NULL);
- }
- else
- {
- return false;
- }
- }//end
- // PATHSHAPE END
|