From 763b9bee2a38fd85453f3acffc44109019d7115c Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Wed, 25 Dec 2024 02:10:23 +0300 Subject: [PATCH] Split func_ladder to base_mover and func_ladder --- proj/sxgame/vs2013/sxgame.vcxproj | 2 + proj/sxgame/vs2013/sxgame.vcxproj.filters | 24 +- source/game/BaseMover.cpp | 467 ++++++++++++++++++++++ source/game/BaseMover.h | 78 ++++ source/game/FuncLadder.cpp | 443 +------------------- source/game/FuncLadder.h | 68 +--- 6 files changed, 574 insertions(+), 508 deletions(-) create mode 100644 source/game/BaseMover.cpp create mode 100644 source/game/BaseMover.h diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index b70be725f..352079e14 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -182,6 +182,7 @@ <ClCompile Include="..\..\..\source\game\BaseHandle.cpp" /> <ClCompile Include="..\..\..\source\game\BaseLight.cpp" /> <ClCompile Include="..\..\..\source\game\BaseMag.cpp" /> + <ClCompile Include="..\..\..\source\game\BaseMover.cpp" /> <ClCompile Include="..\..\..\source\game\BaseRecipe.cpp" /> <ClCompile Include="..\..\..\source\game\BaseScope.cpp" /> <ClCompile Include="..\..\..\source\game\BaseSilencer.cpp" /> @@ -269,6 +270,7 @@ <ClInclude Include="..\..\..\source\game\BaseLight.h" /> <ClInclude Include="..\..\..\source\game\Baseline.h" /> <ClInclude Include="..\..\..\source\game\BaseMag.h" /> + <ClInclude Include="..\..\..\source\game\BaseMover.h" /> <ClInclude Include="..\..\..\source\game\BaseRecipe.h" /> <ClInclude Include="..\..\..\source\game\BaseScope.h" /> <ClInclude Include="..\..\..\source\game\BaseSilencer.h" /> diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters index 912083c6e..1c43d9d0f 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj.filters +++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters @@ -121,6 +121,12 @@ <Filter Include="Source Files\character_movement"> <UniqueIdentifier>{7f56c9eb-5a04-4d29-ab96-b7e3d8d368f1}</UniqueIdentifier> </Filter> + <Filter Include="Source Files\ents\func\mover"> + <UniqueIdentifier>{c06faca7-33f4-4cd1-999d-b47c933d2b66}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\ents\func\mover"> + <UniqueIdentifier>{457c7c3e-8b6b-4173-ba02-c16e1d376e54}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="..\..\..\source\game\sxgame_dll.cpp"> @@ -324,9 +330,6 @@ <ClCompile Include="..\..\..\source\game\EntityList.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\..\..\source\game\FuncLadder.cpp"> - <Filter>Source Files\ents\func</Filter> - </ClCompile> <ClCompile Include="..\..\..\source\game\PointCamera.cpp"> <Filter>Source Files\ents\point</Filter> </ClCompile> @@ -369,6 +372,12 @@ <ClCompile Include="..\..\..\source\game\LadderMovementController.cpp"> <Filter>Source Files\character_movement</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\game\BaseMover.cpp"> + <Filter>Source Files\ents\func\mover</Filter> + </ClCompile> + <ClCompile Include="..\..\..\source\game\FuncLadder.cpp"> + <Filter>Source Files\ents\func\mover</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\game\sxgame.h"> @@ -596,9 +605,6 @@ <ClInclude Include="..\..\..\source\game\physics_util.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\..\..\source\game\FuncLadder.h"> - <Filter>Header Files\ents\func</Filter> - </ClInclude> <ClInclude Include="..\..\..\source\game\PlayerSpawn.h"> <Filter>Header Files\ents\info</Filter> </ClInclude> @@ -644,6 +650,12 @@ <ClInclude Include="..\..\..\source\game\LadderMovementController.h"> <Filter>Header Files\character_movement</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\BaseMover.h"> + <Filter>Header Files\ents\func\mover</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\FuncLadder.h"> + <Filter>Header Files\ents\func\mover</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\game\sxgame.rc"> diff --git a/source/game/BaseMover.cpp b/source/game/BaseMover.cpp new file mode 100644 index 000000000..773eefe87 --- /dev/null +++ b/source/game/BaseMover.cpp @@ -0,0 +1,467 @@ +#include "BaseMover.h" +#include "BaseCharacter.h" + +TODO("Trigger OnPlayerGetOn/OnPlayerGetOff events"); +TODO("Handle MOVER_NO_AUTOMOUNT flag"); + +BEGIN_PROPTABLE(CBaseMover) + DEFINE_FIELD_VECTORFN(m_vUpPoint, PDFF_USE_GIZMO, "up_point", "Up point", setUpPoint, EDITOR_POINTCOORD) + + //! Игрок присоединился + DEFINE_OUTPUT(m_onPlayerGetOn, "OnPlayerGetOn", "On player get on") + //! Игрок отсоединился + DEFINE_OUTPUT(m_onPlayerGetOff, "OnPlayerGetOff", "On player get off") + + //! Включает + DEFINE_INPUT(turnOn, "turnOn", "Turn on", PDF_NONE) + //! Выключает + DEFINE_INPUT(turnOff, "turnOff", "Turn off", PDF_NONE) + //! Переключает состояние + DEFINE_INPUT(toggle, "toggle", "Toggle", PDF_NONE) + + //! Изначально выключена + DEFINE_FLAG(MOVER_INITIALLY_DISABLED, "Start disabled") + DEFINE_FLAG(MOVER_NO_AUTOMOUNT, "Disable automount") +END_PROPTABLE() + +REGISTER_ENTITY(CBaseMover, base_mover); + +IEventChannel<XEventPhysicsStep> *CBaseMover::m_pTickEventChannel = NULL; + +CBaseMover::CBaseMover(): + m_physicsTicker(this) +{ + if(!m_pTickEventChannel) + { + m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID); + } +} + +CBaseMover::~CBaseMover() +{ + disable(); + mem_release(m_pCollideShape); + mem_release(m_pGhostObject); +} + +void CBaseMover::setUpPoint(const float3 &vUp) +{ + m_vUpPoint = vUp; + + initPhysics(); +} + +void CBaseMover::createPhysBody() +{ + if(!m_pGhostObject) + { + GetPhysics()->newGhostObject(&m_pGhostObject); + m_pGhostObject->setPosition(getPos()); + m_pGhostObject->setUserPointer(this); + m_pGhostObject->setUserTypeId(1); + m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() ^ XCF_NO_CONTACT_RESPONSE); + m_pGhostObject->setCollisionShape(m_pCollideShape); + if(m_isEnabled) + { + GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_LADDER, CG_CHARACTER); + } + } + else + { + m_pGhostObject->setCollisionShape(m_pCollideShape); + } +} + +void CBaseMover::setPos(const float3 &pos) +{ + BaseClass::setPos(pos); + initPhysics(); + SAFE_CALL(m_pGhostObject, setPosition, pos); +} + +void CBaseMover::updateFlags() +{ + BaseClass::updateFlags(); + + if(getFlags() & MOVER_INITIALLY_DISABLED) + { + disable(); + } + else + { + enable(); + } +} + +void CBaseMover::turnOn(inputdata_t *pInputdata) +{ + enable(); +} + +void CBaseMover::turnOff(inputdata_t *pInputdata) +{ + disable(); +} + +void CBaseMover::toggle(inputdata_t *pInputdata) +{ + if(m_isEnabled) + { + turnOff(pInputdata); + } + else + { + turnOn(pInputdata); + } +} + +void CBaseMover::initPhysics() +{ + //TODO: сделать обработку ситуации когда m_vUpPoint ниже getPos + mem_release(m_pCollideShape); + + float3 vDelta = getOrient() * m_vUpPoint; + SMAABB aabb = getBound(); + float3 vMinDelta, vMaxDelta; + + float3_t aPointsBot[] = { + {aabb.vMin.x, aabb.vMax.y, aabb.vMin.z }, + {aabb.vMax.x, aabb.vMax.y, aabb.vMin.z }, + {aabb.vMin.x, aabb.vMax.y, aabb.vMax.z }, + {aabb.vMax.x, aabb.vMax.y, aabb.vMax.z } + }; + + vMinDelta = aabb.vMin + vDelta; + vMaxDelta = aabb.vMax + vDelta; + + float3_t aPointsTop[] = { + { vMinDelta.x, vMinDelta.y, vMinDelta.z }, + { vMaxDelta.x, vMinDelta.y, vMinDelta.z }, + { vMinDelta.x, vMinDelta.y, vMaxDelta.z }, + { vMaxDelta.x, vMinDelta.y, vMaxDelta.z } + }; + + const UINT c_uSize = 14; + UINT uIndex = 0; + float3_t aShapePoints[c_uSize] = {}; + + if(vDelta.x > 0.0f || vDelta.z > 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[0]; + aShapePoints[uIndex++] = aPointsTop[3]; + } + if(vDelta.x < 0.0f || vDelta.z < 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[3]; + aShapePoints[uIndex++] = aPointsTop[0]; + } + if(vDelta.x < 0.0f || vDelta.z > 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[1]; + aShapePoints[uIndex++] = aPointsTop[2]; + } + if(vDelta.x > 0.0f || vDelta.z < 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[2]; + aShapePoints[uIndex++] = aPointsTop[1]; + } + + aShapePoints[uIndex++] = aabb.vMin; + aShapePoints[uIndex++] = {aabb.vMin.x, aabb.vMin.y, aabb.vMax.z}; + aShapePoints[uIndex++] = {aabb.vMax.x, aabb.vMin.y, aabb.vMax.z}; + aShapePoints[uIndex++] = {aabb.vMax.x, aabb.vMin.y, aabb.vMin.z}; + + aShapePoints[uIndex++] = vMaxDelta; + aShapePoints[uIndex++] = {vMaxDelta.x, vMaxDelta.y, vMinDelta.z}; + aShapePoints[uIndex++] = {vMinDelta.x, vMaxDelta.y, vMinDelta.z}; + aShapePoints[uIndex++] = {vMinDelta.x, vMaxDelta.y, vMaxDelta.z}; + + GetPhysics()->newConvexHullShape(uIndex, aShapePoints, &m_pCollideShape, sizeof(float3_t), false); + createPhysBody(); +} + +void CBaseMover::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) +{ + if(pRenderer) + { + const float4 c_vLineColor = bRenderSelection ? float4(1.0f, 0.0f, 0.0f, 1.0f) : float4(1.0f, 0.0f, 1.0f, 1.0f); + pRenderer->setColor(c_vLineColor); + pRenderer->setLineWidth(is3D ? 0.02f : 1.0f); + + SMAABB aabb = getBound(); + pRenderer->drawAABB(aabb + getPos()); + pRenderer->drawAABB(aabb + getUpPos()); + pRenderer->jumpTo(getPos()); + pRenderer->lineTo(getUpPos()); + } +} + +void CBaseMover::getMinMax(float3 *min, float3 *max) +{ + SMAABB aabb = getBound(); + aabb = SMAABBConvex(aabb, aabb + getUpPos() - getPos()); + + if(min) + { + *min = aabb.vMin; + } + + if(max) + { + *max = aabb.vMax; + } +} + +SMAABB CBaseMover::getBound() +{ + return(SMAABB(float3(-0.25f, 0.0f, -0.25f), float3(0.25f, 1.8f, 0.25f))); +} + +bool SMAABBIntersectLine(const SMAABB &aabb, const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal) +{ + float3 vPoint; + SMPLANE plane; + + plane = SMPLANE(float3(1.0f, 0.0f, 0.0f), -aabb.vMax.x); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) + { + *pvNormal = float3(1.0f, 0.0f, 0.0f); + } + return(true); + } + + plane = SMPLANE(float3(-1.0f, 0.0f, 0.0f), aabb.vMin.x); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) + { + *pvNormal = float3(-1.0f, 0.0f, 0.0f); + } + return(true); + } + + plane = SMPLANE(float3(0.0f, 1.0f, 0.0f), -aabb.vMax.y); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) + { + *pvNormal = float3(0.0f, 1.0f, 0.0f); + } + return(true); + } + + plane = SMPLANE(float3(0.0f, -1.0f, 0.0f), aabb.vMin.y); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) + { + *pvNormal = float3(0.0f, -1.0f, 0.0f); + } + return(true); + } + + plane = SMPLANE(float3(0.0f, 0.0f, 1.0f), -aabb.vMax.z); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) + { + *pvNormal = float3(0.0f, 0.0f, 1.0f); + } + return(true); + } + + plane = SMPLANE(float3(0.0f, 0.0f, -1.0f), aabb.vMin.z); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) + { + *pvNormal = float3(0.0f, 0.0f, -1.0f); + } + return(true); + } + + return(false); +} + +bool CBaseMover::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal, bool isRayInWorldSpace, bool bReturnNearestPoint) +{ + assert(isRayInWorldSpace); + + SMAABB aabb = getBound(); + + if(bReturnNearestPoint) + { + bool b0, b1; + float3 vPos0, vPos1; + float3 vNormal0, vNormal1; + float3 *pvNormal0 = NULL, *pvNormal1 = NULL; + if(pvNormal) + { + pvNormal0 = &vNormal0; + pvNormal1 = &vNormal1; + } + + b0 = SMAABBIntersectLine(aabb + getPos(), vStart, vEnd, &vPos0, pvNormal0); + b1 = SMAABBIntersectLine(aabb + getUpPos(), vStart, vEnd, &vPos1, pvNormal1); + + if(b0 && b1) + { + if(SMVector3Length2(vPos0 - vStart) > SMVector3Length2(vPos1 - vStart)) + { + b0 = false; + } + else + { + b1 = false; + } + } + + if(b0) + { + *pvOut = vPos0; + if(pvNormal) + { + *pvNormal = vNormal0; + } + } + else if(b1) + { + *pvOut = vPos1; + if(pvNormal) + { + *pvNormal = vNormal1; + } + } + + return(b0 || b1); + } + else + { + if(SMAABBIntersectLine(aabb + getPos(), vStart, vEnd, pvOut, pvNormal) || SMAABBIntersectLine(aabb + getUpPos(), vStart, vEnd, pvOut, pvNormal)) + { + return(true); + } + } + + return(false); +} + +void CBaseMover::onUse(CBaseEntity *pUser) +{ + handleCharacterMount(pUser); + BaseClass::onUse(pUser); +} + +float3 CBaseMover::getUpPos() +{ + return(getOrient() * m_vUpPoint + getPos()); +} + +void CBaseMover::handleCharacterMount(CBaseEntity *pEntity) +{ + if(fstrcmp(pEntity->getClassName(), "player")) + { + return; + } + CBaseCharacter *pCharacter = (CBaseCharacter*)pEntity; + + IMovementController *pController = NULL; + newMovementController(&pController); + + if(pController) + { + pCharacter->setMovementController(pController); + mem_release(pController); + } +} + +void CBaseMover::onPhysicsStep() +{ + if(!m_pGhostObject || !m_isEnabled) + { + return; + } + + Array<CBaseEntity*> aCurrentTouchingEntities(m_aTouchedEntities.size()); + + for(UINT i = 0, l = m_pGhostObject->getOverlappingPairCount(); i < l; ++i) + { + IXCollisionPair *pair = m_pGhostObject->getOverlappingPair(i); + + for(UINT j = 0, jl = pair->getContactManifoldCount(); j < jl; ++j) + { + IXContactManifold *pManifold = pair->getContactManifold(j); + if(pManifold->getContactCount() > 0) + { + IXCollisionObject *p0 = pair->getObject0(); + IXCollisionObject *p1 = pair->getObject1(); + + const IXCollisionObject *pObject = p0 == m_pGhostObject ? p1 : p0; + + if(pObject->getUserPointer() && pObject->getUserTypeId() == 1) + { + CBaseEntity *pEnt = (CBaseEntity*)pObject->getUserPointer(); + if(pEnt) + { + aCurrentTouchingEntities.push_back(pEnt); + if(m_aTouchedEntities.indexOf(pEnt) < 0) + { + handleCharacterMount(pEnt); + //printf("touched %s\n", pEnt->getClassName()); + } + } + } + break; + } + } + } + + m_aTouchedEntities = aCurrentTouchingEntities; +} + + +void CBaseMover::enable() +{ + if(!m_isEnabled) + { + if(m_pGhostObject) + { + GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_LADDER, CG_CHARACTER); + } + m_pTickEventChannel->addListener(&m_physicsTicker); + m_isEnabled = true; + } +} + +void CBaseMover::disable() +{ + if(m_isEnabled) + { + if(m_pGhostObject) + { + GetPhysWorld()->removeCollisionObject(m_pGhostObject); + } + m_pTickEventChannel->removeListener(&m_physicsTicker); + m_isEnabled = false; + } +} + +void CBaseMover::newMovementController(IMovementController **ppOut) +{ + *ppOut = NULL; +} + +//########################################################################## + +void CPhysicsLadderTickEventListener::onEvent(const XEventPhysicsStep *pData) +{ + m_pMover->onPhysicsStep(); +} diff --git a/source/game/BaseMover.h b/source/game/BaseMover.h new file mode 100644 index 000000000..6b9776be3 --- /dev/null +++ b/source/game/BaseMover.h @@ -0,0 +1,78 @@ +#ifndef __BASE_MOVER_H +#define __BASE_MOVER_H + +#include "PointEntity.h" + +#define MOVER_INITIALLY_DISABLED ENT_FLAG_0 +#define MOVER_NO_AUTOMOUNT ENT_FLAG_1 + +class CBaseMover; +class CPhysicsLadderTickEventListener final: public IEventListener<XEventPhysicsStep> +{ +public: + CPhysicsLadderTickEventListener(CBaseMover *pMover): + m_pMover(pMover) + { + } + void onEvent(const XEventPhysicsStep *pData) override; + +private: + CBaseMover *m_pMover; +}; + +class IMovementController; +class CBaseMover: public CPointEntity +{ + DECLARE_CLASS(CBaseMover, CPointEntity); + DECLARE_PROPTABLE(); + friend class CPhysicsLadderTickEventListener; +public: + DECLARE_CONSTRUCTOR(); + ~CBaseMover(); + + void setPos(const float3 &pos) override; + + void renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) override; + + void getMinMax(float3 *min, float3 *max) override; + + bool rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut = NULL, float3 *pvNormal = NULL, bool isRayInWorldSpace = true, bool bReturnNearestPoint = false) override; + + void onUse(CBaseEntity *pUser) override; + + float3 getUpPos(); + +private: + void handleCharacterMount(CBaseEntity *pEntity); + void createPhysBody(); + void setUpPoint(const float3 &vUp); + void updateFlags() override; + + void turnOn(inputdata_t *pInputdata); + void turnOff(inputdata_t *pInputdata); + void toggle(inputdata_t *pInputdata); + void initPhysics(); + void enable(); + void disable(); + void onPhysicsStep(); + + SMAABB getBound(); + + virtual void newMovementController(IMovementController **ppOut); + +private: + float3_t m_vUpPoint = float3_t(0.0f, 2.0f, 0.0f); + bool m_isEnabled = false; + + output_t m_onPlayerGetOn; + output_t m_onPlayerGetOff; + + IXGhostObject *m_pGhostObject = NULL; + IXConvexHullShape *m_pCollideShape = NULL; + static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; + CPhysicsLadderTickEventListener m_physicsTicker; + + Array<CBaseEntity*> m_aTouchedEntities; +}; + +#endif diff --git a/source/game/FuncLadder.cpp b/source/game/FuncLadder.cpp index d738af4db..dc0bea4ab 100644 --- a/source/game/FuncLadder.cpp +++ b/source/game/FuncLadder.cpp @@ -12,449 +12,12 @@ REGISTER_ENTITY(CInfoLadderDismount, info_ladder_dismount); //########################################################################## BEGIN_PROPTABLE(CFuncLadder) - DEFINE_FIELD_VECTORFN(m_vUpPoint, PDFF_USE_GIZMO, "up_point", "Up point", setUpPoint, EDITOR_POINTCOORD) - - //! Плеер залез на лестницу - DEFINE_OUTPUT(m_onPlayerGetOn, "OnPlayerGetOn", "On player get on") - //! Плеер слез с лестницы - DEFINE_OUTPUT(m_onPlayerGetOff, "OnPlayerGetOff", "On player get off") - - //! Включает лестницу - DEFINE_INPUT(turnOn, "turnOn", "Turn on", PDF_NONE) - //! Выключает лестницу - DEFINE_INPUT(turnOff, "turnOff", "Turn off", PDF_NONE) - //! Переключает состояние лестницы - DEFINE_INPUT(toggle, "toggle", "Toggle", PDF_NONE) - - //! Изначально выключена - DEFINE_FLAG(LADDER_INITIALLY_DISABLED, "Start disabled") + // empty END_PROPTABLE() REGISTER_ENTITY(CFuncLadder, func_ladder); -IEventChannel<XEventPhysicsStep> *CFuncLadder::m_pTickEventChannel = NULL; - -CFuncLadder::CFuncLadder(): - m_physicsTicker(this) -{ - if(!m_pTickEventChannel) - { - m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID); - } -} - -CFuncLadder::~CFuncLadder() -{ - disable(); - mem_release(m_pCollideShape); - mem_release(m_pGhostObject); -} - -void CFuncLadder::setUpPoint(const float3 &vUp) -{ - m_vUpPoint = vUp; - - initPhysics(); -} - -void CFuncLadder::createPhysBody() -{ - if(!m_pGhostObject) - { - GetPhysics()->newGhostObject(&m_pGhostObject); - m_pGhostObject->setPosition(getPos()); - m_pGhostObject->setUserPointer(this); - m_pGhostObject->setUserTypeId(1); - m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() ^ XCF_NO_CONTACT_RESPONSE); - m_pGhostObject->setCollisionShape(m_pCollideShape); - if(m_isEnabled) - { - GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_LADDER, CG_CHARACTER); - } - } - else - { - m_pGhostObject->setCollisionShape(m_pCollideShape); - } -} - -void CFuncLadder::setPos(const float3 &pos) -{ - BaseClass::setPos(pos); - initPhysics(); - SAFE_CALL(m_pGhostObject, setPosition, pos); -} - -void CFuncLadder::updateFlags() -{ - BaseClass::updateFlags(); - - if(getFlags() & LADDER_INITIALLY_DISABLED) - { - disable(); - } - else - { - enable(); - } -} - -void CFuncLadder::turnOn(inputdata_t *pInputdata) -{ - enable(); -} - -void CFuncLadder::turnOff(inputdata_t *pInputdata) -{ - disable(); -} - -void CFuncLadder::toggle(inputdata_t *pInputdata) -{ - if(m_isEnabled) - { - turnOff(pInputdata); - } - else - { - turnOn(pInputdata); - } -} - -void CFuncLadder::initPhysics() -{ - //TODO: сделать обработку ситуации когда m_vUpPoint ниже getPos - mem_release(m_pCollideShape); - - float3 vDelta = getOrient() * m_vUpPoint; - SMAABB aabb = getBound(); - float3 vMinDelta, vMaxDelta; - - float3_t aPointsBot[] = { - {aabb.vMin.x, aabb.vMax.y, aabb.vMin.z }, - {aabb.vMax.x, aabb.vMax.y, aabb.vMin.z }, - {aabb.vMin.x, aabb.vMax.y, aabb.vMax.z }, - {aabb.vMax.x, aabb.vMax.y, aabb.vMax.z } - }; - - vMinDelta = aabb.vMin + vDelta; - vMaxDelta = aabb.vMax + vDelta; - - float3_t aPointsTop[] = { - { vMinDelta.x, vMinDelta.y, vMinDelta.z }, - { vMaxDelta.x, vMinDelta.y, vMinDelta.z }, - { vMinDelta.x, vMinDelta.y, vMaxDelta.z }, - { vMaxDelta.x, vMinDelta.y, vMaxDelta.z } - }; - - const UINT c_uSize = 14; - UINT uIndex = 0; - float3_t aShapePoints[c_uSize] = {}; - - if(vDelta.x > 0.0f || vDelta.z > 0.0f) - { - aShapePoints[uIndex++] = aPointsBot[0]; - aShapePoints[uIndex++] = aPointsTop[3]; - } - if(vDelta.x < 0.0f || vDelta.z < 0.0f) - { - aShapePoints[uIndex++] = aPointsBot[3]; - aShapePoints[uIndex++] = aPointsTop[0]; - } - if(vDelta.x < 0.0f || vDelta.z > 0.0f) - { - aShapePoints[uIndex++] = aPointsBot[1]; - aShapePoints[uIndex++] = aPointsTop[2]; - } - if(vDelta.x > 0.0f || vDelta.z < 0.0f) - { - aShapePoints[uIndex++] = aPointsBot[2]; - aShapePoints[uIndex++] = aPointsTop[1]; - } - - aShapePoints[uIndex++] = aabb.vMin; - aShapePoints[uIndex++] = {aabb.vMin.x, aabb.vMin.y, aabb.vMax.z}; - aShapePoints[uIndex++] = {aabb.vMax.x, aabb.vMin.y, aabb.vMax.z}; - aShapePoints[uIndex++] = {aabb.vMax.x, aabb.vMin.y, aabb.vMin.z}; - - aShapePoints[uIndex++] = vMaxDelta; - aShapePoints[uIndex++] = {vMaxDelta.x, vMaxDelta.y, vMinDelta.z}; - aShapePoints[uIndex++] = {vMinDelta.x, vMaxDelta.y, vMinDelta.z}; - aShapePoints[uIndex++] = {vMinDelta.x, vMaxDelta.y, vMaxDelta.z}; - - GetPhysics()->newConvexHullShape(uIndex, aShapePoints, &m_pCollideShape, sizeof(float3_t), false); - createPhysBody(); -} - -void CFuncLadder::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) -{ - if(pRenderer) - { - const float4 c_vLineColor = bRenderSelection ? float4(1.0f, 0.0f, 0.0f, 1.0f) : float4(1.0f, 0.0f, 1.0f, 1.0f); - pRenderer->setColor(c_vLineColor); - pRenderer->setLineWidth(is3D ? 0.02f : 1.0f); - - SMAABB aabb = getBound(); - pRenderer->drawAABB(aabb + getPos()); - pRenderer->drawAABB(aabb + getUpPos()); - pRenderer->jumpTo(getPos()); - pRenderer->lineTo(getUpPos()); - } -} - -void CFuncLadder::getMinMax(float3 *min, float3 *max) -{ - SMAABB aabb = getBound(); - aabb = SMAABBConvex(aabb, aabb + getUpPos() - getPos()); - - if(min) - { - *min = aabb.vMin; - } - - if(max) - { - *max = aabb.vMax; - } -} - -SMAABB CFuncLadder::getBound() -{ - return(SMAABB(float3(-0.25f, 0.0f, -0.25f), float3(0.25f, 1.8f, 0.25f))); -} - -bool SMAABBIntersectLine(const SMAABB &aabb, const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal) -{ - float3 vPoint; - SMPLANE plane; - - plane = SMPLANE(float3(1.0f, 0.0f, 0.0f), -aabb.vMax.x); - if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) - { - *pvOut = vPoint; - if(pvNormal) - { - *pvNormal = float3(1.0f, 0.0f, 0.0f); - } - return(true); - } - - plane = SMPLANE(float3(-1.0f, 0.0f, 0.0f), aabb.vMin.x); - if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) - { - *pvOut = vPoint; - if(pvNormal) - { - *pvNormal = float3(-1.0f, 0.0f, 0.0f); - } - return(true); - } - - plane = SMPLANE(float3(0.0f, 1.0f, 0.0f), -aabb.vMax.y); - if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) - { - *pvOut = vPoint; - if(pvNormal) - { - *pvNormal = float3(0.0f, 1.0f, 0.0f); - } - return(true); - } - - plane = SMPLANE(float3(0.0f, -1.0f, 0.0f), aabb.vMin.y); - if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) - { - *pvOut = vPoint; - if(pvNormal) - { - *pvNormal = float3(0.0f, -1.0f, 0.0f); - } - return(true); - } - - plane = SMPLANE(float3(0.0f, 0.0f, 1.0f), -aabb.vMax.z); - if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) - { - *pvOut = vPoint; - if(pvNormal) - { - *pvNormal = float3(0.0f, 0.0f, 1.0f); - } - return(true); - } - - plane = SMPLANE(float3(0.0f, 0.0f, -1.0f), aabb.vMin.z); - if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) - { - *pvOut = vPoint; - if(pvNormal) - { - *pvNormal = float3(0.0f, 0.0f, -1.0f); - } - return(true); - } - - return(false); -} - -bool CFuncLadder::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal, bool isRayInWorldSpace, bool bReturnNearestPoint) -{ - assert(isRayInWorldSpace); - - SMAABB aabb = getBound(); - - if(bReturnNearestPoint) - { - bool b0, b1; - float3 vPos0, vPos1; - float3 vNormal0, vNormal1; - float3 *pvNormal0 = NULL, *pvNormal1 = NULL; - if(pvNormal) - { - pvNormal0 = &vNormal0; - pvNormal1 = &vNormal1; - } - - b0 = SMAABBIntersectLine(aabb + getPos(), vStart, vEnd, &vPos0, pvNormal0); - b1 = SMAABBIntersectLine(aabb + getUpPos(), vStart, vEnd, &vPos1, pvNormal1); - - if(b0 && b1) - { - if(SMVector3Length2(vPos0 - vStart) > SMVector3Length2(vPos1 - vStart)) - { - b0 = false; - } - else - { - b1 = false; - } - } - - if(b0) - { - *pvOut = vPos0; - if(pvNormal) - { - *pvNormal = vNormal0; - } - } - else if(b1) - { - *pvOut = vPos1; - if(pvNormal) - { - *pvNormal = vNormal1; - } - } - - return(b0 || b1); - } - else - { - if(SMAABBIntersectLine(aabb + getPos(), vStart, vEnd, pvOut, pvNormal) || SMAABBIntersectLine(aabb + getUpPos(), vStart, vEnd, pvOut, pvNormal)) - { - return(true); - } - } - - return(false); -} - -void CFuncLadder::onUse(CBaseEntity *pUser) -{ - connectToLadder(pUser); - BaseClass::onUse(pUser); -} - -float3 CFuncLadder::getUpPos() -{ - return(getOrient() * m_vUpPoint + getPos()); -} - -void CFuncLadder::connectToLadder(CBaseEntity *pEntity) -{ - if(fstrcmp(pEntity->getClassName(), "player")) - { - return; - } - CBaseCharacter *pCharacter = (CBaseCharacter*)pEntity; - CLadderMovementController *pController = new CLadderMovementController(this); - pCharacter->setMovementController(pController); - mem_release(pController); -} - -void CFuncLadder::onPhysicsStep() -{ - if(!m_pGhostObject || !m_isEnabled) - { - return; - } - - Array<CBaseEntity*> aCurrentTouchingEntities(m_aTouchedEntities.size()); - - for(UINT i = 0, l = m_pGhostObject->getOverlappingPairCount(); i < l; ++i) - { - IXCollisionPair *pair = m_pGhostObject->getOverlappingPair(i); - - for(UINT j = 0, jl = pair->getContactManifoldCount(); j < jl; ++j) - { - IXContactManifold *pManifold = pair->getContactManifold(j); - if(pManifold->getContactCount() > 0) - { - IXCollisionObject *p0 = pair->getObject0(); - IXCollisionObject *p1 = pair->getObject1(); - - const IXCollisionObject *pObject = p0 == m_pGhostObject ? p1 : p0; - - if(pObject->getUserPointer() && pObject->getUserTypeId() == 1) - { - CBaseEntity *pEnt = (CBaseEntity*)pObject->getUserPointer(); - if(pEnt) - { - aCurrentTouchingEntities.push_back(pEnt); - if(m_aTouchedEntities.indexOf(pEnt) < 0) - { - connectToLadder(pEnt); - //printf("touched %s\n", pEnt->getClassName()); - } - } - } - break; - } - } - } - - m_aTouchedEntities = aCurrentTouchingEntities; -} - - -void CFuncLadder::enable() -{ - if(!m_isEnabled) - { - if(m_pGhostObject) - { - GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_LADDER, CG_CHARACTER); - } - m_pTickEventChannel->addListener(&m_physicsTicker); - m_isEnabled = true; - } -} - -void CFuncLadder::disable() -{ - if(m_isEnabled) - { - if(m_pGhostObject) - { - GetPhysWorld()->removeCollisionObject(m_pGhostObject); - } - m_pTickEventChannel->removeListener(&m_physicsTicker); - m_isEnabled = false; - } -} - -void CPhysicsLadderTickEventListener::onEvent(const XEventPhysicsStep *pData) +void CFuncLadder::newMovementController(IMovementController **ppOut) { - m_pLadder->onPhysicsStep(); + *ppOut = new CLadderMovementController(this); } diff --git a/source/game/FuncLadder.h b/source/game/FuncLadder.h index 5ea6f958b..9fd556a77 100644 --- a/source/game/FuncLadder.h +++ b/source/game/FuncLadder.h @@ -1,7 +1,7 @@ #ifndef __FUNC_LADDER_H #define __FUNC_LADDER_H -#include "PointEntity.h" +#include "BaseMover.h" class CInfoLadderDismount: public CPointEntity { @@ -13,72 +13,16 @@ public: //########################################################################## -#define LADDER_INITIALLY_DISABLED ENT_FLAG_0 - -class CFuncLadder; -class CPhysicsLadderTickEventListener final : public IEventListener<XEventPhysicsStep> +class CFuncLadder: public CBaseMover { -public: - CPhysicsLadderTickEventListener(CFuncLadder *pLadder) : - m_pLadder(pLadder) - { - } - void onEvent(const XEventPhysicsStep *pData) override; - -private: - CFuncLadder *m_pLadder; -}; - -class CFuncLadder: public CPointEntity -{ - DECLARE_CLASS(CFuncLadder, CPointEntity); + DECLARE_CLASS(CFuncLadder, CBaseMover); DECLARE_PROPTABLE(); friend class CPhysicsLadderTickEventListener; public: - DECLARE_CONSTRUCTOR(); - ~CFuncLadder(); - - void setPos(const float3 &pos) override; - - void renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) override; - - void getMinMax(float3 *min, float3 *max) override; - - bool rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut = NULL, float3 *pvNormal = NULL, bool isRayInWorldSpace = true, bool bReturnNearestPoint = false) override; - - void onUse(CBaseEntity *pUser) override; - - float3 getUpPos(); - -private: - void connectToLadder(CBaseEntity *pEntity); - void createPhysBody(); - void setUpPoint(const float3 &vUp); - void updateFlags() override; - - void turnOn(inputdata_t *pInputdata); - void turnOff(inputdata_t *pInputdata); - void toggle(inputdata_t *pInputdata); - void initPhysics(); - void enable(); - void disable(); - void onPhysicsStep(); - - SMAABB getBound(); - + DECLARE_TRIVIAL_CONSTRUCTOR(); + private: - float3_t m_vUpPoint = float3_t(0.0f, 2.0f, 0.0f); - bool m_isEnabled = false; - - output_t m_onPlayerGetOn; - output_t m_onPlayerGetOff; - - IXGhostObject *m_pGhostObject = NULL; - IXConvexHullShape *m_pCollideShape = NULL; - static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; - CPhysicsLadderTickEventListener m_physicsTicker; - - Array<CBaseEntity*> m_aTouchedEntities; + void newMovementController(IMovementController **ppOut) override; }; #endif -- GitLab