diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index fed316c00790aab5a2a61029057c26bc4a5ba285..c6d0cbd4b2f4bce1c8356195b9170b70b6a95fbd 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -196,6 +196,7 @@ <ClCompile Include="..\..\..\source\game\EditorOutputsTab.cpp" /> <ClCompile Include="..\..\..\source\game\EntityFactory.cpp" /> <ClCompile Include="..\..\..\source\game\EntityManager.cpp" /> + <ClCompile Include="..\..\..\source\game\EntityPointer.cpp" /> <ClCompile Include="..\..\..\source\game\EnvSkybox.cpp" /> <ClCompile Include="..\..\..\source\game\FuncRotating.cpp" /> <ClCompile Include="..\..\..\source\game\FuncTrain.cpp" /> @@ -267,6 +268,7 @@ <ClInclude Include="..\..\..\source\game\EditorExtension.h" /> <ClInclude Include="..\..\..\source\game\EditorObject.h" /> <ClInclude Include="..\..\..\source\game\EditorOutputsTab.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..d826392c715d3701fdb4c19f13d52066ae3513c7 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\EntityPointer.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\game\sxgame.h"> @@ -539,6 +542,9 @@ <ClInclude Include="..\..\..\source\game\SoundEmitter.h"> <Filter>Header Files\ents\sound</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\EntityPointer.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\game\sxgame.rc"> diff --git a/source/common b/source/common index 7ec71171b2e0446fd49751e3ec10176efbdfe867..12785328cefb95553e293d215b37a4cb89cee666 160000 --- a/source/common +++ b/source/common @@ -1 +1 @@ -Subproject commit 7ec71171b2e0446fd49751e3ec10176efbdfe867 +Subproject commit 12785328cefb95553e293d215b37a4cb89cee666 diff --git a/source/game/BaseEntity.cpp b/source/game/BaseEntity.cpp index 42f68bb83186cc50a6430106f26885f5df9109a4..a20c4d1b7996804f159c5c4ae2a4634904209f9d 100644 --- a/source/game/BaseEntity.cpp +++ b/source/game/BaseEntity.cpp @@ -43,15 +43,22 @@ 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_PARENT) + { + (this->*((CEntityPointer ThisClass::*)pt->pData[i].pField)).init(m_pMgr, this); + } } } pt = pt->pBaseProptable; @@ -61,6 +68,9 @@ void CBaseEntity::setDefaults() CBaseEntity::CBaseEntity() { m_pLightSystem = GameData::m_pLightSystem; + + m_pParent.setLinkEstablishedListener(&CBaseEntity::onParentSet); + m_pParent.setLinkBrokenListener(&CBaseEntity::onParentUnset); } /*void CBaseEntity::setDefaults() @@ -104,6 +114,11 @@ CBaseEntity::~CBaseEntity() } pt = pt->pBaseProptable; } + + if(m_pParent) + { + m_pParent->removeChild(this); + } } void CBaseEntity::setClassName(const char * name) @@ -139,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); + } } } @@ -169,6 +183,16 @@ float3 CBaseEntity::getPos() void CBaseEntity::setOrient(const SMQuaternion & q) { m_vOrientation = 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) { @@ -190,6 +214,32 @@ SMQuaternion CBaseEntity::getOrient() return(m_vOrientation); } +void CBaseEntity::onParentMoved(bool bAdjustOffsets) +{ + 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_vOffsetOrient = m_vOrientation * qParentOrient.Conjugate(); + } + else + { + setPos(vParentPos + qParentOrient * m_vOffsetPos); + setOrient(m_vOffsetOrient * qParentOrient); + } + + m_isInOnParentMoved = false; +} + UINT CBaseEntity::getFlags() { return(m_iFlags); @@ -335,8 +385,10 @@ bool CBaseEntity::setKV(const char * name, const char * value) return(true); } return(false); - case PDF_ENTITY: case PDF_PARENT: + (this->*((CEntityPointer ThisClass::*)field->pField)).setEntityName(value); + break; + case PDF_ENTITY: pEnt = m_pMgr->findEntityByName(value); if(pEnt || !value[0]) { @@ -492,9 +544,11 @@ bool CBaseEntity::getKV(const char * name, char * out, int bufsize) //f3 = SMMatrixToEuler(q.GetMatrix()); 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); + (this->*((CEntityPointer ThisClass::*)field->pField)).getEntityName(out, bufsize); + break; + case PDF_ENTITY: + pEnt = this->*((CBaseEntity* ThisClass::*)field->pField); if(!pEnt) { sprintf_s(out, bufsize, ""); @@ -554,21 +608,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; } } @@ -613,35 +691,6 @@ 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() @@ -982,3 +1031,28 @@ void CBaseEntity::renderEditor(bool is3D) { } + +void CBaseEntity::registerPointer(CEntityPointer *pPtr) +{ + ScopedSpinLock lock(m_slPointers); + m_aPointers.push_back(pPtr); +} + +void CBaseEntity::unregisterPointer(CEntityPointer *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(); + } +} diff --git a/source/game/BaseEntity.h b/source/game/BaseEntity.h index e785a1dbe82577de029a29f6fd4848ef81b6f1b6..2b5b68118633c92f95148d136996b2b1adc4fbfc 100644 --- a/source/game/BaseEntity.h +++ b/source/game/BaseEntity.h @@ -45,6 +45,7 @@ class SXGAME_EXPORT CBaseEntity DECLARE_PROPTABLE(); friend class CEntityManager; + friend class CEntityPointer; public: //! Конструктор @@ -139,14 +140,19 @@ 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() + const XGUID* getGUID() { return(m_pGUID); } + void setSeparateMovement(bool set) + { + m_isSeparateMovement = set; + } + private: void setClassName(const char *name); void setDefaults(); @@ -163,6 +169,24 @@ private: const char *m_szClassName = NULL; const XGUID *m_pGUID = NULL; + SpinLock m_slPointers; + Array<CEntityPointer*> m_aPointers; + void registerPointer(CEntityPointer *pPtr); + void unregisterPointer(CEntityPointer *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); + protected: virtual void _cleanup(); virtual void _initEditorBoxes(); @@ -198,7 +222,8 @@ protected: const char *m_szName = NULL; //! Родитель - CBaseEntity *m_pParent = NULL; + // CBaseEntity *m_pParent = NULL; + CEntityPointer m_pParent; //! Индекс кости родителя int m_iParentAttachment = -1; diff --git a/source/game/BaseLight.h b/source/game/BaseLight.h index f3cd1aac80e06808cc636f93cf017792edb9ce56..d24d8716d035aec6ad9ed352e3e98ce311316184 100644 --- a/source/game/BaseLight.h +++ b/source/game/BaseLight.h @@ -99,7 +99,7 @@ protected: void setLinkedTo(CBaseEntity *pEnt); - void onSync(); + void onSync() override; void addLinkedLight(CBaseLight *pEnt); void removeLinkedLight(CBaseLight *pEnt); diff --git a/source/game/BaseTool.h b/source/game/BaseTool.h index 6b00d4b5a6fbd81593c411a80561b2b9a5a70876..5689a976495505ed9c32b6566cba81e62bc3e24f 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,7 +54,7 @@ public: void dbgMove(int dir, float delta); - void onSync(); + void onSync() override; void setParent(CBaseEntity * pEnt, int attachment = -1); diff --git a/source/game/BaseTrigger.h b/source/game/BaseTrigger.h index 87bb957ed45b0f4af09465bd8ff5d4c702ea0ed8..25d6855c841fd7ad82672372d04e70b31502ad46 100644 --- a/source/game/BaseTrigger.h +++ b/source/game/BaseTrigger.h @@ -28,8 +28,8 @@ public: DECLARE_TRIVIAL_CONSTRUCTOR(); ~CBaseTrigger(); - void onSync(); - void onPostLoad(); + void onSync() override; + void onPostLoad() override; void enable(); void disable(); diff --git a/source/game/BaseWeapon.h b/source/game/BaseWeapon.h index ff14e812a4c8ca04d642fb2c593a3269787749e2..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); diff --git a/source/game/EditorObject.cpp b/source/game/EditorObject.cpp index fdd850716425677728253c588672db2a9e40e43a..f30dcc9bfd0bcf962d57df10691813f903173e60 100644 --- a/source/game/EditorObject.cpp +++ b/source/game/EditorObject.cpp @@ -123,29 +123,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) @@ -254,9 +293,9 @@ void XMETHODCALLTYPE CEditorObject::create() 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() diff --git a/source/game/EditorObject.h b/source/game/EditorObject.h index 71b4d2ad131321322bca6163adda3916c81dff17..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; diff --git a/source/game/EntityManager.cpp b/source/game/EntityManager.cpp index 896dea78609b9a3b3244df9e7b4fcf807fff3b99..7de487b99d6da8d7f0be66cf3e1713d12af618ef 100644 --- a/source/game/EntityManager.cpp +++ b/source/game/EntityManager.cpp @@ -260,6 +260,11 @@ const XGUID* CEntityManager::reg(CBaseEntity *pEnt, const XGUID *pGUID) m_vEntList.push_back(pEnt); + if(pGUID) + { + notifyWaitForGUID(*pGUID, pEnt); + } + return(pNewGUID); } void CEntityManager::unreg(CBaseEntity *pEnt) @@ -268,7 +273,10 @@ void CEntityManager::unreg(CBaseEntity *pEnt) int iKey = m_vEntList.indexOf(pEnt); assert(iKey >= 0); - m_vEntList.erase(iKey); + 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; @@ -472,9 +480,9 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress) { pEventChannel = Core_GetIXCore()->getEventChannel<XEventLevelProgress>(EVENT_LEVEL_PROGRESS_GUID); } - ISXConfig * conf = Core_CrConfig(); + ISXConfig *conf = Core_CrConfig(); const char *sect; - CBaseEntity * pEnt = NULL; + CBaseEntity *pEnt = NULL; Array<CBaseEntity*> tmpList; char szFullPath[1024]; @@ -835,6 +843,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; @@ -847,7 +856,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); @@ -958,6 +967,8 @@ void CEntityManager::sheduleDestroy(CBaseEntity *pEnt) { pEnt->_releaseEditorBoxes(); } + + pEnt->notifyPointers(); } void CEntityManager::setEditorMode(bool isEditor) @@ -1293,3 +1304,44 @@ CBaseline *CEntityManager::deserializeBaseline(ID id, INETbuff *pBuf) return(pBaseline); } #endif + +void CEntityManager::registerWaitForGUID(const XGUID &guid, CEntityPointer *pPtr) +{ + ScopedSpinLock lock(m_slWaitingPointers); + + m_maWaitingPointers[guid].push_back(pPtr); +} + +void CEntityManager::unregisterWaitForGUID(const XGUID &guid, CEntityPointer *pPtr) +{ + ScopedSpinLock lock(m_slWaitingPointers); + + Array<CEntityPointer*> &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<CEntityPointer*>>::Node *pNode; + if(m_maWaitingPointers.KeyExists(guid, &pNode)) + { + Array<CEntityPointer*> &list = m_maWaitingPointers[guid]; + for(UINT i = 0, l = list.size(); i < l; ++i) + { + list[i]->onWaitDone(pEnt); + } + m_maWaitingPointers.erase(guid); + } +} diff --git a/source/game/EntityManager.h b/source/game/EntityManager.h index cb031a1f0e3a3cfb2805098a97668aeaab5ab980..5cbd65f3a45fe43bed7cd6fe86838e45e17b77ae 100644 --- a/source/game/EntityManager.h +++ b/source/game/EntityManager.h @@ -89,6 +89,7 @@ class CEntityManager friend class CBaseEntity; friend class CEntityFactoryMap; + friend class CEntityPointer; public: CEntityManager(); ~CEntityManager(); @@ -181,6 +182,12 @@ protected: private: void finalRemove(); + + Map<XGUID, Array<CEntityPointer*>> m_maWaitingPointers; + SpinLock m_slWaitingPointers; + void registerWaitForGUID(const XGUID &guid, CEntityPointer *pPtr); + void unregisterWaitForGUID(const XGUID &guid, CEntityPointer *pPtr); + void notifyWaitForGUID(const XGUID &guid, CBaseEntity *pEnt); }; #endif diff --git a/source/game/EntityPointer.cpp b/source/game/EntityPointer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64764639e83db911e3f7dd916efe8baf0bd3c263 --- /dev/null +++ b/source/game/EntityPointer.cpp @@ -0,0 +1,175 @@ +#include "EntityPointer.h" +#include "BaseEntity.h" + +CEntityPointer::~CEntityPointer() +{ + if(m_pEntity) + { + m_pEntity->unregisterPointer(this); + } + + unregisterWait(); +} + +void CEntityPointer::setEntityName(const char *szName) +{ + if(szName[0] == '{') + { + XGUID guid; + if(XGUIDFromString(&guid, szName)) + { + setEntityGUID(guid); + return; + } + } + + setEntity(m_pMgr->findEntityByName(szName)); +} + +void CEntityPointer::setEntityGUID(const XGUID &guid) +{ + CBaseEntity *pEnt = m_pMgr->getByGUID(guid); + setEntity(pEnt); + if(!pEnt) + { + m_guid = guid; + registerWait(); + } +} + +void CEntityPointer::setEntity(CBaseEntity *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); + } + } +} + +CBaseEntity* CEntityPointer::getEntity() +{ + return(m_pEntity); +} + +CBaseEntity* CEntityPointer::operator->() +{ + return(getEntity()); +} +CEntityPointer::operator CBaseEntity*() +{ + return(getEntity()); +} + +CEntityPointer& CEntityPointer::operator=(CBaseEntity *pEnt) +{ + setEntity(pEnt); + return(*this); +} + +void CEntityPointer::getEntityName(char *szOutput, int iBufSize) +{ + if(m_pEntity && m_pEntity->getName()[0]) + { + if(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& CEntityPointer::getGUID() +{ + return(m_guid); +} + +void CEntityPointer::init(CEntityManager *pWorld, CBaseEntity *pThisEntity) +{ + m_pMgr = pWorld; + m_pThisEntity = pThisEntity; +} + +void CEntityPointer::onLinkBroken(CBaseEntity *pOldEnt) +{ + if(m_pfnOnLinkBroken) + { + (m_pThisEntity->*m_pfnOnLinkBroken)(pOldEnt); + } +} + +void CEntityPointer::onLinkEstablished(CBaseEntity *pNewEnt) +{ + pNewEnt->registerPointer(this); + + if(m_pfnOnLinkEstablished) + { + (m_pThisEntity->*m_pfnOnLinkEstablished)(pNewEnt); + } +} + +void CEntityPointer::onTargetRemoved() +{ + onLinkBroken(NULL); + m_pEntity = NULL; + registerWait(); +} + +void CEntityPointer::registerWait() +{ + if(!m_isWaiting) + { + m_pMgr->registerWaitForGUID(m_guid, this); + m_isWaiting = true; + } +} + +void CEntityPointer::unregisterWait() +{ + if(m_isWaiting) + { + m_pMgr->unregisterWaitForGUID(m_guid, this); + m_isWaiting = false; + } +} + +void CEntityPointer::onWaitDone(CBaseEntity *pEnt) +{ + assert(m_isWaiting); + + m_isWaiting = false; + + m_pEntity = pEnt; + + onLinkEstablished(pEnt); +} diff --git a/source/game/EntityPointer.h b/source/game/EntityPointer.h new file mode 100644 index 0000000000000000000000000000000000000000..647f3c682942b42ab8594fce79348bfc9da24b09 --- /dev/null +++ b/source/game/EntityPointer.h @@ -0,0 +1,76 @@ +#ifndef __ENTITY_POINTER_H +#define __ENTITY_POINTER_H + +#include <gdefines.h> + +class CBaseEntity; +class CEntityManager; +class CEntityPointer +{ + DECLARE_CLASS_NOBASE(CEntityPointer); + friend class CBaseEntity; + friend class CEntityManager; +public: + + ~CEntityPointer(); + + //! Установка имени или GUID связанного объекта + void setEntityName(const char *szName); + + //! Установка GUID + void setEntityGUID(const XGUID &guid); + + //! Установка + void setEntity(CBaseEntity *pEnt); + + //! Получение указателя на объект + CBaseEntity* getEntity(); + + void getEntityName(char *szOutput, int iBufSize); + const XGUID& getGUID(); + + CBaseEntity* operator->(); + operator CBaseEntity*(); + + CEntityPointer& operator=(CBaseEntity *pEnt); + + //! Вызывается при разрушении связи (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; + } + +private: + XGUID m_guid; + CBaseEntity *m_pEntity = NULL; + CEntityManager *m_pMgr = NULL; + CBaseEntity *m_pThisEntity = NULL; + + void(CBaseEntity::*m_pfnOnLinkBroken)(CBaseEntity*) = NULL; + void(CBaseEntity::*m_pfnOnLinkEstablished)(CBaseEntity*) = NULL; + + void init(CEntityManager *pWorld, CBaseEntity *pThisEntity); + + void onLinkBroken(CBaseEntity *pOldEnt); + void onLinkEstablished(CBaseEntity *pNewEnt); + void onTargetRemoved(); + + bool m_isWaiting = false; + void registerWait(); + void unregisterWait(); + void onWaitDone(CBaseEntity *pEnt); +}; + +#endif diff --git a/source/game/FuncTrain.h b/source/game/FuncTrain.h index 458ece6bda83a8126c30dccd41b2a4d0da55780d..d03ad5bc8f1c019e474d665df23609b3adb8a050 100644 --- a/source/game/FuncTrain.h +++ b/source/game/FuncTrain.h @@ -31,7 +31,7 @@ public: void start(); protected: - void onPostLoad(); + void onPostLoad() override; void moveFunc(float dt); //! Начальная точка движения diff --git a/source/game/NPCBase.h b/source/game/NPCBase.h index de5fe426d44975c57dcaa96a29080670b6867135..bc871dad50df2a4158d8856002274a9951fc4032 100644 --- a/source/game/NPCBase.h +++ b/source/game/NPCBase.h @@ -72,7 +72,7 @@ public: void stopOrientAt(); protected: - void onSync(); + void onSync() override; //void think(float fDelta); diff --git a/source/game/PathCorner.h b/source/game/PathCorner.h index d43ada71889815f3fcfeaaa67e14438dc84c2a9b..c15064c6abead767ef84e09d3a4cc9750a68760c 100644 --- a/source/game/PathCorner.h +++ b/source/game/PathCorner.h @@ -55,7 +55,7 @@ public: protected: //! Пересчитывает путь void recalcPath(float t); - void onPostLoad(); + void onPostLoad() override; //! Тип сглаживания int m_type = PCT_SPLINE; diff --git a/source/game/Player.h b/source/game/Player.h index de742773b12fb8fef834494cf612f5c014f51805..c85778560b17befa0e9463727df07c9b37d653b7 100644 --- a/source/game/Player.h +++ b/source/game/Player.h @@ -47,7 +47,7 @@ public: //! Обновляет инпут от игрока virtual void updateInput(float dt); - void onSync(); + void onSync() override; //! Получает смещения для задержки движения модели оружия при вращении игрока float3_t & getWeaponDeltaAngles(); diff --git a/source/game/PointCamera.h b/source/game/PointCamera.h index 93472ef70de4c951e7aa435ecfc40b9765b235f4..6ef275b7ac28398f6ec1d29e6097690c63b39a83 100644 --- a/source/game/PointCamera.h +++ b/source/game/PointCamera.h @@ -35,7 +35,7 @@ public: protected: ICamera * m_pSXC; - void onSync(); + void onSync() override; }; #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/proptable.h b/source/game/proptable.h index 8c2272019d37e05e7d3d0752dbbb47f021928db4..7a72d969b3ddd35d9aa0d0151d912f69e0781289 100644 --- a/source/game/proptable.h +++ b/source/game/proptable.h @@ -8,6 +8,7 @@ See the license in LICENSE #define __PROPTABLE_H #include <common/Math.h> +#include "EntityPointer.h" class CBaseEntity; @@ -420,29 +421,29 @@ 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_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<CEntityPointer 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_FLAGSFN(field, flags, keyname, edname, fn, editor) , {(fieldtype)&DataClass::field, PDF_FLAGS, flags, keyname, edname, fn, editor