diff --git a/Engine/source/T3D/components/animation/animationComponent.cpp b/Engine/source/T3D/components/animation/animationComponent.cpp index e1a71511c..c8fd645d0 100644 --- a/Engine/source/T3D/components/animation/animationComponent.cpp +++ b/Engine/source/T3D/components/animation/animationComponent.cpp @@ -72,7 +72,6 @@ IMPLEMENT_CALLBACK(AnimationComponent, onAnimationTrigger, void, (Component* obj AnimationComponent::AnimationComponent() : Component() { mNetworked = true; - mNetFlags.set(Ghostable | ScopeAlways); mFriendlyName = "Animation(Component)"; mComponentType = "Render"; @@ -223,31 +222,19 @@ U32 AnimationComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stre { U32 retMask = Parent::packUpdate(con, mask, stream); - //early test if we lack an owner, ghost-wise - //no point in trying, just re-queue the mask and go - if (!mOwner || con->getGhostIndex(mOwner) == -1) + /*for (int i = 0; i < MaxScriptThreads; i++) { - stream->writeFlag(false); - return retMask |= ThreadMask; - } - else - { - stream->writeFlag(true); - - for (int i = 0; i < MaxScriptThreads; i++) + Thread& st = mAnimationThreads[i]; + if (stream->writeFlag((st.sequence != -1 || st.state == Thread::Destroy) && (mask & (ThreadMaskN << i)))) { - Thread& st = mAnimationThreads[i]; - if (stream->writeFlag( (st.sequence != -1 || st.state == Thread::Destroy) && (mask & (ThreadMaskN << i)) ) ) - { - stream->writeInt(st.sequence,ThreadSequenceBits); - stream->writeInt(st.state,2); - stream->write(st.timescale); - stream->write(st.position); - stream->writeFlag(st.atEnd); - stream->writeFlag(st.transition); - } + stream->writeInt(st.sequence, ThreadSequenceBits); + stream->writeInt(st.state, 2); + stream->write(st.timescale); + stream->write(st.position); + stream->writeFlag(st.atEnd); + stream->writeFlag(st.transition); } - } + }*/ return retMask; } @@ -256,29 +243,26 @@ void AnimationComponent::unpackUpdate(NetConnection *con, BitStream *stream) { Parent::unpackUpdate(con, stream); - if (stream->readFlag()) + /*for (S32 i = 0; i < MaxScriptThreads; i++) { - for (S32 i = 0; i < MaxScriptThreads; i++) + if (stream->readFlag()) { - if (stream->readFlag()) - { - Thread& st = mAnimationThreads[i]; - U32 seq = stream->readInt(ThreadSequenceBits); - st.state = stream->readInt(2); - stream->read( &st.timescale ); - stream->read( &st.position ); - st.atEnd = stream->readFlag(); - bool transition = stream->readFlag(); + Thread& st = mAnimationThreads[i]; + U32 seq = stream->readInt(ThreadSequenceBits); + st.state = stream->readInt(2); + stream->read( &st.timescale ); + stream->read( &st.position ); + st.atEnd = stream->readFlag(); + bool transition = stream->readFlag(); - if (!st.thread || st.sequence != seq && st.state != Thread::Destroy) - setThreadSequence(i, seq, false, transition); - else - updateThread(st); - - } + if (!st.thread || st.sequence != seq && st.state != Thread::Destroy) + setThreadSequence(i, seq, false, transition); + else + updateThread(st); } - } + }*/ } + void AnimationComponent::processTick() { Parent::processTick(); @@ -327,9 +311,6 @@ const char *AnimationComponent::getThreadSequenceName(U32 slot) bool AnimationComponent::setThreadSequence(U32 slot, S32 seq, bool reset, bool transition, F32 transTime) { - if (!mOwnerShapeInstance) - return false; - Thread& st = mAnimationThreads[slot]; if (st.thread && st.sequence == seq && st.state == Thread::Play && !reset) return true; @@ -340,7 +321,6 @@ bool AnimationComponent::setThreadSequence(U32 slot, S32 seq, bool reset, bool t if (seq < MaxSequenceIndex) { - setMaskBits(-1); setMaskBits(ThreadMaskN << slot); st.sequence = seq; st.transition = transition; @@ -647,7 +627,7 @@ void AnimationComponent::advanceThreads(F32 dt) st.atEnd = true; updateThread(st); - if (!isGhost()) + if (!isClientObject()) { Con::executef(this, "onAnimationEnd", st.thread->getSequenceName()); } @@ -660,7 +640,7 @@ void AnimationComponent::advanceThreads(F32 dt) mOwnerShapeInstance->advanceTime(dt, st.thread); } - if (mOwnerShapeInstance && !isGhost()) + if (mOwnerShapeInstance && !isClientObject()) { for (U32 i = 1; i < 32; i++) { @@ -672,8 +652,16 @@ void AnimationComponent::advanceThreads(F32 dt) } } - if (isGhost()) + if (isClientObject()) + { mOwnerShapeInstance->animate(); + /*mOwnerShapeInstance->animateGround(); + MatrixF groundTransform = mOwnerShapeInstance->getGroundTransform(); + if (groundTransform != MatrixF::Identity) + { + mOwner->setPosition(groundTransform.getPosition()); + }*/ + } } } } diff --git a/Engine/source/T3D/components/camera/cameraComponent.cpp b/Engine/source/T3D/components/camera/cameraComponent.cpp index 60c62fb3a..2cd1b7d08 100644 --- a/Engine/source/T3D/components/camera/cameraComponent.cpp +++ b/Engine/source/T3D/components/camera/cameraComponent.cpp @@ -79,6 +79,7 @@ CameraComponent::CameraComponent() : Component() mTargetNode = ""; mUseParentTransform = true; + mNetworked = true; mFriendlyName = "Camera(Component)"; } @@ -202,7 +203,7 @@ void CameraComponent::setCameraFov(F32 fov) void CameraComponent::onCameraScopeQuery(NetConnection *cr, CameraScopeQuery * query) { // update the camera query - query->camera = this; + query->camera = mOwner;//this; if(GameConnection * con = dynamic_cast(cr)) { @@ -357,7 +358,8 @@ U32 CameraComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) mTargetNodeIdx = nodeIndex; } - stream->writeInt(mTargetNodeIdx, 32); + if(stream->writeFlag(mTargetNodeIdx > -1)) + stream->writeInt(mTargetNodeIdx, 32); //send offsets here stream->writeCompressedPoint(mPosOffset); @@ -382,7 +384,10 @@ void CameraComponent::unpackUpdate(NetConnection *con, BitStream *stream) if(stream->readFlag()) { - mTargetNodeIdx = stream->readInt(32); + if (stream->readFlag()) + mTargetNodeIdx = stream->readInt(32); + else + mTargetNodeIdx = -1; stream->readCompressedPoint(&mPosOffset); diff --git a/Engine/source/T3D/components/collision/collisionComponent.cpp b/Engine/source/T3D/components/collision/collisionComponent.cpp index e680665dc..ccdf818f1 100644 --- a/Engine/source/T3D/components/collision/collisionComponent.cpp +++ b/Engine/source/T3D/components/collision/collisionComponent.cpp @@ -125,8 +125,6 @@ EndImplementEnumType; // CollisionComponent::CollisionComponent() : Component() { - mNetFlags.set(Ghostable | ScopeAlways); - mFriendlyName = "Collision(Component)"; mOwnerRenderInterface = NULL; diff --git a/Engine/source/T3D/components/component.cpp b/Engine/source/T3D/components/component.cpp index cbb2305c1..ff207d2c1 100644 --- a/Engine/source/T3D/components/component.cpp +++ b/Engine/source/T3D/components/component.cpp @@ -31,6 +31,7 @@ #include "console/engineAPI.h" #include "sim/netConnection.h" #include "console/consoleInternal.h" +#include "T3D/assets/MaterialAsset.h" #define DECLARE_NATIVE_COMPONENT( ComponentType ) \ Component* staticComponentTemplate = new ComponentType; \ @@ -52,7 +53,6 @@ Component::Component() mNetworked = false; - // [tom, 1/12/2007] We manage the memory for the description since it // could be loaded from a file and thus massive. This is accomplished with // protected fields, but since they still call Con::getData() the field @@ -66,7 +66,7 @@ Component::Component() mOriginatingAssetId = StringTable->EmptyString(); - mNetFlags.set(Ghostable); + mIsServerObject = true; } Component::~Component() @@ -198,7 +198,6 @@ void Component::onComponentRemove() { mOwner->onComponentAdded.remove(this, &Component::componentAddedToOwner); mOwner->onComponentRemoved.remove(this, &Component::componentRemovedFromOwner); - mOwner->onTransformSet.remove(this, &Component::ownerTransformSet); } mOwner = NULL; @@ -212,7 +211,6 @@ void Component::setOwner(Entity* owner) { mOwner->onComponentAdded.remove(this, &Component::componentAddedToOwner); mOwner->onComponentRemoved.remove(this, &Component::componentRemovedFromOwner); - mOwner->onTransformSet.remove(this, &Component::ownerTransformSet); mOwner->removeComponent(this, false); } @@ -223,11 +221,18 @@ void Component::setOwner(Entity* owner) { mOwner->onComponentAdded.notify(this, &Component::componentAddedToOwner); mOwner->onComponentRemoved.notify(this, &Component::componentRemovedFromOwner); - mOwner->onTransformSet.notify(this, &Component::ownerTransformSet); } if (isServerObject()) + { setMaskBits(OwnerMask); + + //if we have any outstanding maskbits, push them along to have the network update happen on the entity + if (mDirtyMaskBits != 0 && mOwner) + { + mOwner->setMaskBits(Entity::ComponentsUpdateMask); + } + } } void Component::componentAddedToOwner(Component *comp) @@ -240,16 +245,19 @@ void Component::componentRemovedFromOwner(Component *comp) return; } -void Component::ownerTransformSet(MatrixF *mat) +void Component::setMaskBits(U32 orMask) { - return; + AssertFatal(orMask != 0, "Invalid net mask bits set."); + + if (mOwner) + mOwner->setComponentNetMask(this, orMask); } U32 Component::packUpdate(NetConnection *con, U32 mask, BitStream *stream) { - U32 retMask = Parent::packUpdate(con, mask, stream); + U32 retMask = 0; - if (mask & OwnerMask) + /*if (mask & OwnerMask) { if (mOwner != NULL) { @@ -274,7 +282,7 @@ U32 Component::packUpdate(NetConnection *con, U32 mask, BitStream *stream) } } else - stream->writeFlag(false); + stream->writeFlag(false);*/ if (stream->writeFlag(mask & EnableMask)) { @@ -299,9 +307,7 @@ U32 Component::packUpdate(NetConnection *con, U32 mask, BitStream *stream) void Component::unpackUpdate(NetConnection *con, BitStream *stream) { - Parent::unpackUpdate(con, stream); - - if (stream->readFlag()) + /*if (stream->readFlag()) { if (stream->readFlag()) { @@ -317,7 +323,7 @@ void Component::unpackUpdate(NetConnection *con, BitStream *stream) //it's being nulled out setOwner(NULL); } - } + }*/ if (stream->readFlag()) { @@ -467,7 +473,7 @@ void Component::addComponentField(const char *fieldName, const char *desc, const else if (fieldType == StringTable->insert("vector")) fieldTypeMask = TypePoint3F; else if (fieldType == StringTable->insert("material")) - fieldTypeMask = TypeMaterialName; + fieldTypeMask = TypeMaterialAssetPtr; else if (fieldType == StringTable->insert("image")) fieldTypeMask = TypeImageFilename; else if (fieldType == StringTable->insert("shape")) @@ -488,6 +494,7 @@ void Component::addComponentField(const char *fieldName, const char *desc, const fieldTypeMask = TypeGameObjectAssetPtr; else fieldTypeMask = TypeString; + field.mFieldTypeName = fieldType; field.mFieldType = fieldTypeMask; diff --git a/Engine/source/T3D/components/component.h b/Engine/source/T3D/components/component.h index 4f84de17f..b585a30b0 100644 --- a/Engine/source/T3D/components/component.h +++ b/Engine/source/T3D/components/component.h @@ -64,9 +64,9 @@ struct ComponentField /// /// ////////////////////////////////////////////////////////////////////////// -class Component : public NetObject, public UpdateInterface +class Component : public SimObject, public UpdateInterface { - typedef NetObject Parent; + typedef SimObject Parent; protected: StringTableEntry mFriendlyName; @@ -92,6 +92,10 @@ protected: StringTableEntry mOriginatingAssetId; AssetPtr mOriginatingAsset; + U32 mDirtyMaskBits; + + bool mIsServerObject; + public: Component(); virtual ~Component(); @@ -113,7 +117,8 @@ public: //This is called when a different component is removed from our owner entity virtual void componentRemovedFromOwner(Component *comp); - virtual void ownerTransformSet(MatrixF *mat); + //Overridden by components that actually care + virtual void ownerTransformSet(MatrixF *mat) {} void setOwner(Entity* pOwner); inline Entity *getOwner() { return mOwner ? mOwner : NULL; } @@ -190,6 +195,16 @@ public: NextFreeMask = BIT(5) }; + virtual void setMaskBits(U32 orMask); + virtual void clearMaskBits() { + mDirtyMaskBits = 0; + } + + bool isServerObject() { return mIsServerObject; } + bool isClientObject() { return !mIsServerObject; } + + void setIsServerObject(bool isServerObj) { mIsServerObject = isServerObj; } + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); virtual void unpackUpdate(NetConnection *con, BitStream *stream); /// @} diff --git a/Engine/source/T3D/components/game/stateMachineComponent.cpp b/Engine/source/T3D/components/game/stateMachineComponent.cpp index 991d41ce1..d4e9a7d73 100644 --- a/Engine/source/T3D/components/game/stateMachineComponent.cpp +++ b/Engine/source/T3D/components/game/stateMachineComponent.cpp @@ -57,7 +57,6 @@ StateMachineComponent::StateMachineComponent() : Component() //doesn't need to be networked mNetworked = false; - mNetFlags.clear(); } StateMachineComponent::~StateMachineComponent() diff --git a/Engine/source/T3D/components/physics/rigidBodyComponent.cpp b/Engine/source/T3D/components/physics/rigidBodyComponent.cpp index 21e9ecdbe..200e0d65e 100644 --- a/Engine/source/T3D/components/physics/rigidBodyComponent.cpp +++ b/Engine/source/T3D/components/physics/rigidBodyComponent.cpp @@ -288,7 +288,7 @@ void RigidBodyComponent::processTick() return; // SINGLE PLAYER HACK!!!! - if (PHYSICSMGR->isSinglePlayer() && isClientObject() && getServerObject()) + /*if (PHYSICSMGR->isSinglePlayer() && isClientObject() && getServerObject()) { RigidBodyComponent *servObj = (RigidBodyComponent*)getServerObject(); mOwner->setTransform(servObj->mState.getTransform()); @@ -296,7 +296,7 @@ void RigidBodyComponent::processTick() mRenderState[1] = servObj->mRenderState[1]; return; - } + }*/ // Store the last render state. mRenderState[0] = mRenderState[1]; diff --git a/Engine/source/T3D/components/render/meshComponent.cpp b/Engine/source/T3D/components/render/meshComponent.cpp index c9eeee3c3..10186c873 100644 --- a/Engine/source/T3D/components/render/meshComponent.cpp +++ b/Engine/source/T3D/components/render/meshComponent.cpp @@ -45,52 +45,49 @@ #include "core/strings/findMatch.h" #include "T3D/components/render/meshComponent_ScriptBinding.h" +ImplementEnumType(BatchingMode, + "Type of mesh data available in a shape.\n" + "@ingroup gameObjects") +{ + MeshComponent::Individual, "Individual", "This mesh is rendered indivudally, wthout batching or instancing." +}, + { MeshComponent::StaticBatch, "Static Batching", "Statically batches this mesh together with others to reduce drawcalls." }, + //{ MeshComponent::DynamicBatch, "Dynamic Batching", "Dynamical batches this mesh together with others to reduce drawcalls each frame." }, + // { MeshComponent::Instanced, "Instanced", "This mesh is rendered as an instance, reducing draw overhead with others that share the same mesh and material." }, + EndImplementEnumType; + ////////////////////////////////////////////////////////////////////////// // Constructor/Destructor ////////////////////////////////////////////////////////////////////////// MeshComponent::MeshComponent() : Component() { - mShapeName = StringTable->insert(""); - mShapeAsset = StringTable->insert(""); - mShapeInstance = NULL; - - mChangingMaterials.clear(); - - mMaterials.clear(); - mFriendlyName = "Mesh Component"; mComponentType = "Render"; mDescription = getDescriptionText("Causes the object to render a non-animating 3d shape using the file provided."); mNetworked = true; - mNetFlags.set(Ghostable | ScopeAlways); + + mShapeName = StringTable->EmptyString(); + mShapeAsset = StringTable->EmptyString(); + + mMeshAsset = StringTable->EmptyString(); + mMeshAssetId = StringTable->EmptyString(); + + mInterfaceData = new MeshRenderSystemInterface(); + + mRenderMode = Individual; } -MeshComponent::~MeshComponent(){} +MeshComponent::~MeshComponent() +{ + if (mInterfaceData) + SAFE_DELETE(mInterfaceData); +} IMPLEMENT_CO_NETOBJECT_V1(MeshComponent); //========================================================================================== -void MeshComponent::boneObject::addObject(SimObject* object) -{ - SceneObject* sc = dynamic_cast(object); - - if(sc && mOwner) - { - if(TSShape* shape = mOwner->getShape()) - { - S32 nodeID = shape->findNode(mBoneName); - - //we may have a offset on the shape's center - //so make sure we accomodate for that when setting up the mount offsets - MatrixF mat = mOwner->getNodeTransform(nodeID); - - mOwner->getOwner()->mountObject(sc, nodeID, mat); - } - } -} - bool MeshComponent::onAdd() { if(! Parent::onAdd()) @@ -106,6 +103,12 @@ void MeshComponent::onComponentAdd() { Parent::onComponentAdd(); + if (isClientObject()) + mInterfaceData->mIsClient = true; + + // if (mInterfaceData != nullptr) + // mInterfaceData->mIsClient = isClientObject(); + //get the default shape, if any updateShape(); } @@ -113,10 +116,6 @@ void MeshComponent::onComponentAdd() void MeshComponent::onRemove() { Parent::onRemove(); - - mMeshAsset.clear(); - - SAFE_DELETE(mShapeInstance); } void MeshComponent::onComponentRemove() @@ -135,9 +134,14 @@ void MeshComponent::initPersistFields() { Parent::initPersistFields(); + addGroup("Rendering"); + addField("BatchingMode", TypeBatchingMode, Offset(mRenderMode, MeshComponent), + "The mode of batching this shape should be rendered with."); + endGroup("Rendering"); + //create a hook to our internal variables addGroup("Model"); - addProtectedField("MeshAsset", TypeAssetId, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn, + addProtectedField("MeshAsset", TypeShapeAssetPtr, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn, "The asset Id used for the mesh.", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors); endGroup("Model"); } @@ -165,6 +169,9 @@ bool MeshComponent::_setShape( void *object, const char *index, const char *data bool MeshComponent::setMeshAsset(const char* assetName) { // Fetch the asset Id. + if (mInterfaceData == nullptr) + return false; + mMeshAssetId = StringTable->insert(assetName); mMeshAsset = mMeshAssetId; @@ -183,9 +190,129 @@ bool MeshComponent::setMeshAsset(const char* assetName) return true; } +void MeshComponent::updateShape() +{ + if (mInterfaceData == nullptr) + return; + + //if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0')) + if ((mShapeName && mShapeName[0] != '\0') || (mMeshAssetId && mMeshAssetId[0] != '\0')) + + { + if (mMeshAsset == NULL) + return; + + mShape = mMeshAsset->getShape(); + + if (!mMeshAsset->getShape()) + return; + + setupShape(); + + //Do this on both the server and client + S32 materialCount = mMeshAsset->getShape()->materialList->getMaterialNameList().size(); + + if (isServerObject()) + { + //we need to update the editor + for (U32 i = 0; i < mFields.size(); i++) + { + //find any with the materialslot title and clear them out + if (FindMatch::isMatch("MaterialSlot*", mFields[i].mFieldName, false)) + { + setDataField(mFields[i].mFieldName, NULL, ""); + mFields.erase(i); + continue; + } + } + + //next, get a listing of our materials in the shape, and build our field list for them + char matFieldName[128]; + + if (materialCount > 0) + mComponentGroup = StringTable->insert("Materials"); + + for (U32 i = 0; i < materialCount; i++) + { + String materialname = mMeshAsset->getShape()->materialList->getMaterialName(i); + if (materialname == String("ShapeBounds")) + continue; + + dSprintf(matFieldName, 128, "MaterialSlot%d", i); + + addComponentField(matFieldName, "A material used in the shape file", "Material", materialname, ""); + } + + if (materialCount > 0) + mComponentGroup = ""; + } + + if (mOwner != NULL) + { + Point3F min, max, pos; + pos = mOwner->getPosition(); + + mOwner->getWorldToObj().mulP(pos); + + min = mMeshAsset->getShape()->bounds.minExtents; + max = mMeshAsset->getShape()->bounds.maxExtents; + + if (mInterfaceData) + { + mInterfaceData->mBounds.set(min, max); + mInterfaceData->mScale = mOwner->getScale(); + mInterfaceData->mTransform = mOwner->getRenderTransform(); + } + + mOwner->setObjectBox(Box3F(min, max)); + + mOwner->resetWorldBox(); + + if (mOwner->getSceneManager() != NULL) + mOwner->getSceneManager()->notifyObjectDirty(mOwner); + } + + if (isClientObject() && mInterfaceData) + { + if (mRenderMode == StaticBatch) + { + mInterfaceData->mStatic = true; + + OptimizedPolyList geom; + MatrixF transform = mInterfaceData->mTransform; + mInterfaceData->mGeometry.setTransform(&transform, mInterfaceData->mScale); + mInterfaceData->mGeometry.setObject(mOwner); + + mInterfaceData->mShapeInstance->buildPolyList(&mInterfaceData->mGeometry, 0); + } + else + { + mInterfaceData->mStatic = false; + } + + MeshRenderSystem::rebuildBuffers(); + } + + //finally, notify that our shape was changed + onShapeInstanceChanged.trigger(this); + } +} + +void MeshComponent::setupShape() +{ + mInterfaceData->mShapeInstance = new TSShapeInstance(mMeshAsset->getShape(), true); +} + void MeshComponent::_onResourceChanged( const Torque::Path &path ) { - if ( path != Torque::Path( mShapeName ) ) + if (mInterfaceData == nullptr) + return; + + String filePath; + if (mMeshAsset) + filePath = Torque::Path(mMeshAsset->getShapeFilename()); + + if (!mMeshAsset || path != Torque::Path(mMeshAsset->getShapeFilename()) ) return; updateShape(); @@ -216,6 +343,8 @@ U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) if (stream->writeFlag(mask & ShapeMask)) { stream->writeString(mShapeName); + + stream->writeInt(mRenderMode, 8); } if (stream->writeFlag( mask & MaterialMask )) @@ -226,7 +355,7 @@ U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) { stream->writeInt(mChangingMaterials[i].slot, 16); - NetStringHandle matNameStr = mChangingMaterials[i].matName.c_str(); + NetStringHandle matNameStr = mChangingMaterials[i].assetId.c_str(); con->packNetStringHandleU(stream, matNameStr); } @@ -243,6 +372,8 @@ void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream) if(stream->readFlag()) { mShapeName = stream->readSTString(); + + mRenderMode = (RenderMode)stream->readInt(8); setMeshAsset(mShapeName); updateShape(); } @@ -256,7 +387,10 @@ void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream) { matMap newMatMap; newMatMap.slot = stream->readInt(16); - newMatMap.matName = String(con->unpackNetStringHandleU(stream).getString()); + newMatMap.assetId = String(con->unpackNetStringHandleU(stream).getString()); + + //do the lookup, now + newMatMap.matAsset = AssetDatabase.acquireAsset(newMatMap.assetId); mChangingMaterials.push_back(newMatMap); } @@ -267,7 +401,7 @@ void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream) void MeshComponent::prepRenderImage( SceneRenderState *state ) { - if (!mEnabled || !mOwner || !mShapeInstance) + /*if (!mEnabled || !mOwner || !mShapeInstance) return; Point3F cameraOffset; @@ -300,114 +434,41 @@ void MeshComponent::prepRenderImage( SceneRenderState *state ) rdata.setLightQuery(&query); MatrixF mat = mOwner->getRenderTransform(); - Point3F renderPos = mat.getPosition(); - EulerF renderRot = mat.toEuler(); + + if (mOwner->isMounted()) + { + MatrixF wrldPos = mOwner->getWorldTransform(); + Point3F wrldPosPos = wrldPos.getPosition(); + + Point3F mntPs = mat.getPosition(); + EulerF mntRt = RotationF(mat).asEulerF(); + + bool tr = true; + } + mat.scale(objScale); GFX->setWorldMatrix(mat); - mShapeInstance->render(rdata); -} - -void MeshComponent::updateShape() -{ - bool isServer = isServerObject(); - - if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0')) - { - if (mMeshAsset == NULL) - return; - - mShape = mMeshAsset->getShape(); - - if (!mShape) - return; - - setupShape(); - - //Do this on both the server and client - S32 materialCount = mShape->materialList->getMaterialNameList().size(); - - if(isServerObject()) - { - //we need to update the editor - for (U32 i = 0; i < mFields.size(); i++) - { - //find any with the materialslot title and clear them out - if (FindMatch::isMatch("MaterialSlot*", mFields[i].mFieldName, false)) - { - setDataField(mFields[i].mFieldName, NULL, ""); - mFields.erase(i); - continue; - } - } - - //next, get a listing of our materials in the shape, and build our field list for them - char matFieldName[128]; - - if(materialCount > 0) - mComponentGroup = StringTable->insert("Materials"); - - for(U32 i=0; i < materialCount; i++) - { - String materialname = mShape->materialList->getMaterialName(i); - if(materialname == String("ShapeBounds")) - continue; - - dSprintf(matFieldName, 128, "MaterialSlot%d", i); - - addComponentField(matFieldName, "A material used in the shape file", "TypeAssetId", materialname, ""); - } - - if(materialCount > 0) - mComponentGroup = ""; - } - - if(mOwner != NULL) - { - Point3F min, max, pos; - pos = mOwner->getPosition(); - - mOwner->getWorldToObj().mulP(pos); - - min = mShape->bounds.minExtents; - max = mShape->bounds.maxExtents; - - mShapeBounds.set(min, max); - - mOwner->setObjectBox(Box3F(min, max)); - - if( mOwner->getSceneManager() != NULL ) - mOwner->getSceneManager()->notifyObjectDirty( mOwner ); - } - - //finally, notify that our shape was changed - onShapeInstanceChanged.trigger(this); - } -} - -void MeshComponent::setupShape() -{ - mShapeInstance = new TSShapeInstance(mShape, true); + mShapeInstance->render(rdata);*/ } void MeshComponent::updateMaterials() { - if (mChangingMaterials.empty() || !mShape) + if (mChangingMaterials.empty() || !mMeshAsset->getShape()) return; - TSMaterialList* pMatList = mShapeInstance->getMaterialList(); + TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList(); pMatList->setTextureLookupPath(getShapeResource().getPath().getPath()); const Vector &materialNames = pMatList->getMaterialNameList(); for ( S32 i = 0; i < materialNames.size(); i++ ) { - const String &pName = materialNames[i]; - for(U32 m=0; m < mChangingMaterials.size(); m++) { if(mChangingMaterials[m].slot == i) { - pMatList->renameMaterial( i, mChangingMaterials[m].matName ); + //Fetch the actual material asset + pMatList->renameMaterial( i, mChangingMaterials[m].matAsset->getMaterialDefinitionName()); } } @@ -415,22 +476,31 @@ void MeshComponent::updateMaterials() } // Initialize the material instances - mShapeInstance->initMaterialList(); + mInterfaceData->mShapeInstance->initMaterialList(); } MatrixF MeshComponent::getNodeTransform(S32 nodeIdx) { - if (mShape) + if (mInterfaceData != nullptr && mMeshAsset->getShape()) { S32 nodeCount = getShape()->nodes.size(); if(nodeIdx >= 0 && nodeIdx < nodeCount) { //animate(); - MatrixF mountTransform = mShapeInstance->mNodeTransforms[nodeIdx]; - mountTransform.mul(mOwner->getRenderTransform()); + MatrixF nodeTransform = mInterfaceData->mShapeInstance->mNodeTransforms[nodeIdx]; + const Point3F& scale = mOwner->getScale(); - return mountTransform; + // The position of the node needs to be scaled. + Point3F position = nodeTransform.getPosition(); + position.convolve(scale); + nodeTransform.setPosition(position); + + MatrixF finalTransform = MatrixF::Identity; + + finalTransform.mul(mOwner->getRenderTransform(), nodeTransform); + + return finalTransform; } } @@ -439,7 +509,7 @@ MatrixF MeshComponent::getNodeTransform(S32 nodeIdx) S32 MeshComponent::getNodeByName(String nodeName) { - if (mShape) + if (mMeshAsset->getShape()) { S32 nodeIdx = getShape()->findNode(nodeName); @@ -485,12 +555,18 @@ void MeshComponent::onDynamicModified(const char* slotName, const char* newValue if(slot == -1) return; + //Safe to assume the inbound value for the material will be a MaterialAsset, so lets do a lookup on the name + MaterialAsset* matAsset = AssetDatabase.acquireAsset(newValue); + if (!matAsset) + return; + bool found = false; for(U32 i=0; i < mChangingMaterials.size(); i++) { if(mChangingMaterials[i].slot == slot) { - mChangingMaterials[i].matName = String(newValue); + mChangingMaterials[i].matAsset = matAsset; + mChangingMaterials[i].assetId = newValue; found = true; } } @@ -499,7 +575,8 @@ void MeshComponent::onDynamicModified(const char* slotName, const char* newValue { matMap newMatMap; newMatMap.slot = slot; - newMatMap.matName = String(newValue); + newMatMap.matAsset = matAsset; + newMatMap.assetId = newValue; mChangingMaterials.push_back(newMatMap); } @@ -510,14 +587,31 @@ void MeshComponent::onDynamicModified(const char* slotName, const char* newValue Parent::onDynamicModified(slotName, newValue); } -void MeshComponent::changeMaterial(U32 slot, const char* newMat) +void MeshComponent::changeMaterial(U32 slot, MaterialAsset* newMat) { char fieldName[512]; //update our respective field dSprintf(fieldName, 512, "materialSlot%d", slot); - setDataField(fieldName, NULL, newMat); + setDataField(fieldName, NULL, newMat->getAssetId()); +} + +bool MeshComponent::setMatInstField(U32 slot, const char* field, const char* value) +{ + TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList(); + pMatList->setTextureLookupPath(getShapeResource().getPath().getPath()); + + MaterialParameters* params = pMatList->getMaterialInst(slot)->getMaterialParameters(); + + if (pMatList->getMaterialInst(slot)->getFeatures().hasFeature(MFT_DiffuseColor)) + { + MaterialParameterHandle* handle = pMatList->getMaterialInst(slot)->getMaterialParameterHandle("DiffuseColor"); + + params->set(handle, LinearColorF(0, 0, 0)); + } + + return true; } void MeshComponent::onInspect() @@ -526,4 +620,13 @@ void MeshComponent::onInspect() void MeshComponent::onEndInspect() { +} + +void MeshComponent::ownerTransformSet(MatrixF *mat) +{ + if (mInterfaceData != nullptr) + { + MatrixF newTransform = *mat; + mInterfaceData->mTransform = newTransform; + } } \ No newline at end of file diff --git a/Engine/source/T3D/components/render/meshComponent.h b/Engine/source/T3D/components/render/meshComponent.h index 6adc2633e..587038d63 100644 --- a/Engine/source/T3D/components/render/meshComponent.h +++ b/Engine/source/T3D/components/render/meshComponent.h @@ -60,6 +60,8 @@ #include "gfx/gfxVertexFormat.h" #endif +#include "T3D/systems/render/meshRenderSystem.h" + class TSShapeInstance; class SceneRenderState; ////////////////////////////////////////////////////////////////////////// @@ -84,37 +86,38 @@ protected: StringTableEntry mShapeName; StringTableEntry mShapeAsset; TSShape* mShape; - Box3F mShapeBounds; + //Box3F mShapeBounds; Point3F mCenterOffset; + MeshRenderSystemInterface* mInterfaceData; + struct matMap { - String matName; + MaterialAsset* matAsset; + String assetId; U32 slot; }; Vector mChangingMaterials; Vector mMaterials; - class boneObject : public SimGroup +public: + enum RenderMode { - MeshComponent *mOwner; - public: - boneObject(MeshComponent *owner){ mOwner = owner; } - - StringTableEntry mBoneName; - S32 mItemID; - - virtual void addObject(SimObject *obj); + Individual = 0, + DynamicBatch, + StaticBatch, + Instanced }; - Vector mNodesList; +protected: + RenderMode mRenderMode; public: StringTableEntry mMeshAssetId; AssetPtr mMeshAsset; - TSShapeInstance* mShapeInstance; + //TSShapeInstance* mShapeInstance; public: MeshComponent(); @@ -132,7 +135,7 @@ public: virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); virtual void unpackUpdate(NetConnection *con, BitStream *stream); - Box3F getShapeBounds() { return mShapeBounds; } + Box3F getShapeBounds() { return mInterfaceData->mBounds; } virtual MatrixF getNodeTransform(S32 nodeIdx); S32 getNodeByName(String nodeName); @@ -144,6 +147,8 @@ public: virtual void onComponentRemove(); virtual void onComponentAdd(); + virtual void ownerTransformSet(MatrixF *mat); + static bool _setMesh(void *object, const char *index, const char *data); static bool _setShape(void *object, const char *index, const char *data); const char* _getShape(void *object, const char *data); @@ -151,7 +156,7 @@ public: bool setMeshAsset(const char* assetName); virtual TSShape* getShape() { if (mMeshAsset) return mMeshAsset->getShape(); else return NULL; } - virtual TSShapeInstance* getShapeInstance() { return mShapeInstance; } + virtual TSShapeInstance* getShapeInstance() { return mInterfaceData->mShapeInstance; } Resource getShapeResource() { return mMeshAsset->getShapeResource(); } @@ -163,7 +168,8 @@ public: virtual void onDynamicModified(const char* slotName, const char* newValue); - void changeMaterial(U32 slot, const char* newMat); + void changeMaterial(U32 slot, MaterialAsset* newMat); + bool setMatInstField(U32 slot, const char* field, const char* value); virtual void onInspect(); virtual void onEndInspect(); @@ -180,4 +186,7 @@ public: } }; +typedef MeshComponent::RenderMode BatchingMode; +DefineEnumType(BatchingMode); + #endif diff --git a/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h b/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h index 5a19b8f08..396166def 100644 --- a/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h @@ -126,6 +126,28 @@ DefineEngineMethod(MeshComponent, getNodePosition, Point3F, return Point3F(0, 0, 0); } +DefineEngineMethod(MeshComponent, getNodeRotation, EulerF, + (S32 node), (-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)") +{ + if (node != -1) + { + //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->mountObjectToNode( objB, node, /*MatrixF::Identity*/txfm.getMatrix() ); + RotationF mat = object->getNodeTransform(node); + + return mat.asEulerF(RotationF::Degrees); + } + + return EulerF(0, 0, 0); +} + DefineEngineMethod(MeshComponent, getNodeByName, S32, (String nodeName), , "@brief Mount objB to this object at the desired slot with optional transform.\n\n" @@ -148,8 +170,14 @@ DefineEngineMethod(MeshComponent, getNodeByName, S32, return -1; } -DefineEngineMethod(MeshComponent, changeMaterial, void, (U32 slot, const char* newMat), (0, ""), +DefineEngineMethod(MeshComponent, changeMaterial, void, (U32 slot, MaterialAsset* newMat), (0, nullAsType()), "@brief Change one of the materials on the shape.\n\n") { object->changeMaterial(slot, newMat); +} + +DefineEngineMethod(MeshComponent, setMatInstField, bool, (U32 slot, const char* field, const char* value), (0, "", ""), + "@brief Change one of the materials on the shape.\n\n") +{ + return object->setMatInstField(slot, field, value); } \ No newline at end of file diff --git a/Engine/source/T3D/entity.cpp b/Engine/source/T3D/entity.cpp index d58d086c6..a7af19b33 100644 --- a/Engine/source/T3D/entity.cpp +++ b/Engine/source/T3D/entity.cpp @@ -47,7 +47,9 @@ #include "T3D/gameBase/std/stdMoveList.h" #include "T3D/prefab.h" +#include "T3D/gameBase/gameConnection.h" +#include // #include "gfx/sim/debugDraw.h" // @@ -118,6 +120,8 @@ Entity::Entity() mInitialized = false; + mLifetimeMS = 0; + mGameObjectAssetId = StringTable->insert(""); } @@ -147,6 +151,10 @@ void Entity::initPersistFields() endGroup("Transform"); + addGroup("Misc"); + addField("LifetimeMS", TypeS32, Offset(mLifetimeMS, Entity), "Object world orientation."); + endGroup("Misc"); + addGroup("GameObject"); addProtectedField("gameObjectName", TypeGameObjectAssetPtr, Offset(mGameObjectAsset, Entity), &_setGameObject, &defaultProtectedGetFn, "The asset Id used for the game object this entity is based on."); @@ -231,8 +239,19 @@ bool Entity::onAdd() addToScene(); //Make sure we get positioned - setMaskBits(TransformMask); - setMaskBits(NamespaceMask); + if (isServerObject()) + { + setMaskBits(TransformMask); + setMaskBits(NamespaceMask); + } + else + { + //We can shortcut the initialization here because stuff generally ghosts down in order, and onPostAdd isn't called on ghosts. + onPostAdd(); + } + + if (mLifetimeMS != 0) + mStartTimeMS = Platform::getRealMilliseconds(); return true; } @@ -245,6 +264,8 @@ void Entity::onRemove() onDataSet.removeAll(); + mGameObjectAsset.clear(); + Parent::onRemove(); } @@ -258,6 +279,27 @@ void Entity::onPostAdd() mComponents[i]->onComponentAdd(); } + //Set up the networked components + mNetworkedComponents.clear(); + for (U32 i = 0; i < mComponents.size(); i++) + { + if (mComponents[i]->isNetworked()) + { + NetworkedComponent netComp; + netComp.componentIndex = i; + netComp.updateState = NetworkedComponent::Adding; + netComp.updateMaskBits = -1; + + mNetworkedComponents.push_back(netComp); + } + } + + if (!mNetworkedComponents.empty()) + { + setMaskBits(AddComponentsMask); + setMaskBits(ComponentsUpdateMask); + } + if (isMethod("onAdd")) Con::executef(this, "onAdd"); } @@ -396,6 +438,14 @@ void Entity::processTick(const Move* move) mDelta.rot[1] = mRot.asQuatF(); setTransform(getPosition(), mRot); + + //Lifetime test + if (mLifetimeMS != 0) + { + S32 currentTime = Platform::getRealMilliseconds(); + if (currentTime - mStartTimeMS >= mLifetimeMS) + deleteObject(); + } } } @@ -446,62 +496,107 @@ U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream) mathWrite(*stream, mObjBox); } - //pass our behaviors around - if (mask & ComponentsMask || mask & InitialUpdateMask) + if (stream->writeFlag(mask & AddComponentsMask)) { - 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(); + U32 toAddComponentCount = 0; - //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++) + for (U32 i = 0; i < mNetworkedComponents.size(); 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++) + if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding) { - //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; - } + toAddComponentCount++; } } - else if (componentCount) + + //you reaaaaally shouldn't have >255 networked components on a single entity + stream->writeInt(toAddComponentCount, 8); + + for (U32 i = 0; i < mNetworkedComponents.size(); i++) { - //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; + NetworkedComponent::UpdateState state = mNetworkedComponents[i].updateState; + + if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding) + { + const char* className = mComponents[mNetworkedComponents[i].componentIndex]->getClassName(); + stream->writeString(className, strlen(className)); + + mNetworkedComponents[i].updateState = NetworkedComponent::Updating; + } } - else - stream->writeFlag(false); } - else - stream->writeFlag(false); + + if (stream->writeFlag(mask & RemoveComponentsMask)) + { + /*U32 toRemoveComponentCount = 0; + + for (U32 i = 0; i < mNetworkedComponents.size(); i++) + { + if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding) + { + toRemoveComponentCount++; + } + } + + //you reaaaaally shouldn't have >255 networked components on a single entity + stream->writeInt(toRemoveComponentCount, 8); + + for (U32 i = 0; i < mNetworkedComponents.size(); i++) + { + if (mNetworkedComponents[i].updateState == NetworkedComponent::Removing) + { + stream->writeInt(i, 16); + } + }*/ + + /*for (U32 i = 0; i < mNetworkedComponents.size(); i++) + { + if (mNetworkedComponents[i].updateState == NetworkedComponent::UpdateState::Removing) + { + removeComponent(mComponents[mNetworkedComponents[i].componentIndex], true); + mNetworkedComponents.erase(i); + i--; + + } + }*/ + } + + //Update our components + if (stream->writeFlag(mask & ComponentsUpdateMask)) + { + U32 toUpdateComponentCount = 0; + + for (U32 i = 0; i < mNetworkedComponents.size(); i++) + { + if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating) + { + toUpdateComponentCount++; + } + } + + //you reaaaaally shouldn't have >255 networked components on a single entity + stream->writeInt(toUpdateComponentCount, 8); + + bool forceUpdate = false; + + for (U32 i = 0; i < mNetworkedComponents.size(); i++) + { + if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating) + { + stream->writeInt(i, 8); + + mNetworkedComponents[i].updateMaskBits = mComponents[mNetworkedComponents[i].componentIndex]->packUpdate(con, mNetworkedComponents[i].updateMaskBits, stream); + + if (mNetworkedComponents[i].updateMaskBits != 0) + forceUpdate = true; + else + mNetworkedComponents[i].updateState = NetworkedComponent::None; + } + } + + //If we have leftover, we need to re-iterate our packing + if (forceUpdate) + setMaskBits(ComponentsUpdateMask); + } /*if (stream->writeFlag(mask & NamespaceMask)) { @@ -594,25 +689,52 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream) resetWorldBox(); } + //AddComponentMask if (stream->readFlag()) { - //are we passing any behaviors currently? - if (stream->readFlag()) + U32 addedComponentCount = stream->readInt(8); + + for (U32 i = 0; i < addedComponentCount; i++) { - //if we've just started the update, clear our behaviors - if (stream->readFlag()) - clearComponents(false); + char className[256] = ""; + stream->readString(className); - S32 componentCount = stream->readInt(16); + //Change to components, so iterate our list and create any new components + // Well, looks like we have to create a new object. + const char* componentType = className; - for (U32 i = 0; i < componentCount; i++) + ConsoleObject *object = ConsoleObject::create(componentType); + + // Finally, set currentNewObject to point to the new one. + Component* newComponent = dynamic_cast(object); + + if (newComponent) { - S32 gIndex = stream->readInt(NetConnection::GhostIdBitSize); - addComponent(dynamic_cast(con->resolveGhost(gIndex))); + addComponent(newComponent); } } } + //RemoveComponentMask + if (stream->readFlag()) + { + + } + + //ComponentUpdateMask + if (stream->readFlag()) + { + U32 updatingComponents = stream->readInt(8); + + for (U32 i = 0; i < updatingComponents; i++) + { + U32 updateComponentIndex = stream->readInt(8); + + Component* comp = mComponents[updateComponentIndex]; + comp->unpackUpdate(con, stream); + } + } + /*if (stream->readFlag()) { if (stream->readFlag()) @@ -640,6 +762,26 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream) }*/ } +void Entity::setComponentNetMask(Component* comp, U32 mask) +{ + setMaskBits(Entity::ComponentsUpdateMask); + + for (U32 i = 0; i < mNetworkedComponents.size(); i++) + { + U32 netCompId = mComponents[mNetworkedComponents[i].componentIndex]->getId(); + U32 compId = comp->getId(); + + if (netCompId == compId && + (mNetworkedComponents[i].updateState == NetworkedComponent::None || mNetworkedComponents[i].updateState == NetworkedComponent::Updating)) + { + mNetworkedComponents[i].updateState = NetworkedComponent::Updating; + mNetworkedComponents[i].updateMaskBits |= mask; + + break; + } + } +} + //Manipulation void Entity::setTransform(const MatrixF &mat) { @@ -758,7 +900,11 @@ void Entity::setTransform(Point3F position, RotationF rotation) // Update the transforms. Parent::setTransform(newMat); - onTransformSet.trigger(&newMat); + U32 compCount = mComponents.size(); + for (U32 i = 0; i < compCount; ++i) + { + mComponents[i]->ownerTransformSet(&newMat); + } Point3F newPos = newMat.getPosition(); RotationF newRot = newMat; @@ -800,7 +946,11 @@ void Entity::setRenderTransform(Point3F position, RotationF rotation) Parent::setRenderTransform(newMat); - onTransformSet.trigger(&newMat); + U32 compCount = mComponents.size(); + for (U32 i = 0; i < compCount; ++i) + { + mComponents[i]->ownerTransformSet(&newMat); + } } } @@ -1155,11 +1305,28 @@ bool Entity::addComponent(Component *comp) // Register the component with this owner. comp->setOwner(this); + comp->setIsServerObject(isServerObject()); + //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) + //if (mInitialized) + { comp->onComponentAdd(); + if (comp->isNetworked()) + { + NetworkedComponent netComp; + netComp.componentIndex = mComponents.size() - 1; + netComp.updateState = NetworkedComponent::Adding; + netComp.updateMaskBits = -1; + + mNetworkedComponents.push_back(netComp); + + setMaskBits(AddComponentsMask); + setMaskBits(ComponentsUpdateMask); + } + } + onComponentAdded.trigger(comp); return true; @@ -1269,7 +1436,7 @@ Component *Entity::getComponent(String componentType) 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")) + while (dStrcmp(NS->getName(), "SimObject")) { String namespaceName = NS->getName(); @@ -1497,7 +1664,8 @@ void Entity::notifyComponents(String signalFunction, String argA, String argB, S void Entity::setComponentsDirty() { - if (mToLoadComponents.empty()) + bool tmp = true; + /*if (mToLoadComponents.empty()) mStartComponentUpdate = true; //we need to build a list of behaviors that need to be pushed across the network @@ -1522,7 +1690,7 @@ void Entity::setComponentsDirty() } } - setMaskBits(ComponentsMask); + setMaskBits(ComponentsMask);*/ } void Entity::setComponentDirty(Component *comp, bool forceUpdate) @@ -1654,7 +1822,7 @@ ConsoleMethod(Entity, addComponents, void, 2, 2, "() - Add all fielded behaviors object->addComponents(); }*/ -ConsoleMethod(Entity, addComponent, bool, 3, 3, "(Component* bi) - Add a behavior to the object\n" +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") { @@ -1679,7 +1847,7 @@ ConsoleMethod(Entity, addComponent, bool, 3, 3, "(Component* bi) - Add a behavio return false; } -ConsoleMethod(Entity, removeComponent, bool, 3, 4, "(Component* bi, [bool deleteBehavior = true])\n" +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") @@ -1834,4 +2002,43 @@ DefineConsoleMethod(Entity, notify, void, (String signalFunction, String argA, S return; object->notifyComponents(signalFunction, argA, argB, argC, argD, argE); +} + +DefineConsoleFunction(findEntitiesByTag, const char*, (SimGroup* searchingGroup, String tags), (nullAsType(), ""), +"Finds all entities that have the provided tags.\n" +"@param searchingGroup The SimGroup to search inside. If null, we'll search the entire dictionary(this can be slow!).\n" +"@param tags Word delimited list of tags to search for. If multiple tags are included, the list is eclusively parsed, requiring all tags provided to be found on an entity for a match.\n" +"@return A word list of IDs of entities that match the tag search terms.") +{ + //if (tags.isEmpty()) + return ""; + + /*if (searchingGroup == nullptr) + { + searchingGroup = Sim::getRootGroup(); + } + + StringTableEntry entityStr = StringTable->insert("Entity"); + + std::thread threadBob; + + std::thread::id a = threadBob.get_id(); + std::thread::id b = std::this_thread::get_id().; + + if (a == b) + { + //do + } + + for (SimGroup::iterator itr = searchingGroup->begin(); itr != searchingGroup->end(); itr++) + { + Entity* ent = dynamic_cast((*itr)); + + if (ent != nullptr) + { + ent->mTags. + } + } + + object->notifyComponents(signalFunction, argA, argB, argC, argD, argE);*/ } \ No newline at end of file diff --git a/Engine/source/T3D/entity.h b/Engine/source/T3D/entity.h index 1f160e5a9..db65f2866 100644 --- a/Engine/source/T3D/entity.h +++ b/Engine/source/T3D/entity.h @@ -58,7 +58,27 @@ private: Vector mComponents; - Vector mToLoadComponents; + //Bit of helper data to let us track and manage the adding, removal and updating of networked components + struct NetworkedComponent + { + U32 componentIndex; + + enum UpdateState + { + None, + Adding, + Removing, + Updating + }; + + UpdateState updateState; + + U32 updateMaskBits; + }; + + Vector mNetworkedComponents; + + U32 mComponentNetMask; bool mStartComponentUpdate; @@ -69,10 +89,12 @@ private: bool mInitialized; + String mTags; + Signal< void(Component*) > onComponentAdded; Signal< void(Component*) > onComponentRemoved; - Signal< void(MatrixF*) > onTransformSet; + S32 mLifetimeMS; protected: @@ -105,10 +127,12 @@ public: { TransformMask = Parent::NextFreeMask << 0, BoundsMask = Parent::NextFreeMask << 1, - ComponentsMask = Parent::NextFreeMask << 2, - NoWarpMask = Parent::NextFreeMask << 3, - NamespaceMask = Parent::NextFreeMask << 4, - NextFreeMask = Parent::NextFreeMask << 5 + ComponentsUpdateMask = Parent::NextFreeMask << 2, + AddComponentsMask = Parent::NextFreeMask << 3, + RemoveComponentsMask = Parent::NextFreeMask << 4, + NoWarpMask = Parent::NextFreeMask << 5, + NamespaceMask = Parent::NextFreeMask << 6, + NextFreeMask = Parent::NextFreeMask << 7 }; StateDelta mDelta; @@ -116,6 +140,8 @@ public: Move lastMove; + S32 mStartTimeMS; + // Entity(); ~Entity(); @@ -163,6 +189,9 @@ public: /// @param client Client that is now controlling this object virtual void setControllingClient(GameConnection *client); + // + //Networking + // // NetObject U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream); void unpackUpdate(NetConnection *conn, BitStream *stream); @@ -170,6 +199,8 @@ public: void setComponentsDirty(); void setComponentDirty(Component *comp, bool forceUpdate = false); + void setComponentNetMask(Component* comp, U32 mask); + //Components virtual bool deferAddingComponents() const { return true; } diff --git a/Engine/source/scene/sceneManager.cpp b/Engine/source/scene/sceneManager.cpp index e40caecfc..aeca87092 100644 --- a/Engine/source/scene/sceneManager.cpp +++ b/Engine/source/scene/sceneManager.cpp @@ -38,6 +38,9 @@ #include "T3D/gameBase/gameConnection.h" #include "math/mathUtils.h" +#include "T3D/components/render/renderComponentInterface.h" +#include "T3D/systems/render/meshRenderSystem.h" + // For player object bounds workaround. #include "T3D/player.h" @@ -358,6 +361,8 @@ void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZ if( gEditingMission && state->isDiffusePass() ) objectMask = EDITOR_RENDER_TYPEMASK; + MeshRenderSystem::render(this, state); + // Update the zoning state and traverse zones. if( getZoneManager() ) diff --git a/Engine/source/scene/sceneRenderState.cpp b/Engine/source/scene/sceneRenderState.cpp index fa1966ab8..3dda18513 100644 --- a/Engine/source/scene/sceneRenderState.cpp +++ b/Engine/source/scene/sceneRenderState.cpp @@ -106,17 +106,6 @@ void SceneRenderState::renderObjects( SceneObject** objects, U32 numObjects ) object->prepRenderImage( this ); } - U32 interfaceCount = RenderComponentInterface::all.size(); - for (U32 i = 0; i < RenderComponentInterface::all.size(); i++) - { - Component* comp = dynamic_cast(RenderComponentInterface::all[i]); - - if (comp->isClientObject() && comp->isActive()) - { - RenderComponentInterface::all[i]->prepRenderImage(this); - } - } - PROFILE_END(); // Render what the objects have batched. diff --git a/Templates/BaseGame/game/core/CoreComponents.cs b/Templates/BaseGame/game/core/CoreComponents.cs new file mode 100644 index 000000000..5bdca8cd3 --- /dev/null +++ b/Templates/BaseGame/game/core/CoreComponents.cs @@ -0,0 +1,10 @@ + +function CoreComponentsModule::onCreate(%this) +{ + %classList = enumerateConsoleClasses( "Component" ); + + foreach$( %componentClass in %classList ) + { + echo("Native Component of type: " @ %componentClass); + } +} \ No newline at end of file