diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index fed316c00790aab5a2a61029057c26bc4a5ba285..7f3e5ddc166ec66e758f117e73184bdad7a61ab0 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -195,6 +195,7 @@ <ClCompile Include="..\..\..\source\game\EditorObject.cpp" /> <ClCompile Include="..\..\..\source\game\EditorOutputsTab.cpp" /> <ClCompile Include="..\..\..\source\game\EntityFactory.cpp" /> + <ClCompile Include="..\..\..\source\game\EntityList.cpp" /> <ClCompile Include="..\..\..\source\game\EntityManager.cpp" /> <ClCompile Include="..\..\..\source\game\EnvSkybox.cpp" /> <ClCompile Include="..\..\..\source\game\FuncRotating.cpp" /> @@ -267,6 +268,8 @@ <ClInclude Include="..\..\..\source\game\EditorExtension.h" /> <ClInclude Include="..\..\..\source\game\EditorObject.h" /> <ClInclude Include="..\..\..\source\game\EditorOutputsTab.h" /> + <ClInclude Include="..\..\..\source\game\EntityList.h" /> + <ClInclude Include="..\..\..\source\game\EntityPointer.h" /> <ClInclude Include="..\..\..\source\game\EnvSkybox.h" /> <ClInclude Include="..\..\..\source\game\FuncRotating.h" /> <ClInclude Include="..\..\..\source\game\GameStateManager.h" /> diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters index b56011f928a25960c1a89f27dddcc5c7969112e0..7371a9da2d308080086def4dac1f06d82cdde174 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj.filters +++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters @@ -312,6 +312,9 @@ <ClCompile Include="..\..\..\source\common\guid.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\game\EntityList.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\game\sxgame.h"> @@ -539,6 +542,12 @@ <ClInclude Include="..\..\..\source\game\SoundEmitter.h"> <Filter>Header Files\ents\sound</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\EntityPointer.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\EntityList.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\game\sxgame.rc"> diff --git a/source/anim/DynamicModel.cpp b/source/anim/DynamicModel.cpp index f83a8ead9a6580097941f65cc73b3bdfebe4aa13..06f265584ec72f15819474e41dac2a6705795278 100644 --- a/source/anim/DynamicModel.cpp +++ b/source/anim/DynamicModel.cpp @@ -94,9 +94,12 @@ void XMETHODCALLTYPE CDynamicModel::setPosition(const float3 &vPos) m_vPosition = vPos; m_isWorldDirty = true; - m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED); + if(m_isEnabled) + { + m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED); - m_pSceneObject->update(getLocalBound() + getPosition()); + m_pSceneObject->update(getLocalBound() + getPosition()); + } } SMQuaternion XMETHODCALLTYPE CDynamicModel::getOrientation() const @@ -113,9 +116,12 @@ void XMETHODCALLTYPE CDynamicModel::setOrientation(const SMQuaternion &qRot) m_isLocalAABBvalid = false; m_isWorldDirty = true; - m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED); + if(m_isEnabled) + { + m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED); - m_pSceneObject->update(getLocalBound() + getPosition()); + m_pSceneObject->update(getLocalBound() + getPosition()); + } } float XMETHODCALLTYPE CDynamicModel::getScale() const @@ -132,9 +138,12 @@ void XMETHODCALLTYPE CDynamicModel::setScale(float fScale) m_isLocalAABBvalid = false; m_isWorldDirty = true; - m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED); + if(m_isEnabled) + { + m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED); - m_pSceneObject->update(getLocalBound() + getPosition()); + m_pSceneObject->update(getLocalBound() + getPosition()); + } } UINT XMETHODCALLTYPE CDynamicModel::getSkin() const diff --git a/source/anim/DynamicModelProvider.cpp b/source/anim/DynamicModelProvider.cpp index cc06aaed5d550f1b81c80d82e8cdb5accb95aacd..bc5df76e702cb858e02aa3be5cd58e81d4e3bd90 100644 --- a/source/anim/DynamicModelProvider.cpp +++ b/source/anim/DynamicModelProvider.cpp @@ -300,7 +300,7 @@ void CDynamicModelProvider::onSharedModelReady(CDynamicModelShared *pShared) } void CDynamicModelProvider::onSharedModelRelease(CDynamicModelShared *pShared) { - m_mModels[pShared->getResource()] = NULL; + m_mModels.erase(pShared->getResource()); } void CDynamicModelProvider::onSharedModelFeaturesChanged(CDynamicModelShared *pShared) { diff --git a/source/common b/source/common index ace72cd79ddea6874c56131ca7dde7b896f38a03..e3014e94d2fe3e5211344f785df552ad38a62b89 160000 --- a/source/common +++ b/source/common @@ -1 +1 @@ -Subproject commit ace72cd79ddea6874c56131ca7dde7b896f38a03 +Subproject commit e3014e94d2fe3e5211344f785df552ad38a62b89 diff --git a/source/core/ResourceManager.cpp b/source/core/ResourceManager.cpp index 09e48e77e9a392c2e404254bd60b2cceafa04d13..0ff41aa560d0e8711c47e118decad5117156503d 100644 --- a/source/core/ResourceManager.cpp +++ b/source/core/ResourceManager.cpp @@ -92,8 +92,8 @@ CResourceManager::CResourceManager(IXCore *pCore): bool XMETHODCALLTYPE CResourceManager::getModel(const char *szName, IXResourceModel **ppOut, bool bForceReload) { - const AssotiativeArray<String, IXResourceModel*>::Node *pNode1; - if(!bForceReload && m_mpModels.KeyExists(szName, &pNode1) && (*pNode1->Val)) + const Map<String, IXResourceModel*>::Node *pNode1; + if(!bForceReload && m_mpModels.KeyExists(szName, &pNode1)) { (*pNode1->Val)->AddRef(); *ppOut = *pNode1->Val; @@ -112,7 +112,7 @@ bool XMETHODCALLTYPE CResourceManager::getModel(const char *szName, IXResourceMo strlwr(szLowcaseExt); CResourceModel *pResource = NULL; - const AssotiativeArray<AAString, Array<IXModelLoader*>>::Node *pNode; + const Map<AAString, Array<IXModelLoader*>>::Node *pNode; if(m_mapModelLoaders.KeyExists(AAString(szLowcaseExt), &pNode)) { auto &aLoaders = *pNode->Val; @@ -284,7 +284,7 @@ bool XMETHODCALLTYPE CResourceManager::getModelInfo(const char *szName, XModelIn char *szLowcaseExt = strdupa(szExt); strlwr(szLowcaseExt); - const AssotiativeArray<AAString, Array<IXModelLoader*>>::Node *pNode; + const Map<AAString, Array<IXModelLoader*>>::Node *pNode; if(m_mapModelLoaders.KeyExists(AAString(szLowcaseExt), &pNode)) { auto &aLoaders = *pNode->Val; @@ -330,7 +330,7 @@ void CResourceManager::onResourceModelRelease(CResourceModel *pResource) { if(pResource->getFileName()) { - m_mpModels[pResource->getFileName()] = NULL; + m_mpModels.erase(pResource->getFileName()); } } @@ -382,16 +382,13 @@ const XFormatName* XMETHODCALLTYPE CResourceManager::getSoundSupportedFormat(UIN bool XMETHODCALLTYPE CResourceManager::getTexture(const char *szName, IXResourceTexture **ppOut, bool bForceReload) { - const AssotiativeArray<String, IXResourceTexture*>::Node *pNode1; + const Map<String, IXResourceTexture*>::Node *pNode1; if(!bForceReload && m_mpTextures.KeyExists(szName, &pNode1)) { IXResourceTexture *pOut = (*pNode1->Val); - if(pOut) - { - *ppOut = pOut; - pOut->AddRef(); - return(true); - } + *ppOut = pOut; + pOut->AddRef(); + return(true); } char *szFileName = strdupa(szName); @@ -414,7 +411,7 @@ bool XMETHODCALLTYPE CResourceManager::getTexture(const char *szName, IXResource char *szLowcaseExt = strdupa(szExt); strlwr(szLowcaseExt); - const AssotiativeArray<AAString, Array<IXTextureLoader*>>::Node *pNode; + const Map<AAString, Array<IXTextureLoader*>>::Node *pNode; if(m_mapTextureLoaders.KeyExists(AAString(szLowcaseExt), &pNode)) { auto &aLoaders = *pNode->Val; @@ -541,7 +538,7 @@ bool XMETHODCALLTYPE CResourceManager::getTextureInfo(const char *szName, XTextu char *szLowcaseExt = strdupa(szExt); strlwr(szLowcaseExt); - const AssotiativeArray<AAString, Array<IXTextureLoader*>>::Node *pNode; + const Map<AAString, Array<IXTextureLoader*>>::Node *pNode; if(m_mapTextureLoaders.KeyExists(AAString(szLowcaseExt), &pNode)) { auto &aLoaders = *pNode->Val; diff --git a/source/core/ResourceManager.h b/source/core/ResourceManager.h index b8c4c953c78317f1bebf85a991c95fc87c9e45ff..89642c36c7bf3fea66a13f2759b468deece776ec 100644 --- a/source/core/ResourceManager.h +++ b/source/core/ResourceManager.h @@ -50,7 +50,7 @@ public: const char *szName = pTexture->getFileName(); if(szName) { - m_mpTextures[szName] = NULL; + m_mpTextures.erase(szName); } } @@ -60,14 +60,14 @@ public: protected: IXCore *m_pCore; - AssotiativeArray<AAString, Array<IXModelLoader*>> m_mapModelLoaders; - AssotiativeArray<String, IXResourceModel*> m_mpModels; + Map<AAString, Array<IXModelLoader*>> m_mapModelLoaders; + Map<String, IXResourceModel*> m_mpModels; Array<XFormatName> m_aModelExts; - AssotiativeArray<AAString, Array<IXTextureLoader*>> m_mapTextureLoaders; - AssotiativeArray<String, IXResourceTexture*> m_mpTextures; + Map<AAString, Array<IXTextureLoader*>> m_mapTextureLoaders; + Map<String, IXResourceTexture*> m_mpTextures; Array<XFormatName> m_aTextureExts; diff --git a/source/core/TaskManager.cpp b/source/core/TaskManager.cpp index 0581fac28f72fd17da7a92dd1620f1eb46d3df8e..b63dd5ee1574aee7a2ade0a761eb690ffbc3c441 100644 --- a/source/core/TaskManager.cpp +++ b/source/core/TaskManager.cpp @@ -115,7 +115,7 @@ void CTaskManager::forceSinglethreaded() void CTaskManager::addTask(TaskPtr task, std::chrono::steady_clock::time_point tpWhen) { { - ScopedSpinLock lock(m_slShedulerArray); + ScopedLock lock(m_mutexSchedulerThread); m_aScheduled.insert({task, tpWhen}, [](const ScheduledTask &a, const ScheduledTask &b){ return(a.tpRunAt > b.tpRunAt); }); @@ -360,26 +360,25 @@ void CTaskManager::schedulerMain() while(m_isRunning) { tpNow = tpWaitUntil = std::chrono::steady_clock::now(); + + std::unique_lock<std::mutex> lock(m_mutexSchedulerThread); + for(UINT i = 0, l = m_aScheduled.size(); i < l; ++i) { - ScopedSpinLock lock(m_slShedulerArray); - for(UINT i = 0, l = m_aScheduled.size(); i < l; ++i) - { - pScheduledTask = &m_aScheduled[i]; + pScheduledTask = &m_aScheduled[i]; - if(pScheduledTask->tpRunAt <= tpNow) - { - addTask(pScheduledTask->pTask); - m_aScheduled.erase(i); - --i; --l; - } - else - { - tpWaitUntil = pScheduledTask->tpRunAt; - break; - } + if(pScheduledTask->tpRunAt <= tpNow) + { + addTask(pScheduledTask->pTask); + m_aScheduled.erase(i); + --i; --l; + } + else + { + tpWaitUntil = pScheduledTask->tpRunAt; + break; } } - std::unique_lock<std::mutex> lock(m_mutexSchedulerThread); + if(tpWaitUntil != tpNow) { m_ConditionSchedulerThread.wait_until(lock, tpWaitUntil); diff --git a/source/core/TaskManager.h b/source/core/TaskManager.h index 1f4e98d378290581f2831c4ed26942ba0cb64943..0a312fdf23bdd61caac5b877a7319b8f95233217 100644 --- a/source/core/TaskManager.h +++ b/source/core/TaskManager.h @@ -93,7 +93,6 @@ private: mutable mutex m_mutexFor; mutable mutex m_mutexIOThread; mutable mutex m_mutexSchedulerThread; - mutable SpinLock m_slShedulerArray; Condition m_Condition; Condition m_ConditionIOThread; Condition m_ConditionSchedulerThread; diff --git a/source/game/BaseAmmo.cpp b/source/game/BaseAmmo.cpp index 929b4d3996bd33f9386f50be5e062fcc5eab22ea..9624bfd4d80849e2105dd813a309265d7dcb4a69 100644 --- a/source/game/BaseAmmo.cpp +++ b/source/game/BaseAmmo.cpp @@ -61,17 +61,6 @@ protected: btCollisionObject* m_me; }; -CBaseAmmo::CBaseAmmo(CEntityManager * pMgr): - BaseClass(pMgr), - m_fStartSpeed(0.0f), - m_fBulletMass(0.0f), - m_fArmorPiercing(0.0f), - m_fNextBarrierDepth(0.0f) -{ - //m_bPickable = false; - //m_bInvStackable = false; -} - void CBaseAmmo::fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker) { extern CTracer *g_pTracer; diff --git a/source/game/BaseAmmo.h b/source/game/BaseAmmo.h index 05f1e4abe2840d140c801bb4df957f435f37c368..df926eb7c4c1e243740d908a9cb11a8722b7cb1c 100644 --- a/source/game/BaseAmmo.h +++ b/source/game/BaseAmmo.h @@ -26,7 +26,7 @@ class CBaseAmmo: public CBaseSupply DECLARE_CLASS(CBaseAmmo, CBaseSupply); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); //! Стреляет пулю void fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker=NULL); @@ -41,15 +41,15 @@ public: protected: //! Начальная скорость - float m_fStartSpeed; + float m_fStartSpeed = 0.0f; //! Масса пули - float m_fBulletMass; + float m_fBulletMass = 0.0f; //! Бронебойность - float m_fArmorPiercing; + float m_fArmorPiercing = 0.0f; //! Экспансивная? - bool m_isExpansive; + bool m_isExpansive = false; //! Разрывная? - bool m_isBursting; + bool m_isBursting = false; struct HitPoint { @@ -72,7 +72,7 @@ protected: bool canHole(float fDurability, float fCurrentSpeed, float *pfNewSpeed); //! Хранит толщину препятствия во время расчета выстрела. Изменяется во время полета от препятствия к препятствию - float m_fNextBarrierDepth; + float m_fNextBarrierDepth = 0.0f; void fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker, float fSpeed); }; diff --git a/source/game/BaseAmmoBox.cpp b/source/game/BaseAmmoBox.cpp index f2580eb2d18d61521ee5293cc9187b858b8c3ff3..f9ca62acb248706f118b166d6327e6a351e34813 100644 --- a/source/game/BaseAmmoBox.cpp +++ b/source/game/BaseAmmoBox.cpp @@ -24,13 +24,6 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseAmmoBox, base_ammobox); -CBaseAmmoBox::CBaseAmmoBox(CEntityManager * pMgr): - BaseClass(pMgr) -{ - //m_bPickable = false; - //m_bInvStackable = false; -} - void CBaseAmmoBox::onUse(CBaseEntity *pUser) { if(m_iCurItems < 0) diff --git a/source/game/BaseAmmoBox.h b/source/game/BaseAmmoBox.h index 8c5475579f65dc0ba7581bd0e0c1605eca802e9e..ba52e8a1c75ffa067682e402605c9d0a25f8618e 100644 --- a/source/game/BaseAmmoBox.h +++ b/source/game/BaseAmmoBox.h @@ -22,7 +22,7 @@ class CBaseAmmoBox: public CBaseItem DECLARE_CLASS(CBaseAmmoBox, CBaseItem); DECLARE_PROPTABLE(); public: - ThisClass(CEntityManager * pMgr); + DECLARE_TRIVIAL_CONSTRUCTOR(); void onUse(CBaseEntity *pUser); diff --git a/source/game/BaseAnimating.cpp b/source/game/BaseAnimating.cpp index 43f0e921ce2698dbdd26475c53723f52c080fda0..ee58f156ad3c0e9809ab7654ddfe57699f6e52e1 100644 --- a/source/game/BaseAnimating.cpp +++ b/source/game/BaseAnimating.cpp @@ -22,7 +22,7 @@ BEGIN_PROPTABLE(CBaseAnimating) DEFINE_FIELD_FLOATFN(m_fBaseScale, 0, "scale", "Scale", setScale, EDITOR_TEXTFIELD) //! Объект референса для цвета свечения - DEFINE_FIELD_ENTITY(m_pEntColorRef, 0, "glow_color_ref", "Glow color reference", EDITOR_TEXTFIELD) + DEFINE_FIELD_ENTITY(CBaseEntity, m_pEntColorRef, 0, "glow_color_ref", "Glow color reference", EDITOR_TEXTFIELD) //! Цвет свечения DEFINE_FIELD_VECTOR(m_vGlowColor, 0, "glow_color", "Glow color", EDITOR_TEXTFIELD) @@ -77,11 +77,11 @@ private: //########################################################################## -CBaseAnimating::CBaseAnimating(CEntityManager * pMgr): - BaseClass(pMgr) +CBaseAnimating::CBaseAnimating(): + m_motionState(this), + m_pAnimationCallback(new CAnimationCallback(this)) { memset(m_vNextAnim, 0, sizeof(m_vNextAnim)); - m_pAnimationCallback = new CAnimationCallback(this); } CBaseAnimating::~CBaseAnimating() @@ -191,32 +191,19 @@ SMQuaternion CBaseAnimating::getAttachmentRot(int id) return(/*getOrient() * */rot); } +#if 0 void CBaseAnimating::onSync() { BaseClass::onSync(); - if(!m_pParent && m_pRigidBody && !m_isStatic) - { - btVector3 &v = m_pRigidBody->getWorldTransform().getOrigin(); - setPos(BTVEC_F3(v)); - btQuaternion &q = m_pRigidBody->getWorldTransform().getRotation(); - setOrient(BTQUAT_Q4(q)); - } - else if(m_pRigidBody) - { - // m_pRigidBody->getWorldTransform().setOrigin(F3_BTVEC(getPos())); - // m_pRigidBody->getWorldTransform().setRotation(Q4_BTQUAT(getOrient())); - } if(m_pModel && m_pModel->isEnabled()) { - m_pModel->setPosition(getPos()); - m_pModel->setOrientation(getOrient()); - float3_t vGlowColor = m_vGlowColor; //bool isGlowEnabled = m_pEntColorRef ? m_pEntColorRef->getMainColor(&vGlowColor) : m_vGlowColor.x != 0.0f || m_vGlowColor.y != 0.0f || m_vGlowColor.z != 0.0f; m_pModel->setColor(float4(vGlowColor)); //m_pAnimPlayer->setGlowEnabled(isGlowEnabled); } } +#endif void CBaseAnimating::playAnimation(const char * name, UINT iFadeTime, UINT slot) { @@ -382,10 +369,9 @@ void CBaseAnimating::createPhysBody() const float fMass = 1.0f; m_pCollideShape->calculateLocalInertia(fMass, vInertia); - btDefaultMotionState * motionState = new btDefaultMotionState(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition))); btRigidBody::btRigidBodyConstructionInfo rigidBodyCI( fMass, // mass - motionState, // initial position + &m_motionState, // initial position m_pCollideShape, // collision shape of body vInertia // local inertia ); @@ -450,15 +436,15 @@ COLLISION_GROUP CBaseAnimating::getCollisionGroup() return(m_collisionGroup); } -void CBaseAnimating::setPos(const float3 & pos) +void CBaseAnimating::setPos(const float3 &pos) { BaseClass::setPos(pos); if(m_pRigidBody) { - m_pRigidBody->getWorldTransform().setOrigin(F3_BTVEC(pos)); - SPhysics_GetDynWorld()->updateSingleAabb(m_pRigidBody); } + + SAFE_CALL(m_pModel, setPosition, pos); } void CBaseAnimating::setOrient(const SMQuaternion & q) @@ -466,10 +452,10 @@ void CBaseAnimating::setOrient(const SMQuaternion & q) BaseClass::setOrient(q); if(m_pRigidBody) { - m_pRigidBody->getWorldTransform().setRotation(Q4_BTQUAT(q)); - SPhysics_GetDynWorld()->updateSingleAabb(m_pRigidBody); } + + SAFE_CALL(m_pModel, setOrientation, q); } void CBaseAnimating::_cleanup() diff --git a/source/game/BaseAnimating.h b/source/game/BaseAnimating.h index 30195eb793ffa472eafc0075944116dff5da751d..e5336bcd4de9646f8c99ca3cb9dcd20f331e9b19 100644 --- a/source/game/BaseAnimating.h +++ b/source/game/BaseAnimating.h @@ -22,6 +22,37 @@ See the license in LICENSE #define BLEND_MAX 4 +struct CMotionState: public btMotionState +{ +private: + CBaseEntity *m_pEntity; + +public: + CMotionState(CBaseEntity *pEntity): + m_pEntity(pEntity) + { + } + + ///synchronizes world transform from user to physics + void getWorldTransform(btTransform ¢erOfMassWorldTrans) const override + { + float3 vPos = m_pEntity->getPos(); + SMQuaternion qRot = m_pEntity->getOrient(); + + centerOfMassWorldTrans = btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos)); + } + + ///synchronizes world transform from physics to user + ///Bullet only calls the update of worldtransform for active objects + void setWorldTransform(const btTransform& centerOfMassWorldTrans) override + { + const btVector3 &v = centerOfMassWorldTrans.getOrigin(); + const btQuaternion &q = centerOfMassWorldTrans.getRotation(); + m_pEntity->setPos(BTVEC_F3(v)); + m_pEntity->setOrient(BTQUAT_Q4(q)); + } +}; + class CAnimationCallback; //! Анимированный игровой объект class CBaseAnimating: public CBaseEntity @@ -31,19 +62,17 @@ class CBaseAnimating: public CBaseEntity friend class CAnimationCallback; public: - CBaseAnimating(CEntityManager * pMgr); + DECLARE_CONSTRUCTOR(); ~CBaseAnimating(); - void getMinMax(float3 * min, float3 * max); + void getMinMax(float3 *min, float3 *max); // void getSphere(float3 * center, float * radius); virtual void setModel(const char *szMdl); virtual void setScale(float fScale); - float3 getAttachmentPos(int id); - SMQuaternion getAttachmentRot(int id); - - void onSync() override; + float3 getAttachmentPos(int id) override; + SMQuaternion getAttachmentRot(int id) override; void playAnimation(const char * name, UINT uFadeTime = 0, UINT slot = 0); void playActivity(const char * name, UINT uFadeTime = 0, UINT slot = 0); @@ -68,13 +97,13 @@ protected: virtual void _initEditorBoxes(); virtual void _releaseEditorBoxes(); - void inputPlayAnim(inputdata_t * pInputdata); - void inputPlayAnimNext(inputdata_t * pInputdata); + void inputPlayAnim(inputdata_t *pInputdata); + void inputPlayAnimNext(inputdata_t *pInputdata); - void inputPlayActivity(inputdata_t * pInputdata); - void inputPlayActivityNext(inputdata_t * pInputdata); + void inputPlayActivity(inputdata_t *pInputdata); + void inputPlayActivityNext(inputdata_t *pInputdata); - void inputSetSkin(inputdata_t * pInputdata); + void inputSetSkin(inputdata_t *pInputdata); IXModel *m_pModel = NULL; const char * m_szModelFile; @@ -82,7 +111,7 @@ protected: bool m_isStatic = false; bool m_useAutoPhysbox = true; - CBaseEntity *m_pEntColorRef = NULL; + CEntityPointer<CBaseEntity> m_pEntColorRef; float3_t m_vGlowColor; virtual void initPhysics(); @@ -115,6 +144,8 @@ private: COLLISION_GROUP m_collisionGroup = CG_DEFAULT; COLLISION_GROUP m_collisionMask = CG_ALL; CAnimationCallback *m_pAnimationCallback; + + CMotionState m_motionState; }; #endif diff --git a/source/game/BaseCharacter.cpp b/source/game/BaseCharacter.cpp index e11f41959166a54bbd9e95890a59426ad53436e4..c0e866e83e7edd1ac96a29e9235628819647822c 100644 --- a/source/game/BaseCharacter.cpp +++ b/source/game/BaseCharacter.cpp @@ -21,6 +21,8 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseCharacter, base_character); +IEventChannel<XEventPhysicsStep> *CBaseCharacter::m_pTickEventChannel = NULL; + class btKinematicClosestNotMeRayResultCallback: public btCollisionWorld::ClosestRayResultCallback { public: @@ -45,19 +47,24 @@ protected: btCollisionObject* m_me; }; -CBaseCharacter::CBaseCharacter(CEntityManager * pMgr): - BaseClass(pMgr), - m_uMoveDir(PM_OBSERVER), - m_vPitchYawRoll(float3_t(0, 0, 0)), - m_pActiveTool(NULL), - m_fCurrentSpread(0.0f), - m_pHitboxBodies(NULL), - m_fCapsHeight(1.8f), - m_fCapsHeightCrouch(1.2f), - m_fCapsRadius(0.4f), - m_idQuadLast(-1), - m_fCurrentHeight(1.0f) +void CCharacterPhysicsTickEventListener::onEvent(const XEventPhysicsStep *pData) +{ + m_pCharacter->onPhysicsStep(); +} + +CBaseCharacter::CBaseCharacter(): + m_physicsTicker(this) +{ + if(!m_pTickEventChannel) + { + m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID); + } +} + +void CBaseCharacter::onPostLoad() { + BaseClass::onPostLoad(); + m_pCollideShape = new btCapsuleShape(m_fCapsRadius, m_fCapsHeight - m_fCapsRadius * 2.0f); btTransform startTransform; @@ -69,7 +76,8 @@ CBaseCharacter::CBaseCharacter(CEntityManager * pMgr): //btTransform startTransform; startTransform.setIdentity(); - startTransform.setOrigin(F3_BTVEC(m_vPosition + float3(0.0f, m_fCapsHeight * 0.5f, 0.0f))); + float3 vPos = getPos() + float3(0.0f, m_fCapsHeight * 0.5f, 0.0f); + startTransform.setOrigin(F3_BTVEC(vPos)); //startTransform.setOrigin(btVector3(0, 12, 10)); m_pGhostObject = new btPairCachingGhostObject(); @@ -123,10 +131,14 @@ CBaseCharacter::CBaseCharacter(CEntityManager * pMgr): m_idTaskSpread = SET_INTERVAL(updateSpread, 1.0f / 30.0f); m_pInventory = new CCharacterInventory(this); + + m_pTickEventChannel->addListener(&m_physicsTicker); } CBaseCharacter::~CBaseCharacter() { + m_pTickEventChannel->removeListener(&m_physicsTicker); + CLEAR_INTERVAL(m_idTaskSpread); REMOVE_ENTITY(m_pHeadEnt); REMOVE_ENTITY(m_flashlight); @@ -437,10 +449,15 @@ void CBaseCharacter::releaseHitboxes() mem_delete_a(m_pHitboxBodies); } -void CBaseCharacter::onSync() +float3 CBaseCharacter::getHeadOffset() { - BaseClass::onSync(); + float3 vHeadOffset; // = m_pHeadEnt->getOffsetPos(); + vHeadOffset.y = m_fCapsHeight * m_fCurrentHeight - 0.1f; + return(vHeadOffset); +} +void CBaseCharacter::onPhysicsStep() +{ updateHitboxes(); if(m_uMoveDir & PM_OBSERVER) @@ -448,13 +465,11 @@ void CBaseCharacter::onSync() return; } btTransform &trans = m_pGhostObject->getWorldTransform(); - m_vPosition = (float3)(float3(trans.getOrigin().x(), trans.getOrigin().y() - m_fCapsHeight * m_fCurrentHeight * 0.5f, trans.getOrigin().z())); - - float3 vHeadOffset = m_pHeadEnt->getOffsetPos(); - vHeadOffset.y = m_fCapsHeight * m_fCurrentHeight - 0.1f; - m_pHeadEnt->setOffsetPos(vHeadOffset); + setPos(float3(trans.getOrigin().x(), trans.getOrigin().y() - m_fCapsHeight * m_fCurrentHeight * 0.5f, trans.getOrigin().z())); + m_pHeadEnt->setOffsetPos(getHeadOffset()); +#if 0 //находим текущий квад аи сетки на котором находится игрок ID idq = SAIG_QuadGet(&float3(m_vPosition), true); //если нашли @@ -477,6 +492,7 @@ void CBaseCharacter::onSync() m_idQuadCurr = idq; } +#endif } void CBaseCharacter::initPhysics() diff --git a/source/game/BaseCharacter.h b/source/game/BaseCharacter.h index 0c2b1559bc47f0c250fd43640e9f7bb5602b289d..6843723365c5e49fbefdee70ca99b026876a10f2 100644 --- a/source/game/BaseCharacter.h +++ b/source/game/BaseCharacter.h @@ -42,13 +42,29 @@ enum PLAYER_MOVE class CHUDcontroller; +class CBaseCharacter; +class CCharacterPhysicsTickEventListener final: public IEventListener<XEventPhysicsStep> +{ +public: + CCharacterPhysicsTickEventListener(CBaseCharacter *pTrigger): + m_pCharacter(pTrigger) + { + } + void onEvent(const XEventPhysicsStep *pData) override; + +private: + CBaseCharacter *m_pCharacter; +}; + //! Класс игрока \ingroup cbaseanimating class CBaseCharacter: public CBaseAnimating { DECLARE_CLASS(CBaseCharacter, CBaseAnimating); DECLARE_PROPTABLE(); + + friend class CCharacterPhysicsTickEventListener; public: - CBaseCharacter(CEntityManager * pMgr); + DECLARE_CONSTRUCTOR(); ~CBaseCharacter(); //! Запускает/останавливает первичную атаку @@ -83,8 +99,6 @@ public: void releaseHitboxes(); void updateHitboxes(); - void onSync(); - void initPhysics(); void releasePhysics(); @@ -118,26 +132,28 @@ public: return(m_pHandsModelResource); } + void onPostLoad() override; + protected: //! Фонарик CLightDirectional* m_flashlight; //! Текущее движение - UINT m_uMoveDir; + UINT m_uMoveDir = PM_OBSERVER; //! Текущий инструмент в руках - CBaseTool * m_pActiveTool; + CBaseTool *m_pActiveTool = NULL; //! Для физики @{ - btCollisionShape * m_pCollideShape; - btRigidBody * m_pRigidBody; - btPairCachingGhostObject * m_pGhostObject; - btKinematicCharacterController * m_pCharacter; - btRigidBody ** m_pHitboxBodies; + btCollisionShape *m_pCollideShape = NULL; + btRigidBody *m_pRigidBody = NULL; + btPairCachingGhostObject *m_pGhostObject = NULL; + btKinematicCharacterController *m_pCharacter = NULL; + btRigidBody **m_pHitboxBodies = NULL; //! @} //! Углы вращения игрока - float3_t m_vPitchYawRoll; + float3_t m_vPitchYawRoll = float3_t(0, 0, 0); //! Мгновенное значение коэффициента разброса float getMomentSpread(); @@ -149,22 +165,29 @@ protected: virtual void updateSpread(float dt); //! Действующее значение разброса - float m_fCurrentSpread; + float m_fCurrentSpread = 0.0f; - CCharacterInventory * m_pInventory; + CCharacterInventory *m_pInventory = NULL; - ID m_idQuadCurr; //!< текущий квад аи сетки на котором стоит игрок - ID m_idQuadLast; //!< Последний валидный квад аи сетки на котором стоял игрок + ID m_idQuadCurr = -1; //!< текущий квад аи сетки на котором стоит игрок + ID m_idQuadLast = -1; //!< Последний валидный квад аи сетки на котором стоял игрок - float m_fCapsHeight; - float m_fCapsHeightCrouch; - float m_fCapsRadius; + float m_fCapsHeight = 1.8f; + float m_fCapsHeightCrouch = 1.2f; + float m_fCapsRadius = 0.4f; - CPointEntity * m_pHeadEnt; + CPointEntity *m_pHeadEnt = NULL; - float m_fCurrentHeight; + float m_fCurrentHeight = 1.0f; IXResourceModelAnimated *m_pHandsModelResource = NULL; + + virtual float3 getHeadOffset(); + +private: + static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; + CCharacterPhysicsTickEventListener m_physicsTicker; + void onPhysicsStep(); }; #endif diff --git a/source/game/BaseEntity.cpp b/source/game/BaseEntity.cpp index 65a8f2ac5050371187312156379bcbed47e72a6f..18df921c0603dad288073ba305b3ccf39be22221 100644 --- a/source/game/BaseEntity.cpp +++ b/source/game/BaseEntity.cpp @@ -18,17 +18,17 @@ See the license in LICENSE BEGIN_PROPTABLE_NOBASE(CBaseEntity) //! Имя объекта - DEFINE_FIELD_STRING(m_szName, 0, "name", "Name", EDITOR_TEXTFIELD) + DEFINE_FIELD_STRINGFN(m_szName, 0, "name", "Name", setName, EDITOR_TEXTFIELD) //! Позиция в мире DEFINE_FIELD_VECTORFN(m_vPosition, 0, "origin", "Origin", setPos, EDITOR_TEXTFIELD) //! Ориентация в мире, углы эйлера или кватернион - DEFINE_FIELD_ANGLES(m_vOrientation, 0, "rotation", "Rotation", EDITOR_TEXTFIELD) + DEFINE_FIELD_ANGLESFN(m_qOrientation, 0, "rotation", "Rotation", setOrient, EDITOR_TEXTFIELD) //! Родительский объект в иерархии движения - DEFINE_FIELD_PARENT(m_pParent, 0, "parent", "Parent entity", EDITOR_TEXTFIELD) + DEFINE_FIELD_ENTITY(CBaseEntity, m_pParent, 0, "parent", "Parent entity", EDITOR_TEXTFIELD) //! Флаги объекта DEFINE_FIELD_FLAGS(m_iFlags, 0, "flags", "Flags", EDITOR_FLAGS) //! Объект-владелец - DEFINE_FIELD_ENTITY(m_pOwner, PDFF_NOEXPORT | PDFF_NOEDIT, "owner", "", EDITOR_NONE) + DEFINE_FIELD_ENTITY(CBaseEntity, m_pOwner, PDFF_NOEXPORT | PDFF_NOEDIT, "owner", "", EDITOR_NONE) //! Здоровье DEFINE_FIELD_FLOAT(m_fHealth, PDFF_NOEXPORT | PDFF_NOEDIT, "health", "", EDITOR_NONE) @@ -43,36 +43,34 @@ REGISTER_ENTITY_NOLISTING(CBaseEntity, base_entity); void CBaseEntity::setDefaults() { - proptable_t * pt = getPropTable(); - const char * estr = GetEmptyString(); + proptable_t *pt = getPropTable(); + const char *estr = GetEmptyString(); while(pt) { for(int i = 0; i < pt->numFields; ++i) { - if(pt->pData[i].type == PDF_STRING && !(pt->pData[i].flags & PDFF_INPUT)) + if(!(pt->pData[i].flags & PDFF_INPUT)) { - this->*((const char * ThisClass::*)pt->pData[i].pField) = estr; + if(pt->pData[i].type == PDF_STRING) + { + this->*((const char* ThisClass::*)pt->pData[i].pField) = estr; + } + else if(pt->pData[i].type == PDF_ENTITY) + { + (this->*((CEntityPointer<CBaseEntity> ThisClass::*)pt->pData[i].pField)).init(this); + } } } pt = pt->pBaseProptable; } } -CBaseEntity::CBaseEntity(CEntityManager * pWorld): - m_iId(0), - m_iFlags(0), - m_pMgr(pWorld), - m_szClassName(NULL), - m_szName(NULL), - m_pParent(NULL), - m_iParentAttachment(-1), - m_pOwner(NULL), - m_fHealth(100.0f)/*, - m_vDiscreteLinearVelocity(float3_t(0.0f, 0.0f, 0.0f))*/ - , m_bSynced(false) +CBaseEntity::CBaseEntity() { - m_iId = pWorld->reg(this); m_pLightSystem = GameData::m_pLightSystem; + + m_pParent.setLinkEstablishedListener(&CBaseEntity::onParentSet); + m_pParent.setLinkBrokenListener(&CBaseEntity::onParentUnset); } /*void CBaseEntity::setDefaults() @@ -97,7 +95,7 @@ CBaseEntity::~CBaseEntity() { _releaseEditorBoxes(); - m_pMgr->unreg(m_iId); + m_pMgr->unreg(this); proptable_t * pt = getPropTable(); const char * estr = GetEmptyString(); @@ -116,6 +114,11 @@ CBaseEntity::~CBaseEntity() } pt = pt->pBaseProptable; } + + if(m_pParent) + { + m_pParent->removeChild(this); + } } void CBaseEntity::setClassName(const char * name) @@ -123,12 +126,12 @@ void CBaseEntity::setClassName(const char * name) m_szClassName = name; } -const char * CBaseEntity::getName() +const char* CBaseEntity::getName() { return(m_szName); } -const char * CBaseEntity::getClassName() +const char* CBaseEntity::getClassName() { return(m_szClassName); } @@ -151,25 +154,24 @@ void CBaseEntity::getSphere(float3 * center, float * radius) radius = 0; } -void CBaseEntity::setPos(const float3 & pos) +void CBaseEntity::setPos(const float3 &pos) { - CBaseEntity *pParent = NULL; - if(m_pParent) - { - pParent = m_pParent; - setParent(NULL); - } m_vPosition = pos; + onParentMoved(true); + if(m_pEditorRigidBody) { m_pEditorRigidBody->getWorldTransform().setOrigin(F3_BTVEC(m_vPosition)); SPhysics_GetDynWorld()->updateSingleAabb(m_pEditorRigidBody); } - if(pParent) { - setParent(pParent, m_iParentAttachment); + ScopedSpinLock lock(m_slChildren); + for(UINT i = 0, l = m_aChildren.size(); i < l; ++i) + { + m_aChildren[i]->onParentMoved(m_isSeparateMovement); + } } } @@ -180,16 +182,47 @@ float3 CBaseEntity::getPos() void CBaseEntity::setOrient(const SMQuaternion & q) { - m_vOrientation = q; + m_qOrientation = q; + + onParentMoved(true); + + { + ScopedSpinLock lock(m_slChildren); + for(UINT i = 0, l = m_aChildren.size(); i < l; ++i) + { + m_aChildren[i]->onParentMoved(m_isSeparateMovement); + } + } } void CBaseEntity::setOffsetOrient(const SMQuaternion & q) { - m_vOffsetOrient = q; + m_qOffsetOrient = q; + onParentMoved(); } void CBaseEntity::setOffsetPos(const float3 & pos) { m_vOffsetPos = pos; + onParentMoved(); +} + +void CBaseEntity::setXform(const float3 &vPos, const SMQuaternion &q) +{ + bool bOld = m_isInOnParentMoved; + m_isInOnParentMoved = true; + setPos(vPos); + m_isInOnParentMoved = bOld; + + setOrient(q); +} +void CBaseEntity::setOffsetXform(const float3 &vPos, const SMQuaternion &q) +{ + bool bOld = m_isInOnParentMoved; + m_isInOnParentMoved = true; + setOffsetPos(vPos); + m_isInOnParentMoved = bOld; + + setOffsetOrient(q); } float3 CBaseEntity::getOffsetPos() @@ -199,13 +232,33 @@ float3 CBaseEntity::getOffsetPos() SMQuaternion CBaseEntity::getOrient() { - return(m_vOrientation); + return(m_qOrientation); } - -ID CBaseEntity::getId() +void CBaseEntity::onParentMoved(bool bAdjustOffsets) { - return(m_iId); + if(!m_pParent || m_isInOnParentMoved) + { + return; + } + + m_isInOnParentMoved = true; + + float3 vParentPos = ID_VALID(m_iParentAttachment) ? m_pParent->getAttachmentPos(m_iParentAttachment) : m_pParent->getPos(); + SMQuaternion qParentOrient = ID_VALID(m_iParentAttachment) ? m_pParent->getAttachmentRot(m_iParentAttachment) : m_pParent->getOrient(); + + if(bAdjustOffsets) + { + m_vOffsetPos = (float3)(qParentOrient.Conjugate() * (m_vPosition - vParentPos)); + m_qOffsetOrient = m_qOrientation * qParentOrient.Conjugate(); + } + else + { + setPos(vParentPos + qParentOrient * m_vOffsetPos); + setOrient(m_qOffsetOrient * qParentOrient); + } + + m_isInOnParentMoved = false; } UINT CBaseEntity::getFlags() @@ -220,7 +273,7 @@ void CBaseEntity::setFlags(UINT f) SMMATRIX CBaseEntity::getWorldTM() { - return(m_vOrientation.GetMatrix() * SMMatrixTranslation(m_vPosition)); + return(m_qOrientation.GetMatrix() * SMMatrixTranslation(m_vPosition)); } bool CBaseEntity::setKV(const char * name, const char * value) @@ -235,7 +288,6 @@ bool CBaseEntity::setKV(const char * name, const char * value) SMQuaternion q; int d; float f; - CBaseEntity * pEnt; switch(field->type) { case PDF_INT: @@ -354,34 +406,8 @@ bool CBaseEntity::setKV(const char * name, const char * value) } return(false); case PDF_ENTITY: - case PDF_PARENT: - pEnt = m_pMgr->findEntityByName(value); - if(pEnt || !value[0]) - { - if(field->type == PDF_PARENT) - { - setParent(pEnt); - } - else - { - // check type of pEnt - if(field->pfnCheckType && !field->pfnCheckType(pEnt)) - { - LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to set entity field '%s' to entity '%s'. Invalid class. Ent: %s", name, value, m_szName); - return(false); - } - if(field->fnSet.e) - { - (this->*(field->fnSet.e))(pEnt); - } - else - { - this->*((CBaseEntity* ThisClass::*)field->pField) = pEnt; - } - } - return(true); - } - return(false); + (this->*((CEntityPointer<CBaseEntity> ThisClass::*)field->pField)).setEntityName(value); + return(true); case PDF_FLAGS: if(1 == sscanf(value, "%d", &d)) { @@ -402,14 +428,13 @@ bool CBaseEntity::setKV(const char * name, const char * value) iConns = parse_str(str, parts, iConns, ','); output_t *pOutput = &(this->*((output_t ThisClass::*)field->pField)); - mem_delete_a(pOutput->pOutputs); { char *pTmpData = (char*)pOutput->pData; mem_delete_a(pTmpData); } pOutput->pData = str; - pOutput->pOutputs = new named_output_t[iConns]; - pOutput->bDirty = true; + pOutput->aOutputs.clearFast(); + pOutput->aOutputs.reserve(iConns); int curr = 0; for(int i = 0; i < iConns; ++i) @@ -444,11 +469,13 @@ bool CBaseEntity::setKV(const char * name, const char * value) printf(COLOR_LRED "Unable to parse output delay '%s' ent %s\n" COLOR_RESET, name, m_szName); continue; } - pOutput->pOutputs[curr].fDelay = fDelayFrom; - pOutput->pOutputs[curr].fDelayTo = fDelayTo; + named_output_t &out = pOutput->aOutputs[curr]; + + out.fDelay = fDelayFrom; + out.fDelayTo = fDelayTo; if(fDelayFrom < fDelayTo) { - pOutput->pOutputs[curr].useRandomDelay = true; + out.useRandomDelay = true; } if(fDelayFrom > fDelayTo) { @@ -456,14 +483,15 @@ bool CBaseEntity::setKV(const char * name, const char * value) continue; } - pOutput->pOutputs[curr].szTargetName = fields[0]; - pOutput->pOutputs[curr].szTargetInput = fields[1]; - pOutput->pOutputs[curr].szTargetData = param; - pOutput->pOutputs[curr].iFireLimit = iFireLimit; + out.szTargetName = fields[0]; + out.szTargetInput = fields[1]; + out.szTargetData = param; + out.iFireLimit = iFireLimit; + out.init(this); + ++curr; } - pOutput->iOutCount = curr; } // target_name:input:delay:parameter\n<repeat> return(false); @@ -481,7 +509,6 @@ bool CBaseEntity::getKV(const char * name, char * out, int bufsize) } SMQuaternion q; float3_t f3; - CBaseEntity *pEnt; switch(field->type) { case PDF_INT: @@ -511,53 +538,46 @@ bool CBaseEntity::getKV(const char * name, char * out, int bufsize) sprintf_s(out, bufsize, "%f %f %f %f", q.x, q.y, q.z, q.w); break; case PDF_ENTITY: - case PDF_PARENT: - pEnt = this->*((CBaseEntity * ThisClass::*)field->pField); - if(!pEnt) - { - sprintf_s(out, bufsize, ""); - } - else - { - sprintf_s(out, bufsize, "%s", pEnt->getName()); - } + (this->*((CEntityPointer<CBaseEntity> ThisClass::*)field->pField)).getEntityName(out, bufsize); break; case PDF_OUTPUT: { output_t *pOutput = &(this->*((output_t ThisClass::*)field->pField)); int iWritten = 0; char * szOutBuf = out; - if(pOutput->iOutCount == 0) + *out = 0; + if(pOutput->aOutputs.size() == 0) { *out = 0; } - for(int i = 0; i < pOutput->iOutCount; ++i) + for(UINT i = 0, l = pOutput->aOutputs.size(); i < l; ++i) { + named_output_t &out = pOutput->aOutputs[i]; if(i > 0) { *szOutBuf = ','; ++szOutBuf; } int c; - if(pOutput->pOutputs[i].useRandomDelay) + if(out.useRandomDelay) { c = _snprintf(szOutBuf, bufsize - iWritten, "%s:%s:%f-%f:%s:%d", - pOutput->pOutputs[i].szTargetName, - pOutput->pOutputs[i].szTargetInput, - pOutput->pOutputs[i].fDelay, - pOutput->pOutputs[i].fDelayTo, - pOutput->pOutputs[i].szTargetData ? pOutput->pOutputs[i].szTargetData : ENT_OUTPUT_PARAM_NONE, - pOutput->pOutputs[i].iFireLimit + out.szTargetName, + out.szTargetInput, + out.fDelay, + out.fDelayTo, + out.szTargetData ? out.szTargetData : ENT_OUTPUT_PARAM_NONE, + out.iFireLimit ); } else { c = _snprintf(szOutBuf, bufsize - iWritten, "%s:%s:%f:%s:%d", - pOutput->pOutputs[i].szTargetName, - pOutput->pOutputs[i].szTargetInput, - pOutput->pOutputs[i].fDelay, - pOutput->pOutputs[i].szTargetData ? pOutput->pOutputs[i].szTargetData : ENT_OUTPUT_PARAM_NONE, - pOutput->pOutputs[i].iFireLimit + out.szTargetName, + out.szTargetInput, + out.fDelay, + out.szTargetData ? out.szTargetData : ENT_OUTPUT_PARAM_NONE, + out.iFireLimit ); } iWritten += c + 1; @@ -572,21 +592,45 @@ bool CBaseEntity::getKV(const char * name, char * out, int bufsize) return(true); } -void CBaseEntity::setParent(CBaseEntity * pEnt, int attachment) +void CBaseEntity::onParentSet(CBaseEntity *pNewParent) +{ + if(pNewParent) + { + onParentMoved(true); + + pNewParent->addChild(this); + } +} + +void CBaseEntity::onParentUnset(CBaseEntity *pOldParent) +{ + if(pOldParent) + { + pOldParent->removeChild(this); + } +} + +void CBaseEntity::addChild(CBaseEntity *pEnt) +{ + ScopedSpinLock lock(m_slChildren); + m_aChildren.push_back(pEnt); +} +void CBaseEntity::removeChild(CBaseEntity *pEnt) +{ + ScopedSpinLock lock(m_slChildren); + int idx = m_aChildren.indexOf(pEnt); + assert(idx >= 0); + if(idx >= 0) + { + m_aChildren.erase(idx); + } +} + +void CBaseEntity::setParent(CBaseEntity *pEnt, int attachment) { m_pParent = pEnt; if(pEnt) { - if(attachment >= 0) - { - m_vOffsetPos = (float3)(m_vPosition - m_pParent->getAttachmentPos(attachment)); - m_vOffsetOrient = m_vOrientation * m_pParent->getAttachmentRot(attachment).Conjugate(); - } - else - { - m_vOffsetPos = m_pParent->getOrient().Conjugate() * (float3)(m_vPosition - m_pParent->getPos()); - m_vOffsetOrient = m_vOrientation * m_pParent->getOrient().Conjugate(); - } m_iParentAttachment = attachment; } } @@ -628,43 +672,8 @@ CBaseEntity* CBaseEntity::getParent() } }*/ -void CBaseEntity::onSync() -{ - m_bSynced = true; - - if(m_pParent) - { - if(!m_pParent->m_bSynced) - { - m_pParent->onSync(); - } - if(m_iParentAttachment >= 0) - { - m_vPosition = (float3)(m_pParent->getAttachmentPos(m_iParentAttachment) + m_vOffsetPos); - m_vOrientation = m_pParent->getAttachmentRot(m_iParentAttachment) * m_vOffsetOrient; - } - else - { - m_vPosition = (float3)(m_pParent->getPos() + m_pParent->getOrient() * m_vOffsetPos); - m_vOrientation = m_vOffsetOrient * m_pParent->getOrient(); - } - //if(m_pPhysObj) - //{ - // m_pPhysObj->setPos(m_vPosition); - // m_pPhysObj->setOrient(m_vOrientation); - //} - } - //else if(m_pPhysObj) - //{ - // m_vPosition = m_pPhysObj->GetPos(); - // m_vOrientation = m_pPhysObj->getOrient(); - //} - -} - void CBaseEntity::onPostLoad() { - updateOutputs(); updateFlags(); } @@ -726,126 +735,6 @@ int CBaseEntity::countEntByName(const char *szName) return(m_pMgr->countEntityByName(szName)); } -void CBaseEntity::updateOutputs() -{ - proptable_t * pt = getPropTable(); - while(pt) - { - for(int i = 0; i < pt->numFields; ++i) - { - if(pt->pData[i].type == PDF_OUTPUT) - { - output_t *pOutput = &(this->*((output_t ThisClass::*)pt->pData[i].pField)); - - for(int j = 0, jl = pOutput->iOutCount; j < jl; ++j) - { - named_output_t *pOut = &pOutput->pOutputs[j]; - mem_delete_a(pOut->pOutputs); - - pOut->iOutCount = countEntByName(pOut->szTargetName); - if(!pOut->iOutCount) - { - printf(COLOR_CYAN "Broken output target '%s' source '%s'.'%s'\n" COLOR_RESET, pOut->szTargetName, getClassName(), m_szName); - continue; - } - pOut->pOutputs = new input_t[pOut->iOutCount]; - memset(pOut->pOutputs, 0, sizeof(input_t) * pOut->iOutCount); - - - CBaseEntity * pEnt = NULL; - int c = 0; - while((pEnt = getEntByName(pOut->szTargetName, pEnt))) - { - propdata_t * pField = pEnt->getField(pOut->szTargetInput); - if(!pField || !(pField->flags & PDFF_INPUT)) - { - printf(COLOR_CYAN "Class '%s' has no input '%s', obj '%s'\n" COLOR_RESET, pEnt->getClassName(), pOut->szTargetInput, pOut->szTargetName); - --pOut->iOutCount; - continue; - } - - pOut->pOutputs[c].fnInput = pField->fnInput; - pOut->pOutputs[c].pTarget = pEnt; - pOut->pOutputs[c].data.type = pField->type; - if((pOut->pOutputs[c].useOverrideData = pOut->szTargetData != NULL)) - { - float3_t f3; - float4_t f4; - SMQuaternion q; - int d; - float f; - const char * value = pOut->szTargetData; - bool bParsed = false; - switch(pField->type) - { - case PDF_NONE: - bParsed = true; - break; - case PDF_INT: - if(1 == sscanf(value, "%d", &d)) - { - pOut->pOutputs[c].data.parameter.i = d; - bParsed = true; - } - break; - case PDF_FLOAT: - if(1 == sscanf(value, "%f", &f)) - { - pOut->pOutputs[c].data.parameter.f = f; - bParsed = true; - } - break; - case PDF_VECTOR: - if(3 == sscanf(value, "%f %f %f", &f3.x, &f3.y, &f3.z)) - { - pOut->pOutputs[c].data.v3Parameter = f3; - bParsed = true; - } - break; - case PDF_VECTOR4: - { - int iPrm = sscanf(value, "%f %f %f %f", &f4.x, &f4.y, &f4.z, &f4.w); - if(iPrm > 2) - { - if(iPrm == 3) - { - f4.w = 1.0f; - } - pOut->pOutputs[c].data.v4Parameter = f4; - bParsed = true; - } - } - break; - case PDF_BOOL: - if(1 == sscanf(value, "%d", &d)) - { - pOut->pOutputs[c].data.parameter.b = d != 0; - bParsed = true; - } - break; - case PDF_STRING: - _setStrVal(&pOut->pOutputs[c].data.parameter.str, value); - bParsed = true; - break; - } - - if(!bParsed) - { - printf(COLOR_CYAN "Cannot parse input parameter '%s', class '%s', input '%s', obj '%s'\n" COLOR_RESET, value, pEnt->getClassName(), pOut->szTargetInput, pOut->szTargetName); - --pOut->iOutCount; - continue; - } - } - - ++c; - } - } - } - } - pt = pt->pBaseProptable; - } -} - void CBaseEntity::dispatchDamage(CTakeDamageInfo &takeDamageInfo) { float fHealth = takeDamageInfo.m_fDamage * 0.1f; @@ -1000,3 +889,37 @@ void CBaseEntity::renderEditor(bool is3D) { } + +void CBaseEntity::registerPointer(IEntityPointer *pPtr) +{ + ScopedSpinLock lock(m_slPointers); + m_aPointers.push_back(pPtr); +} + +void CBaseEntity::unregisterPointer(IEntityPointer *pPtr) +{ + ScopedSpinLock lock(m_slPointers); + int idx = m_aPointers.indexOf(pPtr); + if(idx >= 0) + { + m_aPointers.erase(idx); + } +} + +void CBaseEntity::notifyPointers() +{ + ScopedSpinLock lock(m_slPointers); + for(UINT i = 0, l = m_aPointers.size(); i < l; ++i) + { + m_aPointers[i]->onTargetRemoved(this); + } +} + +void CBaseEntity::setName(const char *szName) +{ + if(fstrcmp(m_szName, szName)) + { + m_pMgr->onEntityNameChanged(this, m_szName, szName); + _setStrVal(&m_szName, szName); + } +} diff --git a/source/game/BaseEntity.h b/source/game/BaseEntity.h index 3d5bd758066f751ec9c9604d4d8b7ca8867314ff..68a3595589f16edabde539a34e456e41374336f0 100644 --- a/source/game/BaseEntity.h +++ b/source/game/BaseEntity.h @@ -46,9 +46,12 @@ class SXGAME_EXPORT CBaseEntity friend class CEntityManager; + template<typename T> + friend class CEntityPointer; + friend class CEntityList; public: //! Конструктор - CBaseEntity(CEntityManager * pMgr); + CBaseEntity(); virtual ~CBaseEntity(); //! Возвращает имя движкового класса объекта @@ -58,22 +61,19 @@ public: const char* getName(); //! Возвращает баунд объекта - virtual void getMinMax(float3 * min, float3 * max); + virtual void getMinMax(float3 *min, float3 *max); //! Возвращает баунд сферу объекта - virtual void getSphere(float3 * center, float * radius); + virtual void getSphere(float3 *center, float *radius); //! Устанавливает мировую позицию объекта - virtual void setPos(const float3 & pos); + virtual void setPos(const float3 &pos); //! Устанавливает относительное смещение объекта - virtual void setOffsetPos(const float3 & pos); + virtual void setOffsetPos(const float3 &pos); //! Получает мировую позицию объекта float3 getPos(); float3 getOffsetPos(); - //! Получает ID объекта в системе - ID getId(); - //! Получает флаги объекта UINT getFlags(); //! Устанавливает флаги объекта @@ -83,12 +83,15 @@ public: SMMATRIX getWorldTM(); //! Устанавливает вращение объекта - virtual void setOrient(const SMQuaternion & q); + virtual void setOrient(const SMQuaternion &q); //! Устанавливает относительное вращение объекта - virtual void setOffsetOrient(const SMQuaternion & q); + virtual void setOffsetOrient(const SMQuaternion &q); //! Возвращает вращение объекта SMQuaternion getOrient(); + void setXform(const float3 &vPos, const SMQuaternion &q); + void setOffsetXform(const float3 &vPos, const SMQuaternion &q); + //! Устанавливает свойство объекта virtual bool setKV(const char *name, const char *value); //! Получает свойство объекта @@ -114,13 +117,13 @@ public: virtual void onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor); - void broadcastMessage(const char * szInputName, inputdata_t inputData, float fRadius); - void broadcastMessage(const char * szInputName, float fArg, float fRadius); - void broadcastMessage(const char * szInputName, int iArg, float fRadius); - void broadcastMessage(const char * szInputName, bool bArg, float fRadius); - void broadcastMessage(const char * szInputName, const char *szArg, float fRadius); - void broadcastMessage(const char * szInputName, const float3_t &f3Arg, float fRadius); - void broadcastMessage(const char * szInputName, float fRadius); + void broadcastMessage(const char *szInputName, inputdata_t inputData, float fRadius); + void broadcastMessage(const char *szInputName, float fArg, float fRadius); + void broadcastMessage(const char *szInputName, int iArg, float fRadius); + void broadcastMessage(const char *szInputName, bool bArg, float fRadius); + void broadcastMessage(const char *szInputName, const char *szArg, float fRadius); + void broadcastMessage(const char *szInputName, const float3_t &f3Arg, float fRadius); + void broadcastMessage(const char *szInputName, float fRadius); virtual void onUse(CBaseEntity *pUser); @@ -142,60 +145,87 @@ public: virtual void renderEditor(bool is3D); - CBaseEntity *getEntByName(const char *szName, CBaseEntity *pStartFrom); + CBaseEntity* getEntByName(const char *szName, CBaseEntity *pStartFrom); int countEntByName(const char *szName); + const XGUID* getGUID() + { + return(m_pGUID); + } + + void setSeparateMovement(bool set) + { + m_isSeparateMovement = set; + } + + void setName(const char *szName); + private: - void setClassName(const char * name); + void setClassName(const char *name); void setDefaults(); - const char * m_szClassName; + void setGUID(const XGUID *pGUID) + { + m_pGUID = pGUID; + } + void setWorld(CEntityManager *pWorld) + { + m_pMgr = pWorld; + } + const char *m_szClassName = NULL; + const XGUID *m_pGUID = NULL; -protected: - virtual void _cleanup(); - virtual void _initEditorBoxes(); - virtual void _releaseEditorBoxes(); + SpinLock m_slPointers; + Array<IEntityPointer*> m_aPointers; + void registerPointer(IEntityPointer *pPtr); + void unregisterPointer(IEntityPointer *pPtr); + void notifyPointers(); + + void onParentSet(CBaseEntity *pNewParent); + void onParentUnset(CBaseEntity *pOldParent); + + Array<CBaseEntity*> m_aChildren; + SpinLock m_slChildren; + void addChild(CBaseEntity *pEnt); + void removeChild(CBaseEntity *pEnt); + + bool m_isSeparateMovement = false; + bool m_isInOnParentMoved = false; + void onParentMoved(bool bAdjustOffsets = false); - CEntityManager * m_pMgr; //! Позиция объекта float3_t m_vPosition; - - /*! Скорость - \note вероятно, не используется - */ - float3_t m_vSpeed; - //! вращение - SMQuaternion m_vOrientation; - //float3_t m_vDiscreteLinearVelocity; - //float3_t m_vOldPosition; + SMQuaternion m_qOrientation; //! Позиция смещения (для иерархической структуры) float3_t m_vOffsetPos; //! Вращение смещения (для иерархической структуры) - SMQuaternion m_vOffsetOrient; + SMQuaternion m_qOffsetOrient; - //! Идентификатор в системе - ID m_iId; + //! Имя объекта + const char *m_szName = NULL; //! Флаги - UINT m_iFlags; - - //! Имя объекта - const char * m_szName; + UINT m_iFlags = 0; +protected: + virtual void _cleanup(); + virtual void _initEditorBoxes(); + virtual void _releaseEditorBoxes(); + CEntityManager *m_pMgr = NULL; + //! Родитель - CBaseEntity * m_pParent; + // CBaseEntity *m_pParent = NULL; + CEntityPointer<CBaseEntity> m_pParent; //! Индекс кости родителя - int m_iParentAttachment; + int m_iParentAttachment = -1; //! Владелец - CBaseEntity * m_pOwner; + CEntityPointer<CBaseEntity> m_pOwner; - //! Вызывается на стадии синхронизации - virtual void onSync(); //! Вызывается при создании после установки всех свойств virtual void onPostLoad(); @@ -204,29 +234,17 @@ protected: //! Получает вращение для кости virtual SMQuaternion getAttachmentRot(int id); -// /*! Устанавливает значение строкового свойства -// \note только для внутреннего использования -// */ -// void _setStrVal(const char ** to, const char * value); - - /*! Обновляет выходы - \note только для внутреннего использования - */ - void updateOutputs(); - //! здоровье [0,+inf] - float m_fHealth; + float m_fHealth = 100.0f; void takeHealth(float fVal, CBaseEntity *pAttacker, CBaseEntity *pInflictor=NULL); - bool m_bSynced; - //! Для редактора //@{ float3_t m_vEditorBoxSize = float3_t(0.16f, 0.16f, 0.16f); - btCollisionShape * m_pEditorCollideShape = NULL; - btRigidBody * m_pEditorRigidBody = NULL; + btCollisionShape *m_pEditorCollideShape = NULL; + btRigidBody *m_pEditorRigidBody = NULL; //@} IXLightSystem *m_pLightSystem = NULL; diff --git a/source/game/BaseHandle.cpp b/source/game/BaseHandle.cpp index ab4abe1a7b9c3e13ff6036e83f9c809c5351cfa4..c97d9cc3e42b56dd1bcb719199a2ece555651f71 100644 --- a/source/game/BaseHandle.cpp +++ b/source/game/BaseHandle.cpp @@ -16,8 +16,7 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseHandle, base_handle); -CBaseHandle::CBaseHandle(CEntityManager * pMgr): - BaseClass(pMgr) +CBaseHandle::CBaseHandle() { m_addonType = WPN_ADDON_HANDLE; } \ No newline at end of file diff --git a/source/game/BaseItem.cpp b/source/game/BaseItem.cpp index c3837d54967f241caa4134ba00bf350979f60d94..752f4753be1e8514f4b7212b017ef4b77e36a5d5 100644 --- a/source/game/BaseItem.cpp +++ b/source/game/BaseItem.cpp @@ -35,17 +35,13 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseItem, base_item); -CBaseItem::CBaseItem(CEntityManager * pMgr): - BaseClass(pMgr), - m_bInvStackable(true), - m_iInvStackCurSize(0), - m_iInvStackMaxSize(1), - m_iInvWeight(0.0f), - m_bPickable(true) +void CBaseItem::onPostLoad() { - if(m_bPickable) + BaseClass::onPostLoad(); + + if(m_bPickable && !m_pTriggerUse) { - m_pTriggerUse = (CTriggerItemUse*)CREATE_ENTITY("trigger_itemuse", m_pMgr); + m_pTriggerUse = (CTriggerItemUse *)CREATE_ENTITY("trigger_itemuse", m_pMgr); m_pTriggerUse->setItem(this); m_pTriggerUse->setModel("meshes/dev/item_trigger.dse"); m_pTriggerUse->setPos(getPos()); @@ -205,25 +201,19 @@ void CBaseItem::onModelChanged() } } -void CBaseItem::onSync() +void CBaseItem::setPos(const float3 &pos) { - BaseClass::onSync(); - - if(m_pViewModel) - { - m_pViewModel->setPosition(getPos()); - m_pViewModel->setOrientation(getOrient()); - } + BaseClass::setPos(pos); + + SAFE_CALL(m_pViewModel, setPosition, pos); + SAFE_CALL(m_pTriggerUse, setPos, pos); } -void CBaseItem::setPos(const float3 &pos) +void CBaseItem::setOrient(const SMQuaternion &q) { - BaseClass::setPos(pos); + BaseClass::setOrient(q); - if(m_pTriggerUse) - { - m_pTriggerUse->setPos(getPos()); - } + SAFE_CALL(m_pViewModel, setOrientation, q); } void CBaseItem::onIsPickableChanged(bool isPickable) diff --git a/source/game/BaseItem.h b/source/game/BaseItem.h index 087524d58783e346ef53326327599ac36480cd59..e3ae75ebaa8d31cc907d616f041ae2d412b5967f 100644 --- a/source/game/BaseItem.h +++ b/source/game/BaseItem.h @@ -35,7 +35,7 @@ class CBaseItem: public CBaseAnimating DECLARE_PROPTABLE(); friend class CCharacterInventory; public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CBaseItem(); //! Масса объекта @@ -46,22 +46,24 @@ public: void setHandsResource(IXResourceModelAnimated *pResource); - void setPos(const float3 &pos); + void setPos(const float3 &pos) override; + void setOrient(const SMQuaternion &q) override; protected: virtual void onModeChanged(INVENTORY_ITEM_MODE oldMode, INVENTORY_ITEM_MODE newMode); void onSetViewModel(const char *mdl); void onModelChanged(); - void onSync() override; + + void onPostLoad() override; void setScale(float fScale) override; const char *m_szInvName; //!< Имя, отображаемое в инвентаре - bool m_bInvStackable; //!< Можно ли хранить несколько итемов в одной ячейке - int m_iInvStackCurSize; //!< Количество итемов в стеке - int m_iInvStackMaxSize; //!< Максимальное количество итемов в стеке - float m_iInvWeight; //!< Масса объекта - bool m_bPickable; //!< Можно ли поднять объект + bool m_bInvStackable = true; //!< Можно ли хранить несколько итемов в одной ячейке + int m_iInvStackCurSize = 0; //!< Количество итемов в стеке + int m_iInvStackMaxSize = 1; //!< Максимальное количество итемов в стеке + float m_iInvWeight = 0.0f; //!< Масса объекта + bool m_bPickable = true; //!< Можно ли поднять объект output_t m_onPickUp; output_t m_onDrop; diff --git a/source/game/BaseLight.cpp b/source/game/BaseLight.cpp index dd90a186a968a2691dd7286eb573c9f9cae79a6a..4940347deaa2e964e3ba13d32ee9a2496cba1372 100644 --- a/source/game/BaseLight.cpp +++ b/source/game/BaseLight.cpp @@ -12,18 +12,16 @@ See the license in LICENSE BEGIN_PROPTABLE(CBaseLight) //! Цвет - DEFINE_FIELD_VECTOR4(m_vColor, 0, "color", "Color", EDITOR_TEXTFIELD) + DEFINE_FIELD_VECTOR4FN(m_vColor, 0, "color", "Color", setColor, EDITOR_TEXTFIELD) //! Дальность DEFINE_FIELD_FLOAT(m_fDist, 0, "dist", "Distance", EDITOR_TEXTFIELD) //! Дальность дальняя //DEFINE_FIELD_FLOAT(m_fShadowDist, 0, "light_far", "Shadow far plane", EDITOR_TEXTFIELD) //! Интенсивность теней - DEFINE_FIELD_FLOAT(m_fShadowIntensity, 0, "shadow_intensity", "Shadow intensity", EDITOR_TEXTFIELD) - //! Связанный свет (повторяет его состояние включения) - DEFINE_FIELD_ENTITYFN(m_pLinkedTo, 0, "linked_to", "Linked light to", setLinkedTo, EDITOR_TEXTFIELD) + DEFINE_FIELD_FLOATFN(m_fShadowIntensity, 0, "shadow_intensity", "Shadow intensity", setShadowIntensity, EDITOR_TEXTFIELD) //! Тип тени - DEFINE_FIELD_INT(m_iShadowType, 0, "type_shadow", "Type shadow", EDITOR_COMBOBOX) + DEFINE_FIELD_INTFN(m_iShadowType, 0, "type_shadow", "Type shadow", setShadowType, EDITOR_COMBOBOX) //COMBO_OPTION("None", "-1") //!< Нет COMBO_OPTION("Static", "0") //!< Статическая тень COMBO_OPTION("Dynamic", "1") //!< Динамическая тень @@ -45,21 +43,9 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseLight, base_light); -CBaseLight::CBaseLight(CEntityManager * pMgr): -BaseClass(pMgr) -{ - m_vColor = float4(1.0f, 1.0f, 1.0f, 1.0f); - m_fDist = 10; - m_iShadowType = 1; - m_fShadowIntensity = 1.0f; -} - CBaseLight::~CBaseLight() { - if(m_pLinkedTo) - { - ((CBaseLight*)m_pLinkedTo)->removeLinkedLight(this); - } + mem_release(m_pLight); } void CBaseLight::toggleEnable() @@ -67,32 +53,14 @@ void CBaseLight::toggleEnable() setEnable(!m_isEnable); } -void CBaseLight::onSync() -{ - BaseClass::onSync(); - - if(m_pLight) - { - m_pLight->setEnabled(m_isEnable); - m_pLight->setPosition(m_vPosition); - m_pLight->setColor(float3(m_vColor) * m_vColor.w); - m_pLight->setShadowIntencity(m_fShadowIntensity); - m_pLight->setShadowDynamic(m_iShadowType != 0); - } -} - - void CBaseLight::turnOn(inputdata_t * pInputdata) { if(!m_isEnable) { m_isEnable = true; + SAFE_CALL(m_pLight, setEnabled, m_isEnable); FIRE_OUTPUT(m_onTurnOn, pInputdata->pInflictor); } - for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i) - { - m_vpLinkedLights[i]->turnOn(pInputdata); - } } void CBaseLight::turnOff(inputdata_t * pInputdata) @@ -100,12 +68,9 @@ void CBaseLight::turnOff(inputdata_t * pInputdata) if(m_isEnable) { m_isEnable = false; + SAFE_CALL(m_pLight, setEnabled, m_isEnable); FIRE_OUTPUT(m_onTurnOff, pInputdata->pInflictor); } - for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i) - { - m_vpLinkedLights[i]->turnOff(pInputdata); - } } void CBaseLight::setEnable(bool isEnable) @@ -113,18 +78,15 @@ void CBaseLight::setEnable(bool isEnable) if(!m_isEnable && isEnable) { m_isEnable = isEnable; + SAFE_CALL(m_pLight, setEnabled, m_isEnable); FIRE_OUTPUT(m_onTurnOn, this); } else if(m_isEnable && !isEnable) { m_isEnable = isEnable; + SAFE_CALL(m_pLight, setEnabled, m_isEnable); FIRE_OUTPUT(m_onTurnOff, this); } - - for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i) - { - m_vpLinkedLights[i]->setEnable(isEnable); - } } void CBaseLight::updateFlags() @@ -132,19 +94,7 @@ void CBaseLight::updateFlags() BaseClass::updateFlags(); m_isEnable = !(getFlags() & LIGHT_INITIALLY_DARK); - - for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i) - { - if(m_isEnable) - { - m_vpLinkedLights[i]->setFlags(m_vpLinkedLights[i]->getFlags() & ~LIGHT_INITIALLY_DARK); - } - else - { - m_vpLinkedLights[i]->setFlags(m_vpLinkedLights[i]->getFlags() | LIGHT_INITIALLY_DARK); - } - m_vpLinkedLights[i]->updateFlags(); - } + SAFE_CALL(m_pLight, setEnabled, m_isEnable); } bool CBaseLight::getMainColor(float3_t *pOut) @@ -156,56 +106,9 @@ bool CBaseLight::getMainColor(float3_t *pOut) return(m_isEnable); } -void CBaseLight::setLinkedTo(CBaseEntity *pEnt) +void CBaseLight::setPos(const float3 &pos) { - if(m_pLinkedTo) - { - ((CBaseLight*)m_pLinkedTo)->removeLinkedLight(this); - } - m_pLinkedTo = pEnt; - if(m_pLinkedTo) - { - ((CBaseLight*)m_pLinkedTo)->addLinkedLight(this); - if((((CBaseLight*)m_pLinkedTo)->getFlags() & LIGHT_INITIALLY_DARK)) - { - setFlags(getFlags() | LIGHT_INITIALLY_DARK); - } - else - { - setFlags(getFlags() & ~LIGHT_INITIALLY_DARK); - } - updateFlags(); - } -} + BaseClass::setPos(pos); -void CBaseLight::addLinkedLight(CBaseLight *pEnt) -{ - if(!pEnt) - { - return; - } - for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i) - { - if(m_vpLinkedLights[i] == pEnt) - { - return; - } - } - m_vpLinkedLights.push_back(pEnt); -} - -void CBaseLight::removeLinkedLight(CBaseLight *pEnt) -{ - if(!pEnt) - { - return; - } - for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i) - { - if(m_vpLinkedLights[i] == pEnt) - { - m_vpLinkedLights.erase(i); - return; - } - } + SAFE_CALL(m_pLight, setPosition, pos); } diff --git a/source/game/BaseLight.h b/source/game/BaseLight.h index e0bb6ae35241bd14181fc3d653ac308d51c3ba27..c29f632ec85511cbe339256fa930f95bd07ca111 100644 --- a/source/game/BaseLight.h +++ b/source/game/BaseLight.h @@ -24,7 +24,7 @@ class CBaseLight: public CPointEntity DECLARE_CLASS(CBaseLight, CPointEntity); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CBaseLight(); void toggleEnable(); @@ -32,6 +32,7 @@ public: void setColor(const float4 &vColor) { m_vColor = vColor; + SAFE_CALL(m_pLight, setColor, float3(m_vColor) * m_vColor.w); } const float4_t& getColor() const { @@ -59,6 +60,7 @@ public: void setShadowIntensity(float fShadowIntensity) { m_fShadowIntensity = fShadowIntensity; + SAFE_CALL(m_pLight, setShadowIntencity, fShadowIntensity); } float getShadowIntensity() const { @@ -68,6 +70,7 @@ public: void setShadowType(int iShadowType) { m_iShadowType = iShadowType; + SAFE_CALL(m_pLight, setShadowDynamic, iShadowType != 0); } int getShadowType() const { @@ -84,26 +87,18 @@ public: void updateFlags(); + void setPos(const float3 &pos) override; + protected: IXLight *m_pLight = NULL; - float4_t m_vColor; - float m_fDist; + float4_t m_vColor = float4(1.0f, 1.0f, 1.0f, 1.0f); + float m_fDist = 10.0f; //float m_fShadowDist; - int m_iShadowType; - bool m_isEnable; - float m_fShadowIntensity; - CBaseEntity *m_pLinkedTo = NULL; - - Array<CBaseLight*> m_vpLinkedLights; - - void setLinkedTo(CBaseEntity *pEnt); - - void onSync(); - - void addLinkedLight(CBaseLight *pEnt); - void removeLinkedLight(CBaseLight *pEnt); - + int m_iShadowType = 1; + bool m_isEnable = true; + float m_fShadowIntensity = 1.0f; + void turnOn(inputdata_t * pInputdata); void turnOff(inputdata_t * pInputdata); diff --git a/source/game/BaseMag.cpp b/source/game/BaseMag.cpp index a783175313b8e9f9806ca14921c2c8cf1eb78cac..ad2518574bd7226dbdde191f0a6b2a730cde6f2a 100644 --- a/source/game/BaseMag.cpp +++ b/source/game/BaseMag.cpp @@ -19,10 +19,7 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseMag, base_mag); -CBaseMag::CBaseMag(CEntityManager * pMgr): - BaseClass(pMgr), - m_iCapacity(0), - m_iCurrentLoad(0) +CBaseMag::CBaseMag() { m_addonType = WPN_ADDON_MAG; } diff --git a/source/game/BaseMag.h b/source/game/BaseMag.h index aae2f46e12b3deac565ddf9620dc0cb8f6f41dc9..10fb7e90d248cbb8527315f847af4d61d476e7d8 100644 --- a/source/game/BaseMag.h +++ b/source/game/BaseMag.h @@ -28,8 +28,8 @@ public: int getCapacity(); void load(int count); protected: - int m_iCapacity; - int m_iCurrentLoad; + int m_iCapacity = 0; + int m_iCurrentLoad = 0; }; #endif diff --git a/source/game/BaseScope.cpp b/source/game/BaseScope.cpp index 05539b6b22da50ea9022562db0583022f8436cd5..9d89197ee89edbdfeb452ae06d871efb7a3f411a 100644 --- a/source/game/BaseScope.cpp +++ b/source/game/BaseScope.cpp @@ -16,8 +16,7 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseScope, base_scope); -CBaseScope::CBaseScope(CEntityManager * pMgr): - BaseClass(pMgr) +CBaseScope::CBaseScope() { m_addonType = WPN_ADDON_SCOPE; -} \ No newline at end of file +} diff --git a/source/game/BaseSilencer.cpp b/source/game/BaseSilencer.cpp index 946fb65908ae930c425ced7a31ca8a4f486fc4e3..ee43f1c4da7ae5de1cb48a26867380b3011fdefa 100644 --- a/source/game/BaseSilencer.cpp +++ b/source/game/BaseSilencer.cpp @@ -16,8 +16,7 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseSilencer, base_silencer); -CBaseSilencer::CBaseSilencer(CEntityManager * pMgr): - BaseClass(pMgr) +CBaseSilencer::CBaseSilencer() { m_addonType = WPN_ADDON_SILENCER; -} \ No newline at end of file +} diff --git a/source/game/BaseTool.cpp b/source/game/BaseTool.cpp index 9bfb41ebf5f257d60b15737d3f6d4403c3e49c29..877cfd464516e5dedeb4334723e460b0a0ff2a45 100644 --- a/source/game/BaseTool.cpp +++ b/source/game/BaseTool.cpp @@ -85,24 +85,9 @@ protected: btCollisionObject* m_me; }; -CBaseTool::CBaseTool(CEntityManager * pMgr): - BaseClass(pMgr), - m_bInPrimaryAction(false), - m_bInSecondaryAction(false), - m_bWorldModel(false), - m_bCanUse(true), - m_fZoomTime(0.0f), - m_fReloadTime(0.0f), - m_iZoomable(1), - m_iMuzzleFlash(-1), - m_iMuzzleFlash2(-1), - m_fMaxDistance(1000.0f), - m_bIsWeapon(false), - m_pLoadedAmmo(NULL) +CBaseTool::CBaseTool() { m_bInvStackable = false; - - m_iIvalUpdate = SET_INTERVAL(_update, 0); } CBaseTool::~CBaseTool() @@ -117,6 +102,8 @@ void CBaseTool::onPostLoad() { BaseClass::onPostLoad(); + m_iIvalUpdate = SET_INTERVAL(_update, 0); + IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID)); if(pSound) { @@ -192,7 +179,7 @@ void CBaseTool::secondaryAction(BOOL st) m_bInSecondaryAction = st != FALSE; if(m_iZoomable) { - ((CPlayer*)m_pOwner)->getCrosshair()->enable(!st); + ((CPlayer*)m_pOwner.getEntity())->getCrosshair()->enable(!st); } } @@ -240,25 +227,18 @@ void CBaseTool::dbgMove(int dir, float dy) printf(COLOR_GREEN "slot_offset = " COLOR_LGREEN "%f %f %f\n" COLOR_GREEN "slot_rotation = " COLOR_LGREEN "%f %f %f %f\n" COLOR_GREEN "center_length = " COLOR_LGREEN "%f\n" COLOR_RESET - , m_vOffsetPos.x, m_vOffsetPos.y, m_vOffsetPos.z + , m_vSlotPosResult.x, m_vSlotPosResult.y, m_vSlotPosResult.z , m_qSlotRotResult.x, m_qSlotRotResult.y, m_qSlotRotResult.z, m_qSlotRotResult.w , m_fCenterLength); break; } + + updateTransform(); } +#if 0 void CBaseTool::onSync() { - if(m_pOwner) - { - float3_t ang = ((CPlayer*)m_pOwner)->getWeaponDeltaAngles(); - m_vOffsetOrient = m_qSlotRotResult * SMQuaternion(ang.x, 'x') * SMQuaternion(ang.y, 'y') * SMQuaternion(ang.z, 'z'); - } - else - { - m_vOffsetOrient = m_qSlotRotResult; - } - m_vOffsetPos = m_vSlotPosResult; BaseClass::onSync(); if(m_pModel && m_pModel->asAnimatedModel()) { @@ -269,6 +249,18 @@ void CBaseTool::onSync() SPE_EffectSetRotQ(m_iMuzzleFlash, m_vOrientation); } } +#endif + +void CBaseTool::setShakeRotation(const SMQuaternion &q) +{ + m_qShakeRotation = q; + updateTransform(); +} + +void CBaseTool::updateTransform() +{ + setOffsetXform(m_vSlotPosResult, m_qSlotRotResult * m_qShakeRotation); +} void CBaseTool::_update(float dt) { @@ -278,7 +270,7 @@ void CBaseTool::_update(float dt) float3 start = m_pParent->getPos(); float3 dir = m_pParent->getOrient() * float3(0.0f, 0.0f, 1.0f); float3 end = start + dir * m_fCenterLength; - btKinematicClosestNotMeRayResultCallback cb(((CBaseCharacter*)m_pOwner)->getBtCollisionObject(), F3_BTVEC(start), F3_BTVEC(end)); + btKinematicClosestNotMeRayResultCallback cb(((CBaseCharacter*)m_pOwner.getEntity())->getBtCollisionObject(), F3_BTVEC(start), F3_BTVEC(end)); SPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb); m_isClose = cb.hasHit(); @@ -357,8 +349,9 @@ void CBaseTool::_rezoom() m_qSlotRotResult = SMquaternionSlerp(SMquaternionSlerp(m_qSlotRot, m_qSlotRotClose, m_fCloseProgress), m_qSlotRotAim, m_fZoomProgress); if(m_pOwner && m_pOwner->getClassName() && !fstrcmp(m_pOwner->getClassName(), "player")) { - ((CPlayer*)m_pOwner)->getCamera()->getCamera()->setFOV(SMToRadian(vlerp(*r_default_fov, *r_default_fov - 10.0f, m_fZoomProgress))); + ((CPlayer*)m_pOwner.getEntity())->getCamera()->getCamera()->setFOV(SMToRadian(vlerp(*r_default_fov, *r_default_fov - 10.0f, m_fZoomProgress))); } + updateTransform(); } bool CBaseTool::isWeapon() const diff --git a/source/game/BaseTool.h b/source/game/BaseTool.h index 144911221c3678849ab0e535f7749a7cae0bbffd..bd6dcb86977261a661cae9fe0328413d74caa484 100644 --- a/source/game/BaseTool.h +++ b/source/game/BaseTool.h @@ -39,7 +39,7 @@ public: DECLARE_CONSTRUCTOR(); ~CBaseTool(); - virtual void onPostLoad(); + void onPostLoad() override; virtual void primaryAction(BOOL st); virtual void secondaryAction(BOOL st); @@ -54,8 +54,6 @@ public: void dbgMove(int dir, float delta); - void onSync(); - void setParent(CBaseEntity * pEnt, int attachment = -1); //! Этот инструмент - оружие @@ -77,18 +75,20 @@ public: virtual void updateHUDinfo(); + void setShakeRotation(const SMQuaternion &q); + protected: bool isValidAmmo(CBaseSupply *pAmmo); - bool m_bInPrimaryAction; - bool m_bInSecondaryAction; + bool m_bInPrimaryAction = false; + bool m_bInSecondaryAction = false; - bool m_bWorldModel; + bool m_bWorldModel = false; - bool m_bCanUse; + bool m_bCanUse = true; - float m_fZoomTime; + float m_fZoomTime = 0.0f; float m_fZoomProgress = 0.0f; float m_fCloseProgress = 0.0f; @@ -104,7 +104,9 @@ protected: void _update(float dt); void _rezoom(); - float m_fReloadTime; + void updateTransform(); + + float m_fReloadTime = 0.0f; float3_t m_vSlotPos; float3_t m_vSlotPosAim; @@ -115,29 +117,31 @@ protected: SMQuaternion m_qSlotRotClose; SMQuaternion m_qSlotRotResult; - int m_iZoomable; + int m_iZoomable = 1; ID m_iIvalUpdate; - ID m_iMuzzleFlash; - ID m_iMuzzleFlash2; + ID m_iMuzzleFlash = -1; + ID m_iMuzzleFlash2 = -1; IXSoundEmitter *m_pSoundAction1 = NULL; IXSoundEmitter *m_pSoundAction2 = NULL; - const char * m_szPrimaryActionSound; - const char * m_szSecondaryActionSound; + const char *m_szPrimaryActionSound = NULL; + const char *m_szSecondaryActionSound = NULL; - const char * m_szPrimaryActionMuzzleflash; - const char * m_szSecondaryActionMuzzleflash; + const char *m_szPrimaryActionMuzzleflash = NULL; + const char *m_szSecondaryActionMuzzleflash = NULL; - const char * m_szUsableAmmos; - const char * m_szLoadedAmmo; - CBaseSupply * m_pLoadedAmmo; + const char *m_szUsableAmmos = NULL; + const char *m_szLoadedAmmo = NULL; + CBaseSupply *m_pLoadedAmmo = NULL; - float m_fMaxDistance; + float m_fMaxDistance = 1000.0f; //! Этот инструмент - оружие - bool m_bIsWeapon; + bool m_bIsWeapon = false; + + SMQuaternion m_qShakeRotation; }; #endif diff --git a/source/game/BaseTrigger.cpp b/source/game/BaseTrigger.cpp index 6a4bd04f866b6719ea08b7457b6b60706080abe6..3d23d5f18d63ef089cb2eebb4583c096bd1d473e 100644 --- a/source/game/BaseTrigger.cpp +++ b/source/game/BaseTrigger.cpp @@ -30,19 +30,20 @@ END_PROPTABLE() REGISTER_ENTITY(CBaseTrigger, trigger); -CBaseTrigger::CBaseTrigger(CEntityManager * pMgr): - BaseClass(pMgr), - m_bEnabled(true), - m_pGhostObject(NULL), - m_idUpdateInterval(-1) +IEventChannel<XEventPhysicsStep> *CBaseTrigger::m_pTickEventChannel = NULL; + +CBaseTrigger::CBaseTrigger(): + m_physicsTicker(this) { - m_idUpdateInterval = SET_INTERVAL(update, 0); + if(!m_pTickEventChannel) + { + m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID); + } } CBaseTrigger::~CBaseTrigger() { removePhysBody(); - CLEAR_INTERVAL(m_idUpdateInterval); } void CBaseTrigger::onPostLoad() @@ -61,10 +62,10 @@ void CBaseTrigger::enable() if(!m_bEnabled) { m_bEnabled = true; - m_idUpdateInterval = SET_INTERVAL(update, 0); if(m_pGhostObject) { SPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, CG_TRIGGER, CG_CHARACTER); + m_pTickEventChannel->addListener(&m_physicsTicker); } } } @@ -73,9 +74,9 @@ void CBaseTrigger::disable() if(m_bEnabled) { m_bEnabled = false; - CLEAR_INTERVAL(m_idUpdateInterval); if(m_pGhostObject) { + m_pTickEventChannel->removeListener(&m_physicsTicker); SPhysics_GetDynWorld()->removeCollisionObject(m_pGhostObject); } } @@ -92,15 +93,15 @@ void CBaseTrigger::toggle() } } -void CBaseTrigger::inEnable(inputdata_t * pInputdata) +void CBaseTrigger::inEnable(inputdata_t *pInputdata) { enable(); } -void CBaseTrigger::inDisable(inputdata_t * pInputdata) +void CBaseTrigger::inDisable(inputdata_t *pInputdata) { disable(); } -void CBaseTrigger::inToggle(inputdata_t * pInputdata) +void CBaseTrigger::inToggle(inputdata_t *pInputdata) { toggle(); } @@ -109,13 +110,17 @@ void CBaseTrigger::createPhysBody() { if(m_pCollideShape) { + float3 vPos = getPos(); + SMQuaternion qRot = getOrient(); + m_pGhostObject = new btPairCachingGhostObject(); - m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition))); + m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos))); m_pGhostObject->setUserPointer(this); m_pGhostObject->setCollisionShape(m_pCollideShape); m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() ^ btCollisionObject::CF_NO_CONTACT_RESPONSE); SPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, CG_TRIGGER, CG_CHARACTER); + m_pTickEventChannel->addListener(&m_physicsTicker); } } @@ -124,6 +129,7 @@ void CBaseTrigger::removePhysBody() if(m_pGhostObject) { SPhysics_GetDynWorld()->removeCollisionObject(m_pGhostObject); + m_pTickEventChannel->removeListener(&m_physicsTicker); mem_delete(m_pGhostObject); } } @@ -141,16 +147,17 @@ void CBaseTrigger::onTouchEndAll(CBaseEntity *pActivator) FIRE_OUTPUT(m_onTouchEndAll, pActivator); } -void CBaseTrigger::onSync() +void CBaseTrigger::onPhysicsStep() { - BaseClass::onSync(); - - static const bool *dev_show_triggers = GET_PCVAR_BOOL("dev_show_triggers"); - - if(m_pModel && *dev_show_triggers != m_isModelEnabled) { - m_isModelEnabled = *dev_show_triggers; - m_pModel->enable(m_isModelEnabled); + // TODO move this! + static const bool *dev_show_triggers = GET_PCVAR_BOOL("dev_show_triggers"); + + if(m_pModel && *dev_show_triggers != m_isModelEnabled) + { + m_isModelEnabled = *dev_show_triggers; + m_pModel->enable(m_isModelEnabled); + } } if(!m_pGhostObject || !m_bEnabled) @@ -193,17 +200,12 @@ void CBaseTrigger::onSync() } } //m_pGhostObject->getOverlappingObject(0); - //printf("%d\n", m_iTouches); + + update(); } -void CBaseTrigger::update(float dt) +void CBaseTrigger::update() { - if(!m_bEnabled) - { - return; - } - - bool bFound; for(int i = 0, l = m_aNewTouches.size(); i < l; ++i) { @@ -212,7 +214,8 @@ void CBaseTrigger::update(float dt) { if(m_aNewTouches[i] == m_aTouches[j]) { - m_aTouches[j] = NULL; + m_aTouches[j] = m_aTouches[jl - 1]; + m_aTouches.erase(jl - 1); bFound = true; break; } @@ -222,16 +225,11 @@ void CBaseTrigger::update(float dt) onTouchStart(m_aNewTouches[i]); } } - CBaseEntity * pLastTouch = NULL; for(int j = 0, jl = m_aTouches.size(); j < jl; ++j) { - if(m_aTouches[j]) - { - onTouchEnd(m_aTouches[j]); - pLastTouch = m_aTouches[j]; - } + onTouchEnd(m_aTouches[j]); } - if(pLastTouch && !m_aNewTouches.size()) + if(m_aTouches.size() && !m_aNewTouches.size()) { onTouchEndAll(m_aTouches[0]); } @@ -260,3 +258,8 @@ void CBaseTrigger::setOrient(const SMQuaternion & q) SPhysics_GetDynWorld()->updateSingleAabb(m_pGhostObject); } } + +void CPhysicsTickEventListener::onEvent(const XEventPhysicsStep *pData) +{ + m_pTrigger->onPhysicsStep(); +} diff --git a/source/game/BaseTrigger.h b/source/game/BaseTrigger.h index 116883366eb5a6642a52d9d945b84e266c567c9a..f9dc832c137df29676a8862c92904577415399a4 100644 --- a/source/game/BaseTrigger.h +++ b/source/game/BaseTrigger.h @@ -19,17 +19,32 @@ See the license in LICENSE #include "BaseAnimating.h" +class CBaseTrigger; +class CPhysicsTickEventListener final: public IEventListener<XEventPhysicsStep> +{ +public: + CPhysicsTickEventListener(CBaseTrigger *pTrigger): + m_pTrigger(pTrigger) + { + } + void onEvent(const XEventPhysicsStep *pData) override; + +private: + CBaseTrigger *m_pTrigger; +}; + //! Базовый класс триггера class CBaseTrigger: public CBaseAnimating { DECLARE_CLASS(CBaseTrigger, CBaseAnimating); DECLARE_PROPTABLE(); + + friend class CPhysicsTickEventListener; public: DECLARE_CONSTRUCTOR(); ~CBaseTrigger(); - void onSync(); - void onPostLoad(); + void onPostLoad() override; void enable(); void disable(); @@ -39,10 +54,9 @@ public: void setOrient(const SMQuaternion & q) override; protected: - bool m_bEnabled; - ID m_idUpdateInterval; + bool m_bEnabled = true; - ID m_idDevMaterial; + ID m_idDevMaterial = -1; Array<CBaseEntity*> m_aTouches; Array<CBaseEntity*> m_aNewTouches; @@ -51,9 +65,9 @@ protected: output_t m_onTouchEnd; output_t m_onTouchEndAll; - void update(float dt); + void update(); - btPairCachingGhostObject *m_pGhostObject; + btPairCachingGhostObject *m_pGhostObject = NULL; bool m_isModelEnabled = true; @@ -67,6 +81,13 @@ protected: virtual void onTouchStart(CBaseEntity *pActivator); virtual void onTouchEnd(CBaseEntity *pActivator); virtual void onTouchEndAll(CBaseEntity *pActivator); + +private: + static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; + + CPhysicsTickEventListener m_physicsTicker; + + void onPhysicsStep(); }; #endif diff --git a/source/game/BaseWeapon.cpp b/source/game/BaseWeapon.cpp index 48e6217cf4e53b25ac6a525e890857322e147710..67f5c8803f5bbcb3e3cf75a34eee39b56ff4cc73 100644 --- a/source/game/BaseWeapon.cpp +++ b/source/game/BaseWeapon.cpp @@ -93,33 +93,7 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseWeapon, base_weapon); -CBaseWeapon::CBaseWeapon(CEntityManager * pMgr): - BaseClass(pMgr), - - m_idTaskShoot(-1), - - m_pSilencer(NULL), - m_pScope(NULL), - m_pHandle(NULL), - m_pMag(NULL), - m_fireMode(FIRE_MODE_SINGLE), - m_iFireModes(0), - - m_iCapacity(1), - m_iCurrentLoad(0), - - m_fBaseSpread(0.33f), - m_fSpreadIdle(0.01f), - m_fSpreadCrouch(0.007f), - m_fSpreadCrawl(0.001f), - m_fSpreadWalk(1.0f), - m_fSpreadRun(4.0f), - m_fSpreadAirborne(5.0f), - m_fSpreadCondition(3.0f), - m_fSpreadArm(3.0f), - m_fSpreadIronSight(-0.8f), - - m_fAimingRange(100.f) +CBaseWeapon::CBaseWeapon() { m_bIsWeapon = true; } @@ -256,7 +230,7 @@ void CBaseWeapon::secondaryAction(BOOL st) m_bInSecondaryAction = st != FALSE; if(m_iZoomable) { - ((CPlayer*)m_pOwner)->getCrosshair()->enable(!st); + ((CPlayer*)m_pOwner.getEntity())->getCrosshair()->enable(!st); } } @@ -280,7 +254,7 @@ void CBaseWeapon::reload() printf(COLOR_MAGENTA "Mag full!\n" COLOR_RESET); return; } - int count = ((CBaseCharacter*)m_pOwner)->getInventory()->consumeItems(m_szLoadedAmmo, iWantLoad); + int count = ((CBaseCharacter*)m_pOwner.getEntity())->getInventory()->consumeItems(m_szLoadedAmmo, iWantLoad); if(count) { bool isFast = m_iCapacity == m_iCurrentLoad; @@ -309,7 +283,7 @@ void CBaseWeapon::reload() if(pHUD) { pHUD->setWeaponCurrentLoad((m_pMag ? m_pMag->getLoad() : 0) + m_iCurrentLoad); - pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner)->getInventory()->getItemCount(m_szLoadedAmmo)); + pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner.getEntity())->getInventory()->getItemCount(m_szLoadedAmmo)); } } else @@ -531,12 +505,12 @@ void CBaseWeapon::updateHUDinfo() { if(m_pOwner) { - CHUDcontroller * pHUD = ((CBaseCharacter*)m_pOwner)->getHUDcontroller(); + CHUDcontroller *pHUD = ((CBaseCharacter*)m_pOwner.getEntity())->getHUDcontroller(); if(pHUD) { pHUD->setWeaponMaxLoad((m_pMag ? m_pMag->getCapacity() : 0)/* + m_iCapacity*/); pHUD->setWeaponCurrentLoad((m_pMag ? m_pMag->getLoad() : 0) + m_iCurrentLoad); - pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner)->getInventory()->getItemCount(m_szLoadedAmmo)); + pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner.getEntity())->getInventory()->getItemCount(m_szLoadedAmmo)); } } } diff --git a/source/game/BaseWeapon.h b/source/game/BaseWeapon.h index fbd1dcc3bbc887afe6ac3da3093a2a7e10a9c45e..f9f6203a0a33efd63cfde21633c307bb31829ba1 100644 --- a/source/game/BaseWeapon.h +++ b/source/game/BaseWeapon.h @@ -63,7 +63,7 @@ class CBaseWeapon: public CBaseTool public: DECLARE_CONSTRUCTOR(); ~CBaseWeapon(); - virtual void onPostLoad(); + void onPostLoad() override; virtual void primaryAction(BOOL st); virtual void secondaryAction(BOOL st); @@ -104,38 +104,38 @@ protected: //! Задача стрельбы virtual void taskShoot(float dt); - ID m_idTaskShoot; + ID m_idTaskShoot = -1; // Compatible addons - const char * m_szAddonScopes; - const char * m_szAddonSilencers; - const char * m_szAddonMags; - const char * m_szAddonHandlers; + const char *m_szAddonScopes = NULL; + const char *m_szAddonSilencers = NULL; + const char *m_szAddonMags = NULL; + const char *m_szAddonHandlers = NULL; // Addons - CBaseSilencer * m_pSilencer; - CBaseScope * m_pScope; - CBaseHandle * m_pHandle; - CBaseMag * m_pMag; + CBaseSilencer *m_pSilencer = NULL; + CBaseScope *m_pScope = NULL; + CBaseHandle *m_pHandle = NULL; + CBaseMag *m_pMag = NULL; // Fire modes - FIRE_MODE m_fireMode; - int m_iFireModes; - const char * m_szFireModes; - int m_iSingleRate; - int m_iBurstRate; - int m_iCutoffRate; - int m_iCutoffSize; + FIRE_MODE m_fireMode = FIRE_MODE_SINGLE; + int m_iFireModes = 0; + const char *m_szFireModes = NULL; + int m_iSingleRate = 1; + int m_iBurstRate = 1; + int m_iCutoffRate = 1; + int m_iCutoffSize = 1; - int m_iCutoffCurrent; + int m_iCutoffCurrent = 0; // Sounds - const char *m_szSndDraw; - const char *m_szSndHolster; - const char *m_szSndShoot; - const char *m_szSndEmpty; - const char *m_szSndReload; - const char *m_szSndSwitch; + const char *m_szSndDraw = NULL; + const char *m_szSndHolster = NULL; + const char *m_szSndShoot = NULL; + const char *m_szSndEmpty = NULL; + const char *m_szSndReload = NULL; + const char *m_szSndSwitch = NULL; IXSoundPlayer *m_pSndDraw = NULL; IXSoundPlayer *m_pSndHolster = NULL; @@ -145,26 +145,26 @@ protected: IXSoundPlayer *m_pSndSwitch = NULL; // Shooting - float m_fEffectiveDistance; - RIFLE_TYPE m_rifleType; - float m_fRifleStep; - float m_fAimingRange; + float m_fEffectiveDistance = 1000.0f; + RIFLE_TYPE m_rifleType = RIFLE_TYPE_UNRIFLED; + float m_fRifleStep = 0.0f; + float m_fAimingRange = 100.0f; // Without mag - int m_iCapacity; - int m_iCurrentLoad; + int m_iCapacity = 1; + int m_iCurrentLoad = 0; // Spread - float m_fBaseSpread; - float m_fSpreadIdle; - float m_fSpreadCrouch; - float m_fSpreadCrawl; - float m_fSpreadWalk; - float m_fSpreadRun; - float m_fSpreadAirborne; - float m_fSpreadCondition; - float m_fSpreadArm; - float m_fSpreadIronSight; + float m_fBaseSpread = 0.33f; + float m_fSpreadIdle = 0.01f; + float m_fSpreadCrouch = 0.007f; + float m_fSpreadCrawl = 0.001f; + float m_fSpreadWalk = 1.0f; + float m_fSpreadRun = 4.0f; + float m_fSpreadAirborne = 5.0f; + float m_fSpreadCondition = 3.0f; + float m_fSpreadArm = 3.0f; + float m_fSpreadIronSight = -0.8f; }; #endif diff --git a/source/game/BaseWeaponAddon.cpp b/source/game/BaseWeaponAddon.cpp index 03e94db9ff4e3bceecacd595ab4ec7e9b2e8971c..6234e216d1b4ac83be0814b6ca87d626133c319b 100644 --- a/source/game/BaseWeaponAddon.cpp +++ b/source/game/BaseWeaponAddon.cpp @@ -16,12 +16,6 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CBaseWeaponAddon, base_wpn_addon); -CBaseWeaponAddon::CBaseWeaponAddon(CEntityManager * pMgr): - BaseClass(pMgr), - m_addonType(WPN_ADDON_NONE) -{ -} - WPN_ADDON CBaseWeaponAddon::getType() const { return(m_addonType); diff --git a/source/game/BaseWeaponAddon.h b/source/game/BaseWeaponAddon.h index 5d3922b21c39facd9410ee4523ca34d322d5a7c9..c2f1ad13512428746f09d03918884ca6819c8820 100644 --- a/source/game/BaseWeaponAddon.h +++ b/source/game/BaseWeaponAddon.h @@ -34,14 +34,14 @@ class CBaseWeaponAddon: public CBaseItem DECLARE_CLASS(CBaseWeaponAddon, CBaseItem); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); //! Получить тип навеса WPN_ADDON getType() const; protected: //! Тип навеса - WPN_ADDON m_addonType; + WPN_ADDON m_addonType = WPN_ADDON_NONE; }; #endif diff --git a/source/game/Baseline.h b/source/game/Baseline.h index 103516a477f98ce5778bff7d5231ee92bf5ed4df..1526f336094452a95f121d85f7da0fa858454650 100644 --- a/source/game/Baseline.h +++ b/source/game/Baseline.h @@ -16,7 +16,7 @@ class CBaseline struct ent_record_s { - UINT m_id; + XGUID m_guid; String m_sClassname; AssotiativeArray<String, String> m_mProps; }; diff --git a/source/game/EditorObject.cpp b/source/game/EditorObject.cpp index 9bb29d1105cf9013ba7862bde423aea5157b0351..11af1e264f46b7b7d47f0209a4a20f45149e92c2 100644 --- a/source/game/EditorObject.cpp +++ b/source/game/EditorObject.cpp @@ -8,7 +8,7 @@ CEditorObject::CEditorObject(CEditable *pEditable, CBaseEntity *pEntity): m_pEditable(pEditable), m_pEntity(pEntity), - m_idEnt(pEntity->getId()) + m_guidEnt(*pEntity->getGUID()) { assert(pEntity); @@ -40,13 +40,22 @@ void CEditorObject::_iniFieldList() { proptable_t *pTable = CEntityFactoryMap::GetInstance()->getPropTable(m_szClassName); propdata_t *pField = NULL; - X_PROP_FIELD xField; + X_PROP_FIELD xField = {}; for(UINT i = 0; i < 16; ++i) { m_aszFlags[i] = NULL; } + { + xField.editorType = XPET_TEXT; + xField.szHelp = ""; + xField.szKey = "guid"; + xField.szName = "GUID"; + + m_aFields.push_back(xField); + } + while(pTable) { for(int i = 0; i < pTable->numFields; ++i) @@ -123,29 +132,68 @@ void CEditorObject::_iniFieldList() void XMETHODCALLTYPE CEditorObject::setPos(const float3_t &pos) { - if(m_pEntity) + SAFE_CALL(m_pEntity, setPos, pos); + m_vPos = pos; +} + +void CEditorObject::setPos(const float3_t &pos, bool isSeparate) +{ + if(isSeparate) { - m_pEntity->setPos(pos); + SAFE_CALL(m_pEntity, setSeparateMovement, true); + } + + setPos(pos); + + if(isSeparate) + { + SAFE_CALL(m_pEntity, setSeparateMovement, false); } - m_vPos = pos; } void XMETHODCALLTYPE CEditorObject::setScale(const float3_t &vScale) { - //@TODO: Implement me + // TODO Implement me m_vScale = vScale; } -void XMETHODCALLTYPE CEditorObject::setOrient(const SMQuaternion &orient) +void CEditorObject::setScale(const float3_t &vScale, bool isSeparate) { - if(m_pEntity) + if(isSeparate) { - m_pEntity->setOrient(orient); + SAFE_CALL(m_pEntity, setSeparateMovement, true); } + setScale(vScale); + + if(isSeparate) + { + SAFE_CALL(m_pEntity, setSeparateMovement, false); + } +} + +void XMETHODCALLTYPE CEditorObject::setOrient(const SMQuaternion &orient) +{ + SAFE_CALL(m_pEntity, setOrient, orient); + m_qRot = orient; } +void CEditorObject::setOrient(const SMQuaternion &orient, bool isSeparate) +{ + if(isSeparate) + { + SAFE_CALL(m_pEntity, setSeparateMovement, true); + } + + setOrient(orient); + + if(isSeparate) + { + SAFE_CALL(m_pEntity, setSeparateMovement, false); + } +} + float3_t XMETHODCALLTYPE CEditorObject::getPos() { if(m_pEntity) @@ -228,7 +276,7 @@ void XMETHODCALLTYPE CEditorObject::remove() } REMOVE_ENTITY(m_pEntity); m_pEntity = NULL; - m_idEnt = -1; + //m_guidEnt = XGUID(); } void XMETHODCALLTYPE CEditorObject::preSetup() { @@ -241,22 +289,29 @@ void XMETHODCALLTYPE CEditorObject::postSetup() void XMETHODCALLTYPE CEditorObject::create() { assert(!m_pEntity); - m_pEntity = CREATE_ENTITY(m_szClassName, GameData::m_pMgr); - m_idEnt = m_pEntity->getId(); + if(m_guidEnt == XGUID()) + { + m_pEntity = CREATE_ENTITY(m_szClassName, GameData::m_pMgr); + m_guidEnt = *m_pEntity->getGUID(); + } + else + { + m_pEntity = CEntityFactoryMap::GetInstance()->create(m_szClassName, GameData::m_pMgr, false, &m_guidEnt); + } m_pEntity->setFlags(m_pEntity->getFlags() | EF_LEVEL | EF_EXPORT); - setPos(getPos()); - setOrient(getOrient()); - setScale(getScale()); + setPos(m_vPos, true); + setOrient(m_qRot, true); + setScale(m_vScale, true); } void CEditorObject::resync() { - if(ID_VALID(m_idEnt)) + if(m_pEntity) { - m_pEntity = GameData::m_pMgr->getById(m_idEnt); + m_pEntity = GameData::m_pMgr->getByGUID(m_guidEnt); } } @@ -276,7 +331,14 @@ const char* XMETHODCALLTYPE CEditorObject::getKV(const char *szKey) char tmp[4096]; - m_pEntity->getKV(szKey, tmp, sizeof(tmp)); + if(!fstrcmp(szKey, "guid")) + { + XGUIDToSting(*m_pEntity->getGUID(), tmp, sizeof(tmp)); + } + else + { + m_pEntity->getKV(szKey, tmp, sizeof(tmp)); + } m_msPropCache[szKey] = tmp; return(m_msPropCache[szKey].c_str()); diff --git a/source/game/EditorObject.h b/source/game/EditorObject.h index e9bab6d374cc047f83c735a9a8e791f532e044ea..e0b4c8141a6fc1df9d2191cfa9bf23a7ab56f616 100644 --- a/source/game/EditorObject.h +++ b/source/game/EditorObject.h @@ -16,8 +16,11 @@ public: ~CEditorObject(); void XMETHODCALLTYPE setPos(const float3_t &pos) override; + void setPos(const float3_t &pos, bool isSeparate); void XMETHODCALLTYPE setOrient(const SMQuaternion &orient) override; - void XMETHODCALLTYPE setScale(const float3_t &pos) override; + void setOrient(const SMQuaternion &orient, bool isSeparate); + void XMETHODCALLTYPE setScale(const float3_t &scale) override; + void setScale(const float3_t &scale, bool isSeparate); void XMETHODCALLTYPE getBound(float3 *pvMin, float3 *pvMax) override; @@ -74,7 +77,7 @@ protected: void _iniFieldList(); - ID m_idEnt = -1; + XGUID m_guidEnt; protected: bool m_isSelected = false; diff --git a/source/game/EditorOutputsTab.cpp b/source/game/EditorOutputsTab.cpp index fe0a6236d8514b85cd27783f4251293cc78544e8..a5efe61d073bf5208d7280aba8fab7315aba03e7 100644 --- a/source/game/EditorOutputsTab.cpp +++ b/source/game/EditorOutputsTab.cpp @@ -427,9 +427,9 @@ void CEditorOutputsTab::initSelection() propdata_t *pField = pEnt->getField(pPropData->szKey); output_t *pOutput = &(pEnt->*((output_t CBaseEntity::*)pField->pField)); - for(int i = 0; i < pOutput->iOutCount; ++i) + for(int i = 0, l = pOutput->aOutputs.size(); i < l; ++i) { - const named_output_t &namedOutput = pOutput->pOutputs[i]; + const named_output_t &namedOutput = pOutput->aOutputs[i]; int idx = m_pCurrentCommand->m_aRows.indexOf(namedOutput, [&](const Row &row, const named_output_t &out){ return( @@ -594,7 +594,7 @@ INT_PTR CALLBACK CEditorOutputsTab::dlgProc(HWND hWnd, UINT msg, WPARAM wParam, if(pNMLV->hdr.idFrom == IDC_LIST_OUTPUTS && !m_isSkipUpdate && (pNMLV->uChanged & LVIF_STATE) && ((pNMLV->uNewState ^ pNMLV->uOldState) & LVIS_SELECTED)) { Row *pRow = &m_pCurrentCommand->m_aRows[pNMLV->iItem]; - pRow->isSelected = pNMLV->uNewState & LVIS_SELECTED; + pRow->isSelected = (pNMLV->uNewState & LVIS_SELECTED) != 0; updateButtons(); } diff --git a/source/game/EntityFactory.cpp b/source/game/EntityFactory.cpp index ac4de7c989f397e60b0ec0e9e99d763874c4daa9..fcfa2eb693c8ad01247ef3651741726f32faf4d5 100644 --- a/source/game/EntityFactory.cpp +++ b/source/game/EntityFactory.cpp @@ -22,13 +22,14 @@ void CEntityFactoryMap::addFactory(IEntityFactory *pFactory, const char *szName) } m_mFactories[AAString(szName)] = pFactory; } -CBaseEntity* CEntityFactoryMap::create(const char *szName, CEntityManager *pWorld, bool bDelayPostLoad) +CBaseEntity* CEntityFactoryMap::create(const char *szName, CEntityManager *pWorld, bool bDelayPostLoad, const XGUID *pGUID) { IEntityFactory *pFactory = getFactory(szName); if(pFactory) { EntDefaultsMap *defs = pFactory->getDefaults(); - CBaseEntity *pEnt = pFactory->create(pWorld); + CBaseEntity *pEnt = pFactory->create(); + pWorld->reg(pEnt, pGUID); pEnt->setDefaults(); pEnt->setClassName(pFactory->getClassName()); @@ -60,11 +61,6 @@ CBaseEntity* CEntityFactoryMap::create(const char *szName, CEntityManager *pWorl pEnt->_initEditorBoxes(); } - if(pFactory->isSyncable()) - { - pWorld->regSync(pEnt); - } - return(pEnt); } return(NULL); @@ -76,10 +72,6 @@ void CEntityFactoryMap::destroy(CBaseEntity *pEnt) IEntityFactory *pFactory = getFactory(pEnt->getClassName()); if(pFactory) { - if(pFactory->isSyncable()) - { - pEnt->m_pMgr->unregSync(pEnt); - } return(pFactory->destroy(pEnt)); } } diff --git a/source/game/EntityFactory.h b/source/game/EntityFactory.h index 3aa8d7ef9128fb79c6c7a4b0adee045b14e9547d..bde74bf914ec1c024c8986bcd8ff38e83d0bd019 100644 --- a/source/game/EntityFactory.h +++ b/source/game/EntityFactory.h @@ -22,14 +22,13 @@ class CEntityManager; class IEntityFactory { public: - virtual CBaseEntity* create(CEntityManager * pWorld) = 0; + virtual CBaseEntity* create() = 0; virtual void destroy(CBaseEntity * pEnt) = 0; virtual const char* getClassName() = 0; virtual proptable_t* getPropTable() = 0; virtual bool isEditorHidden() = 0; virtual EntDefaultsMap* getDefaults() = 0; virtual IEntityFactory* copy(const char * szName, bool showInListing) = 0; - virtual bool isSyncable() = 0; }; class CEntityFactoryMap @@ -39,7 +38,7 @@ public: CEntityFactoryMap(); void addFactory(IEntityFactory *pFactory, const char *szName); - CBaseEntity* create(const char *szName, CEntityManager *pMgr, bool bDelayPostLoad=false); + CBaseEntity* create(const char *szName, CEntityManager *pMgr, bool bDelayPostLoad=false, const XGUID *pGUID=NULL); void destroy(CBaseEntity *pEnt); static CEntityFactoryMap* GetInstance(); @@ -86,12 +85,11 @@ template <class T> class CEntityFactory: public IEntityFactory { public: - CEntityFactory(const char * szName, bool showInListing, bool isSyncable=true) + CEntityFactory(const char * szName, bool showInListing) { m_bShowInListing = showInListing; m_szClassName = szName; m_pPropTable = T::SGetPropTable(); - m_isSyncable = isSyncable; CEntityFactoryMap::GetInstance()->addFactory(this, szName); } @@ -113,9 +111,9 @@ public: return(newF); } - CBaseEntity* create(CEntityManager *pWorld) override + CBaseEntity* create() override { - return(new T(pWorld)); + return(new T()); } void destroy(CBaseEntity *pEnt) override @@ -141,11 +139,6 @@ public: return(!m_bShowInListing); } - bool isSyncable() override - { - return(m_isSyncable); - } - EntDefaultsMap* getDefaults() override { return(&m_mDefaults); @@ -155,7 +148,6 @@ private: const char * m_szClassName; proptable_t * m_pPropTable; bool m_bShowInListing; - bool m_isSyncable; EntDefaultsMap m_mDefaults; Array<CEntityFactory<T>*> m_vDerivatives; }; @@ -163,9 +155,6 @@ private: #define REGISTER_ENTITY(cls, name) \ CEntityFactory<cls> ent_ ## name ## _factory(#name, 1) -#define REGISTER_ENTITY_NOSYNC(cls, name) \ - CEntityFactory<cls> ent_ ## name ## _factory(#name, 1, 0) - #define REGISTER_ENTITY_NOLISTING(cls, name) \ CEntityFactory<cls> ent_ ## name ## _factory(#name, 0) diff --git a/source/game/EntityList.cpp b/source/game/EntityList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c5f9ad0476f88c5373aacaef261a593f17bfd28 --- /dev/null +++ b/source/game/EntityList.cpp @@ -0,0 +1,146 @@ +#include "EntityList.h" +#include "BaseEntity.h" + +CEntityList::~CEntityList() +{ + clearList(); + + unregisterWait(); +} + +//! Установка имени или GUID связанного объекта +void CEntityList::setEntityName(const char *szName) +{ + clearList(); + + unregisterWait(); + m_sName = szName; + + if(szName[0]) + { + registerWait(); + + CBaseEntity *pEnt = NULL; + while((pEnt = m_pThisEntity->getEntByName(szName, pEnt))) + { + addEntity(pEnt); + } + } +} + +//! Установка +void CEntityList::addEntity(CBaseEntity *pEnt) +{ + assert(pEnt); + + pEnt->registerPointer(this); + + int idx = m_aEntities.indexOf(pEnt); + assert(idx < 0); + if(idx < 0) + { + m_aEntities.push_back(pEnt); + onLinkEstablished(pEnt); + } +} + +void CEntityList::removeEntity(CBaseEntity *pEnt) +{ + assert(pEnt); + int idx = m_aEntities.indexOf(pEnt); + assert(idx >= 0); + if(idx >= 0) + { + onLinkBroken(pEnt); + m_aEntities[idx] = m_aEntities[m_aEntities.size() - 1]; + m_aEntities.erase(m_aEntities.size() - 1); + } +} + +//! Получение указателя на объект +CBaseEntity* CEntityList::getEntity(int idx) +{ + return((int)m_aEntities.size() >= idx ? m_aEntities[idx] : NULL); +} + +UINT CEntityList::getEntityCount() +{ + return(m_aEntities.size()); +} + +const char* CEntityList::getEntityName() +{ + return(m_sName.c_str()); +} + +CBaseEntity* CEntityList::operator[](int idx) +{ + return(getEntity(idx)); +} + +CEntityList& CEntityList::operator+=(CBaseEntity *pEnt) +{ + addEntity(pEnt); + return(*this); +} + +CEntityList& CEntityList::operator-=(CBaseEntity *pEnt) +{ + removeEntity(pEnt); + return(*this); +} + +void CEntityList::onLinkBroken(CBaseEntity *pOldEnt) +{ + if(m_pfnOnLinkBroken) + { + (m_pThisEntity->*m_pfnOnLinkBroken)(pOldEnt); + } + if(m_pOnLinkBroken) + { + m_pOnLinkBroken->onEvent(pOldEnt); + } +} +void CEntityList::onLinkEstablished(CBaseEntity *pNewEnt) +{ + if(m_pfnOnLinkEstablished) + { + (m_pThisEntity->*m_pfnOnLinkEstablished)(pNewEnt); + } + if(m_pOnLinkEstablished) + { + m_pOnLinkEstablished->onEvent(pNewEnt); + } +} +void CEntityList::onTargetRemoved(CBaseEntity *pEnt) +{ + removeEntity(pEnt); +} + +void CEntityList::registerWait() +{ + if(!m_isWaiting) + { + m_pThisEntity->m_pMgr->registerWaitForName(m_sName.c_str(), this); + m_isWaiting = true; + } +} +void CEntityList::unregisterWait() +{ + if(m_isWaiting) + { + m_pThisEntity->m_pMgr->unregisterWaitForName(m_sName.c_str(), this); + m_isWaiting = false; + } +} + +void CEntityList::clearList() +{ + for(UINT i = 0, l = m_aEntities.size(); i < l; ++i) + { + m_aEntities[i]->unregisterPointer(this); + } + m_aEntities.clearFast(); +} + + diff --git a/source/game/EntityList.h b/source/game/EntityList.h new file mode 100644 index 0000000000000000000000000000000000000000..5e03cb9ad4ded82c260d7bca0afaa4945d4cedba --- /dev/null +++ b/source/game/EntityList.h @@ -0,0 +1,95 @@ +#ifndef __ENTITY_LIST_H +#define __ENTITY_LIST_H + +#include <gdefines.h> +#include "EntityPointer.h" +#include <common/string.h> + +class CBaseEntity; +class CEntityManager; +class CEntityList: public IEntityPointer +{ + DECLARE_CLASS_NOBASE(CEntityList); + friend class CBaseEntity; + friend struct named_output_t; +public: + ~CEntityList(); + + //! Установка имени или GUID связанного объекта + void setEntityName(const char *szName); + + //! Установка + void addEntity(CBaseEntity *pEnt); + + void removeEntity(CBaseEntity *pEnt); + + //! Получение указателя на объект + CBaseEntity* getEntity(int idx); + + UINT getEntityCount(); + + const char* getEntityName(); + + CBaseEntity* operator[](int idx); + + CEntityList& operator+=(CBaseEntity *pEnt); + + CEntityList& operator-=(CBaseEntity *pEnt); + + //! Вызывается при разрушении связи + template<typename F> + void setLinkBrokenListener(void(F::*func)(CBaseEntity*)) + { + static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity"); + + m_pfnOnLinkBroken = func; + } + + //! Вызывается при установке связи + template<typename F> + void setLinkEstablishedListener(void(F::*func)(CBaseEntity*)) + { + static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity"); + + m_pfnOnLinkEstablished = func; + } + + void setLinkBrokenListener(IEntityPointerEvent *pFunc) + { + m_pOnLinkBroken = pFunc; + } + void setLinkEstablishedListener(IEntityPointerEvent *pFunc) + { + m_pOnLinkEstablished = pFunc; + } + +private: + String m_sName; + Array<CBaseEntity*> m_aEntities; + CBaseEntity *m_pThisEntity = NULL; + + void(CBaseEntity::*m_pfnOnLinkEstablished)(CBaseEntity*) = NULL; + void(CBaseEntity::*m_pfnOnLinkBroken)(CBaseEntity*) = NULL; + IEntityPointerEvent *m_pOnLinkEstablished = NULL; + IEntityPointerEvent *m_pOnLinkBroken = NULL; + + void onLinkBroken(CBaseEntity *pOldEnt); + void onLinkEstablished(CBaseEntity *pNewEnt); + void onTargetRemoved(CBaseEntity *pEnt) override; + + bool m_isWaiting = false; + void registerWait(); + void unregisterWait(); + void onWaitDone(CBaseEntity *pEnt) override + { + } + + void clearList(); + + void init(CBaseEntity *pThisEntity) + { + m_pThisEntity = pThisEntity; + } +}; + +#endif diff --git a/source/game/EntityManager.cpp b/source/game/EntityManager.cpp index 7075321213822d2510c056703d53f226be6184ad..1f808ecc7eef7fee82a41b1741286f61a7a1dbe8 100644 --- a/source/game/EntityManager.cpp +++ b/source/game/EntityManager.cpp @@ -72,30 +72,31 @@ void CEntityManager::update(int thread) inputData.pActivator = to->data.pActivator; inputData.pInflictor = to->data.pInflictor; - for(int j = 0; j < to->pOutput->iOutCount; ++j) + for(UINT j = 0, jl = to->pOutput->aOutputs.size(); j < jl; ++j) { - if(!to->pOutput->pOutputs[j].pTarget) + input_t &out = to->pOutput->aOutputs[j]; + if(!out.pTarget) { continue; } - inputData.type = to->pOutput->pOutputs[j].data.type; + inputData.type = out.data.type; if(inputData.type == PDF_STRING) { inputData.parameter.str = NULL; } - if(to->pOutput->pOutputs[j].useOverrideData) + if(out.useOverrideData) { - inputData.setParameter(to->pOutput->pOutputs[j].data); + inputData.setParameter(out.data); } else { inputData.setParameter(to->data); } - (to->pOutput->pOutputs[j].pTarget->*(to->pOutput->pOutputs[j].fnInput))(&inputData); + (out.pTarget->*(out.fnInput))(&inputData); if(inputData.type == PDF_STRING && inputData.parameter.str != GetEmptyString()) { @@ -167,8 +168,6 @@ void CEntityManager::finalRemove() void CEntityManager::sync() { - CBaseEntity * pEnt; - finalRemove(); for(int i = 0, l = m_vTimeout.size(); i < l; ++i) @@ -199,25 +198,7 @@ void CEntityManager::sync() //static time_point tOld = std::chrono::high_resolution_clock::now(); //float dt; //dt = (float)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - tOld).count() / 1000000.0f; - for(int i = 0, l = m_vEntSyncList.size(); i < l; ++i) - { - pEnt = m_vEntSyncList[i]; - if(pEnt) - { - pEnt->m_bSynced = false; - } - } - for(int i = 0, l = m_vEntSyncList.size(); i < l; ++i) - { - pEnt = m_vEntSyncList[i]; - if(pEnt && !pEnt->m_bSynced) - { - //pEnt->updateDiscreteLinearVelocity(0, dt); - pEnt->onSync(); - //pEnt->updateDiscreteLinearVelocity(1, dt); - } - } //tOld = std::chrono::high_resolution_clock::now(); } @@ -234,54 +215,74 @@ void CEntityManager::unloadObjLevel() } } -ID CEntityManager::reg(CBaseEntity *pEnt) +const XGUID* CEntityManager::reg(CBaseEntity *pEnt, const XGUID *pGUID) { - ID ent; if(!pEnt) { - return(-1); + return(NULL); } - if(m_vFreeIDs.size()) + + XGUID guid; + if(pGUID) { - ent = m_vFreeIDs[0]; - m_vFreeIDs.erase(0); - m_vEntList[ent] = pEnt; + guid = *pGUID; } else { - ent = m_vEntList.size(); - m_vEntList.push_back(pEnt); + XCreateGUID(&guid); } - return(ent); -} -void CEntityManager::unreg(ID ent) -{ - //@TODO: Clear all outputs - if(m_vEntList.size() <= (UINT)ent || ent < 0) + + m_mEnts[guid] = pEnt; + + const XGUID *pNewGUID = &m_mEnts.TmpNode->Key; + + pEnt->setGUID(pNewGUID); + pEnt->setWorld(this); + + m_vEntList.push_back(pEnt); + + if(pGUID) { - return; + notifyWaitForGUID(*pGUID, pEnt); + + char tmp[64]; + XGUIDToSting(*pGUID, tmp, sizeof(tmp)); + onEntityNameChanged(pEnt, "", tmp); } + return(pNewGUID); +} +void CEntityManager::unreg(CBaseEntity *pEnt) +{ + assert(pEnt && pEnt->getGUID()); + + int iKey = m_vEntList.indexOf(pEnt); + assert(iKey >= 0); + UINT uLast = m_vEntList.size() - 1; + m_vEntList[iKey] = m_vEntList[uLast]; + m_vEntList[uLast] = NULL; + m_vEntList.erase(uLast); + timeout_t * t; timeout_output_t * to; - CBaseEntity *pEnt = m_vEntList[ent]; - for(int i = 0, l = m_vOutputTimeout.size(); i < l; ++i) { to = &m_vOutputTimeout[i]; if(to->status == TS_WAIT) { - int iRemoved = 0; - for(int j = 0; j < to->pOutput->iOutCount; ++j) + UINT iRemoved = 0; + for(UINT j = 0, jl = to->pOutput->aOutputs.size(); j < jl; ++j) { - if(to->pOutput->pOutputs[j].pTarget == pEnt) + input_t &out = to->pOutput->aOutputs[j]; + + if(out.pTarget == pEnt) { - to->pOutput->pOutputs[j].pTarget = NULL; + out.pTarget = NULL; ++iRemoved; } } - if(iRemoved == to->pOutput->iOutCount) + if(iRemoved == to->pOutput->aOutputs.size()) { to->status = TS_DONE; } @@ -306,26 +307,7 @@ void CEntityManager::unreg(ID ent) } } - m_vEntList[ent] = NULL; - m_vFreeIDs.push_back(ent); -} - -void CEntityManager::regSync(CBaseEntity *pEnt) -{ - assert(pEnt); - m_vEntSyncList.push_back(pEnt); -} -void CEntityManager::unregSync(CBaseEntity *pEnt) -{ - assert(pEnt); - for(UINT i = 0, l = m_vEntSyncList.size(); i < l; ++i) - { - if(m_vEntSyncList[i] == pEnt) - { - m_vEntSyncList.erase(i); - break; - } - } + m_mEnts.erase(*pEnt->getGUID()); } ID CEntityManager::setTimeout(void(CBaseEntity::*func)(float dt), CBaseEntity *pEnt, float delay) @@ -412,11 +394,21 @@ bool CEntityManager::exportList(const char * file) { ISXConfig * conf = Core_CrConfig(); conf->New(file); - char buf[4096], sect[32]; + char buf[4096], sect[64]; CBaseEntity * pEnt; proptable_t * pTbl; int ic = 0; + if(m_isOldImported) + { + FILE *fp = fopen(file, "w"); + if(fp) + { + fclose(fp); + } + m_isOldImported = false; + } + // conf->set("meta", "count", "0"); for(int i = 0, l = m_vEntList.size(); i < l; ++i) @@ -426,13 +418,14 @@ bool CEntityManager::exportList(const char * file) { continue; } - sprintf(sect, "ent_%d", ic); if(!(pEnt->getFlags() & EF_EXPORT)) { continue; } + XGUIDToSting(*pEnt->getGUID(), sect, sizeof(sect)); + conf->set(sect, "classname", pEnt->getClassName()); pTbl = CEntityFactoryMap::GetInstance()->getPropTable(pEnt->getClassName()); do @@ -450,8 +443,8 @@ bool CEntityManager::exportList(const char * file) ++ic; } - sprintf(buf, "%d", ic); - conf->set("meta", "count", buf); + // sprintf(buf, "%d", ic); + // conf->set("meta", "count", buf); bool ret = !conf->save(); mem_release(conf); @@ -465,9 +458,9 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress) { pEventChannel = Core_GetIXCore()->getEventChannel<XEventLevelProgress>(EVENT_LEVEL_PROGRESS_GUID); } - ISXConfig * conf = Core_CrConfig(); - char sect[32]; - CBaseEntity * pEnt = NULL; + ISXConfig *conf = Core_CrConfig(); + const char *sect; + CBaseEntity *pEnt = NULL; Array<CBaseEntity*> tmpList; char szFullPath[1024]; @@ -481,20 +474,13 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress) goto err; } - if(!conf->keyExists("meta", "count")) - { - goto err; - } - - int ic; - if(sscanf(conf->getKey("meta", "count"), "%d", &ic) != 1) - { - goto err; - } - + int ic = conf->getSectionCount(); tmpList.reserve(ic); + m_isOldImported = conf->getKeyCount("meta") != 0; + { + XGUID guid; XEventLevelProgress ev; ev.idPlugin = -3; @@ -503,64 +489,87 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress) ev.fProgress = 0.0f; for(int i = 0; i < ic; ++i) { - sprintf(sect, "ent_%d", i); - if(!conf->keyExists(sect, "classname")) + sect = conf->getSectionName(i); + + if(sect[0] == '{' || (sect[0] == 'e' && sect[1] == 'n' && sect[2] == 't' && sect[3] == '_')) { - printf(COLOR_LRED "Unable to load entity #%d, classname undefined\n" COLOR_RESET, i); - tmpList[i] = NULL; - continue; + if(!conf->keyExists(sect, "classname")) + { + printf(COLOR_LRED "Unable to load entity #%d, classname undefined\n" COLOR_RESET, i); + tmpList[i] = NULL; + continue; + } + + XGUID *pGUID = NULL; + if(XGUIDFromString(&guid, sect)) + { + pGUID = &guid; + } + + if(!(pEnt = CEntityFactoryMap::GetInstance()->create(conf->getKey(sect, "classname"), this, true, pGUID))) + { + printf(COLOR_LRED "Unable to load entity #%d, classname '%s' undefined\n" COLOR_RESET, i, conf->getKey(sect, "classname")); + tmpList[i] = NULL; + continue; + } + if(conf->keyExists(sect, "name")) + { + pEnt->setKV("name", conf->getKey(sect, "name")); + } + if(conf->keyExists(sect, "origin")) + { + pEnt->setKV("origin", conf->getKey(sect, "origin")); + } + if(conf->keyExists(sect, "rotation")) + { + pEnt->setKV("rotation", conf->getKey(sect, "rotation")); + } + pEnt->setFlags(pEnt->getFlags() | EF_EXPORT | EF_LEVEL); + tmpList[i] = pEnt; + + if((i & 0xF) == 0 && pEventChannel) + { + ev.fProgress = (float)i / (float)ic * 0.1f; + pEventChannel->broadcastEvent(&ev); + } } - if(!(pEnt = CREATE_ENTITY_NOPOST(conf->getKey(sect, "classname"), this))) + else { - printf(COLOR_LRED "Unable to load entity #%d, classname '%s' undefined\n" COLOR_RESET, i, conf->getKey(sect, "classname")); tmpList[i] = NULL; - continue; - } - if(conf->keyExists(sect, "name")) - { - pEnt->setKV("name", conf->getKey(sect, "name")); - } - if(conf->keyExists(sect, "origin")) - { - pEnt->setKV("origin", conf->getKey(sect, "origin")); - } - if(conf->keyExists(sect, "rotation")) - { - pEnt->setKV("rotation", conf->getKey(sect, "rotation")); - } - pEnt->setFlags(pEnt->getFlags() | EF_EXPORT | EF_LEVEL); - tmpList[i] = pEnt; - - if((i & 0xF) == 0 && pEventChannel) - { - ev.fProgress = (float)i / (float)ic * 0.1f; - pEventChannel->broadcastEvent(&ev); } } for(int i = 0; i < ic; ++i) { - sprintf(sect, "ent_%d", i); - if(!(pEnt = tmpList[i])) - { - continue; - } - int keyc = conf->getKeyCount(sect); - const char * key; - for(int j = 0; j < keyc; ++j) + sect = conf->getSectionName(i); + + if(sect[0] == '{' || (sect[0] == 'e' && sect[1] == 'n' && sect[2] == 't' && sect[3] == '_')) { - key = conf->getKeyName(sect, j); - if(strcmp(key, "classname") && strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation")) + if(!(pEnt = tmpList[i])) { - pEnt->setKV(key, conf->getKey(sect, key)); + continue; } - } - pEnt->onPostLoad(); + int keyc = conf->getKeyCount(sect); + const char *key; + for(int j = 0; j < keyc; ++j) + { + key = conf->getKeyName(sect, j); + if(strcmp(key, "classname") && strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation")) + { + pEnt->setKV(key, conf->getKey(sect, key)); + } + } + pEnt->onPostLoad(); - if(/*(i & 0xF) == 0 && */pEventChannel) + if(/*(i & 0xF) == 0 && */pEventChannel) + { + ev.fProgress = (float)i / (float)ic * 0.9f + 0.1f; + pEventChannel->broadcastEvent(&ev); + } + } + else { - ev.fProgress = (float)i / (float)ic * 0.9f + 0.1f; - pEventChannel->broadcastEvent(&ev); + tmpList[i] = NULL; } } } @@ -770,14 +779,14 @@ void CEntityManager::dumpList(int argc, const char **argv) filter = argv[1]; } - printf(COLOR_GREEN "-----------------------------------------------------\n" + printf(COLOR_GREEN "---------------------------------------------------------------------------------------\n" COLOR_GREEN " Filter: " COLOR_LGREEN "%s\n" COLOR_GREEN " Total count: " COLOR_LGREEN "%u\n" - COLOR_GREEN "-----------------------------------------------------\n" - " id | class | name |\n" - "------|--------------------------|------------------|\n" + COLOR_GREEN "---------------------------------------------------------------------------------------\n" + " guid | class | name |\n" + "----------------------------------------|--------------------------|------------------|\n" , filter, m_vEntList.size()); - + char tmp[64]; for(int i = 0, l = m_vEntList.size(); i < l; ++i) { CBaseEntity * pEnt = m_vEntList[i]; @@ -787,11 +796,12 @@ void CEntityManager::dumpList(int argc, const char **argv) } if(!filter[0] || strstr(pEnt->getClassName(), filter)) { - printf(" " COLOR_LGREEN "%-4d" COLOR_GREEN " | " COLOR_LGREEN "%-24s" COLOR_GREEN " | " COLOR_LGREEN "%-16s" COLOR_GREEN " |\n", i, pEnt->getClassName(), pEnt->getName()); + XGUIDToSting(*pEnt->getGUID(), tmp, sizeof(tmp)); + printf(" " COLOR_LGREEN "%s" COLOR_GREEN " | " COLOR_LGREEN "%-24s" COLOR_GREEN " | " COLOR_LGREEN "%-16s" COLOR_GREEN " |\n", tmp, pEnt->getClassName(), pEnt->getName()); } } - printf("-----------------------------------------------------\n" COLOR_RESET); + printf("---------------------------------------------------------------------------------------\n" COLOR_RESET); } void CEntityManager::entKV(int argc, const char **argv) @@ -811,6 +821,7 @@ void CEntityManager::entKV(int argc, const char **argv) if(id < 0 || (UINT)id >= m_vEntList.size() || !(pEnt = m_vEntList[id])) { printf(COLOR_LRED "Invalid entity id\n" COLOR_RESET); + return; } char buf[128]; buf[0] = 0; @@ -823,7 +834,7 @@ void CEntityManager::entKV(int argc, const char **argv) { for(int i = 0; i < pt->numFields; ++i) { - if(pt->pData[i].szKey) + if(pt->pData[i].szKey && !(pt->pData[i].flags & PDFF_INPUT)) { pEnt->getKV(pt->pData[i].szKey, buf, sizeof(buf)); printf("%s = %s\n", pt->pData[i].szKey, buf); @@ -859,6 +870,12 @@ CBaseEntity* CEntityManager::getById(ID id) return(pEnt ? (pEnt->getFlags() & EF_REMOVED ? NULL : pEnt) : NULL); } +CBaseEntity* CEntityManager::getByGUID(const XGUID &guid) +{ + CBaseEntity *const *ppEnt = m_mEnts.at(guid); + return(ppEnt ? *ppEnt : NULL); +} + CBaseEntity* CEntityManager::cloneEntity(CBaseEntity *pOther) { if(!pOther) @@ -928,6 +945,8 @@ void CEntityManager::sheduleDestroy(CBaseEntity *pEnt) { pEnt->_releaseEditorBoxes(); } + + pEnt->notifyPointers(); } void CEntityManager::setEditorMode(bool isEditor) @@ -1044,7 +1063,7 @@ CBaseline* CEntityManager::createBaseline(ID id) if(pEnt && (pEnt->getFlags() & EF_LEVEL) && !(pEnt->getFlags() & EF_REMOVED)) { CBaseline::ent_record_s record; - record.m_id = pEnt->getId(); + record.m_guid = *pEnt->getGUID(); record.m_sClassname = pEnt->getClassName(); pDefaults = CEntityFactoryMap::GetInstance()->getDefaults(pEnt->getClassName()); @@ -1095,23 +1114,31 @@ void CEntityManager::dispatchBaseline(CBaseline *pBaseline) return; } +#if 0 UINT idMax = pBaseline->m_aRecords[pBaseline->m_aRecords.size() - 1].m_id; if(m_vEntList.size() <= idMax) { m_vEntList.reserve(idMax + 1); } +#endif + + Array<CBaseEntity*> aPostLoadList(pBaseline->m_aRecords.size()); const AssotiativeArray<String, String>::Node *pNode; for(int i = 0, l = pBaseline->m_aRecords.size(); i < l; ++i) { CBaseline::ent_record_s *pRecord = &pBaseline->m_aRecords[i]; - if(!(pEnt = CREATE_ENTITY_NOPOST(pRecord->m_sClassname.c_str(), this))) + if(!(pEnt = CEntityFactoryMap::GetInstance()->create(pRecord->m_sClassname.c_str(), this, true, &pRecord->m_guid))) { printf(COLOR_LRED "Unable to load entity #%d, classname '%s' undefined\n" COLOR_RESET, i, pRecord->m_sClassname.c_str()); + aPostLoadList[i] = NULL; continue; } + aPostLoadList[i] = pEnt; + +#if 0 if(pEnt->getId() != pRecord->m_id) { m_vEntList[pEnt->getId()] = NULL; @@ -1144,6 +1171,7 @@ void CEntityManager::dispatchBaseline(CBaseline *pBaseline) m_vEntList[pRecord->m_id] = pEnt; pEnt->m_iId = pRecord->m_id; } +#endif if(pRecord->m_mProps.KeyExists("name", &pNode)) { @@ -1166,25 +1194,23 @@ void CEntityManager::dispatchBaseline(CBaseline *pBaseline) { CBaseline::ent_record_s *pRecord = &pBaseline->m_aRecords[i]; - pEnt = m_vEntList[pRecord->m_id]; - for(AssotiativeArray<String, String>::Iterator it = pRecord->m_mProps.begin(); it; it++) + if((pEnt = aPostLoadList[i])) { - key = it.first->c_str(); - - if(strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation")) + for(AssotiativeArray<String, String>::Iterator it = pRecord->m_mProps.begin(); it; it++) { - pEnt->setKV(key, it.second->c_str()); + key = it.first->c_str(); + + if(strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation")) + { + pEnt->setKV(key, it.second->c_str()); + } } } } - for(int i = 1, l = m_vEntList.size(); i < l; ++i) + for(UINT i = 0, l = aPostLoadList.size(); i < l; ++i) { - pEnt = m_vEntList[i]; - if(pEnt) - { - pEnt->onPostLoad(); - } + SAFE_CALL(aPostLoadList[i], onPostLoad); } } @@ -1256,3 +1282,88 @@ CBaseline *CEntityManager::deserializeBaseline(ID id, INETbuff *pBuf) return(pBaseline); } #endif + +void CEntityManager::registerWaitForGUID(const XGUID &guid, IEntityPointer *pPtr) +{ + ScopedSpinLock lock(m_slWaitingPointers); + + m_maWaitingPointers[guid].push_back(pPtr); +} + +void CEntityManager::unregisterWaitForGUID(const XGUID &guid, IEntityPointer *pPtr) +{ + ScopedSpinLock lock(m_slWaitingPointers); + + Array<IEntityPointer*> &list = m_maWaitingPointers[guid]; + + int idx = list.indexOf(pPtr); + assert(idx >= 0); + if(idx >= 0) + { + list.erase(idx); + } + if(!list.size()) + { + m_maWaitingPointers.erase(guid); + } +} + +void CEntityManager::notifyWaitForGUID(const XGUID &guid, CBaseEntity *pEnt) +{ + ScopedSpinLock lock(m_slWaitingPointers); + + const Map<XGUID, Array<IEntityPointer*>>::Node *pNode; + if(m_maWaitingPointers.KeyExists(guid, &pNode)) + { + Array<IEntityPointer*> &list = m_maWaitingPointers[guid]; + for(UINT i = 0, l = list.size(); i < l; ++i) + { + list[i]->onWaitDone(pEnt); + } + m_maWaitingPointers.erase(guid); + } +} + +void CEntityManager::registerWaitForName(const char *szName, CEntityList *pList) +{ + ScopedSpinLock lock(m_slWaitingLists); + + Array<CEntityList*> &list = m_maWaitingLists[szName]; + + assert(list.indexOf(pList) < 0); + + list.push_back(pList); +} +void CEntityManager::unregisterWaitForName(const char *szName, CEntityList *pList) +{ + ScopedSpinLock lock(m_slWaitingLists); + + Array<CEntityList*> &list = m_maWaitingLists[szName]; + + int idx = list.indexOf(pList); + assert(idx >= 0); + list[idx] = list[list.size() - 1]; + list.erase(list.size() - 1); +} + +void CEntityManager::onEntityNameChanged(CBaseEntity *pEnt, const char *szOldName, const char *szNewName) +{ + const Map<String, Array<CEntityList*>>::Node *pNode; + if(szOldName[0] && m_maWaitingLists.KeyExists(szOldName, &pNode)) + { + Array<CEntityList*> &list = *pNode->Val; + for(UINT i = 0, l = list.size(); i < l; ++i) + { + list[i]->removeEntity(pEnt); + } + } + + if(szNewName[0] && m_maWaitingLists.KeyExists(szNewName, &pNode)) + { + Array<CEntityList*> &list = *pNode->Val; + for(UINT i = 0, l = list.size(); i < l; ++i) + { + list[i]->addEntity(pEnt); + } + } +} diff --git a/source/game/EntityManager.h b/source/game/EntityManager.h index 03cd994d3df1453b7708ab743569c6cf8f2e90bd..1444c9dede3c96560b45583a38bbb7003234b437 100644 --- a/source/game/EntityManager.h +++ b/source/game/EntityManager.h @@ -89,6 +89,9 @@ class CEntityManager friend class CBaseEntity; friend class CEntityFactoryMap; + template<typename T> + friend class CEntityPointer; + friend class CEntityList; public: CEntityManager(); ~CEntityManager(); @@ -122,7 +125,8 @@ public: void entKV(int argc, const char **argv); int getCount(); - CBaseEntity* getById(ID id); + CBaseEntity *getById(ID id); + CBaseEntity *getByGUID(const XGUID &guid); CBaseEntity* cloneEntity(CBaseEntity *pEnt); @@ -143,16 +147,13 @@ public: #endif protected: - ID reg(CBaseEntity *pEnt); - void unreg(ID ent); - - void regSync(CBaseEntity *pEnt); - void unregSync(CBaseEntity *pEnt); + const XGUID* reg(CBaseEntity *pEnt, const XGUID *pGUID=NULL); + void unreg(CBaseEntity *pEnt); + Map<XGUID, CBaseEntity*> m_mEnts; Array<CBaseEntity*, 64> m_vEntList; - Array<CBaseEntity*, 64> m_vEntSyncList; Array<CBaseEntity*> m_vEntRemoveList; - Array<ID> m_vFreeIDs; + Array<UINT> m_vFreeIDs; Array<timeout_t> m_vTimeout; Array<timeout_t> m_vInterval; @@ -179,6 +180,20 @@ protected: private: void finalRemove(); + + Map<XGUID, Array<IEntityPointer*>> m_maWaitingPointers; + SpinLock m_slWaitingPointers; + void registerWaitForGUID(const XGUID &guid, IEntityPointer *pPtr); + void unregisterWaitForGUID(const XGUID &guid, IEntityPointer *pPtr); + void notifyWaitForGUID(const XGUID &guid, CBaseEntity *pEnt); + + bool m_isOldImported = false; + + SpinLock m_slWaitingLists; + Map<String, Array<CEntityList*>> m_maWaitingLists; + void registerWaitForName(const char *szName, CEntityList *pList); + void unregisterWaitForName(const char *szName, CEntityList *pList); + void onEntityNameChanged(CBaseEntity *pEnt, const char *szOldName, const char *szNewName); }; #endif diff --git a/source/game/EntityPointer.h b/source/game/EntityPointer.h new file mode 100644 index 0000000000000000000000000000000000000000..5a4a45efbda53ef29aaff41be5db1be3a67b8b66 --- /dev/null +++ b/source/game/EntityPointer.h @@ -0,0 +1,294 @@ +#ifndef __ENTITY_POINTER_H +#define __ENTITY_POINTER_H + +#include <gdefines.h> + +class IEntityPointer +{ + friend class CBaseEntity; + friend class CEntityManager; + +private: + virtual void onTargetRemoved(CBaseEntity *pEnt) = 0; + virtual void onWaitDone(CBaseEntity *pEnt) = 0; +}; + +class IEntityPointerEvent +{ +public: + virtual void onEvent(CBaseEntity *pEnt) = 0; +}; + +class CBaseEntity; +class CEntityManager; +template<typename T> +class CEntityPointer: public IEntityPointer +{ + DECLARE_CLASS_NOBASE(CEntityPointer); + friend class CBaseEntity; +public: + + CEntityPointer(): + m_pfnCheckEntityType(&CEntityFactoryMap::IsEntityOfClass<T>) + { + } + + ~CEntityPointer() + { + SAFE_CALL(m_pEntity, unregisterPointer, this); + + unregisterWait(); + } + + //! Установка имени или GUID связанного объекта + void setEntityName(const char *szName) + { + if(szName[0] == '{') + { + XGUID guid; + if(XGUIDFromString(&guid, szName)) + { + setEntityGUID(guid); + return; + } + } + + CBaseEntity *pEnt = ((CBaseEntity*)m_pThisEntity)->getEntByName(szName, NULL); + + if(pEnt) + { + if(m_pfnCheckEntityType(pEnt)) + { + setEntity(pEnt); + } + else + { + char tmp1[64], tmp2[64]; + XGUIDToSting(m_guid, tmp1, sizeof(tmp1)); + XGUIDToSting(*m_pThisEntity->getGUID(), tmp2, sizeof(tmp2)); + LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to link entity '%s' to entity '%s'. Invalid class %s\n", tmp1, tmp2, pEnt->getClassName()); + } + } + } + + //! Установка GUID + void setEntityGUID(const XGUID &guid) + { + CBaseEntity *pEnt = ((CBaseEntity*)m_pThisEntity)->m_pMgr->getByGUID(guid); + + if(pEnt) + { + if(m_pfnCheckEntityType(pEnt)) + { + setEntity(pEnt); + } + else + { + char tmp1[64], tmp2[64]; + XGUIDToSting(m_guid, tmp1, sizeof(tmp1)); + XGUIDToSting(*m_pThisEntity->getGUID(), tmp2, sizeof(tmp2)); + LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to link entity '%s' to entity '%s'. Invalid class %s\n", tmp1, tmp2, pEnt->getClassName()); + } + } + else + { + m_guid = guid; + registerWait(); + } + } + + //! Установка + void setEntity(T *pEnt) + { + if(m_pEntity != pEnt) + { + unregisterWait(); + + if(m_pEntity) + { + onLinkBroken(m_pEntity); + } + m_pEntity = pEnt; + if(pEnt) + { + m_guid = *pEnt->getGUID(); + } + else + { + m_guid = XGUID(); + } + if(m_pEntity) + { + onLinkEstablished(m_pEntity); + } + } + } + + //! Получение указателя на объект + T* getEntity() + { + return(m_pEntity); + } + + void getEntityName(char *szOutput, int iBufSize) + { + if(m_pEntity && m_pEntity->getName()[0]) + { + if(((CBaseEntity*)m_pThisEntity)->m_pMgr->countEntityByName(m_pEntity->getName()) == 1) + { + strncpy(szOutput, m_pEntity->getName(), iBufSize); + szOutput[iBufSize - 1] = 0; + return; + } + } + + if(m_guid == XGUID()) + { + if(iBufSize) + { + szOutput[0] = 0; + } + return; + } + + char tmp[64]; + XGUIDToSting(m_guid, tmp, sizeof(tmp)); + strncpy(szOutput, tmp, iBufSize); + szOutput[iBufSize - 1] = 0; + } + const XGUID& getGUID() + { + return(m_guid); + } + + T* operator->() + { + return(getEntity()); + } + operator T*() + { + return(getEntity()); + } + + CEntityPointer& operator=(T *pEnt) + { + setEntity(pEnt); + return(*this); + } + + //! Вызывается при разрушении связи (pEnt -- указатель на объект, если причиной разрыва связи стало не удаление объекта) + template<typename F> + void setLinkBrokenListener(void(F::*func)(T*)) + { + static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity"); + + m_pfnOnLinkBroken = (void(CBaseEntity::*)(T*))func; + } + + //! Вызывается при установке связи + template<typename F> + void setLinkEstablishedListener(void(F::*func)(T*)) + { + static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity"); + + m_pfnOnLinkEstablished = (void(CBaseEntity::*)(T*))func; + } + + void setLinkBrokenListener(IEntityPointerEvent *pFunc) + { + m_pOnLinkBroken = pFunc; + } + void setLinkEstablishedListener(IEntityPointerEvent *pFunc) + { + m_pOnLinkEstablished = pFunc; + } + +private: + XGUID m_guid; + T *m_pEntity = NULL; + CBaseEntity *m_pThisEntity = NULL; + bool(*m_pfnCheckEntityType)(CBaseEntity*) = NULL; + + void(CBaseEntity::*m_pfnOnLinkEstablished)(T*) = NULL; + void(CBaseEntity::*m_pfnOnLinkBroken)(T*) = NULL; + IEntityPointerEvent *m_pOnLinkEstablished = NULL; + IEntityPointerEvent *m_pOnLinkBroken = NULL; + + void init(CBaseEntity *pThisEntity) + { + m_pThisEntity = pThisEntity; + } + + void onLinkBroken(T *pOldEnt) + { + if(m_pfnOnLinkBroken) + { + (m_pThisEntity->*m_pfnOnLinkBroken)(pOldEnt); + } + if(m_pOnLinkBroken) + { + m_pOnLinkBroken->onEvent(pOldEnt); + } + } + void onLinkEstablished(T *pNewEnt) + { + pNewEnt->registerPointer(this); + + if(m_pfnOnLinkEstablished) + { + (m_pThisEntity->*m_pfnOnLinkEstablished)(pNewEnt); + } + if(m_pOnLinkEstablished) + { + m_pOnLinkEstablished->onEvent(pNewEnt); + } + } + void onTargetRemoved(CBaseEntity *pEnt) override + { + assert(pEnt == m_pEntity); + + onLinkBroken(NULL); + m_pEntity = NULL; + registerWait(); + } + + bool m_isWaiting = false; + void registerWait() + { + if(!m_isWaiting) + { + ((CBaseEntity*)m_pThisEntity)->m_pMgr->registerWaitForGUID(m_guid, this); + m_isWaiting = true; + } + } + void unregisterWait() + { + if(m_isWaiting) + { + ((CBaseEntity*)m_pThisEntity)->m_pMgr->unregisterWaitForGUID(m_guid, this); + m_isWaiting = false; + } + } + void onWaitDone(CBaseEntity *pEnt) override + { + assert(m_isWaiting); + + m_isWaiting = false; + + if(m_pfnCheckEntityType(pEnt)) + { + m_pEntity = (T*)pEnt; + + onLinkEstablished((T*)pEnt); + } + else + { + char tmp1[64], tmp2[64]; + XGUIDToSting(m_guid, tmp1, sizeof(tmp1)); + XGUIDToSting(*m_pThisEntity->getGUID(), tmp2, sizeof(tmp2)); + LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to link entity '%s' to entity '%s'. Invalid class %s\n", tmp1, tmp2, pEnt->getClassName()); + } + } +}; + +#endif diff --git a/source/game/EnvSkybox.cpp b/source/game/EnvSkybox.cpp index 6593000852727c61de2fd855bf5904e2e23e1279..2727e874a5bbe2bc3d2d6bc0a82968f9acd2f85a 100644 --- a/source/game/EnvSkybox.cpp +++ b/source/game/EnvSkybox.cpp @@ -24,8 +24,7 @@ END_PROPTABLE() REGISTER_ENTITY(CEnvSkybox, env_skybox); -CEnvSkybox::CEnvSkybox(CEntityManager *pMgr): - BaseClass(pMgr) +CEnvSkybox::CEnvSkybox() { m_pAmbient = (IXAmbient*)Core_GetIXCore()->getPluginManager()->getInterface(IXAMBIENT_GUID); } diff --git a/source/game/FuncRotating.cpp b/source/game/FuncRotating.cpp index 1daa3f06133138012981a0a1c6e3b3637d6c2671..a1bd46b4f5599eab645af5364d5b90c8ed71efaa 100644 --- a/source/game/FuncRotating.cpp +++ b/source/game/FuncRotating.cpp @@ -19,11 +19,6 @@ END_PROPTABLE() REGISTER_ENTITY(CFuncRotating, func_rotating); -CFuncRotating::CFuncRotating(CEntityManager * pMgr): - BaseClass(pMgr) -{ -} - CFuncRotating::~CFuncRotating() { if(ID_VALID(m_idThinkInterval)) @@ -63,7 +58,7 @@ void CFuncRotating::toggle(inputdata_t *pInputdata) void CFuncRotating::think(float fDt) { float3 fAxis = getOrient() * float3(0.0f, m_isReversed ? -1.0f : 1.0f, 0.0f); - setOrient(getOrient() * SMQuaternion(fAxis, m_fSpeed * fDt)); + setOrient((getOrient() * SMQuaternion(fAxis, m_fSpeed * fDt)).Normalize()); } void CFuncRotating::updateFlags() diff --git a/source/game/FuncRotating.h b/source/game/FuncRotating.h index 0caea4942bdfa1e6cf07ad31e44ac25f705780cb..8e4bf9127358cc6a3cf2577741f43b14510341b7 100644 --- a/source/game/FuncRotating.h +++ b/source/game/FuncRotating.h @@ -11,7 +11,7 @@ class CFuncRotating: public CPointEntity DECLARE_CLASS(CFuncRotating, CPointEntity); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CFuncRotating(); protected: diff --git a/source/game/FuncTrain.cpp b/source/game/FuncTrain.cpp index 531f72f549ceaa01a31032897e1206ffd9a88022..550adde21b3ef0d56f6aae4c3b13c06a5e518e18 100644 --- a/source/game/FuncTrain.cpp +++ b/source/game/FuncTrain.cpp @@ -16,20 +16,11 @@ BEGIN_PROPTABLE(CFuncTrain) DEFINE_FIELD_FLOAT(m_fSpeed, 0, "speed", "Move speed", EDITOR_TEXTFIELD) //! path_corner, с которого начнется движение - DEFINE_FIELD_ENTITY2(CPathCorner, m_pStartStop, 0, "start", "Start point", EDITOR_TEXTFIELD) + DEFINE_FIELD_ENTITY(CPathCorner, m_pStartStop, 0, "start", "Start point", EDITOR_TEXTFIELD) END_PROPTABLE() REGISTER_ENTITY(CFuncTrain, func_train); -CFuncTrain::CFuncTrain(CEntityManager * pMgr): - BaseClass(pMgr), - m_fSpeed(0.0f), - m_pStartStop(NULL), - m_bRunning(false), - m_fCurDist(0.0f) -{ -} - void CFuncTrain::onPostLoad() { BaseClass::onPostLoad(); diff --git a/source/game/FuncTrain.h b/source/game/FuncTrain.h index da64b30dc7f9411cb51431cddfcd71443a7f20b9..cc1630befc7d50117e8a94d1e57a27f1cd0d5299 100644 --- a/source/game/FuncTrain.h +++ b/source/game/FuncTrain.h @@ -12,8 +12,7 @@ See the license in LICENSE #define __FUNC_TRAIN_H #include "PointEntity.h" - -class CPathCorner; +#include "PathCorner.h" /*! Поезда класс \ingroup cpointentity @@ -23,7 +22,7 @@ class CFuncTrain: public CPointEntity DECLARE_CLASS(CFuncTrain, CPointEntity); DECLARE_PROPTABLE(); public: - CFuncTrain(CEntityManager * pMgr); + DECLARE_TRIVIAL_CONSTRUCTOR(); //! Остановить void stop(); @@ -31,24 +30,24 @@ public: void start(); protected: - void onPostLoad(); + void onPostLoad() override; void moveFunc(float dt); //! Начальная точка движения - CPathCorner * m_pStartStop; + CEntityPointer<CPathCorner> m_pStartStop; //! Текущая точка - CPathCorner * m_pCurStop; + CPathCorner *m_pCurStop = NULL; //! Скорость - float m_fSpeed; + float m_fSpeed = 0.0f; //! Текущая дистанция от начала пути - float m_fCurDist; + float m_fCurDist = 0.0f; //! Запущен ли - bool m_bRunning; + bool m_bRunning = false; //! ID таймера - ID m_iPostIval; + ID m_iPostIval = -1; }; #endif diff --git a/source/game/GameData.cpp b/source/game/GameData.cpp index a8d93d1dbd081d26ad4860c07ee4794ef7e3a781..a026c74de1a3cff78d487fe975251f5816b22150 100644 --- a/source/game/GameData.cpp +++ b/source/game/GameData.cpp @@ -573,7 +573,9 @@ GameData::GameData(HWND hWnd, bool isGame): CBaseEntity *pEnt; if(sscanf(argv[1], "%p", &pEnt)) { - LibReport(REPORT_MSG_LEVEL_WARNING, "Ent: id:%d; cls:'%s'; name:'%s'\n", pEnt->getId(), pEnt->getClassName(), pEnt->getName()); + char tmp[64]; + XGUIDToSting(*pEnt->getGUID(), tmp, sizeof(tmp)); + LibReport(REPORT_MSG_LEVEL_WARNING, "Ent: guid:%s; cls:'%s'; name:'%s'\n", tmp, pEnt->getClassName(), pEnt->getName()); } }); @@ -1322,7 +1324,7 @@ void GameData::render() , g_uFPS, pAdapterDesc->szDescription, - pAdapterDesc->sizeTotalMemory / 1024 / 1024, + (UINT)(pAdapterDesc->sizeTotalMemory / 1024 / 1024), (float)(pMemoryStats->sizeIndexBufferBytes + pMemoryStats->sizeRenderTargetBytes + pMemoryStats->sizeShaderConstBytes + pMemoryStats->sizeTextureBytes + pMemoryStats->sizeVertexBufferBytes) / 1024.0f / 1024.0f, (float)pMemoryStats->sizeTextureBytes / 1024.0f / 1024.0f, diff --git a/source/game/LightDirectional.cpp b/source/game/LightDirectional.cpp index 106198f4b5db20c06280b9f82e77c87aa9ef285d..d0ae981e3f5d54eb575c03b7fed1e3cf856cf073 100644 --- a/source/game/LightDirectional.cpp +++ b/source/game/LightDirectional.cpp @@ -14,14 +14,12 @@ BEGIN_PROPTABLE(CLightDirectional) //! Внешний угол DEFINE_FIELD_FLOAT(m_fOuterAngle, 0, "angle", "Outer angle", EDITOR_TEXTFIELD) //! Внутренний угол - DEFINE_FIELD_FLOAT(m_fInnerAngle, 0, "inner_angle", "Inner angle", EDITOR_TEXTFIELD) - //! Верхний радиус - DEFINE_FIELD_FLOAT(m_fRadiusTop, 0, "radius_top", "Radius top", EDITOR_TEXTFIELD) + DEFINE_FIELD_FLOATFN(m_fInnerAngle, 0, "inner_angle", "Inner angle", setInnerAngle, EDITOR_TEXTFIELD) END_PROPTABLE() REGISTER_ENTITY(CLightDirectional, light_directional); -CLightDirectional::CLightDirectional(CEntityManager *pMgr):BaseClass(pMgr) +CLightDirectional::CLightDirectional() { if(m_pLightSystem) { @@ -38,24 +36,30 @@ CLightDirectional::CLightDirectional(CEntityManager *pMgr):BaseClass(pMgr) } } -CLightDirectional::~CLightDirectional() +void CLightDirectional::setOrient(const SMQuaternion &q) { - mem_release(m_pLight); + BaseClass::setOrient(q); + + SAFE_CALL(m_pLightSpot, setDirection, q); } -void CLightDirectional::onSync() +void CLightDirectional::setOuterAngle(float fAngle) { - BaseClass::onSync(); + m_fOuterAngle = fAngle; - if(m_pLightSpot) - { - m_pLightSpot->setDirection(m_vOrientation); - m_pLightSpot->setOuterAngle(m_fOuterAngle); - m_pLightSpot->setInnerAngle(m_fInnerAngle); - } -#if 0 - if (SLight_GetTopRadius(m_idLight) != m_fRadiusTop) - SLight_SetTopRadius(m_idLight, m_fRadiusTop); -#endif + SAFE_CALL(m_pLightSpot, setOuterAngle, fAngle); } +float CLightDirectional::getOuterAngle() const +{ + return m_fOuterAngle; +} +void CLightDirectional::setInnerAngle(float fAngle) +{ + m_fInnerAngle = fAngle; + SAFE_CALL(m_pLightSpot, setInnerAngle, fAngle); +} +float CLightDirectional::getInnerAngle() const +{ + return m_fInnerAngle; +} diff --git a/source/game/LightDirectional.h b/source/game/LightDirectional.h index ba49edf9c54b301377216495d931f3c5d40dc660..c9e981194f2cda96e2c9ee649d8028dac928ee60 100644 --- a/source/game/LightDirectional.h +++ b/source/game/LightDirectional.h @@ -23,34 +23,17 @@ class CLightDirectional: public CBaseLight DECLARE_PROPTABLE(); public: DECLARE_CONSTRUCTOR(); - ~CLightDirectional(); - - void setOuterAngle(float fAngle) - { - m_fOuterAngle = fAngle; - } - float getOuterAngle() const - { - return m_fOuterAngle; - } - void setInnerAngle(float fAngle) - { - m_fInnerAngle = fAngle; - } - float getInnerAngle() const - { - return m_fInnerAngle; - } - - void setRadiusTop(float fRadiusTop) { m_fRadiusTop = fRadiusTop; }; - float getRadiusTop() const { return m_fRadiusTop; }; - -protected: - void onSync() override; + void setOuterAngle(float fAngle); + float getOuterAngle() const; + void setInnerAngle(float fAngle); + float getInnerAngle() const; + + void setOrient(const SMQuaternion &q) override; + +protected: float m_fOuterAngle = SM_PI * 0.4f; float m_fInnerAngle = SM_PI * 0.4f * 0.7f; - float m_fRadiusTop = 0.01f; IXLightSpot *m_pLightSpot = NULL; }; diff --git a/source/game/LightPoint.cpp b/source/game/LightPoint.cpp index 484a931ccfd3f23150a525975129c7839fc44cfb..dd08c1ea832595f2a281dd509762a18c416b5d2b 100644 --- a/source/game/LightPoint.cpp +++ b/source/game/LightPoint.cpp @@ -16,18 +16,12 @@ END_PROPTABLE() REGISTER_ENTITY(CLightPoint, light_point); -CLightPoint::CLightPoint(CEntityManager * pMgr):BaseClass(pMgr) +CLightPoint::CLightPoint() { if(m_pLightSystem) { m_pLight = m_pLightSystem->newPoint(); - //m_pLight->setDistance(m_fDist); m_pLight->setColor(float4(float3(m_vColor) * m_vColor.w, m_fDist)); } } -CLightPoint::~CLightPoint() -{ - mem_release(m_pLight); -} - diff --git a/source/game/LightPoint.h b/source/game/LightPoint.h index 5eeb62f983b5d4c08f003ef1ef51a3267a8d27a7..ecf3c0e0de384bebca697df97d30c428674a6855 100644 --- a/source/game/LightPoint.h +++ b/source/game/LightPoint.h @@ -23,7 +23,6 @@ class CLightPoint: public CBaseLight DECLARE_PROPTABLE(); public: DECLARE_CONSTRUCTOR(); - ~CLightPoint(); }; #endif diff --git a/source/game/LightSun.cpp b/source/game/LightSun.cpp index c52dec51121541b4f63ff89cb7686778ee561aea..e4e1817806e9ea42c56f218eeb7ba47357375bad 100644 --- a/source/game/LightSun.cpp +++ b/source/game/LightSun.cpp @@ -16,7 +16,7 @@ END_PROPTABLE() REGISTER_ENTITY(CLightSun, light_sun); -CLightSun::CLightSun(CEntityManager * pMgr):BaseClass(pMgr) +CLightSun::CLightSun() { if(m_pLightSystem) { @@ -25,17 +25,9 @@ CLightSun::CLightSun(CEntityManager * pMgr):BaseClass(pMgr) } } -CLightSun::~CLightSun() +void CLightSun::setOrient(const SMQuaternion &q) { - mem_release(m_pLight); -} - -void CLightSun::onSync() -{ - BaseClass::onSync(); + BaseClass::setOrient(q); - if(m_pSun) - { - m_pSun->setDirection(m_vOrientation); - } + SAFE_CALL(m_pSun, setDirection, q); } diff --git a/source/game/LightSun.h b/source/game/LightSun.h index 08f933975d23dc475c2d4eddb0dd1f79cab97216..291b36f8d95a92e9a279830266199bdeaac06884 100644 --- a/source/game/LightSun.h +++ b/source/game/LightSun.h @@ -23,10 +23,10 @@ class CLightSun: public CBaseLight DECLARE_PROPTABLE(); public: DECLARE_CONSTRUCTOR(); - ~CLightSun(); + + void setOrient(const SMQuaternion &q) override; protected: - void onSync() override; IXLightSun *m_pSun = NULL; }; diff --git a/source/game/LogicAuto.cpp b/source/game/LogicAuto.cpp index 332fd232fe16e518de08cebed35cef91684f9674..b01741d60975cc32d0857f1ccf092ca9b71fd5d0 100644 --- a/source/game/LogicAuto.cpp +++ b/source/game/LogicAuto.cpp @@ -20,11 +20,6 @@ END_PROPTABLE() REGISTER_ENTITY(CLogicAuto, logic_auto); -CLogicAuto::CLogicAuto(CEntityManager * pMgr): - BaseClass(pMgr) -{ -} - void CLogicAuto::activate() { SET_TIMEOUT(doTrigger, m_fDelay); diff --git a/source/game/LogicAuto.h b/source/game/LogicAuto.h index 445c91e327db420548225a5f9ede20ba92055226..2b6160e72b2120d9dc1379da37bcf90e844eac3f 100644 --- a/source/game/LogicAuto.h +++ b/source/game/LogicAuto.h @@ -8,7 +8,7 @@ class CLogicAuto: public CPointEntity DECLARE_CLASS(CLogicAuto, CPointEntity); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); void activate(); diff --git a/source/game/LogicRelay.cpp b/source/game/LogicRelay.cpp index d467453432c66dc692ae849f8582e5a5ba32cdef..b4e66070be51a06364a25150135ea0adddd62999 100644 --- a/source/game/LogicRelay.cpp +++ b/source/game/LogicRelay.cpp @@ -29,12 +29,6 @@ END_PROPTABLE() REGISTER_ENTITY(CLogicRelay, logic_relay); -CLogicRelay::CLogicRelay(CEntityManager * pMgr): - BaseClass(pMgr) -{ - m_isEnabled = true; -} - void CLogicRelay::turnOn(inputdata_t * pInputdata) { m_isEnabled = true; diff --git a/source/game/LogicRelay.h b/source/game/LogicRelay.h index 89afdd9b1bed934b806f17e4e05570b38c12d933..05d976e762ad1df29e41a1522858169dbe082bb6 100644 --- a/source/game/LogicRelay.h +++ b/source/game/LogicRelay.h @@ -1,12 +1,12 @@ /*********************************************************** -Copyright � Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018 +Copyright © Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018 See the license in LICENSE ***********************************************************/ /*! \file -���������� ���� +Логическое реле */ #ifndef __LOGIC_RELAY_H @@ -16,7 +16,7 @@ See the license in LICENSE #define LOGIC_START_DISABLED ENT_FLAG_0 -/*! ���������� ���� +/*! Логическое реле \ingroup cpointentity */ class CLogicRelay: public CPointEntity @@ -24,7 +24,7 @@ class CLogicRelay: public CPointEntity DECLARE_CLASS(CLogicRelay, CPointEntity); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); protected: void turnOn(inputdata_t * pInputdata); @@ -32,11 +32,11 @@ protected: void trigger(inputdata_t * pInputdata); void toggle(inputdata_t * pInputdata); - void onPostLoad(); + void onPostLoad() override; output_t m_onTrigger; - bool m_isEnabled; + bool m_isEnabled = true; }; #endif diff --git a/source/game/NPCBase.cpp b/source/game/NPCBase.cpp index 7b5e7d3ea8cbbb0de130b85cdd265bd78c8fb5d0..4b715957f582b42b85407598f81e67ce4b5427eb 100644 --- a/source/game/NPCBase.cpp +++ b/source/game/NPCBase.cpp @@ -44,8 +44,7 @@ protected: btCollisionObject* m_me; }; -CNPCBase::CNPCBase(CEntityManager * pMgr): - BaseClass(pMgr), +CNPCBase::CNPCBase(): m_idQuadGoingTo(-1), m_idFindPathInterval(-1), m_idPathFollowInterval(-1), @@ -112,6 +111,7 @@ void CNPCBase::setPos(const float3 &pos) float3 tpos = pos; m_idQuadCurr = SAIG_QuadGet(&tpos, true); +#if 0 if(ID_VALID(m_idQuadCurr)) { if(SAIG_QuadGetState(m_idQuadCurr) == AIQUAD_STATE_FREE) @@ -128,13 +128,13 @@ void CNPCBase::setPos(const float3 &pos) SAIG_QuadSetState(m_idQuadCurr, AIQUAD_STATE_BUSY); SAIG_QuadSetStateWho(m_idQuadCurr, getId()); SAIG_QuadGetPos(m_idQuadCurr, &tpos); - tpos.y += 0.7f; - setPos(tpos); + tpos.y += 0.7f; + setPos(tpos); return; - } } } - + } +#endif if(ID_VALID(m_idQuadGoingTo)) { m_idQuadGoingTo = -1; @@ -224,7 +224,7 @@ void CNPCBase::findPathThinker(float fDelta) m_aPathQuads.resize(iCount); SAIG_GridGetPath(m_idQueueFindPath, &(m_aPathQuads[0]), m_aPathQuads.size(), true); SAIG_GridSetColorArr(&(m_aPathQuads[0]), m_ulColor, m_aPathQuads.size()); - m_vLastPathPos = m_vPosition; + m_vLastPathPos = getPos(); m_idQueueFindPath = -1; CLEAR_INTERVAL(m_idFindPathInterval); @@ -256,7 +256,7 @@ void CNPCBase::pathFollowThinker(float fDelta) float fDirLen = fMoveSpeed * fDelta; float fMovDirLen = fDirLen; - float fDist2 = SMVector3Length2(m_vLastPathPos - m_vPosition); // Расстояние между актуальным положением NPC и точкой следования + float fDist2 = SMVector3Length2(m_vLastPathPos - getPos()); // Расстояние между актуальным положением NPC и точкой следования if(m_iCurrQuaidInPath < (int)m_aPathQuads.size()) { @@ -296,7 +296,7 @@ void CNPCBase::pathFollowThinker(float fDelta) //m_vPosition = m_vLastPathPos; //m_pGhostObject->getWorldTransform().setOrigin(F3_BTVEC(m_vLastPathPos)); - float3 vDir = m_vLastPathPos - m_vPosition; + float3 vDir = m_vLastPathPos - getPos(); float fDist = SMVector3Length(vDir); vDir /= fDist; @@ -315,9 +315,9 @@ void CNPCBase::pathFollowThinker(float fDelta) //SPhysics_GetDynWorld()->getDebugDrawer()->drawLine(F3_BTVEC(m_vLastPathPos), F3_BTVEC(m_vPosition), btVector3(0, 1, 0)); m_qOrientTo = SMQuaternion(NPC_BASE_DIR, vDir); - setOrient(SMquaternionSlerp(m_vOrientation, m_qOrientTo, clampf(fDelta, 0.1f, 1.0f))); + setOrient(SMquaternionSlerp(getOrient(), m_qOrientTo, clampf(fDelta, 0.1f, 1.0f))); - if(SMVector3Length(m_vPosition - m_vLastFramePos) < fDelta * fMoveSpeed * 0.1f) // застряли, похоже + if(SMVector3Length(getPos() - m_vLastFramePos) < fDelta * fMoveSpeed * 0.1f) // застряли, похоже { if(bMayJump) { @@ -346,7 +346,7 @@ void CNPCBase::pathFollowThinker(float fDelta) { m_iStuckCount = 0; } - m_vLastFramePos = m_vPosition; + m_vLastFramePos = getPos(); // это последний, дошли! if(m_iCurrQuaidInPath >= (int)m_aPathQuads.size() && fDist < 0.5) @@ -568,6 +568,8 @@ void CNPCBase::stopOrientAt() } } + +#if 0 void CNPCBase::onSync() { BaseClass::onSync(); @@ -589,7 +591,6 @@ void CNPCBase::onSync() //SMQuaternion rot = m_pHeadEnt->getOrient(); //SPhysics_GetDynWorld()->getDebugDrawer()->drawLine(F3_BTVEC(m_pHeadEnt->getPos()), F3_BTVEC(m_pHeadEnt->getPos() + (rot * float3(0,0,1))), btVector3(1,1,1)); } -#if 0 void CNPCBase::gridCheckBeyond() { //находим ближайший квад к текущей позиции нпс diff --git a/source/game/NPCBase.h b/source/game/NPCBase.h index 20cc652c05ca4b7e38d9e1c84466c7f43b730d22..1f4ef794fd983bcc6033c6975dd769c00a05dbca 100644 --- a/source/game/NPCBase.h +++ b/source/game/NPCBase.h @@ -47,10 +47,8 @@ class CNPCBase: public CBaseCharacter DECLARE_PROPTABLE(); public: - SX_ALIGNED_OP_MEM(); - - CNPCBase(CEntityManager * pMgr); + DECLARE_CONSTRUCTOR(); ~CNPCBase(); ID getAIQuad(); //!< id квада аи сетки на котором стоит нпс @@ -74,8 +72,6 @@ public: void stopOrientAt(); protected: - void onSync(); - //void think(float fDelta); //! процедура проверки найденности пути diff --git a/source/game/NPCZombie.cpp b/source/game/NPCZombie.cpp index a021c37327bb63f1f24d96414f86a134b65e60f0..8359a23ff5f8fed36213a69dfcaefa92301ee7c0 100644 --- a/source/game/NPCZombie.cpp +++ b/source/game/NPCZombie.cpp @@ -21,8 +21,7 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CNPCZombie, npc_zombie); -CNPCZombie::CNPCZombie(CEntityManager * pMgr) : - BaseClass(pMgr), +CNPCZombie::CNPCZombie(): m_stateDanger(NPC_STATE_DANGER_CALM), m_iObserveRotateStep(0), m_idRotateInterval(-1), @@ -70,13 +69,11 @@ void CNPCZombie::onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor) m_pActiveTool->stopAction(); } -void CNPCZombie::onSync() +void CNPCZombie::setPos(const float3 &pos) { - BaseClass::onSync(); - - SAFE_CALL(m_pSndIdle, setWorldPos, getPos()); - SAFE_CALL(m_pSndIdle2, setWorldPos, getPos()); - SAFE_CALL(m_pSndDeath, setWorldPos, getPos()); + SAFE_CALL(m_pSndIdle, setWorldPos, pos); + SAFE_CALL(m_pSndIdle2, setWorldPos, pos); + SAFE_CALL(m_pSndDeath, setWorldPos, pos); } void CNPCZombie::rotateThink(float dt) @@ -294,9 +291,12 @@ void CNPCZombie::randWalk() {*/ float rndradius = randf(20.f, 40.f)*0.5f; float3 rndpos; - rndpos.x = m_vPosition.x + randf(-rndradius, rndradius); - rndpos.y = m_vPosition.y + randf(-rndradius, rndradius); - rndpos.z = m_vPosition.z + randf(-rndradius, rndradius); + + float3 vPos = getPos(); + + rndpos.x = vPos.x + randf(-rndradius, rndradius); + rndpos.y = vPos.y + randf(-rndradius, rndradius); + rndpos.z = vPos.z + randf(-rndradius, rndradius); //Core_RFloat3Get(G_RI_FLOAT3_OBSERVER_POSITION, &rndpos); diff --git a/source/game/NPCZombie.h b/source/game/NPCZombie.h index 42b26a47ad8fac9469b25b3361df9e808c1fd5e7..44253c35f0ca667a0f75bc70c452d1e6d3c02554 100644 --- a/source/game/NPCZombie.h +++ b/source/game/NPCZombie.h @@ -33,17 +33,16 @@ class CNPCZombie: public CNPCBase DECLARE_PROPTABLE(); public: - CNPCZombie(CEntityManager * pMgr); + DECLARE_CONSTRUCTOR(); ~CNPCZombie(); void onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor); void dispatchDamage(CTakeDamageInfo &takeDamageInfo); -protected: - - void onSync(); + void setPos(const float3 & pos) override; +protected: void think(float fDelta); void removeThis(float fDelta); diff --git a/source/game/PathCorner.cpp b/source/game/PathCorner.cpp index 726020c1186313f88e42fcf97af542d692896a70..a421a920c563f029f206284a56998d97e687eff8 100644 --- a/source/game/PathCorner.cpp +++ b/source/game/PathCorner.cpp @@ -21,20 +21,17 @@ BEGIN_PROPTABLE(CPathCorner) DEFINE_FIELD_FLOAT(m_fNewSpeed, 0, "speed", "New speed", EDITOR_TEXTFIELD) //! Следующая точка пути - DEFINE_FIELD_ENTITY2FN(CPathCorner, m_pNextStop, 0, "next", "Next stop", setNextPoint, EDITOR_TEXTFIELD) + DEFINE_FIELD_ENTITY(CPathCorner, m_pNextStop, 0, "next", "Next stop", EDITOR_TEXTFIELD) + + DEFINE_FIELD_ENTITY(CPathCorner, m_pPrevStop, PDFF_NOEDIT | PDFF_NOEXPORT, "prev", "Prev stop", EDITOR_NONE) END_PROPTABLE() REGISTER_ENTITY(CPathCorner, path_corner); -CPathCorner::CPathCorner(CEntityManager * pMgr): - BaseClass(pMgr), - m_type(PCT_SPLINE), - m_fNewSpeed(0.0f), - m_pNextStop(NULL), - m_pPrevStop(NULL), - m_fLength(0.0f) +CPathCorner::CPathCorner() { + m_pNextStop.setLinkEstablishedListener(&CPathCorner::setNextPoint); } CPathCorner::~CPathCorner() @@ -109,7 +106,7 @@ void CPathCorner::recalcPath(float t) pCur->m_fLength = SMVector3Length(vec); //pCur->m_fLength = 1.0f; pCur->m_fH = (float3)(vec / pCur->m_fLength); - pCur->m_fCoeffsA = pCur->m_pNextStop->m_vPosition; + pCur->m_fCoeffsA = pCur->m_pNextStop->getPos(); pCur = pNext; } @@ -192,7 +189,7 @@ float3 CPathCorner::getPoint(float dist) } else { - return(m_vPosition); + return(getPos()); } } else if(dist > m_fLength) @@ -203,7 +200,7 @@ float3 CPathCorner::getPoint(float dist) } else { - return(m_vPosition); + return(getPos()); } } dist -= m_fLength; @@ -220,7 +217,7 @@ SMQuaternion CPathCorner::getRot(float dist) } else { - return(m_vOrientation); + return(getOrient()); } } else if(dist > m_fLength) @@ -231,16 +228,16 @@ SMQuaternion CPathCorner::getRot(float dist) } else { - return(m_vOrientation); + return(getOrient()); } } if(m_pNextStop) { - return(SMquaternionSlerp(m_vOrientation, m_pNextStop->m_vOrientation, (dist / m_fLength)*(dist / m_fLength) * (3.0f - 2.0f * (dist / m_fLength)))); + return(SMquaternionSlerp(getOrient(), m_pNextStop->getOrient(), (dist / m_fLength)*(dist / m_fLength) * (3.0f - 2.0f * (dist / m_fLength)))); } else { - return(m_vOrientation); + return(getOrient()); } } diff --git a/source/game/PathCorner.h b/source/game/PathCorner.h index 6336ef2dad3ff81a54c49d196367b0d2583f97b8..2e67c98e19964cea56e672c6ae4c5d6973af0e9c 100644 --- a/source/game/PathCorner.h +++ b/source/game/PathCorner.h @@ -31,7 +31,7 @@ class CPathCorner: public CPointEntity DECLARE_CLASS(CPathCorner, CPointEntity); DECLARE_PROPTABLE(); public: - CPathCorner(CEntityManager * pMgr); + DECLARE_CONSTRUCTOR(); ~CPathCorner(); //! получает координаты точки на пути на расстоянии dist от начала @@ -55,32 +55,32 @@ public: protected: //! Пересчитывает путь void recalcPath(float t); - void onPostLoad(); + void onPostLoad() override; //! Тип сглаживания - int m_type; + int m_type = PCT_SPLINE; //! Новая скорость поезда - float m_fNewSpeed; + float m_fNewSpeed = 0.0f; //! Длина сегмента пути - float m_fLength; + float m_fLength = 0.0f; //! Для расчета сплайна @{ - float3_t m_fH; + float3_t m_fH = 0.0f; - float3_t m_fCoeffsA; - float3_t m_fCoeffsB; - float3_t m_fCoeffsC; - float3_t m_fCoeffsD; + float3_t m_fCoeffsA = 0.0f; + float3_t m_fCoeffsB = 0.0f; + float3_t m_fCoeffsC = 0.0f; + float3_t m_fCoeffsD = 0.0f; - float3_t m_fDelta; - float3_t m_fLambda; + float3_t m_fDelta = 0.0f; + float3_t m_fLambda = 0.0f; //! @} //! Следующая точка - CPathCorner * m_pNextStop; + CEntityPointer<CPathCorner> m_pNextStop; //! Предыдущая точка - CPathCorner * m_pPrevStop; + CEntityPointer<CPathCorner> m_pPrevStop; }; #endif diff --git a/source/game/Player.cpp b/source/game/Player.cpp index ea356e0841ba38ef74824cd6ccfdb20723f9ce8c..d2f2782e21a8c0f987c60a844ce0a48a34549815 100644 --- a/source/game/Player.cpp +++ b/source/game/Player.cpp @@ -7,7 +7,6 @@ See the license in LICENSE #include <input/sxinput.h> #include "Player.h" #include "LightDirectional.h" -#include "BaseTool.h" #include "BaseAmmo.h" #include "BaseWeapon.h" @@ -29,17 +28,11 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CPlayer, player); -CPlayer::CPlayer(CEntityManager * pMgr): - BaseClass(pMgr), - m_canJump(true), - m_fViewbobStep(0.0f), - m_fViewbobY(0.0f), - m_fViewbobStrafe(float3_t(0, 0, 0)), - m_vWpnShakeAngles(float3_t(0.0f, 0.0f, 0.0f)), - m_iDSM(DSM_NONE), - m_bCanRespawn(false) +void CPlayer::onPostLoad() { - m_pCamera = (CPointCamera*)CREATE_ENTITY("point_camera", pMgr); + BaseClass::onPostLoad(); + + m_pCamera = (CPointCamera*)CREATE_ENTITY("point_camera", m_pMgr); m_pCamera->setPos(m_pHeadEnt->getPos()); m_pCamera->setParent(m_pHeadEnt); @@ -102,7 +95,8 @@ void CPlayer::updateInput(float dt) return; } - m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles * 0.4f); + // m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles * 0.4f); + m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles / (1.05f + dt)); if(!*editor_mode || SSInput_GetKeyState(SIM_LBUTTON)) { @@ -209,7 +203,7 @@ void CPlayer::updateInput(float dt) if(m_uMoveDir & PM_OBSERVER) { - m_vPosition = (float3)(m_vPosition + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt)); + setPos(getPos() + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt)); } else { @@ -298,7 +292,7 @@ void CPlayer::updateInput(float dt) float sin = cosf(m_fViewbobStep * 2.0f); float sin2 = sinf(m_fViewbobStep); float3 vec(1.0f, 0.0f, 0.0f); - vec = m_vOrientation * vec; + vec = getOrient() * vec; m_fViewbobY = (sin * ((m_uMoveDir & PM_RUN) ? *cl_bob_run_y : *cl_bob_walk_y)); m_fViewbobStrafe = (float3)(vec * sin2 * ((m_uMoveDir & PM_RUN) ? *cl_bob_run_x : *cl_bob_walk_x)); //m_vOrientation = SMQuaternion(SMToRadian(10) * sinf(m_fViewbobStep), 'z') * m_vOrientation; @@ -316,10 +310,12 @@ void CPlayer::updateInput(float dt) m_vWpnShakeAngles.x = clampf(m_vWpnShakeAngles.x, -fMaxAng, fMaxAng); } - GameData::m_pHUDcontroller->setPlayerPos(m_vPosition); + GameData::m_pHUDcontroller->setPlayerPos(getPos()); } + m_pActiveTool->setShakeRotation(SMQuaternion(m_vWpnShakeAngles.x, 'x') * SMQuaternion(m_vWpnShakeAngles.y, 'y') * SMQuaternion(m_vWpnShakeAngles.z, 'z')); + #ifndef _SERVER if(*grab_cursor && (!*editor_mode || SSInput_GetKeyState(SIM_LBUTTON))) { @@ -352,17 +348,17 @@ CPointCamera * CPlayer::getCamera() return(m_pCamera); } -void CPlayer::onSync() +float3 CPlayer::getHeadOffset() { - BaseClass::onSync(); + float3 vOffset = BaseClass::getHeadOffset(); - if(m_uMoveDir & PM_OBSERVER) + if(!(m_uMoveDir & PM_OBSERVER)) { - return; + vOffset.y += m_fViewbobY; + vOffset += m_fViewbobStrafe; } - m_vPosition.y += m_fViewbobY; - m_vPosition = (float3)(m_vPosition + m_fViewbobStrafe); + return(vOffset); } void CPlayer::observe() @@ -391,7 +387,7 @@ void CPlayer::spawn() m_pCrosshair->enable(); GameData::m_pHUDcontroller->setPlayerRot(m_vPitchYawRoll); - GameData::m_pHUDcontroller->setPlayerPos(m_vPosition); + GameData::m_pHUDcontroller->setPlayerPos(getPos()); GameData::m_pHUDcontroller->setPlayerHealth(m_fHealth); return; } diff --git a/source/game/Player.h b/source/game/Player.h index 22087408352d2eed90be18da590c10a9e7967650..9b4f3f7cc804a81de74695db152a44e3b346dcff 100644 --- a/source/game/Player.h +++ b/source/game/Player.h @@ -19,6 +19,7 @@ See the license in LICENSE #include "BaseCharacter.h" #include "PointCamera.h" #include "crosshair.h" +#include "BaseTool.h" //! Класс игрока \ingroup cbaseanimating class CPlayer: public CBaseCharacter @@ -26,7 +27,7 @@ class CPlayer: public CBaseCharacter DECLARE_CLASS(CPlayer, CBaseCharacter); DECLARE_PROPTABLE(); public: - CPlayer(CEntityManager * pMgr); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CPlayer(); //! Возвращает камеру игрока @@ -45,8 +46,6 @@ public: //! Обновляет инпут от игрока virtual void updateInput(float dt); - - void onSync(); //! Получает смещения для задержки движения модели оружия при вращении игрока float3_t & getWeaponDeltaAngles(); @@ -84,24 +83,28 @@ protected: ID m_iUpdIval; //! Может ли прыгать - bool m_canJump; + bool m_canJump = true; //! Для качания камеры @{ - float m_fViewbobStep; - float m_fViewbobY; - float3_t m_fViewbobStrafe; - float3_t m_vWpnShakeAngles; + float m_fViewbobStep = 0.0f; + float m_fViewbobY = 0.0f; + float3_t m_fViewbobStrafe = float3_t(0.0f, 0.0f, 0.0f); + float3_t m_vWpnShakeAngles = float3_t(0.0f, 0.0f, 0.0f); //! @} - int m_iDSM; + int m_iDSM = DSM_NONE; //! Перекрестие - CCrosshair * m_pCrosshair; + CCrosshair *m_pCrosshair = NULL; //! Обновляет разброса значение virtual void updateSpread(float dt); - bool m_bCanRespawn; + void onPostLoad() override; + + bool m_bCanRespawn = false; + + float3 getHeadOffset() override; }; #endif diff --git a/source/game/PointCamera.cpp b/source/game/PointCamera.cpp index 77bfcee3e82b15f143fe861596978305702eab2c..addfa707908944d2731e4aeb19259434fcdd976e 100644 --- a/source/game/PointCamera.cpp +++ b/source/game/PointCamera.cpp @@ -16,8 +16,7 @@ END_PROPTABLE() REGISTER_ENTITY(CPointCamera, point_camera); -CPointCamera::CPointCamera(CEntityManager * pMgr): - BaseClass(pMgr) +CPointCamera::CPointCamera() { const float * r_default_fov = GET_PCVAR_FLOAT("r_default_fov"); m_pSXC = SGCore_CrCamera(); @@ -29,15 +28,21 @@ CPointCamera::~CPointCamera() mem_release(m_pSXC); } -ICamera * CPointCamera::getCamera() +ICamera* CPointCamera::getCamera() { return(m_pSXC); } -void CPointCamera::onSync() +void CPointCamera::setPos(const float3 &pos) { - BaseClass::onSync(); + BaseClass::setPos(pos); - m_pSXC->setPosition(m_vPosition); - m_pSXC->setOrientation(m_vOrientation); + m_pSXC->setPosition(pos); +} + +void CPointCamera::setOrient(const SMQuaternion &q) +{ + BaseClass::setOrient(q); + + m_pSXC->setOrientation(q); } diff --git a/source/game/PointCamera.h b/source/game/PointCamera.h index ed21f4fb31be8cf9964d554c2bbdc8728f41ffd3..154a81e4a830e28db6e7a36499457af4a93d8476 100644 --- a/source/game/PointCamera.h +++ b/source/game/PointCamera.h @@ -26,16 +26,17 @@ class CPointCamera: public CPointEntity DECLARE_CLASS(CPointCamera, CPointEntity); DECLARE_PROPTABLE(); public: - CPointCamera(CEntityManager * pMgr); + DECLARE_CONSTRUCTOR(); ~CPointCamera(); //! Возвращает объект камеры из графической либы - ICamera * getCamera(); + ICamera* getCamera(); -protected: - ICamera * m_pSXC; + void setPos(const float3 &pos) override; + void setOrient(const SMQuaternion &q) override; - void onSync(); +protected: + ICamera *m_pSXC; }; #endif diff --git a/source/game/PropBreakable.h b/source/game/PropBreakable.h index 5209a0c5275823d8accd370a985cec2d11fef847..bc00d2aa0906c95eff56a981a9293acf87b2e49b 100644 --- a/source/game/PropBreakable.h +++ b/source/game/PropBreakable.h @@ -24,7 +24,7 @@ class CPropBreakable: public CPropDynamic public: DECLARE_TRIVIAL_CONSTRUCTOR(); ~CPropBreakable(); - virtual void onPostLoad(); + void onPostLoad() override; void onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor); protected: diff --git a/source/game/PropButton.cpp b/source/game/PropButton.cpp index aecf975d4177815cb4b49ae0449e97be356c8484..730847d5e9f311569bdef273e48608ecca405186 100644 --- a/source/game/PropButton.cpp +++ b/source/game/PropButton.cpp @@ -45,14 +45,6 @@ END_PROPTABLE() REGISTER_ENTITY(CPropButton, prop_button); -CPropButton::CPropButton(CEntityManager * pMgr): - BaseClass(pMgr) -{ - m_isEnabled = true; - m_isToggleable = false; - m_bState = false; -} - void CPropButton::turnOn(inputdata_t * pInputdata) { m_isEnabled = true; diff --git a/source/game/PropButton.h b/source/game/PropButton.h index 3a4315000269056a647d82dc6d95a3f4e081b815..887d7b6d507869d52eaa5257b52434f7daecfef2 100644 --- a/source/game/PropButton.h +++ b/source/game/PropButton.h @@ -1,12 +1,12 @@ /*********************************************************** -Copyright � Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018 +Copyright © Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018 See the license in LICENSE ***********************************************************/ /*! \file -������ +Кнопка */ #ifndef __PROP_BUTTON_H @@ -18,7 +18,7 @@ See the license in LICENSE #define BUTTON_TOGGLEABLE ENT_FLAG_1 #define BUTTON_START_PRESSED ENT_FLAG_2 -/*! ������ +/*! Кнопка \ingroup cbaseanimating */ class CPropButton: public CPropDynamic @@ -26,19 +26,19 @@ class CPropButton: public CPropDynamic DECLARE_CLASS(CPropButton, CPropDynamic); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); void onUse(CBaseEntity *pUser); protected: - void turnOn(inputdata_t * pInputdata); - void turnOff(inputdata_t * pInputdata); - void press(inputdata_t * pInputdata); - void pushUp(inputdata_t * pInputdata); - void pushDown(inputdata_t * pInputdata); - void toggle(inputdata_t * pInputdata); + void turnOn(inputdata_t *pInputdata); + void turnOff(inputdata_t *pInputdata); + void press(inputdata_t *pInputdata); + void pushUp(inputdata_t *pInputdata); + void pushDown(inputdata_t *pInputdata); + void toggle(inputdata_t *pInputdata); - void onPostLoad(); + void onPostLoad() override; output_t m_onPressed; output_t m_onPushUp; @@ -46,10 +46,10 @@ protected: output_t m_onToggle; output_t m_onUseDisabled; - bool m_isEnabled; - bool m_isToggleable; + bool m_isEnabled = true; + bool m_isToggleable = false; - bool m_bState; + bool m_bState = false; }; #endif diff --git a/source/game/PropDebris.cpp b/source/game/PropDebris.cpp index 210fe2329e802889b5f049e292bc881e769b8cdf..f6137b7c81343a0355e8a6d69b01d8766cbf2a7a 100644 --- a/source/game/PropDebris.cpp +++ b/source/game/PropDebris.cpp @@ -15,7 +15,7 @@ END_PROPTABLE() REGISTER_ENTITY(CPropDebris, prop_debris); -CPropDebris::CPropDebris(CEntityManager *pMgr):BaseClass(pMgr) +CPropDebris::CPropDebris() { setCollisionGroup(CG_DEBRIS); } @@ -30,7 +30,8 @@ void CPropDebris::sheduleRemove() void CPropDebris::checkRemove(float fDT) { - //@TODO: Reimplement me + REMOVE_ENTITY(this); + // TODO Reimplement me #if 0 if(!m_pAnimPlayer->isVisibleFor(SX_ANIM_DEFAULT_VISCALCOBJ)) { diff --git a/source/game/PropDoor.cpp b/source/game/PropDoor.cpp index e07700ea403f76af505764f7b86fcbc5b183e91a..f9532aa51acd53f1e32e08de39678ede64a37b69 100644 --- a/source/game/PropDoor.cpp +++ b/source/game/PropDoor.cpp @@ -68,10 +68,6 @@ END_PROPTABLE() REGISTER_ENTITY(CPropDoor, prop_door); -CPropDoor::CPropDoor(CEntityManager *pMgr):BaseClass(pMgr) -{ -} - CPropDoor::~CPropDoor() { releasePhysics(); @@ -221,8 +217,11 @@ void CPropDoor::createPhysBody() { if(m_pCollideShape) { + float3 vPos = getPos(); + SMQuaternion qRot = getOrient(); + m_pGhostObject = new btPairCachingGhostObject(); - m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition))); + m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos))); m_pGhostObject->setCollisionShape(m_pCollideShape); m_pGhostObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); m_pGhostObject->setUserPointer(this); @@ -269,7 +268,7 @@ void CPropDoor::createPhysBody() m_fDistance = fMax - fMin; } - m_vStartPos = m_vPosition; + m_vStartPos = vPos; m_vEndPos = (float3)(m_vStartPos + vDir * m_fDistance); if(m_bState) diff --git a/source/game/PropDoor.h b/source/game/PropDoor.h index 28ce7e953bf7d8f2cd99a1d082bb357504267a29..c239e8c0c76625ee089b2fe41d8062eac252d54e 100644 --- a/source/game/PropDoor.h +++ b/source/game/PropDoor.h @@ -33,9 +33,10 @@ class CPropDoor: public CPropDynamic DECLARE_CLASS(CPropDoor, CPropDynamic); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CPropDoor(); - virtual void onPostLoad(); + + void onPostLoad() override; void onUse(CBaseEntity *pUser); diff --git a/source/game/PropStatic.cpp b/source/game/PropStatic.cpp index 75ca87b30bea5099135ebcd984ba449030f7ab8f..4305c48ba0f79244e6f614ddac5980e719a66553 100644 --- a/source/game/PropStatic.cpp +++ b/source/game/PropStatic.cpp @@ -18,10 +18,9 @@ BEGIN_PROPTABLE(CPropStatic) EDITOR_COMBO_END() END_PROPTABLE() -REGISTER_ENTITY_NOSYNC(CPropStatic, prop_static); +REGISTER_ENTITY(CPropStatic, prop_static); -CPropStatic::CPropStatic(CEntityManager *pMgr): - BaseClass(pMgr) +CPropStatic::CPropStatic() { m_isStatic = true; } @@ -35,7 +34,10 @@ void CPropStatic::createPhysBody() { if(m_pCollideShape) { - btDefaultMotionState * motionState = new btDefaultMotionState(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition))); + float3 vPos = getPos(); + SMQuaternion qRot = getOrient(); + + btDefaultMotionState * motionState = new btDefaultMotionState(btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos))); btRigidBody::btRigidBodyConstructionInfo rigidBodyCI( 0, // mass motionState, // initial position diff --git a/source/game/SoundEmitter.cpp b/source/game/SoundEmitter.cpp index 1ec6f3fc69b606de4e44cbb9f908e7751667da91..23a641f76bff401bb8dad4c77203432300b5c55c 100644 --- a/source/game/SoundEmitter.cpp +++ b/source/game/SoundEmitter.cpp @@ -15,10 +15,10 @@ BEGIN_PROPTABLE(CSoundEmitter) DEFINE_FIELD_STRINGFN(m_szPathSound, 0, "file", "Sound file", setSound, EDITOR_SOUND) //! Громкость - DEFINE_FIELD_FLOAT(m_fVolume, 0, "volume", "Volume", EDITOR_TEXTFIELD) + DEFINE_FIELD_FLOATFN(m_fVolume, 0, "volume", "Volume", setVolume, EDITOR_TEXTFIELD) //! Дистанция слышимости - DEFINE_FIELD_FLOAT(m_fDist, 0, "distance", "Hearing distance", EDITOR_TEXTFIELD) + DEFINE_FIELD_FLOATFN(m_fDist, 0, "distance", "Hearing distance", setDistance, EDITOR_TEXTFIELD) //! Включить DEFINE_INPUT(play, "play", "Play", PDF_NONE) @@ -39,12 +39,6 @@ REGISTER_ENTITY(CSoundEmitter, sound_emitter); //########################################################################## -CSoundEmitter::CSoundEmitter(CEntityManager *pMgr): - BaseClass(pMgr) -{ - -} - CSoundEmitter::~CSoundEmitter() { mem_release(m_pEmitter); @@ -54,8 +48,10 @@ CSoundEmitter::~CSoundEmitter() void CSoundEmitter::setSound(const char *szSound) { - if(!m_pEmitter || fstrcmp(m_pEmitter->getName(), szSound) != 0) + if(!m_pEmitter || fstrcmp(m_szPathSound, szSound) != 0) { + _setStrVal(&m_szPathSound, szSound); + mem_release(m_pEmitter); IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID)); IXSoundLayer *pGameLayer = pSound->findLayer("xGame"); @@ -65,34 +61,50 @@ void CSoundEmitter::setSound(const char *szSound) if(m_pEmitter) { - _setStrVal(&m_szPathSound, szSound); m_pEmitter->setVolume(m_fVolume); + m_pEmitter->setWorldPos(getPos()); + m_pEmitter->setDistance(m_fDist); } } } //########################################################################## -void CSoundEmitter::onSync() +void CSoundEmitter::setPos(const float3 &pos) { - BaseClass::onSync(); - if(!m_pEmitter) - return; + BaseClass::setPos(pos); - float3 vPos = getPos(); - m_pEmitter->setWorldPos(vPos); + SAFE_CALL(m_pEmitter, setWorldPos, pos); +} - m_pEmitter->setVolume(m_fVolume); +void CSoundEmitter::setVolume(float fVolume) +{ + m_fVolume = fVolume; + + SAFE_CALL(m_pEmitter, setVolume, fVolume); +} +float CSoundEmitter::getVolume() +{ + return(m_fVolume); +} + +void CSoundEmitter::setDistance(float fDistance) +{ + m_fDist = fDistance; + + SAFE_CALL(m_pEmitter, setDistance, fDistance); +} +float CSoundEmitter::getDistance() +{ + return(m_fDist); } //########################################################################## void CSoundEmitter::play(inputdata_t * pInputdata) { - if(m_pEmitter) - { - m_pEmitter->play(); - } + SAFE_CALL(m_pEmitter, play); + FIRE_OUTPUT(m_onTurnOn, pInputdata->pInflictor); } @@ -105,7 +117,7 @@ void CSoundEmitter::updateFlags() if(!m_pEmitter) return; - if (getFlags() & SND_EMITTER_TYPE_AMBIENT) + if(getFlags() & SND_EMITTER_TYPE_AMBIENT) { m_pEmitter->setSpace(SOUND_SPACE_2D); } diff --git a/source/game/SoundEmitter.h b/source/game/SoundEmitter.h index c96e49165363380f2099147ec0dca2cd3ae886a5..10271cd8d81f2c12e6781a2bbe6a2e489fb4a2fa 100644 --- a/source/game/SoundEmitter.h +++ b/source/game/SoundEmitter.h @@ -29,15 +29,20 @@ class CSoundEmitter: public CPointEntity DECLARE_CLASS(CSoundEmitter, CPointEntity); DECLARE_PROPTABLE(); public: - CSoundEmitter(CEntityManager * pMgr); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CSoundEmitter(); - virtual void setSound(const char *szSound); + void setSound(const char *szSound); - void onSync() override; + void setPos(const float3 &pos) override; -protected: + void setVolume(float fVolume); + float getVolume(); + + void setDistance(float fDistance); + float getDistance(); +protected: void updateFlags() override; void play(inputdata_t *pInputdata); diff --git a/source/game/SoundPlayer.cpp b/source/game/SoundPlayer.cpp index 50c83755b885332c5259b59ddff73259c8f434b0..7b835981d8b9116a1c20aad5b94d31300e8c266c 100644 --- a/source/game/SoundPlayer.cpp +++ b/source/game/SoundPlayer.cpp @@ -15,13 +15,13 @@ BEGIN_PROPTABLE(CSoundPlayer) DEFINE_FIELD_STRINGFN(m_szPathSound, 0, "file", "Sound file", setSound, EDITOR_SOUND) //! Громкость - DEFINE_FIELD_FLOAT(m_fVolume, 0, "volume", "Volume", EDITOR_TEXTFIELD) + DEFINE_FIELD_FLOATFN(m_fVolume, 0, "volume", "Volume", setVolume, EDITOR_TEXTFIELD) //! Дистанция слышимости - DEFINE_FIELD_FLOAT(m_fDist, 0, "distance", "Hearing distance", EDITOR_TEXTFIELD) + DEFINE_FIELD_FLOATFN(m_fDist, 0, "distance", "Hearing distance", setDistance, EDITOR_TEXTFIELD) //! Зацикливание - DEFINE_FIELD_INT(m_iLoop, 0, "loop", "Loop", EDITOR_COMBOBOX) + DEFINE_FIELD_INTFN(m_iLoop, 0, "loop", "Loop", setLoop, EDITOR_COMBOBOX) COMBO_OPTION("None", "0") //!< Нет COMBO_OPTION("Simple", "1") //!< Простое (могут быть пустоты на стыках конца с началом) COMBO_OPTION("Seamless", "2") //!< Непрерывное (пустот не будет, все будет заполнено звуком) @@ -51,12 +51,6 @@ REGISTER_ENTITY(CSoundPlayer, sound_player); //########################################################################## -CSoundPlayer::CSoundPlayer(CEntityManager *pMgr): - BaseClass(pMgr) -{ - -} - CSoundPlayer::~CSoundPlayer() { mem_release(m_pPlayer); @@ -66,8 +60,10 @@ CSoundPlayer::~CSoundPlayer() void CSoundPlayer::setSound(const char *szSound) { - if(!m_pPlayer || fstrcmp(m_pPlayer->getName(), szSound) != 0) + if(!m_pPlayer || fstrcmp(m_szPathSound, szSound) != 0) { + _setStrVal(&m_szPathSound, szSound); + mem_release(m_pPlayer); IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID)); IXSoundLayer *pGameLayer = pSound->findLayer("xGame"); @@ -77,9 +73,10 @@ void CSoundPlayer::setSound(const char *szSound) if(m_pPlayer) { - _setStrVal(&m_szPathSound, szSound); m_pPlayer->setLoop((SOUND_LOOP)m_iLoop); m_pPlayer->setVolume(m_fVolume); + m_pPlayer->setDistance(m_fDist); + m_pPlayer->setWorldPos(getPos()); if(getFlags() & SND_PLAYER_START_PLAYED) m_pPlayer->play(); @@ -89,20 +86,43 @@ void CSoundPlayer::setSound(const char *szSound) //########################################################################## -void CSoundPlayer::onSync() +void CSoundPlayer::setPos(const float3 &pos) { - BaseClass::onSync(); - if (!m_pPlayer) - return; + BaseClass::setPos(pos); + + SAFE_CALL(m_pPlayer, setWorldPos, pos); +} + +void CSoundPlayer::setVolume(float fVolume) +{ + m_fVolume = fVolume; - float3 vPos = getPos(); - m_pPlayer->setWorldPos(vPos); + SAFE_CALL(m_pPlayer, setVolume, fVolume); +} +float CSoundPlayer::getVolume() +{ + return(m_fVolume); +} - if (m_pPlayer->getLoop() != (SOUND_LOOP)m_iLoop) - m_pPlayer->setLoop((SOUND_LOOP)m_iLoop); +void CSoundPlayer::setDistance(float fDistance) +{ + m_fDist = fDistance; - if (m_pPlayer->getVolume() != m_fVolume) - m_pPlayer->setVolume(m_fVolume); + SAFE_CALL(m_pPlayer, setDistance, fDistance); +} +float CSoundPlayer::getDistance() +{ + return(m_fDist); +} + +void CSoundPlayer::setLoop(int iLoop) +{ + m_iLoop = iLoop; + SAFE_CALL(m_pPlayer, setLoop, (SOUND_LOOP)iLoop); +} +SOUND_LOOP CSoundPlayer::getLoop() +{ + return((SOUND_LOOP)m_iLoop); } //########################################################################## diff --git a/source/game/SoundPlayer.h b/source/game/SoundPlayer.h index 550095ee1675c17c6ad7a71c699c8ec729cb51c8..e90daef7220e4ee55b778e8325be33111a42bea7 100644 --- a/source/game/SoundPlayer.h +++ b/source/game/SoundPlayer.h @@ -31,12 +31,21 @@ class CSoundPlayer: public CPointEntity DECLARE_CLASS(CSoundPlayer, CPointEntity); DECLARE_PROPTABLE(); public: - CSoundPlayer(CEntityManager * pMgr); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CSoundPlayer(); - virtual void setSound(const char *szSound); + void setSound(const char *szSound); - void onSync() override; + void setPos(const float3 &pos) override; + + void setVolume(float fVolume); + float getVolume(); + + void setDistance(float fDistance); + float getDistance(); + + void setLoop(int iLoop); + SOUND_LOOP getLoop(); protected: diff --git a/source/game/TriggerHurt.cpp b/source/game/TriggerHurt.cpp index c4ef6d9d4f85c823ad73b58c53782124495289ff..46ae2421b9f010dba07baf7a366881dc28378604 100644 --- a/source/game/TriggerHurt.cpp +++ b/source/game/TriggerHurt.cpp @@ -21,12 +21,6 @@ END_PROPTABLE() REGISTER_ENTITY(CTriggerHurt, trigger_hurt); -CTriggerHurt::CTriggerHurt(CEntityManager * pMgr): - BaseClass(pMgr) -{ - //m_idHurtInterval = SET_INTERVAL(think, 1000.0f); -} - CTriggerHurt::~CTriggerHurt() { CLEAR_INTERVAL(m_idHurtInterval); diff --git a/source/game/TriggerHurt.h b/source/game/TriggerHurt.h index 435e5317d3a7e405d4b76ffa83d2965098c147f3..7260a990f16dbaa88171aa2699249181979a00c0 100644 --- a/source/game/TriggerHurt.h +++ b/source/game/TriggerHurt.h @@ -25,7 +25,7 @@ class CTriggerHurt: public CBaseTrigger DECLARE_CLASS(CTriggerHurt, CBaseTrigger); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); ~CTriggerHurt(); protected: diff --git a/source/game/TriggerItemUse.cpp b/source/game/TriggerItemUse.cpp index d5d3e786e9a9d2d58d303bcc1eb6f83794727ee4..57c19756a505d1611032537575972d456ffc440e 100644 --- a/source/game/TriggerItemUse.cpp +++ b/source/game/TriggerItemUse.cpp @@ -17,12 +17,6 @@ END_PROPTABLE() REGISTER_ENTITY_NOLISTING(CTriggerItemUse, trigger_itemuse); -CTriggerItemUse::CTriggerItemUse(CEntityManager * pMgr): - BaseClass(pMgr) -{ - //m_idHurtInterval = SET_INTERVAL(think, 1000.0f); -} - void CTriggerItemUse::setItem(CBaseItem *pItem) { m_pItem = pItem; diff --git a/source/game/TriggerItemUse.h b/source/game/TriggerItemUse.h index f116da065ea49810a835818440a95a51b768d019..141feb0f404df5718fcc00978fb0eadf2c1b805c 100644 --- a/source/game/TriggerItemUse.h +++ b/source/game/TriggerItemUse.h @@ -26,7 +26,7 @@ class CTriggerItemUse: public CBaseTrigger DECLARE_CLASS(CTriggerItemUse, CBaseTrigger); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); + DECLARE_TRIVIAL_CONSTRUCTOR(); void setItem(CBaseItem *pItem); diff --git a/source/game/TriggerTeleport.cpp b/source/game/TriggerTeleport.cpp index 6f68091226d8cebaf842d441399c838e8bc5ee1f..d96649db9b2372c0926545162c218be4254abd91 100644 --- a/source/game/TriggerTeleport.cpp +++ b/source/game/TriggerTeleport.cpp @@ -14,24 +14,13 @@ See the license in LICENSE BEGIN_PROPTABLE(CTriggerTeleport) //! Локальный маркер для относительных координат - DEFINE_FIELD_ENTITY(m_pLandmark, PDFF_NONE, "landmark", "Landmark object", EDITOR_TEXTFIELD) + DEFINE_FIELD_ENTITY(CBaseEntity, m_pLandmark, PDFF_NONE, "landmark", "Landmark object", EDITOR_TEXTFIELD) //! Цель - DEFINE_FIELD_ENTITY(m_pDestination, PDFF_NONE, "destination", "Destination landmark object", EDITOR_TEXTFIELD) + DEFINE_FIELD_ENTITY(CBaseEntity, m_pDestination, PDFF_NONE, "destination", "Destination landmark object", EDITOR_TEXTFIELD) END_PROPTABLE() REGISTER_ENTITY(CTriggerTeleport, trigger_teleport); -CTriggerTeleport::CTriggerTeleport(CEntityManager * pMgr): - BaseClass(pMgr) -{ - //m_idHurtInterval = SET_INTERVAL(think, 1000.0f); -} - -CTriggerTeleport::~CTriggerTeleport() -{ - //CLEAR_INTERVAL(m_idHurtInterval); -} - void CTriggerTeleport::onTouchStart(CBaseEntity *pActivator) { if(!m_pDestination) diff --git a/source/game/TriggerTeleport.h b/source/game/TriggerTeleport.h index 0f8eb54adb9cd1af2b591fba6422bf2b15298c57..61042aa7568c90513d6f8d444b3497c4efc64f67 100644 --- a/source/game/TriggerTeleport.h +++ b/source/game/TriggerTeleport.h @@ -25,15 +25,14 @@ class CTriggerTeleport: public CBaseTrigger DECLARE_CLASS(CTriggerTeleport, CBaseTrigger); DECLARE_PROPTABLE(); public: - DECLARE_CONSTRUCTOR(); - ~CTriggerTeleport(); + DECLARE_TRIVIAL_CONSTRUCTOR(); protected: virtual void onTouchStart(CBaseEntity *pActivator) override; private: - CBaseEntity *m_pLandmark = NULL; - CBaseEntity *m_pDestination = NULL; + CEntityPointer<CBaseEntity> m_pLandmark; + CEntityPointer<CBaseEntity> m_pDestination; }; #endif diff --git a/source/game/proptable.cpp b/source/game/proptable.cpp index c203467d4501ba223d96a114e0e812d8725b9ef4..6210a2f8dbd4e59066dec68f97a43105ac50d27a 100644 --- a/source/game/proptable.cpp +++ b/source/game/proptable.cpp @@ -81,7 +81,7 @@ prop_editor_t _GetEditorFilefield(int start, ...) return(out); } -const char * GetEmptyString() +const char* GetEmptyString() { static const char * str = ""; return(str); @@ -92,30 +92,31 @@ void output_t::fire(CBaseEntity *pInflictor, CBaseEntity *pActivator, inputdata_ inputdata_t data = {0}; data.pActivator = pActivator; data.pInflictor = pInflictor; - for(int i = 0; i < iOutCount; ++i) + for(UINT i = 0, l = aOutputs.size(); i < l; ++i) { + named_output_t &out = aOutputs[i]; data.type = PDF_NONE; - if(pOutputs[i].fDelay == 0.0f && !pOutputs[i].useRandomDelay) + if(out.fDelay == 0.0f && !out.useRandomDelay) { - for(int j = 0; j < pOutputs[i].iOutCount; ++j) + for(int j = 0, jl = out.aOutputs.size(); j < jl; ++j) { - data.type = pOutputs[i].pOutputs[j].data.type; + data.type = out.aOutputs[j].data.type; if(data.type == PDF_STRING) { data.parameter.str = NULL; } - if(pOutputs[i].pOutputs[j].useOverrideData) + if(out.aOutputs[j].useOverrideData) { - data.setParameter(pOutputs[i].pOutputs[j].data); + data.setParameter(out.aOutputs[j].data); } else if(pInputData) { data.setParameter(*pInputData); } - (pOutputs[i].pOutputs[j].pTarget->*(pOutputs[i].pOutputs[j].fnInput))(&data); + (out.aOutputs[j].pTarget->*(out.aOutputs[j].fnInput))(&data); if(data.type == PDF_STRING && data.parameter.str != GetEmptyString()) { @@ -130,11 +131,120 @@ void output_t::fire(CBaseEntity *pInflictor, CBaseEntity *pActivator, inputdata_ data.type = pInputData->type; data.setParameter(*pInputData); } - pActivator->getManager()->setOutputTimeout(&pOutputs[i], &data); + pActivator->getManager()->setOutputTimeout(&out, &data); } } } +void named_output_t::init(CBaseEntity *pThisEntity) +{ + listTargets.init(pThisEntity); + listTargets.setEntityName(szTargetName); +} + +void named_output_t::onEntityAdded(CBaseEntity *pEnt) +{ + propdata_t * pField = pEnt->getField(szTargetInput); + if(!pField || !(pField->flags & PDFF_INPUT)) + { + printf(COLOR_CYAN "Class '%s' has no input '%s', obj '%s'\n" COLOR_RESET, pEnt->getClassName(), szTargetInput, szTargetName); + } + + input_t &out = aOutputs[aOutputs.size()]; + + out.fnInput = pField->fnInput; + out.pTarget = pEnt; + memset(&out.data, 0, sizeof(out.data)); + out.data.type = pField->type; + if((out.useOverrideData = szTargetData != NULL)) + { + float3_t f3; + float4_t f4; + SMQuaternion q; + int d; + float f; + const char *value = szTargetData; + bool bParsed = false; + switch(pField->type) + { + case PDF_NONE: + bParsed = true; + break; + case PDF_INT: + if(1 == sscanf(value, "%d", &d)) + { + out.data.parameter.i = d; + bParsed = true; + } + break; + case PDF_FLOAT: + if(1 == sscanf(value, "%f", &f)) + { + out.data.parameter.f = f; + bParsed = true; + } + break; + case PDF_VECTOR: + if(3 == sscanf(value, "%f %f %f", &f3.x, &f3.y, &f3.z)) + { + out.data.v3Parameter = f3; + bParsed = true; + } + break; + case PDF_VECTOR4: + { + int iPrm = sscanf(value, "%f %f %f %f", &f4.x, &f4.y, &f4.z, &f4.w); + if(iPrm > 2) + { + if(iPrm == 3) + { + f4.w = 1.0f; + } + out.data.v4Parameter = f4; + bParsed = true; + } + } + break; + case PDF_BOOL: + if(1 == sscanf(value, "%d", &d)) + { + out.data.parameter.b = d != 0; + bParsed = true; + } + break; + case PDF_STRING: + _setStrVal(&out.data.parameter.str, value); + bParsed = true; + break; + } + + if(!bParsed) + { + printf(COLOR_CYAN "Cannot parse input parameter '%s', class '%s', input '%s', obj '%s'\n" COLOR_RESET, value, pEnt->getClassName(), szTargetInput, szTargetName); + aOutputs.erase(aOutputs.size() - 1); + } + } +} +void named_output_t::onEntityRemoved(CBaseEntity *pEnt) +{ + int idx = aOutputs.indexOf(pEnt, [](const input_t &a, CBaseEntity *b){ + return(a.pTarget == b); + }); + assert(idx >= 0); + if(idx >= 0) + { + if(aOutputs[idx].useOverrideData && aOutputs[idx].data.type == PDF_STRING) + { + const char *estr = GetEmptyString(); + if(estr != aOutputs[idx].data.parameter.str) + { + mem_delete_a(aOutputs[idx].data.parameter.str); + } + } + aOutputs[idx] = aOutputs[aOutputs.size() - 1]; + aOutputs.erase(aOutputs.size() - 1); + } +} void _setStrVal(const char **to, const char *value) { diff --git a/source/game/proptable.h b/source/game/proptable.h index 9f00d7aed5e1886ebca34aa9e90ac89b72183d38..c77a4b75ab038d1d030130d22a8f3963d022f5d9 100644 --- a/source/game/proptable.h +++ b/source/game/proptable.h @@ -8,6 +8,8 @@ See the license in LICENSE #define __PROPTABLE_H #include <common/Math.h> +#include "EntityPointer.h" +#include "EntityList.h" class CBaseEntity; @@ -50,7 +52,6 @@ enum PDF_TYPE PDF_STRING, PDF_ANGLES, PDF_ENTITY, - PDF_PARENT, PDF_FLAGS, PDF_FLAG, @@ -192,7 +193,6 @@ struct inputdata_t }; typedef void(CBaseEntity::*input_func)(inputdata_t *pInputData); -typedef bool(*PFNCHECKENTTYPE)(CBaseEntity*); struct propdata_t { @@ -204,7 +204,7 @@ struct propdata_t szEdName(NULL), editor({}) {} - propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, PFNCHECKENTTYPE pfnCheckType, prop_editor_t ed): + propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, prop_editor_t ed): pField(f), type(t), flags(fl), @@ -212,7 +212,7 @@ struct propdata_t szEdName(edname), editor(ed) {} - propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, PFNFIELDSET _fnSet, PFNCHECKENTTYPE pfnCheckType, prop_editor_t ed): + propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, PFNFIELDSET _fnSet, prop_editor_t ed): pField(f), type(t), flags(fl), @@ -241,8 +241,6 @@ struct propdata_t prop_editor_t editor; PFNFIELDSET fnSet; - PFNCHECKENTTYPE pfnCheckType = NULL; - template<typename T> static fieldtype ToFieldType(T arg) { @@ -281,25 +279,64 @@ struct named_output_t const char *szTargetData = NULL; int iFireLimit = -1; - int iOutCount = 0; - input_t *pOutputs = NULL; + CEntityList listTargets; + Array<input_t> aOutputs; + // int iOutCount = 0; + // input_t *pOutputs = NULL; + + void init(CBaseEntity *pThisEntity); + void onEntityAdded(CBaseEntity *pEnt); + void onEntityRemoved(CBaseEntity *pEnt); + + class OnLinkEstablished final: public IEntityPointerEvent + { + public: + OnLinkEstablished(named_output_t *pOut): + m_pOut(pOut) + { + } + void onEvent(CBaseEntity *pEnt) override + { + m_pOut->onEntityAdded(pEnt); + } + private: + named_output_t *m_pOut; + }; + class OnLinkBroken final: public IEntityPointerEvent + { + public: + OnLinkBroken(named_output_t *pOut): + m_pOut(pOut) + { + } + void onEvent(CBaseEntity *pEnt) override + { + m_pOut->onEntityRemoved(pEnt); + } + private: + named_output_t *m_pOut; + }; + + OnLinkEstablished onLinkEstablished; + OnLinkBroken onLinkBroken; + + named_output_t(): + onLinkEstablished(this), + onLinkBroken(this) + { + listTargets.setLinkEstablishedListener(&onLinkEstablished); + listTargets.setLinkBrokenListener(&onLinkBroken); + } }; struct output_t { - output_t(): - iOutCount(0), - pOutputs(NULL), - pData(NULL), - bDirty(false) - { - } void fire(CBaseEntity *pInflictor, CBaseEntity *pActivator, inputdata_t *pInputData = NULL); - - bool bDirty; - int iOutCount; - named_output_t * pOutputs; - void * pData; + + // bool bDirty = false; + // int iOutCount = 0; + Array<named_output_t> aOutputs; + void *pData = NULL; }; #define FIRE_OUTPUT(output, inflictor) (output).fire((inflictor), this) @@ -396,8 +433,8 @@ void cls::InitPropData() \ } \ } -#define DECLARE_TRIVIAL_CONSTRUCTOR() ThisClass(CEntityManager * pMgr):BaseClass(pMgr){} -#define DECLARE_CONSTRUCTOR() ThisClass(CEntityManager * pMgr); +#define DECLARE_TRIVIAL_CONSTRUCTOR() ThisClass():BaseClass(){} +#define DECLARE_CONSTRUCTOR() ThisClass(); const char * GetEmptyString(); @@ -420,36 +457,31 @@ const char * GetEmptyString(); #define EDITOR_SOUND EDITOR_FILEFIELD FILE_OPTION("Select sound", "ogg") EDITOR_FILE_END() #define EDITOR_TEXTURE EDITOR_FILEFIELD FILE_OPTION("Select texture", "dds") EDITOR_FILE_END() -#define DEFINE_FIELD_STRING(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field), PDF_STRING, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_VECTOR(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field), PDF_VECTOR, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_VECTOR4(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field), PDF_VECTOR4, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_ANGLES(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field), PDF_ANGLES, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_INT(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_ENUM(type, field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_FLOAT(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field), PDF_FLOAT, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_BOOL(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field), PDF_BOOL, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_ENTITY(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<CBaseEntity* DataClass::*>(&DataClass::field), PDF_ENTITY, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_ENTITY2(type, field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<type* DataClass::*>(&DataClass::field), PDF_ENTITY, flags, keyname, edname, CEntityFactoryMap::IsEntityOfClass<type>, editor -#define DEFINE_FIELD_PARENT(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<CBaseEntity* DataClass::*>(&DataClass::field), PDF_PARENT, flags, keyname, edname, NULL, editor -#define DEFINE_FIELD_FLAGS(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<UINT DataClass::*>(&DataClass::field), PDF_FLAGS, flags, keyname, edname, NULL, editor - -#define DEFINE_FIELD_STRINGFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field), PDF_STRING, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const char*>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_VECTORFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field), PDF_VECTOR, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float3&>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_VECTOR4FN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field), PDF_VECTOR4, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float4&>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_ANGLESFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field), PDF_ANGLES, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const SMQuaternion&>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_INTFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_ENUMFN(type, field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_FLOATFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field), PDF_FLOAT, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, float>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_BOOLFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field), PDF_BOOL, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, bool>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_ENTITYFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<CBaseEntity* DataClass::*>(&DataClass::field), PDF_ENTITY, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, CBaseEntity*>(&DataClass::fn), NULL, editor -#define DEFINE_FIELD_ENTITY2FN(type, field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<type* DataClass::*>(&DataClass::field), PDF_ENTITY, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, type*>(&DataClass::fn), CEntityFactoryMap::IsEntityOfClass<type>, editor -//#define DEFINE_FIELD_PARENTFN(field, flags, keyname, edname, fn, editor) , {(fieldtype)&DataClass::field, PDF_PARENT, flags, keyname, edname, fn, editor +#define DEFINE_FIELD_STRING(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field), PDF_STRING, flags, keyname, edname, editor +#define DEFINE_FIELD_VECTOR(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field), PDF_VECTOR, flags, keyname, edname, editor +#define DEFINE_FIELD_VECTOR4(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field), PDF_VECTOR4, flags, keyname, edname, editor +#define DEFINE_FIELD_ANGLES(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field), PDF_ANGLES, flags, keyname, edname, editor +#define DEFINE_FIELD_INT(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, editor +#define DEFINE_FIELD_ENUM(type, field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, editor +#define DEFINE_FIELD_FLOAT(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field), PDF_FLOAT, flags, keyname, edname, editor +#define DEFINE_FIELD_BOOL(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field), PDF_BOOL, flags, keyname, edname, editor +#define DEFINE_FIELD_ENTITY(type, field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<CEntityPointer<type> DataClass::*>(&DataClass::field), PDF_ENTITY, flags, keyname, edname, editor +#define DEFINE_FIELD_FLAGS(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<UINT DataClass::*>(&DataClass::field), PDF_FLAGS, flags, keyname, edname, editor + +#define DEFINE_FIELD_STRINGFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field), PDF_STRING, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const char*>(&DataClass::fn), editor +#define DEFINE_FIELD_VECTORFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field), PDF_VECTOR, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float3&>(&DataClass::fn), editor +#define DEFINE_FIELD_VECTOR4FN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field), PDF_VECTOR4, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float4&>(&DataClass::fn), editor +#define DEFINE_FIELD_ANGLESFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field), PDF_ANGLES, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const SMQuaternion&>(&DataClass::fn), editor +#define DEFINE_FIELD_INTFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn), editor +#define DEFINE_FIELD_ENUMFN(type, field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field), PDF_INT, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn), editor +#define DEFINE_FIELD_FLOATFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field), PDF_FLOAT, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, float>(&DataClass::fn), editor +#define DEFINE_FIELD_BOOLFN(field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field), PDF_BOOL, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, bool>(&DataClass::fn), editor //#define DEFINE_FIELD_FLAGSFN(field, flags, keyname, edname, fn, editor) , {(fieldtype)&DataClass::field, PDF_FLAGS, flags, keyname, edname, fn, editor #define DEFINE_INPUT(method, keyname, edname, argtype) , {propdata_t::ToInputFunc<void(DataClass::*)(inputdata_t*)>(&DataClass::method), argtype, PDFF_NOEDIT | PDFF_INPUT, keyname, edname, EDITOR_NONE -#define DEFINE_OUTPUT(field, keyname, edname) , {propdata_t::ToFieldType<output_t DataClass::*>(&DataClass::field), PDF_OUTPUT, PDFF_NOEDIT | PDFF_OUTPUT, keyname, edname, NULL, EDITOR_NONE +#define DEFINE_OUTPUT(field, keyname, edname) , {propdata_t::ToFieldType<output_t DataClass::*>(&DataClass::field), PDF_OUTPUT, PDFF_NOEDIT | PDFF_OUTPUT, keyname, edname, EDITOR_NONE #define DEFINE_MESSAGE(method, keyname, edname, argtype) , {propdata_t::ToInputFunc<void(DataClass::*)(inputdata_t*)>(&DataClass::method), argtype, PDFF_NOEDIT | PDFF_MESSAGE, keyname, edname, EDITOR_NONE -#define DEFINE_FLAG(value, edname) , {(fieldtype)NULL, PDF_FLAG, value, NULL, edname, NULL, EDITOR_FLAGS +#define DEFINE_FLAG(value, edname) , {(fieldtype)NULL, PDF_FLAG, value, NULL, edname, EDITOR_FLAGS #endif diff --git a/source/game/sxgame.h b/source/game/sxgame.h index be0f9185628f89202bf592efd6c12ed52a6ef56d..39ac95bfbee0e59b842a02175079659fb85f726c 100644 --- a/source/game/sxgame.h +++ b/source/game/sxgame.h @@ -246,13 +246,11 @@ SX_LIB_API CBaseEntity *SGame_EntGetByName(const char *szName, ID idStart = 0); SX_LIB_API BOOL SGame_AddWMsg(UINT message, WPARAM wParam, LPARAM lParam); -/*! Копирует объект, возвращает ID копии -*/ -SX_LIB_API ID SGame_EntClone(ID idSrc); - +#if 0 /*! Находит объект по пересечению с лучем, в режиме редактора так же находит точечные объекты, в режиме игры - нет */ SX_LIB_API ID SGame_EntGetByRay(const float3 &vStart, const float3 &vDir, float3 *pHitPos = NULL); +#endif #endif diff --git a/source/game/sxgame_dll.cpp b/source/game/sxgame_dll.cpp index d1dd32483d28feeefe53938e587605c9da990661..8a023f1aa2b5ef80987d715fbe42f2f6a8ca342b 100644 --- a/source/game/sxgame_dll.cpp +++ b/source/game/sxgame_dll.cpp @@ -379,19 +379,7 @@ SX_LIB_API BOOL SGame_AddWMsg(UINT message, WPARAM wParam, LPARAM lParam) return(GameData::m_pGUIStack->putMessage(message, wParam, lParam)); } -SX_LIB_API ID SGame_EntClone(ID idSrc) -{ - SG_PRECOND(-1); - CBaseEntity *pEnt = GameData::m_pMgr->cloneEntity(GameData::m_pMgr->getById(idSrc)); - - if(!pEnt) - { - return(-1); - } - - return(pEnt->getId()); -} - +#if 0 SX_LIB_API ID SGame_EntGetByRay(const float3 &vStart, const float3 &vDir, float3 *pHitPos) { SG_PRECOND(-1); @@ -416,3 +404,4 @@ SX_LIB_API ID SGame_EntGetByRay(const float3 &vStart, const float3 &vDir, float3 } return(-1); } +#endif diff --git a/source/mtrl/MaterialSystem.cpp b/source/mtrl/MaterialSystem.cpp index a772e6dd3babe84773332e7617b4f5343ff34bd1..6c395b8aa2324b1ef7a2be91fad4d2aab524a9ff 100644 --- a/source/mtrl/MaterialSystem.cpp +++ b/source/mtrl/MaterialSystem.cpp @@ -109,7 +109,7 @@ void XMETHODCALLTYPE CMaterialSystem::loadMaterial(const char *szName, IXMateria String sName(szName); const AssotiativeArray<String, CMaterial*>::Node *pNode; - if(m_mapMaterials.KeyExists(sName, &pNode) && *(pNode->Val)) + if(m_mapMaterials.KeyExists(sName, &pNode)) { *ppMaterial = *(pNode->Val); (*ppMaterial)->AddRef(); @@ -132,7 +132,7 @@ void XMETHODCALLTYPE CMaterialSystem::loadMaterial(const char *szName, IXMateria bool XMETHODCALLTYPE CMaterialSystem::getMaterial(const char *szName, IXMaterial **ppMaterial) { const AssotiativeArray<String, CMaterial*>::Node *pNode; - if(m_mapMaterials.KeyExists(szName, &pNode) && *(pNode->Val)) + if(m_mapMaterials.KeyExists(szName, &pNode)) { *ppMaterial = *(pNode->Val); (*ppMaterial)->AddRef(); @@ -176,10 +176,7 @@ void XMETHODCALLTYPE CMaterialSystem::reloadAll() { for(AssotiativeArray<String, CMaterial*>::Iterator i = m_mapMaterials.begin(); i; ++i) { - if(*(i.second)) - { - loadMaterial(i.first->c_str(), *(i.second)); - } + loadMaterial(i.first->c_str(), *(i.second)); } } @@ -263,7 +260,7 @@ bool XMETHODCALLTYPE CMaterialSystem::loadTexture(const char *szName, IXTexture String sName(szName); const AssotiativeArray<String, CTexture*>::Node *pNode; - if(m_mpTextures.KeyExists(sName, &pNode) && *(pNode->Val)) + if(m_mpTextures.KeyExists(sName, &pNode)) { *ppTexture = *(pNode->Val); (*ppTexture)->AddRef(); @@ -414,7 +411,7 @@ bool XMETHODCALLTYPE CMaterialSystem::loadTexture(const char *szName, IXTexture bool XMETHODCALLTYPE CMaterialSystem::getTexture(const char *szName, IXTexture **ppTexture) { const AssotiativeArray<String, CTexture*>::Node *pNode; - if(m_mpTextures.KeyExists(szName, &pNode) && *(pNode->Val)) + if(m_mpTextures.KeyExists(szName, &pNode)) { *ppTexture = *(pNode->Val); (*ppTexture)->AddRef(); @@ -660,7 +657,7 @@ void CMaterialSystem::onTextureRelease(CTexture *pTexture) { assert(pTexture); - m_mpTextures[pTexture->getName()] = NULL; + m_mpTextures.erase(pTexture->getName()); m_poolTextures.Delete(pTexture); } @@ -669,7 +666,7 @@ void CMaterialSystem::onMaterialRelease(CMaterial *pMaterial) { assert(pMaterial); - m_mapMaterials[pMaterial->getName()] = NULL; + m_mapMaterials.erase(pMaterial->getName()); } void CMaterialSystem::queueTextureUpload(CTexture *pTexture) diff --git a/source/mtrl/MaterialSystem.h b/source/mtrl/MaterialSystem.h index 445e8bed175f66fc4d266be2019fb793d9e9c3d4..a4c2c4d8b380d31c70a6aac1370801d00b28e761 100644 --- a/source/mtrl/MaterialSystem.h +++ b/source/mtrl/MaterialSystem.h @@ -353,7 +353,7 @@ protected: MemAlloc<CTexture> m_poolTextures; Array<IXTextureProxy*> m_aTextureProxies; AssotiativeArray<String, IXTextureFilter*> m_mapTextureFilters; - AssotiativeArray<String, CTexture*> m_mpTextures; + Map<String, CTexture*> m_mpTextures; CConcurrentQueue<CTexture*> m_queueTextureToLoad; IXTexture *m_pDefaultTexture = NULL; @@ -366,7 +366,7 @@ protected: Array<IXMaterialProxy*> m_aMaterialProxies; AssotiativeArray<AAString, Array<MaterialLoader>> m_mapMaterialLoaders; Array<XFormatName> m_aMaterialExts; - AssotiativeArray<String, CMaterial*> m_mapMaterials; + Map<String, CMaterial*> m_mapMaterials; IEventChannel<XEventMaterialChanged> *m_pNotifyChannel = NULL; diff --git a/source/physics/PhyWorld.cpp b/source/physics/PhyWorld.cpp index 3abb3c949dcce3546d1ff7ab0887ab9fcc41603c..9e294766d2f2d30338247b1a4dc7d6eee2ef7157 100644 --- a/source/physics/PhyWorld.cpp +++ b/source/physics/PhyWorld.cpp @@ -106,6 +106,10 @@ CPhyWorld::CPhyWorld(): m_pDynamicsWorld->getSolverInfo().m_numIterations = 30; + // typedef void (*btInternalTickCallback)(btDynamicsWorld *world, btScalar timeStep); + + m_pDynamicsWorld->setInternalTickCallback(TickCallback, this); + //btCreateDefaultTaskScheduler(); static CTaskScheduler taskSheduler; btSetTaskScheduler(&taskSheduler); @@ -126,6 +130,8 @@ CPhyWorld::CPhyWorld(): btSetCustomEnterProfileZoneFunc(CProfileManager::Start_Profile); btSetCustomLeaveProfileZoneFunc(CProfileManager::Stop_Profile); + m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID); + #if 0 Core_GetIXCore()->getEventChannel<XEventLevel>(EVENT_LEVEL_GUID)->addListener([](const XEventLevel *pData) { @@ -853,6 +859,17 @@ void CPhyWorld::enableSimulation() m_iSkipFrames = 3; } +void CPhyWorld::TickCallback(btDynamicsWorld *world, btScalar timeStep) +{ + CPhyWorld *pThis = (CPhyWorld*)world->getWorldUserInfo(); + + XEventPhysicsStep ev; + ev.fTimeStep = timeStep; + ev.pPhysics = NULL; + + pThis->m_pTickEventChannel->broadcastEvent(&ev); +} + //############################################################## void XMETHODCALLTYPE CPhyWorld::CRenderable::renderStage(X_RENDER_STAGE stage, IXRenderableVisibility *pVisibility) diff --git a/source/physics/PhyWorld.h b/source/physics/PhyWorld.h index 5985d411a632acca6343d920696c569ee8d40f87..1112d84dc01f6151961b907491d1bbf0b0e00b3e 100644 --- a/source/physics/PhyWorld.h +++ b/source/physics/PhyWorld.h @@ -197,6 +197,10 @@ protected: bool m_isRunning; int m_iSkipFrames = 3; + + IEventChannel<XEventPhysicsStep> *m_pTickEventChannel = NULL; + + static void TickCallback(btDynamicsWorld *world, btScalar timeStep); }; #endif diff --git a/source/xcommon/IXSoundSystem.h b/source/xcommon/IXSoundSystem.h index f33663b531408d3aea0737fe65e9a9c4a1a3795b..87d1d85e1c1c3f52509e58579414912aa1ef791b 100644 --- a/source/xcommon/IXSoundSystem.h +++ b/source/xcommon/IXSoundSystem.h @@ -37,7 +37,9 @@ enum SOUND_LOOP { SOUND_LOOP_NONE = 0, SOUND_LOOP_SIMPLE = 1, - SOUND_LOOP_SEAMLESS = 2 + SOUND_LOOP_SEAMLESS = 2, + + SOUND_LOOP_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ }; //########################################################################## diff --git a/source/xcommon/XEvents.h b/source/xcommon/XEvents.h index 7231051f7c4628df58f5169138db2e7b02229d5b..2a3929d35ceb605a2b64f06474bfbe5ecfe529a3 100644 --- a/source/xcommon/XEvents.h +++ b/source/xcommon/XEvents.h @@ -27,46 +27,34 @@ class IEventChannel: public IBaseEventChannel public: void addListener(PFNLISTENER fnListener) { - for(UINT i = 0, l = m_vListeners.size(); i < l; ++i) + if(m_vListeners.indexOf(fnListener) < 0) { - if(m_vListeners[i] == fnListener) - { - return; - } + m_vListeners.push_back(fnListener); } - m_vListeners.push_back(fnListener); } void addListener(IEventListener<T> *pListener) { - for(UINT i = 0, l = m_vListeners2.size(); i < l; ++i) + if(m_vListeners2.indexOf(pListener) < 0) { - if(m_vListeners2[i] == pListener) - { - return; - } + m_vListeners2.push_back(pListener); } - m_vListeners2.push_back(pListener); } void removeListener(PFNLISTENER fnListener) { - for(UINT i = 0, l = m_vListeners.size(); i < l; ++i) + int idx = m_vListeners.indexOf(fnListener); + if(idx >= 0) { - if(m_vListeners[i] == fnListener) - { - m_vListeners.erase(i); - return; - } + m_vListeners[idx] = m_vListeners[m_vListeners.size() - 1]; + m_vListeners.erase(m_vListeners.size() - 1); } } void removeListener(IEventListener<T> *pListener) { - for(UINT i = 0, l = m_vListeners2.size(); i < l; ++i) + int idx = m_vListeners2.indexOf(pListener); + if(idx >= 0) { - if(m_vListeners2[i] == pListener) - { - m_vListeners2.erase(i); - return; - } + m_vListeners2[idx] = m_vListeners2[m_vListeners2.size() - 1]; + m_vListeners2.erase(m_vListeners2.size() - 1); } } void broadcastEvent(const T *pEvent) @@ -241,4 +229,15 @@ struct XEventSkyboxChanged IXTexture *pTexture; }; + +// {1DB80A19-7DFA-4D61-923B-34906590DBB0} +#define EVENT_PHYSICS_STEP_GUID DEFINE_XGUID(0x1db80a19, 0x7dfa, 0x4d61, 0x92, 0x3b, 0x34, 0x90, 0x65, 0x90, 0xdb, 0xb0) + +class IXPhysics; +struct XEventPhysicsStep +{ + IXPhysics *pPhysics; + float fTimeStep; +}; + #endif