12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898 |
- //-----------------------------------------------------------------------------
- // 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.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "T3D/Entity.h"
- #include "core/stream/bitStream.h"
- #include "console/consoleTypes.h"
- #include "console/consoleObject.h"
- #include "sim/netConnection.h"
- #include "scene/sceneRenderState.h"
- #include "scene/sceneManager.h"
- #include "T3D/gameBase/gameProcess.h"
- #include "console/engineAPI.h"
- #include "T3D/gameBase/gameConnection.h"
- #include "math/mathIO.h"
- #include "math/mTransform.h"
- #include "T3D/Components/coreInterfaces.h"
- #include "T3D/Components/render/renderComponentInterface.h"
- #include "T3D/Components/Collision/collisionInterfaces.h"
- #include "gui/controls/guiTreeViewCtrl.h"
- #include "console/consoleInternal.h"
- #include "T3D/gameBase/std/stdMoveList.h"
- #include "T3D/prefab.h"
- //
- #include "gfx/sim/debugDraw.h"
- //
- extern bool gEditingMission;
- // Client prediction
- static F32 sMinWarpTicks = 0.5f; // Fraction of tick at which instant warp occurs
- static S32 sMaxWarpTicks = 3; // Max warp duration in ticks
- static S32 sMaxPredictionTicks = 30; // Number of ticks to predict
- IMPLEMENT_CO_NETOBJECT_V1(Entity);
- ConsoleDocClass(Entity,
- "@brief Base Entity class.\n\n"
- "Entity is typically made up of a shape and up to two particle emitters. In most cases Entity objects are "
- "not created directly. They are usually produced automatically by other means, such as through the Explosion "
- "class. When an explosion goes off, its ExplosionData datablock determines what Entity to emit.\n"
- "@tsexample\n"
- "datablock ExplosionData(GrenadeLauncherExplosion)\n"
- "{\n"
- " // Assiging Entity data\n"
- " Entity = GrenadeEntity;\n\n"
- " // Adjust how Entity is ejected\n"
- " EntityThetaMin = 10;\n"
- " EntityThetaMax = 60;\n"
- " EntityNum = 4;\n"
- " EntityNumVariance = 2;\n"
- " EntityVelocity = 25;\n"
- " EntityVelocityVariance = 5;\n\n"
- " // Note: other ExplosionData properties are not listed for this example\n"
- "};\n"
- "@endtsexample\n\n"
- "@note Entity are client side only objects.\n"
- "@see EntityData\n"
- "@see ExplosionData\n"
- "@see Explosion\n"
- "@ingroup FX\n"
- );
- Entity::Entity()
- {
- //mTypeMask |= DynamicShapeObjectType | StaticObjectType | ;
- mTypeMask |= EntityObjectType;
- mNetFlags.set(Ghostable | ScopeAlways);
- mPos = Point3F(0, 0, 0);
- mRot = Point3F(0, 0, 0);
- mDelta.pos = mDelta.posVec = Point3F::Zero;
- mDelta.rot[0].identity();
- mDelta.rot[1].identity();
- mDelta.warpOffset.set(0.0f, 0.0f, 0.0f);
- mDelta.warpTicks = mDelta.warpCount = 0;
- mDelta.dt = 1.0f;
- mDelta.move = NullMove;
- mComponents.clear();
- mStartComponentUpdate = false;
- mInitialized = false;
- }
- Entity::~Entity()
- {
- }
- void Entity::initPersistFields()
- {
- Parent::initPersistFields();
- removeField("DataBlock");
- addGroup("Transform");
- removeField("Position");
- addProtectedField("Position", TypePoint3F, Offset(mPos, Entity), &_setPosition, &_getPosition, "Object world orientation.");
- removeField("Rotation");
- addProtectedField("Rotation", TypeRotationF, Offset(mRot, Entity), &_setRotation, &_getRotation, "Object world orientation.");
- //These are basically renamed mountPos/Rot. pretty much there for conveinence
- addField("LocalPosition", TypeMatrixPosition, Offset(mMount.xfm, Entity), "Position we are mounted at ( object space of our mount object ).");
- addField("LocalRotation", TypeMatrixRotation, Offset(mMount.xfm, Entity), "Rotation we are mounted at ( object space of our mount object ).");
- endGroup("Transform");
- }
- //
- bool Entity::_setPosition(void *object, const char *index, const char *data)
- {
- Entity* so = static_cast<Entity*>(object);
- if (so)
- {
- Point3F pos;
- if (!dStrcmp(data, ""))
- pos = Point3F(0, 0, 0);
- else
- Con::setData(TypePoint3F, &pos, 0, 1, &data);
- so->setTransform(pos, so->mRot);
- }
- return false;
- }
- const char * Entity::_getPosition(void* obj, const char* data)
- {
- Entity* so = static_cast<Entity*>(obj);
- if (so)
- {
- Point3F pos = so->getPosition();
- static const U32 bufSize = 256;
- char* returnBuffer = Con::getReturnBuffer(bufSize);
- dSprintf(returnBuffer, bufSize, "%g %g %g", pos.x, pos.y, pos.z);
- return returnBuffer;
- }
- return "0 0 0";
- }
- bool Entity::_setRotation(void *object, const char *index, const char *data)
- {
- Entity* so = static_cast<Entity*>(object);
- if (so)
- {
- RotationF rot;
- Con::setData(TypeRotationF, &rot, 0, 1, &data);
- //so->mRot = rot;
- //MatrixF mat = rot.asMatrixF();
- //mat.setPosition(so->getPosition());
- //so->setTransform(mat);
- so->setTransform(so->getPosition(), rot);
- }
- return false;
- }
- const char * Entity::_getRotation(void* obj, const char* data)
- {
- Entity* so = static_cast<Entity*>(obj);
- if (so)
- {
- EulerF eulRot = so->mRot.asEulerF();
- static const U32 bufSize = 256;
- char* returnBuffer = Con::getReturnBuffer(bufSize);
- dSprintf(returnBuffer, bufSize, "%g %g %g", mRadToDeg(eulRot.x), mRadToDeg(eulRot.y), mRadToDeg(eulRot.z));
- return returnBuffer;
- }
- return "0 0 0";
- }
- bool Entity::onAdd()
- {
- if (!Parent::onAdd())
- return false;
- mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
- resetWorldBox();
- setObjectBox(mObjBox);
- addToScene();
- //Make sure we get positioned
- setMaskBits(TransformMask);
- return true;
- }
- void Entity::onRemove()
- {
- clearComponents(false);
- removeFromScene();
- onDataSet.removeAll();
- Parent::onRemove();
- }
- void Entity::onPostAdd()
- {
- mInitialized = true;
- //everything's done and added. go ahead and initialize the components
- for (U32 i = 0; i < mComponents.size(); i++)
- {
- mComponents[i]->onComponentAdd();
- }
- if (isMethod("onAdd"))
- Con::executef(this, "onAdd");
- }
- void Entity::setDataField(StringTableEntry slotName, const char *array, const char *value)
- {
- Parent::setDataField(slotName, array, value);
- onDataSet.trigger(this, slotName, value);
- }
- void Entity::onStaticModified(const char* slotName, const char* newValue)
- {
- Parent::onStaticModified(slotName, newValue);
- onDataSet.trigger(this, slotName, newValue);
- }
- //Updating
- void Entity::processTick(const Move* move)
- {
- if (!isHidden())
- {
- if (mDelta.warpCount < mDelta.warpTicks)
- {
- mDelta.warpCount++;
- // Set new pos.
- mObjToWorld.getColumn(3, &mDelta.pos);
- mDelta.pos += mDelta.warpOffset;
- mDelta.rot[0] = mDelta.rot[1];
- mDelta.rot[1].interpolate(mDelta.warpRot[0], mDelta.warpRot[1], F32(mDelta.warpCount) / mDelta.warpTicks);
- setTransform(mDelta.pos, mDelta.rot[1]);
- // Pos backstepping
- mDelta.posVec.x = -mDelta.warpOffset.x;
- mDelta.posVec.y = -mDelta.warpOffset.y;
- mDelta.posVec.z = -mDelta.warpOffset.z;
- }
- else
- {
- if (isMounted())
- {
- MatrixF mat;
- mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat);
- Parent::setTransform(mat);
- Parent::setRenderTransform(mat);
- }
- else
- {
- if (!move)
- {
- if (isGhost())
- {
- // If we haven't run out of prediction time,
- // predict using the last known move.
- if (mPredictionCount-- <= 0)
- return;
- move = &mDelta.move;
- }
- else
- {
- move = &NullMove;
- }
- }
- }
- }
- Move prevMove = lastMove;
- if (move != NULL)
- lastMove = *move;
- else
- lastMove = NullMove;
- if (move && isServerObject())
- {
- if ((move->y != 0 || prevMove.y != 0)
- || (move->x != 0 || prevMove.x != 0)
- || (move->z != 0 || prevMove.x != 0))
- {
- if (isMethod("moveVectorEvent"))
- Con::executef(this, "moveVectorEvent", move->x, move->y, move->z);
- }
- if (move->yaw != 0)
- {
- if (isMethod("moveYawEvent"))
- Con::executef(this, "moveYawEvent", move->yaw);
- }
- if (move->pitch != 0)
- {
- if (isMethod("movePitchEvent"))
- Con::executef(this, "movePitchEvent", move->pitch);
- }
- if (move->roll != 0)
- {
- if (isMethod("moveRollEvent"))
- Con::executef(this, "moveRollEvent", move->roll);
- }
- for (U32 i = 0; i < MaxTriggerKeys; i++)
- {
- if (move->trigger[i] != prevMove.trigger[i])
- {
- if (isMethod("moveTriggerEvent"))
- Con::executef(this, "moveTriggerEvent", i, move->trigger[i]);
- }
- }
- }
- if (isMethod("processTick"))
- Con::executef(this, "processTick");
- }
- }
- void Entity::advanceTime(F32 dt)
- {
- }
- void Entity::interpolateTick(F32 dt)
- {
- if (dt == 0.0f)
- {
- setRenderTransform(mDelta.pos, mDelta.rot[1]);
- }
- else
- {
- QuatF rot;
- rot.interpolate(mDelta.rot[1], mDelta.rot[0], dt);
- Point3F pos = mDelta.pos + mDelta.posVec * dt;
- setRenderTransform(pos, rot);
- }
- mDelta.dt = dt;
- }
- //Render
- void Entity::prepRenderImage(SceneRenderState *state)
- {
- }
- //Networking
- U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
- {
- U32 retMask = Parent::packUpdate(con, mask, stream);
- if (stream->writeFlag(mask & TransformMask))
- {
- //mathWrite( *stream, getScale() );
- //stream->writeAffineTransform(mObjToWorld);
- //mathWrite(*stream, getPosition());
- mathWrite(*stream, mPos);
- //mathWrite(*stream, getRotation());
- mathWrite(*stream, getRotation().asEulerF());
- mDelta.move.pack(stream);
- stream->writeFlag(!(mask & NoWarpMask));
- }
- /*if (stream->writeFlag(mask & MountedMask))
- {
- mathWrite(*stream, mMount.xfm.getPosition());
- mathWrite(*stream, mMount.xfm.toEuler());
- }*/
- if (stream->writeFlag(mask & BoundsMask))
- {
- mathWrite(*stream, mObjBox);
- }
- //pass our behaviors around
- if (mask & ComponentsMask || mask & InitialUpdateMask)
- {
- stream->writeFlag(true);
- //now, we run through a list of our to-be-sent behaviors and begin sending them
- //if any fail, we keep our list and re-queue the mask
- S32 componentCount = mToLoadComponents.size();
- //build our 'ready' list
- //This requires both the instance and the instances' template to be prepped(if the template hasn't been ghosted,
- //then we know we shouldn't be passing the instance's ghosts around yet)
- U32 ghostedCompCnt = 0;
- for (U32 i = 0; i < componentCount; i++)
- {
- if (con->getGhostIndex(mToLoadComponents[i]) != -1)
- ghostedCompCnt++;
- }
- if (ghostedCompCnt != 0)
- {
- stream->writeFlag(true);
- stream->writeFlag(mStartComponentUpdate);
- //if not all the behaviors have been ghosted, we'll need another pass
- if (ghostedCompCnt != componentCount)
- retMask |= ComponentsMask;
- //write the currently ghosted behavior count
- stream->writeInt(ghostedCompCnt, 16);
- for (U32 i = 0; i < mToLoadComponents.size(); i++)
- {
- //now fetch them and pass the ghost
- S32 ghostIndex = con->getGhostIndex(mToLoadComponents[i]);
- if (ghostIndex != -1)
- {
- stream->writeInt(ghostIndex, NetConnection::GhostIdBitSize);
- mToLoadComponents.erase(i);
- i--;
- mStartComponentUpdate = false;
- }
- }
- }
- else if (componentCount)
- {
- //on the odd chance we have behaviors to ghost, but NONE of them have been yet, just set the flag now
- stream->writeFlag(false);
- retMask |= ComponentsMask;
- }
- else
- stream->writeFlag(false);
- }
- else
- stream->writeFlag(false);
- return retMask;
- }
- void Entity::unpackUpdate(NetConnection *con, BitStream *stream)
- {
- Parent::unpackUpdate(con, stream);
- if (stream->readFlag())
- {
- /*Point3F scale;
- mathRead( *stream, &scale );
- setScale( scale);*/
- //MatrixF objToWorld;
- //stream->readAffineTransform(&objToWorld);
- Point3F pos;
- mathRead(*stream, &pos);
- RotationF rot;
- EulerF eRot;
- mathRead(*stream, &eRot);
- rot = RotationF(eRot);
- mDelta.move.unpack(stream);
- if (stream->readFlag() && isProperlyAdded())
- {
- // Determine number of ticks to warp based on the average
- // of the client and server velocities.
- /*mDelta.warpOffset = pos - mDelta.pos;
- F32 dt = mDelta.warpOffset.len() / (0.5f * TickSec);
- mDelta.warpTicks = (S32)((dt > sMinWarpTicks) ? getMax(mFloor(dt + 0.5f), 1.0f) : 0.0f);
- //F32 as = (speed + mVelocity.len()) * 0.5f * TickSec;
- //F32 dt = (as > 0.00001f) ? mDelta.warpOffset.len() / as : sMaxWarpTicks;
- //mDelta.warpTicks = (S32)((dt > sMinWarpTicks) ? getMax(mFloor(dt + 0.5f), 1.0f) : 0.0f);
- //mDelta.warpTicks = (S32)((dt > sMinWarpTicks) ? getMax(mFloor(dt + 0.5f), 1.0f) : 0.0f);
- //mDelta.warpTicks = sMaxWarpTicks;
- mDelta.warpTicks = 0;
- if (mDelta.warpTicks)
- {
- // Setup the warp to start on the next tick.
- if (mDelta.warpTicks > sMaxWarpTicks)
- mDelta.warpTicks = sMaxWarpTicks;
- mDelta.warpOffset /= (F32)mDelta.warpTicks;
- mDelta.rot[0] = rot.asQuatF();
- mDelta.rot[1] = rot.asQuatF();
- mDelta.rotOffset = rot.asEulerF() - mDelta.rot.asEulerF();
- // Ignore small rotation differences
- if (mFabs(mDelta.rotOffset.x) < 0.001f)
- mDelta.rotOffset.x = 0;
- if (mFabs(mDelta.rotOffset.y) < 0.001f)
- mDelta.rotOffset.y = 0;
- if (mFabs(mDelta.rotOffset.z) < 0.001f)
- mDelta.rotOffset.z = 0;
- mDelta.rotOffset /= (F32)mDelta.warpTicks;
- }
- else
- {
- // Going to skip the warp, server and client are real close.
- // Adjust the frame interpolation to move smoothly to the
- // new position within the current tick.
- Point3F cp = mDelta.pos + mDelta.posVec * mDelta.dt;
- if (mDelta.dt == 0)
- {
- mDelta.posVec.set(0.0f, 0.0f, 0.0f);
- mDelta.rotVec.set(0.0f, 0.0f, 0.0f);
- }
- else
- {
- F32 dti = 1.0f / mDelta.dt;
- mDelta.posVec = (cp - pos) * dti;
- mDelta.rotVec.z = mRot.z - rot.z;
- mDelta.rotVec.z *= dti;
- }
- mDelta.pos = pos;
- mDelta.rot = rot;
- setTransform(pos, rot);
- }*/
- Point3F cp = mDelta.pos + mDelta.posVec * mDelta.dt;
- mDelta.warpOffset = pos - cp;
- // Calc the distance covered in one tick as the average of
- // the old speed and the new speed from the server.
- VectorF vel = pos - mDelta.pos;
- F32 dt, as = vel.len() * 0.5 * TickSec;
- // Cal how many ticks it will take to cover the warp offset.
- // If it's less than what's left in the current tick, we'll just
- // warp in the remaining time.
- if (!as || (dt = mDelta.warpOffset.len() / as) > sMaxWarpTicks)
- dt = mDelta.dt + sMaxWarpTicks;
- else
- dt = (dt <= mDelta.dt) ? mDelta.dt : mCeil(dt - mDelta.dt) + mDelta.dt;
- // Adjust current frame interpolation
- if (mDelta.dt)
- {
- mDelta.pos = cp + (mDelta.warpOffset * (mDelta.dt / dt));
- mDelta.posVec = (cp - mDelta.pos) / mDelta.dt;
- QuatF cr;
- cr.interpolate(mDelta.rot[1], mDelta.rot[0], mDelta.dt);
- mDelta.rot[1].interpolate(cr, pos, mDelta.dt / dt);
- mDelta.rot[0].extrapolate(mDelta.rot[1], cr, mDelta.dt);
- }
- // Calculated multi-tick warp
- mDelta.warpCount = 0;
- mDelta.warpTicks = (S32)(mFloor(dt));
- if (mDelta.warpTicks)
- {
- mDelta.warpOffset = pos - mDelta.pos;
- mDelta.warpOffset /= mDelta.warpTicks;
- mDelta.warpRot[0] = mDelta.rot[1];
- mDelta.warpRot[1] = rot.asQuatF();
- }
- }
- else
- {
- // Set the entity to the server position
- mDelta.dt = 0;
- mDelta.pos = pos;
- mDelta.posVec.set(0, 0, 0);
- mDelta.rot[1] = mDelta.rot[0] = rot.asQuatF();
- mDelta.warpCount = mDelta.warpTicks = 0;
- setTransform(pos, rot);
- }
- }
- /*if (stream->readFlag())
- {
- Point3F mountOffset;
- EulerF mountRot;
- mathRead(*stream, &mountOffset);
- mathRead(*stream, &mountRot);
- RotationF rot = RotationF(mountRot);
- mountRot = rot.asEulerF(RotationF::Degrees);
- setMountOffset(mountOffset);
- setMountRotation(mountRot);
- }*/
- if (stream->readFlag())
- {
- mathRead(*stream, &mObjBox);
- resetWorldBox();
- }
- if (stream->readFlag())
- {
- //are we passing any behaviors currently?
- if (stream->readFlag())
- {
- //if we've just started the update, clear our behaviors
- if (stream->readFlag())
- clearComponents(false);
- S32 componentCount = stream->readInt(16);
- for (U32 i = 0; i < componentCount; i++)
- {
- S32 gIndex = stream->readInt(NetConnection::GhostIdBitSize);
- addComponent(dynamic_cast<Component*>(con->resolveGhost(gIndex)));
- }
- }
- }
- }
- //Manipulation
- void Entity::setTransform(const MatrixF &mat)
- {
- //setMaskBits(TransformMask);
- setMaskBits(TransformMask | NoWarpMask);
- if (isMounted())
- {
- // Use transform from mounted object
- Point3F newPos = mat.getPosition();
- Point3F parentPos = mMount.object->getTransform().getPosition();
- Point3F newOffset = newPos - parentPos;
- if (!newOffset.isZero())
- {
- //setMountOffset(newOffset);
- mPos = newOffset;
- }
- Point3F matEul = mat.toEuler();
- //mRot = Point3F(mRadToDeg(matEul.x), mRadToDeg(matEul.y), mRadToDeg(matEul.z));
- if (matEul != Point3F(0, 0, 0))
- {
- Point3F mountEul = mMount.object->getTransform().toEuler();
- Point3F diff = matEul - mountEul;
- //setMountRotation(Point3F(mRadToDeg(diff.x), mRadToDeg(diff.y), mRadToDeg(diff.z)));
- mRot = diff;
- }
- else
- {
- //setMountRotation(Point3F(0, 0, 0));
- mRot = Point3F(0, 0, 0);
- }
- RotationF addRot = mRot + RotationF(mMount.object->getTransform());
- MatrixF transf = addRot.asMatrixF();
- transf.setPosition(mPos + mMount.object->getPosition());
- Parent::setTransform(transf);
- }
- else
- {
- //Are we part of a prefab?
- /*Prefab* p = Prefab::getPrefabByChild(this);
- if (p)
- {
- //just let our prefab know we moved
- p->childTransformUpdated(this, mat);
- }*/
- //else
- {
- //mRot.set(mat);
- //Parent::setTransform(mat);
- RotationF rot = RotationF(mat);
- EulerF tempRot = rot.asEulerF(RotationF::Degrees);
- Point3F pos;
- mat.getColumn(3,&pos);
- setTransform(pos, rot);
- }
- }
- }
- void Entity::setTransform(Point3F position, RotationF rotation)
- {
- if (isMounted())
- {
- mPos = position;
- mRot = rotation;
- RotationF addRot = mRot + RotationF(mMount.object->getTransform());
- MatrixF transf = addRot.asMatrixF();
- transf.setPosition(mPos + mMount.object->getPosition());
- Parent::setTransform(transf);
- setMaskBits(TransformMask);
- }
- else
- {
- /*MatrixF newMat, imat, xmat, ymat, zmat;
- Point3F radRot = Point3F(mDegToRad(rotation.x), mDegToRad(rotation.y), mDegToRad(rotation.z));
- xmat.set(EulerF(radRot.x, 0, 0));
- ymat.set(EulerF(0.0f, radRot.y, 0.0f));
- zmat.set(EulerF(0, 0, radRot.z));
- imat.mul(zmat, xmat);
- newMat.mul(imat, ymat);*/
- MatrixF newMat = rotation.asMatrixF();
- newMat.setColumn(3, position);
- mPos = position;
- mRot = rotation;
- setMaskBits(TransformMask);
- //if (isServerObject())
- // setMaskBits(TransformMask);
- //setTransform(temp);
- // This test is a bit expensive so turn it off in release.
- #ifdef TORQUE_DEBUG
- //AssertFatal( mat.isAffine(), "SceneObject::setTransform() - Bad transform (non affine)!" );
- #endif
- //PROFILE_SCOPE(Entity_setTransform);
- // Update the transforms.
- Parent::setTransform(newMat);
- onTransformSet.trigger(&newMat);
- /*mObjToWorld = mWorldToObj = newMat;
- mWorldToObj.affineInverse();
- // Update the world-space AABB.
- resetWorldBox();
- // If we're in a SceneManager, sync our scene state.
- if (mSceneManager != NULL)
- mSceneManager->notifyObjectDirty(this);
- setRenderTransform(newMat);*/
- }
- }
- void Entity::setRenderTransform(const MatrixF &mat)
- {
- Parent::setRenderTransform(mat);
- }
- void Entity::setRenderTransform(Point3F position, RotationF rotation)
- {
- if (isMounted())
- {
- mPos = position;
- mRot = rotation;
- RotationF addRot = mRot + RotationF(mMount.object->getTransform());
- MatrixF transf = addRot.asMatrixF();
- transf.setPosition(mPos + mMount.object->getPosition());
- Parent::setRenderTransform(transf);
- }
- else
- {
- MatrixF newMat = rotation.asMatrixF();
- newMat.setColumn(3, position);
- mPos = position;
- mRot = rotation;
- Parent::setRenderTransform(newMat);
- onTransformSet.trigger(&newMat);
- }
- }
- MatrixF Entity::getTransform()
- {
- if (isMounted())
- {
- MatrixF mat;
- //Use transform from mount
- mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat);
- Point3F transPos = mat.getPosition() + mPos;
- mat.mul(mRot.asMatrixF());
- mat.setPosition(transPos);
- return mat;
- }
- else
- {
- return Parent::getTransform();
- }
- }
- void Entity::setMountOffset(Point3F posOffset)
- {
- if (isMounted())
- {
- mMount.xfm.setColumn(3, posOffset);
- //mPos = posOffset;
- setMaskBits(MountedMask);
- }
- }
- void Entity::setMountRotation(EulerF rotOffset)
- {
- if (isMounted())
- {
- MatrixF temp, imat, xmat, ymat, zmat;
- Point3F radRot = Point3F(mDegToRad(rotOffset.x), mDegToRad(rotOffset.y), mDegToRad(rotOffset.z));
- xmat.set(EulerF(radRot.x, 0, 0));
- ymat.set(EulerF(0.0f, radRot.y, 0.0f));
- zmat.set(EulerF(0, 0, radRot.z));
- imat.mul(zmat, xmat);
- temp.mul(imat, ymat);
- temp.setColumn(3, mMount.xfm.getPosition());
- mMount.xfm = temp;
- //mRot = RotationF(temp);
- setMaskBits(MountedMask);
- }
- }
- //
- void Entity::getCameraTransform(F32* pos, MatrixF* mat)
- {
- Vector<CameraInterface*> updaters = getComponents<CameraInterface>();
- for (Vector<CameraInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++) {
- if ((*it)->getCameraTransform(pos, mat)) {
- return;
- }
- }
- }
- void Entity::getMountTransform(S32 index, const MatrixF &xfm, MatrixF *outMat)
- {
- RenderComponentInterface* renderInterface = getComponent<RenderComponentInterface>();
- if (renderInterface)
- {
- renderInterface->getShapeInstance()->animate();
- S32 nodeCount = renderInterface->getShapeInstance()->getShape()->nodes.size();
- if (index >= 0 && index < nodeCount)
- {
- MatrixF mountTransform = renderInterface->getShapeInstance()->mNodeTransforms[index];
- mountTransform.mul(xfm);
- const Point3F& scale = getScale();
- // The position of the mount point needs to be scaled.
- Point3F position = mountTransform.getPosition();
- position.convolve(scale);
- mountTransform.setPosition(position);
- // Also we would like the object to be scaled to the model.
- outMat->mul(mObjToWorld, mountTransform);
- return;
- }
- }
- // Then let SceneObject handle it.
- Parent::getMountTransform(index, xfm, outMat);
- }
- void Entity::getRenderMountTransform(F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat)
- {
- RenderComponentInterface* renderInterface = getComponent<RenderComponentInterface>();
- if (renderInterface && renderInterface->getShapeInstance())
- {
- renderInterface->getShapeInstance()->animate();
- S32 nodeCount = renderInterface->getShapeInstance()->getShape()->nodes.size();
- if (index >= 0 && index < nodeCount)
- {
- MatrixF mountTransform = renderInterface->getShapeInstance()->mNodeTransforms[index];
- mountTransform.mul(xfm);
- const Point3F& scale = getScale();
- // The position of the mount point needs to be scaled.
- Point3F position = mountTransform.getPosition();
- position.convolve(scale);
- mountTransform.setPosition(position);
- // Also we would like the object to be scaled to the model.
- outMat->mul(getRenderTransform(), mountTransform);
- return;
- }
- }
- // Then let SceneObject handle it.
- Parent::getMountTransform(index, xfm, outMat);
- }
- void Entity::setForwardVector(VectorF newForward, VectorF upVector)
- {
- MatrixF mat = getTransform();
- VectorF up(0.0f, 0.0f, 1.0f);
- VectorF axisX;
- VectorF axisY = newForward;
- VectorF axisZ;
- if (upVector != VectorF::Zero)
- up = upVector;
- // Validate and normalize input:
- F32 lenSq;
- lenSq = axisY.lenSquared();
- if (lenSq < 0.000001f)
- {
- axisY.set(0.0f, 1.0f, 0.0f);
- Con::errorf("Entity::setForwardVector() - degenerate forward vector");
- }
- else
- {
- axisY /= mSqrt(lenSq);
- }
- lenSq = up.lenSquared();
- if (lenSq < 0.000001f)
- {
- up.set(0.0f, 0.0f, 1.0f);
- Con::errorf("SceneObject::setForwardVector() - degenerate up vector - too small");
- }
- else
- {
- up /= mSqrt(lenSq);
- }
- if (fabsf(mDot(up, axisY)) > 0.9999f)
- {
- Con::errorf("SceneObject::setForwardVector() - degenerate up vector - same as forward");
- // i haven't really tested this, but i think it generates something which should be not parallel to the previous vector:
- F32 tmp = up.x;
- up.x = -up.y;
- up.y = up.z;
- up.z = tmp;
- }
- // construct the remaining axes:
- mCross(axisY, up, &axisX);
- mCross(axisX, axisY, &axisZ);
- mat.setColumn(0, axisX);
- mat.setColumn(1, axisY);
- mat.setColumn(2, axisZ);
- setTransform(mat);
- }
- //
- //These basically just redirect to any collision behaviors we have
- bool Entity::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
- {
- Vector<CastRayInterface*> updaters = getComponents<CastRayInterface>();
- for (Vector<CastRayInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
- {
- if ((*it)->castRay(start, end, info))
- {
- return true;
- }
- }
- return false;
- }
- bool Entity::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info)
- {
- Vector<CastRayRenderedInterface*> updaters = getComponents<CastRayRenderedInterface>();
- for (Vector<CastRayRenderedInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
- {
- if ((*it)->castRayRendered(start, end, info))
- {
- return true;
- }
- }
- return false;
- }
- bool Entity::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere)
- {
- Vector<BuildPolyListInterface*> updaters = getComponents<BuildPolyListInterface>();
- for (Vector<BuildPolyListInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
- {
- return (*it)->buildPolyList(context, polyList, box, sphere);
- }
- return false;
- }
- void Entity::buildConvex(const Box3F& box, Convex* convex)
- {
- Vector<BuildConvexInterface*> updaters = getComponents<BuildConvexInterface>();
- for (Vector<BuildConvexInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
- {
- (*it)->buildConvex(box, convex);
- }
- }
- //
- // Mounting and heirarchy manipulation
- void Entity::mountObject(SceneObject* objB, MatrixF txfm)
- {
- Parent::mountObject(objB, -1, txfm);
- Parent::addObject(objB);
- }
- void Entity::mountObject(SceneObject *obj, S32 node, const MatrixF &xfm)
- {
- Parent::mountObject(obj, node, xfm);
- }
- void Entity::onMount(SceneObject *obj, S32 node)
- {
- deleteNotify(obj);
- // Are we mounting to a GameBase object?
- Entity *entityObj = dynamic_cast<Entity*>(obj);
- if (entityObj && entityObj->getControlObject() != this)
- processAfter(entityObj);
- if (!isGhost()) {
- setMaskBits(MountedMask);
- //TODO implement this callback
- //onMount_callback( this, obj, node );
- }
- }
- void Entity::onUnmount(SceneObject *obj, S32 node)
- {
- clearNotify(obj);
- Entity *entityObj = dynamic_cast<Entity*>(obj);
- if (entityObj && entityObj->getControlObject() != this)
- clearProcessAfter();
- if (!isGhost()) {
- setMaskBits(MountedMask);
- //TODO implement this callback
- //onUnmount_callback( this, obj, node );
- }
- }
- //Heirarchy stuff
- void Entity::addObject(SimObject* object)
- {
- Component* component = dynamic_cast<Component*>(object);
- if (component)
- {
- addComponent(component);
- return;
- }
- Entity* e = dynamic_cast<Entity*>(object);
- if (e)
- {
- MatrixF offset;
- //offset.mul(getWorldTransform(), e->getWorldTransform());
- //check if we're mounting to a node on a shape we have
- String node = e->getDataField("mountNode", NULL);
- if (!node.isEmpty())
- {
- RenderComponentInterface *renderInterface = getComponent<RenderComponentInterface>();
- if (renderInterface)
- {
- TSShape* shape = renderInterface->getShape();
- S32 nodeIdx = shape->findNode(node);
- mountObject(e, nodeIdx, MatrixF::Identity);
- }
- else
- {
- mountObject(e, MatrixF::Identity);
- }
- }
- else
- {
- /*Point3F posOffset = mPos - e->getPosition();
- mPos = posOffset;
- RotationF rotOffset = mRot - e->getRotation();
- mRot = rotOffset;
- setMaskBits(TransformMask);
- mountObject(e, MatrixF::Identity);*/
- mountObject(e, MatrixF::Identity);
- }
- //e->setMountOffset(e->getPosition() - getPosition());
- //Point3F diff = getWorldTransform().toEuler() - e->getWorldTransform().toEuler();
- //e->setMountRotation(Point3F(mRadToDeg(diff.x),mRadToDeg(diff.y),mRadToDeg(diff.z)));
- //mountObject(e, offset);
- }
- else
- {
- SceneObject* so = dynamic_cast<SceneObject*>(object);
- if (so)
- {
- //get the difference and build it as our offset!
- Point3F posOffset = so->getPosition() - mPos;
- RotationF rotOffset = RotationF(so->getTransform()) - mRot;
- MatrixF offset = rotOffset.asMatrixF();
- offset.setPosition(posOffset);
- mountObject(so, offset);
- return;
- }
- }
- Parent::addObject(object);
- }
- void Entity::removeObject(SimObject* object)
- {
- Entity* e = dynamic_cast<Entity*>(object);
- if (e)
- {
- mPos = mPos + e->getPosition();
- mRot = mRot + e->getRotation();
- unmountObject(e);
- setMaskBits(TransformMask);
- }
- else
- {
- SceneObject* so = dynamic_cast<SceneObject*>(object);
- if (so)
- unmountObject(so);
- }
- Parent::removeObject(object);
- }
- bool Entity::addComponent(Component *comp)
- {
- if (comp == NULL || !comp->isProperlyAdded())
- return false;
- //double-check were not re-adding anything
- mComponents.push_back(comp);
- // Register the component with this owner.
- comp->setOwner(this);
- //if we've already been added and this is being added after the fact(at runtime),
- //then just go ahead and call it's onComponentAdd so it can get to work
- if (mInitialized)
- comp->onComponentAdd();
- onComponentAdded.trigger(comp);
- return true;
- }
- SimObject* Entity::findObjectByInternalName(StringTableEntry internalName, bool searchChildren)
- {
- for (U32 i = 0; i < mComponents.size(); i++)
- {
- if (mComponents[i]->getInternalName() == internalName)
- {
- return mComponents[i];
- }
- }
- return Parent::findObjectByInternalName(internalName, searchChildren);
- }
- //////////////////////////////////////////////////////////////////////////
- bool Entity::removeComponent(Component *comp, bool deleteComponent)
- {
- if (comp == NULL)
- return false;
- if(mComponents.remove(comp))
- {
- AssertFatal(comp->isProperlyAdded(), "Don't know how but a component is not registered w/ the sim");
- //setComponentsDirty();
- onComponentRemoved.trigger(comp);
- comp->setOwner(NULL);
- comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner
- if (deleteComponent)
- comp->safeDeleteObject();
- return true;
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- //NOTE:
- //The actor class calls this and flags the deletion of the behaviors to false so that behaviors that should no longer be attached during
- //a network update will indeed be removed from the object. The reason it doesn't delete them is because when clearing the local behavior
- //list, it would delete them, purging the ghost, and causing a crash when the unpack update tried to fetch any existing behaviors' ghosts
- //to re-add them. Need to implement a clean clear function that will clear the local list, and only delete unused behaviors during an update.
- void Entity::clearComponents(bool deleteComponents)
- {
- bool srv = isServerObject();
- if (!deleteComponents)
- {
- while (mComponents.size() > 0)
- {
- removeComponent(mComponents.first(), deleteComponents);
- }
- }
- else
- {
- while (mComponents.size() > 0)
- {
- Component* comp = mComponents.first();
- if (comp)
- {
- comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner
- bool removed = mComponents.remove(comp);
- //we only need to delete them on the server side. they'll be cleaned up on the client side
- //via the ghosting system for us
- if (isServerObject())
- comp->deleteObject();
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- Component *Entity::getComponent(const U32 index) const
- {
- if (index < mComponents.size())
- return mComponents[index];
- return NULL;
- }
- Component *Entity::getComponent(String componentType)
- {
- for (U32 i = 0; i < mComponents.size(); i++)
- {
- Component* comp = mComponents[i];
- /*String namespaceName = comp->getNamespace()->mName;
- //check our namespace first
- if (namespaceName == componentType)
- {
- return comp;
- }
- else
- {*/
- //lets scan up, just to be sure
- Namespace *NS = comp->getNamespace();
- //we shouldn't ever go past Component into net object, as we're no longer dealing with component classes
- while (dStrcmp(NS->getName(), "NetObject"))
- {
- String namespaceName = NS->getName();
- if (namespaceName == componentType)
- {
- return comp;
- }
- else
- {
- NS = NS->getParent();
- }
- }
- //}
- }
- return NULL;
- }
- void Entity::onInspect()
- {
- Vector<EditorInspectInterface*> updaters = getComponents<EditorInspectInterface>();
- for (Vector<EditorInspectInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++) {
- (*it)->onInspect();
- }
- GuiTreeViewCtrl *editorTree = dynamic_cast<GuiTreeViewCtrl*>(Sim::findObject("EditorTree"));
- if (!editorTree)
- return;
- GuiTreeViewCtrl::Item *newItem, *parentItem;
- parentItem = editorTree->getItem(editorTree->findItemByObjectId(getId()));
- S32 componentID = editorTree->insertItem(parentItem->getID(), "Components");
- newItem = editorTree->getItem(componentID);
- newItem->mState.set(GuiTreeViewCtrl::Item::VirtualParent);
- newItem->mState.set(GuiTreeViewCtrl::Item::DenyDrag);
- //newItem->mState.set(GuiTreeViewCtrl::Item::InspectorData);
- newItem->mState.set(GuiTreeViewCtrl::Item::ForceItemName);
- //newItem->mInspectorInfo.mObject = this;
- for (U32 i = 0; i < mComponents.size(); i++)
- {
- String compName = mComponents[i]->getFriendlyName();
- S32 compID = editorTree->insertItem(componentID, compName);
- newItem = editorTree->getItem(compID);
- newItem->mInspectorInfo.mObject = mComponents[i];
- newItem->mState.set(GuiTreeViewCtrl::Item::ForceItemName);
- newItem->mState.set(GuiTreeViewCtrl::Item::DenyDrag);
- newItem->mState.set(GuiTreeViewCtrl::Item::InspectorData);
- }
- editorTree->buildVisibleTree(true);
- }
- void Entity::onEndInspect()
- {
- Vector<EditorInspectInterface*> updaters = getComponents<EditorInspectInterface>();
- for (Vector<EditorInspectInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++) {
- (*it)->onEndInspect();
- }
- GuiTreeViewCtrl *editorTree = dynamic_cast<GuiTreeViewCtrl*>(Sim::findObject("EditorTree"));
- if (!editorTree)
- return;
- S32 componentItemIdx = editorTree->findItemByName("Components");
- editorTree->removeItem(componentItemIdx, false);
- }
- static void writeTabs(Stream &stream, U32 count)
- {
- char tab[] = " ";
- while (count--)
- stream.write(3, (void*)tab);
- }
- void Entity::write(Stream &stream, U32 tabStop, U32 flags)
- {
- // Do *not* call parent on this
- /*VectorPtr<ComponentObject *> &componentList = lockComponentList();
- // export selected only?
- if( ( flags & SelectedOnly ) && !isSelected() )
- {
- for( BehaviorObjectIterator i = componentList.begin(); i != componentList.end(); i++ )
- (*i)->write(stream, tabStop, flags);
- goto write_end;
- }*/
- //catch if we have any written behavior fields already in the file, and clear them. We don't need to double-up
- //the entries for no reason.
- /*if(getFieldDictionary())
- {
- //get our dynamic field count, then parse through them to see if they're a behavior or not
- //reset it
- SimFieldDictionary* fieldDictionary = getFieldDictionary();
- SimFieldDictionaryIterator itr(fieldDictionary);
- for (S32 i = 0; i < fieldDictionary->getNumFields(); i++)
- {
- if (!(*itr))
- break;
- SimFieldDictionary::Entry* entry = *itr;
- if(strstr(entry->slotName, "_behavior"))
- {
- entry->slotName = "";
- entry->value = "";
- }
- ++itr;
- }
- }*/
- //all existing written behavior fields should be cleared. now write the object block
- writeTabs(stream, tabStop);
- char buffer[1024];
- dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : "");
- stream.write(dStrlen(buffer), buffer);
- writeFields(stream, tabStop + 1);
- stream.write(1, "\n");
- ////first, write out our behavior objects
- // NOW we write the behavior fields proper
- if (mComponents.size() > 0)
- {
- // Pack out the behaviors into fields
- U32 i = 0;
- for (U32 i = 0; i < mComponents.size(); i++)
- {
- writeTabs(stream, tabStop + 1);
- char buffer[1024];
- dSprintf(buffer, sizeof(buffer), "new %s() {\r\n", mComponents[i]->getClassName());
- stream.write(dStrlen(buffer), buffer);
- //bi->writeFields( stream, tabStop + 2 );
- mComponents[i]->packToStream(stream, tabStop + 2, i - 1, flags);
- writeTabs(stream, tabStop + 1);
- stream.write(4, "};\r\n");
- }
- }
- //
- //if (size() > 0)
- // stream.write(2, "\r\n");
- for (U32 i = 0; i < size(); i++)
- {
- SimObject* child = (*this)[i];
- if (child->getCanSave())
- child->write(stream, tabStop + 1, flags);
- }
- //stream.write(2, "\r\n");
- writeTabs(stream, tabStop);
- stream.write(4, "};\r\n");
- //write_end:
- //unlockComponentList();
- }
- SimObject* Entity::getTamlChild(const U32 childIndex) const
- {
- // Sanity!
- AssertFatal(childIndex < getTamlChildCount(), "SimSet::getTamlChild() - Child index is out of range.");
- // For when the assert is not used.
- if (childIndex >= getTamlChildCount())
- return NULL;
- //we always order components first, child objects second
- if (childIndex >= getComponentCount())
- return at(childIndex - getComponentCount());
- else
- return getComponent(childIndex);
- }
- //
- void Entity::onCameraScopeQuery(NetConnection* connection, CameraScopeQuery* query)
- {
- // Object itself is in scope.
- Parent::onCameraScopeQuery(connection, query);
- if (CameraInterface* cI = getComponent<CameraInterface>())
- {
- cI->onCameraScopeQuery(connection, query);
- }
- }
- //
- void Entity::setObjectBox(Box3F objBox)
- {
- mObjBox = objBox;
- resetWorldBox();
- if (isServerObject())
- setMaskBits(BoundsMask);
- }
- void Entity::updateContainer()
- {
- PROFILE_SCOPE(Entity_updateContainer);
- // Update container drag and buoyancy properties
- containerInfo.box = getWorldBox();
- //containerInfo.mass = mMass;
- getContainer()->findObjects(containerInfo.box, WaterObjectType | PhysicalZoneObjectType, findRouter, &containerInfo);
- //mWaterCoverage = info.waterCoverage;
- //mLiquidType = info.liquidType;
- //mLiquidHeight = info.waterHeight;
- //setCurrentWaterObject( info.waterObject );
- // This value might be useful as a datablock value,
- // This is what allows the player to stand in shallow water (below this coverage)
- // without jiggling from buoyancy
- /*if (info.waterCoverage >= 0.25f)
- {
- // water viscosity is used as drag for in water.
- // ShapeBaseData drag is used for drag outside of water.
- // Combine these two components to calculate this ShapeBase object's
- // current drag.
- mDrag = (info.waterCoverage * info.waterViscosity) +
- (1.0f - info.waterCoverage) * mDrag;
- //mBuoyancy = (info.waterDensity / mDataBlock->density) * info.waterCoverage;
- }
- //mAppliedForce = info.appliedForce;
- mGravityMod = info.gravityScale;*/
- }
- //
- void Entity::setComponentsDirty()
- {
- if (mToLoadComponents.empty())
- mStartComponentUpdate = true;
- //we need to build a list of behaviors that need to be pushed across the network
- for (U32 i = 0; i < mComponents.size(); i++)
- {
- // We can do this because both are in the string table
- Component *comp = mComponents[i];
- if (comp->isNetworked())
- {
- bool unique = true;
- for (U32 i = 0; i < mToLoadComponents.size(); i++)
- {
- if (mToLoadComponents[i]->getId() == comp->getId())
- {
- unique = false;
- break;
- }
- }
- if (unique)
- mToLoadComponents.push_back(comp);
- }
- }
- setMaskBits(ComponentsMask);
- }
- void Entity::setComponentDirty(Component *comp, bool forceUpdate)
- {
- bool found = false;
- for (U32 i = 0; i < mComponents.size(); i++)
- {
- if (mComponents[i]->getId() == comp->getId())
- {
- mComponents[i]->setOwner(this);
- return;
- }
- }
- if (!found)
- return;
- //if(mToLoadComponents.empty())
- // mStartComponentUpdate = true;
- /*if (comp->isNetworked() || forceUpdate)
- {
- bool unique = true;
- for (U32 i = 0; i < mToLoadComponents.size(); i++)
- {
- if (mToLoadComponents[i]->getId() == comp->getId())
- {
- unique = false;
- break;
- }
- }
- if (unique)
- mToLoadComponents.push_back(comp);
- }
- setMaskBits(ComponentsMask);*/
-
- }
- DefineEngineMethod(Entity, mountObject, bool,
- (SceneObject* objB, TransformF txfm), (MatrixF::Identity),
- "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
- "@param objB Object to mount onto us\n"
- "@param slot Mount slot ID\n"
- "@param txfm (optional) mount offset transform\n"
- "@return true if successful, false if failed (objB is not valid)")
- {
- if (objB)
- {
- //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen
- //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity
- object->mountObject(objB, /*MatrixF::Identity*/txfm.getMatrix());
- return true;
- }
- return false;
- }
- DefineEngineMethod(Entity, setMountOffset, void,
- (Point3F posOffset), (Point3F(0, 0, 0)),
- "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
- "@param objB Object to mount onto us\n"
- "@param slot Mount slot ID\n"
- "@param txfm (optional) mount offset transform\n"
- "@return true if successful, false if failed (objB is not valid)")
- {
- object->setMountOffset(posOffset);
- }
- DefineEngineMethod(Entity, setMountRotation, void,
- (EulerF rotOffset), (EulerF(0, 0, 0)),
- "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
- "@param objB Object to mount onto us\n"
- "@param slot Mount slot ID\n"
- "@param txfm (optional) mount offset transform\n"
- "@return true if successful, false if failed (objB is not valid)")
- {
- object->setMountRotation(rotOffset);
- }
- DefineEngineMethod(Entity, getMountTransform, TransformF, (), ,
- "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
- "@param objB Object to mount onto us\n"
- "@param slot Mount slot ID\n"
- "@param txfm (optional) mount offset transform\n"
- "@return true if successful, false if failed (objB is not valid)")
- {
- MatrixF mat;
- object->getMountTransform(0, MatrixF::Identity, &mat);
- return mat;
- }
- DefineEngineMethod(Entity, setBox, void,
- (Point3F box), (Point3F(1, 1, 1)),
- "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
- "@param objB Object to mount onto us\n"
- "@param slot Mount slot ID\n"
- "@param txfm (optional) mount offset transform\n"
- "@return true if successful, false if failed (objB is not valid)")
- {
- object->setObjectBox(Box3F(-box, box));
- }
- /*DefineConsoleMethod(Entity, callOnComponents, void, (const char* functionName), ,
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- object->callOnComponents(functionName);
- }
- ConsoleMethod(Entity, callMethod, void, 3, 64, "(methodName, argi) Calls script defined method\n"
- "@param methodName The method's name as a string\n"
- "@param argi Any arguments to pass to the method\n"
- "@return No return value"
- "@note %obj.callMethod( %methodName, %arg1, %arg2, ... );\n")
- {
- object->callMethodArgList(argc - 1, argv + 2);
- }
- ConsoleMethod(Entity, addComponents, void, 2, 2, "() - Add all fielded behaviors\n"
- "@return No return value")
- {
- object->addComponents();
- }*/
- ConsoleMethod(Entity, addComponent, bool, 3, 3, "(ComponentInstance bi) - Add a behavior to the object\n"
- "@param bi The behavior instance to add"
- "@return (bool success) Whether or not the behavior was successfully added")
- {
- Component *comp = dynamic_cast<Component *>(Sim::findObject(argv[2]));
- if (comp != NULL)
- {
- bool success = object->addComponent(comp);
- if (success)
- {
- //Placed here so we can differentiate against adding a new behavior during runtime, or when we load all
- //fielded behaviors on mission load. This way, we can ensure that we only call the callback
- //once everything is loaded. This avoids any problems with looking for behaviors that haven't been added yet, etc.
- if (comp->isMethod("onBehaviorAdd"))
- Con::executef(comp, "onBehaviorAdd");
- return true;
- }
- }
- return false;
- }
- ConsoleMethod(Entity, removeComponent, bool, 3, 4, "(ComponentInstance bi, [bool deleteBehavior = true])\n"
- "@param bi The behavior instance to remove\n"
- "@param deleteBehavior Whether or not to delete the behavior\n"
- "@return (bool success) Whether the behavior was successfully removed")
- {
- bool deleteComponent = true;
- if (argc > 3)
- deleteComponent = dAtob(argv[3]);
- return object->removeComponent(dynamic_cast<Component *>(Sim::findObject(argv[2])), deleteComponent);
- }
- ConsoleMethod(Entity, clearComponents, void, 2, 2, "() - Clear all behavior instances\n"
- "@return No return value")
- {
- object->clearComponents();
- }
- ConsoleMethod(Entity, getComponentByIndex, S32, 3, 3, "(int index) - Gets a particular behavior\n"
- "@param index The index of the behavior to get\n"
- "@return (ComponentInstance bi) The behavior instance you requested")
- {
- Component *comp = object->getComponent(dAtoi(argv[2]));
- return (comp != NULL) ? comp->getId() : 0;
- }
- DefineConsoleMethod(Entity, getComponent, S32, (String componentName), (""),
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- Component *comp = object->getComponent(componentName);
- return (comp != NULL) ? comp->getId() : 0;
- return 0;
- }
- /*ConsoleMethod(Entity, getBehaviorByType, S32, 3, 3, "(string BehaviorTemplateName) - gets a behavior\n"
- "@param BehaviorTemplateName The name of the template of the behavior instance you want\n"
- "@return (ComponentInstance bi) The behavior instance you requested")
- {
- ComponentInstance *bInstance = object->getComponentByType(StringTable->insert(argv[2]));
- return (bInstance != NULL) ? bInstance->getId() : 0;
- }*/
- /*ConsoleMethod(Entity, reOrder, bool, 3, 3, "(ComponentInstance inst, [int desiredIndex = 0])\n"
- "@param inst The behavior instance you want to reorder\n"
- "@param desiredIndex The index you want the behavior instance to be reordered to\n"
- "@return (bool success) Whether or not the behavior instance was successfully reordered")
- {
- Component *inst = dynamic_cast<Component *>(Sim::findObject(argv[1]));
- if (inst == NULL)
- return false;
- U32 idx = 0;
- if (argc > 2)
- idx = dAtoi(argv[2]);
- return object->reOrder(inst, idx);
- }*/
- ConsoleMethod(Entity, getComponentCount, S32, 2, 2, "() - Get the count of behaviors on an object\n"
- "@return (int count) The number of behaviors on an object")
- {
- return object->getComponentCount();
- }
- DefineConsoleMethod(Entity, setComponentDirty, void, (S32 componentID, bool forceUpdate), (0, false),
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- /*Component* comp;
- if (Sim::findObject(componentID, comp))
- object->setComponentDirty(comp, forceUpdate);*/
- }
- DefineConsoleMethod(Entity, getMoveVector, VectorF, (),,
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- if (object->getControllingClient() != NULL)
- {
- //fetch our last move
- if (object->lastMove.x != 0 || object->lastMove.y != 0 || object->lastMove.z != 0)
- return VectorF(object->lastMove.x, object->lastMove.y, object->lastMove.z);
- }
- return VectorF::Zero;
- }
- DefineConsoleMethod(Entity, getMoveRotation, VectorF, (), ,
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- if(object->getControllingClient() != NULL)
- {
- //fetch our last move
- if (object->lastMove.pitch != 0 || object->lastMove.roll != 0 || object->lastMove.yaw != 0)
- return VectorF(object->lastMove.pitch, object->lastMove.roll, object->lastMove.yaw);
- }
- return VectorF::Zero;
- }
- DefineConsoleMethod(Entity, getMoveTrigger, bool, (S32 triggerNum), (0),
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- if (object->getControllingClient() != NULL && triggerNum < MaxTriggerKeys)
- {
- return object->lastMove.trigger[triggerNum];
- }
- return false;
- }
- DefineConsoleMethod(Entity, setForwardVector, void, (VectorF newForward), (VectorF(0,0,0)),
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- object->setForwardVector(newForward);
- }
- DefineConsoleMethod(Entity, lookAt, void, (Point3F lookPosition),,
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- //object->setForwardVector(newForward);
- }
- DefineConsoleMethod(Entity, rotateTo, void, (Point3F lookPosition, F32 degreePerSecond), (1.0),
- "Get the number of static fields on the object.\n"
- "@return The number of static fields defined on the object.")
- {
- //object->setForwardVector(newForward);
- }
|