BVB Source Codes

CRYENGINE Show FlowPhysicsNodes.cpp Source code

Return Download CRYENGINE: download FlowPhysicsNodes.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4.  
  5. #include <CryEntitySystem/IEntitySystem.h>
  6. #include <CryAISystem/IAISystem.h>
  7. #include <CryAISystem/IAgent.h>
  8. #include <CryAISystem/IAIObject.h>
  9. #include <CryFlowGraph/IFlowBaseNode.h>
  10.  
  11. class CFlowNode_Dynamics : public CFlowBaseNode<eNCT_Singleton>
  12. {
  13. public:
  14.         CFlowNode_Dynamics(SActivationInfo* pActInfo)
  15.         {
  16.         }
  17.  
  18.         virtual void GetConfiguration(SFlowNodeConfig& config)
  19.         {
  20.                 static const SInputPortConfig in_config[] = {
  21.                         InputPortConfig<bool>("active", true, _HELP("Update data on/off")),
  22.                         { 0 }
  23.                 };
  24.  
  25.                 static const SOutputPortConfig out_config[] = {
  26.                         OutputPortConfig<Vec3>("v",  _HELP("Velocity of entity")),
  27.                         OutputPortConfig<Vec3>("a",  _HELP("Acceleration of entity")),
  28.                         OutputPortConfig<Vec3>("w",  _HELP("Angular velocity of entity")),
  29.                         OutputPortConfig<Vec3>("wa", _HELP("Angular acceleration of entity")),
  30.                         OutputPortConfig<float>("m", _HELP("Mass of entity")),
  31.                         { 0 }
  32.                 };
  33.                 config.nFlags |= EFLN_TARGET_ENTITY;
  34.                 config.pInputPorts = in_config;
  35.                 config.pOutputPorts = out_config;
  36.                 config.sDescription = _HELP("Dynamic physical state of an entity");
  37.                 config.SetCategory(EFLN_APPROVED); // POLICY CHANGE: Maybe an Enable/Disable Port
  38.         }
  39.  
  40.         virtual void GetMemoryUsage(ICrySizer* s) const
  41.         {
  42.                 s->Add(*this);
  43.         }
  44.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  45.         {
  46.                 switch (event)
  47.                 {
  48.                 case eFE_Initialize:
  49.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  50.                         break;
  51.                 case eFE_Update:
  52.                         {
  53.                                 if (!GetPortBool(pActInfo, 0))
  54.                                         return;
  55.  
  56.                                 IEntity* pEntity = pActInfo->pEntity;
  57.                                 if (pEntity)
  58.                                 {
  59.                                         IPhysicalEntity* pPhysEntity = pEntity->GetPhysics();
  60.                                         if (pPhysEntity)
  61.                                         {
  62.                                                 pe_status_dynamics dyn;
  63.                                                 pPhysEntity->GetStatus(&dyn);
  64.                                                 ActivateOutput(pActInfo, 0, dyn.v);
  65.                                                 ActivateOutput(pActInfo, 1, dyn.a);
  66.                                                 ActivateOutput(pActInfo, 2, dyn.w);
  67.                                                 ActivateOutput(pActInfo, 3, dyn.wa);
  68.                                                 ActivateOutput(pActInfo, 4, dyn.mass);
  69.                                         }
  70.                                 }
  71.                         }
  72.                 }
  73.         }
  74. };
  75.  
  76. class CFlowNode_PhysicsSleepQuery : public CFlowBaseNode<eNCT_Instanced>
  77. {
  78.         enum EInPorts
  79.         {
  80.                 IN_CONDITION = 0,
  81.                 IN_RESET
  82.         };
  83.         enum EOutPorts
  84.         {
  85.                 OUT_SLEEPING = 0,
  86.                 OUT_ONSLEEP,
  87.                 OUT_ONAWAKE
  88.         };
  89.  
  90.         bool m_Activated;
  91.  
  92. public:
  93.         CFlowNode_PhysicsSleepQuery(SActivationInfo* pActInfo) : m_Activated(false) {}
  94.  
  95.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  96.         {
  97.                 return new CFlowNode_PhysicsSleepQuery(pActInfo);
  98.         }
  99.  
  100.         virtual void GetMemoryUsage(ICrySizer* s) const
  101.         {
  102.                 s->Add(*this);
  103.         }
  104.  
  105.         virtual void GetConfiguration(SFlowNodeConfig& config)
  106.         {
  107.                 static const SInputPortConfig in_config[] = {
  108.                         InputPortConfig<bool>("condition", _HELP("Setting this input to TRUE sends the sleeping condition of the entity to the [sleeping] port, and triggers [sleep] and [awake]")),
  109.                         InputPortConfig<bool>("reset",     _HELP("Triggering this input to TRUE resets the node")),
  110.                         { 0 }
  111.                 };
  112.                 static const SOutputPortConfig out_config[] = {
  113.                         OutputPortConfig<bool>("sleeping",         _HELP("Set to TRUE when the physics of the entity are sleeping (passes the value through)")),
  114.                         OutputPortConfig<SFlowSystemVoid>("sleep", _HELP("Triggers to TRUE when the physics of the entity switch to sleep")),
  115.                         OutputPortConfig<SFlowSystemVoid>("awake", _HELP("Triggers to TRUE when the physics of the entity switch to awake")),
  116.                         { 0 }
  117.                 };
  118.                 config.nFlags |= EFLN_TARGET_ENTITY;
  119.                 config.pInputPorts = in_config;
  120.                 config.pOutputPorts = out_config;
  121.                 config.sDescription = _HELP("Node that returns the sleeping state of the physics of a given entity.");
  122.                 config.SetCategory(EFLN_APPROVED);
  123.         }
  124.  
  125.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  126.         {
  127.                 switch (event)
  128.                 {
  129.                 case eFE_Initialize:
  130.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  131.                         m_Activated = false;
  132.                         break;
  133.  
  134.                 case eFE_Update:
  135.                         {
  136.                                 bool bReset = GetPortBool(pActInfo, IN_RESET);
  137.                                 bool bCondition = GetPortBool(pActInfo, IN_CONDITION);
  138.  
  139.                                 if (bReset)
  140.                                 {
  141.                                         ActivateOutput(pActInfo, OUT_SLEEPING, !bCondition);
  142.                                 }
  143.                                 else
  144.                                 {
  145.                                         if (bCondition != m_Activated)
  146.                                         {
  147.                                                 IEntity* pEntity = pActInfo->pEntity;
  148.  
  149.                                                 if (pEntity)
  150.                                                 {
  151.                                                         IPhysicalEntity* pPhysEntity = pEntity->GetPhysics();
  152.  
  153.                                                         if (pPhysEntity)
  154.                                                         {
  155.                                                                 pe_status_awake psa;
  156.  
  157.                                                                 bool isSleeping = pPhysEntity->GetStatus(&psa) ? false : true;
  158.  
  159.                                                                 ActivateOutput(pActInfo, OUT_SLEEPING, isSleeping);
  160.  
  161.                                                                 if (isSleeping)
  162.                                                                         ActivateOutput(pActInfo, OUT_ONSLEEP, true);
  163.                                                                 else
  164.                                                                         ActivateOutput(pActInfo, OUT_ONAWAKE, true);
  165.                                                         }
  166.                                                 }
  167.  
  168.                                                 m_Activated = bCondition;
  169.                                         }
  170.                                 }
  171.                         }
  172.                 }
  173.         }
  174. };
  175.  
  176. class CFlowNode_ActionImpulse : public CFlowBaseNode<eNCT_Singleton>
  177. {
  178.         enum ECoordSys
  179.         {
  180.                 CS_PARENT = 0,
  181.                 CS_WORLD,
  182.                 CS_LOCAL
  183.         };
  184.  
  185.         enum EInPorts
  186.         {
  187.                 IN_ACTIVATE = 0,
  188.                 IN_IMPULSE,
  189.                 IN_ANGIMPULSE,
  190.                 IN_POINT,
  191.                 IN_PARTINDEX,
  192.                 IN_COORDSYS,
  193.         };
  194.  
  195. public:
  196.         CFlowNode_ActionImpulse(SActivationInfo* pActInfo) {}
  197.  
  198.         virtual void GetMemoryUsage(ICrySizer* s) const
  199.         {
  200.                 s->Add(*this);
  201.         }
  202.  
  203.         virtual void GetConfiguration(SFlowNodeConfig& config)
  204.         {
  205.                 static const SInputPortConfig in_config[] = {
  206.                         InputPortConfig_Void("activate",    _HELP("Trigger the impulse")),
  207.                         InputPortConfig<Vec3>("impulse",    Vec3(0,                       0,                                                                                             0),                _HELP("Impulse vector")),
  208.                         InputPortConfig<Vec3>("angImpulse", Vec3(0,                       0,                                                                                             0),                _HELP("The angular impulse")),
  209.                         InputPortConfig<Vec3>("Point",      Vec3(0,                       0,                                                                                             0),                _HELP("Point of application (optional)")),
  210.                         InputPortConfig<int>("partIndex",   0,                            _HELP("Index of the part that will receive the impulse (optional, 1-based, 0=unspecified)")),
  211.                         InputPortConfig<int>("CoordSys",    1,                            _HELP("Defines which coordinate system is used for the inputs values"),                        _HELP("CoordSys"), _UICONFIG("enum_int:Parent=0,World=1,Local=2")),
  212.                         { 0 }
  213.                 };
  214.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  215.                 config.pInputPorts = in_config;
  216.                 config.pOutputPorts = 0;
  217.                 config.sDescription = _HELP("Applies an impulse on an entity");
  218.                 config.SetCategory(EFLN_APPROVED);
  219.         }
  220.  
  221.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  222.         {
  223.                 if (!pActInfo->pEntity)
  224.                         return;
  225.  
  226.                 if (event == eFE_Activate && IsPortActive(pActInfo, IN_ACTIVATE))
  227.                 {
  228.                         pe_action_impulse action;
  229.  
  230.                         int ipart = GetPortInt(pActInfo, IN_PARTINDEX);
  231.                         if (ipart > 0)
  232.                                 action.ipart = ipart - 1;
  233.  
  234.                         IEntity* pEntity = pActInfo->pEntity;
  235.                         ECoordSys coordSys = (ECoordSys)GetPortInt(pActInfo, IN_COORDSYS);
  236.  
  237.                         if (coordSys == CS_PARENT && !pEntity->GetParent())
  238.                                 coordSys = CS_WORLD;
  239.  
  240.                         // When a "zero point" is set in the node, the value is left undefined and physics assume it is the CM of the object.
  241.                         // but when the entity has a parent (is linked), then we have to use a real world coordinate for the point, because we have to apply the impulse to the highest entity
  242.                         // on the hierarchy and physics will use the position of that entity instead of the position of the entity assigned to the node
  243.                         bool bHaveToUseTransformedZeroPoint = false;
  244.                         Vec3 transformedZeroPoint;
  245.                         Matrix34 transMat;
  246.  
  247.                         switch (coordSys)
  248.                         {
  249.                         case CS_WORLD:
  250.                         default:
  251.                                 {
  252.                                         transMat.SetIdentity();
  253.                                         bHaveToUseTransformedZeroPoint = pEntity->GetParent() != NULL;
  254.                                         transformedZeroPoint = pEntity->GetWorldPos();
  255.                                         break;
  256.                                 }
  257.  
  258.                         case CS_PARENT:
  259.                                 {
  260.                                         transMat = pEntity->GetParent()->GetWorldTM();
  261.                                         bHaveToUseTransformedZeroPoint = pEntity->GetParent()->GetParent() != NULL;
  262.                                         transformedZeroPoint = pEntity->GetParent()->GetWorldPos();
  263.                                         break;
  264.                                 }
  265.  
  266.                         case CS_LOCAL:
  267.                                 {
  268.                                         transMat = pEntity->GetWorldTM();
  269.                                         bHaveToUseTransformedZeroPoint = pEntity->GetParent() != NULL;
  270.                                         transformedZeroPoint = pEntity->GetWorldPos();
  271.                                         break;
  272.                                 }
  273.                         }
  274.  
  275.                         action.impulse = GetPortVec3(pActInfo, IN_IMPULSE);
  276.                         action.impulse = transMat.TransformVector(action.impulse);
  277.  
  278.                         Vec3 angImpulse = GetPortVec3(pActInfo, IN_ANGIMPULSE);
  279.                         if (!angImpulse.IsZero())
  280.                                 action.angImpulse = transMat.TransformVector(angImpulse);
  281.  
  282.                         Vec3 pointApplication = GetPortVec3(pActInfo, IN_POINT);
  283.                         if (!pointApplication.IsZero())
  284.                                 action.point = transMat.TransformPoint(pointApplication);
  285.                         else
  286.                         {
  287.                                 if (bHaveToUseTransformedZeroPoint)
  288.                                         action.point = transformedZeroPoint;
  289.                         }
  290.  
  291.                         // the impulse has to be applied to the highest entity in the hierarchy. This comes from how physics manage linked entities.
  292.                         IEntity* pEntityImpulse = pEntity;
  293.                         while (pEntityImpulse->GetParent())
  294.                         {
  295.                                 pEntityImpulse = pEntityImpulse->GetParent();
  296.                         }
  297.  
  298.                         IPhysicalEntity* pPhysEntity = pEntityImpulse->GetPhysics();
  299.                         if (pPhysEntity)
  300.                                 pPhysEntity->Action(&action);
  301.                 }
  302.         }
  303. };
  304.  
  305. class CFlowNode_Raycast : public CFlowBaseNode<eNCT_Singleton>
  306. {
  307. public:
  308.         CFlowNode_Raycast(SActivationInfo* pActInfo) {}
  309.  
  310.         enum EInPorts
  311.         {
  312.                 GO = 0,
  313.                 DIR,
  314.                 MAXLENGTH,
  315.                 POS,
  316.                 TRANSFORM_DIRECTION,
  317.         };
  318.         enum EOutPorts
  319.         {
  320.                 NOHIT = 0,
  321.                 HIT,
  322.                 DIROUT,
  323.                 DISTANCE,
  324.                 HITPOINT,
  325.                 NORMAL,
  326.                 SURFTYPE,
  327.                 HIT_ENTITY,
  328.         };
  329.  
  330.         virtual void GetMemoryUsage(ICrySizer* s) const
  331.         {
  332.                 s->Add(*this);
  333.         }
  334.  
  335.         virtual void GetConfiguration(SFlowNodeConfig& config)
  336.         {
  337.                 static const SInputPortConfig in_config[] = {
  338.                         InputPortConfig<SFlowSystemVoid>("go", SFlowSystemVoid(), _HELP("Perform Raycast")),
  339.                         InputPortConfig<Vec3>("direction",     Vec3(0,            1,                                                        0),  _HELP("Direction of Raycast")),
  340.                         InputPortConfig<float>("maxLength",    10.0f,             _HELP("Maximum length of Raycast")),
  341.                         InputPortConfig<Vec3>("position",      Vec3(0,            0,                                                        0),  _HELP("Ray start position, relative to entity")),
  342.                         InputPortConfig<bool>("transformDir",  true,              _HELP("Direction is transformed by entity orientation.")),
  343.                         { 0 }
  344.                 };
  345.                 static const SOutputPortConfig out_config[] = {
  346.                         OutputPortConfig<SFlowSystemVoid>("nohit", _HELP("Triggered if NO object was hit by raycast")),
  347.                         OutputPortConfig<SFlowSystemVoid>("hit",   _HELP("Triggered if an object was hit by raycast")),
  348.                         OutputPortConfig<Vec3>("direction",        _HELP("Actual direction of the cast ray (transformed by entity rotation")),
  349.                         OutputPortConfig<float>("distance",        _HELP("Distance to object hit")),
  350.                         OutputPortConfig<Vec3>("hitpoint",         _HELP("Position the ray hit")),
  351.                         OutputPortConfig<Vec3>("normal",           _HELP("Normal of the surface at the hitpoint")),
  352.                         OutputPortConfig<int>("surfacetype",       _HELP("Surface type index at the hit point")),
  353.                         OutputPortConfig<EntityId>("entity",       _HELP("Entity which was hit")),
  354.                         { 0 }
  355.                 };
  356.                 config.nFlags |= EFLN_TARGET_ENTITY;
  357.                 config.pInputPorts = in_config;
  358.                 config.pOutputPorts = out_config;
  359.                 config.SetCategory(EFLN_APPROVED);
  360.         }
  361.  
  362.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  363.         {
  364.                 if (event == eFE_Activate && IsPortActive(pActInfo, GO))
  365.                 {
  366.                         IEntity* pEntity = pActInfo->pEntity;
  367.                         if (pEntity)
  368.                         {
  369.                                 ray_hit hit;
  370.                                 IPhysicalEntity* pSkip = pEntity->GetPhysics();
  371.                                 Vec3 direction = GetPortVec3(pActInfo, DIR).GetNormalized();
  372.                                 if (GetPortBool(pActInfo, TRANSFORM_DIRECTION))
  373.                                         direction = pEntity->GetWorldTM().TransformVector(GetPortVec3(pActInfo, DIR).GetNormalized());
  374.                                 IPhysicalWorld* pWorld = gEnv->pPhysicalWorld;
  375.                                 int numHits = pWorld->RayWorldIntersection(
  376.                                   pEntity->GetPos() + GetPortVec3(pActInfo, POS),
  377.                                   direction * GetPortFloat(pActInfo, MAXLENGTH),
  378.                                   ent_all,
  379.                                   rwi_stop_at_pierceable | rwi_colltype_any,
  380.                                   &hit, 1,
  381.                                   &pSkip, 1);
  382.  
  383.                                 if (numHits)
  384.                                 {
  385.                                         pEntity = (IEntity*)hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY);
  386.                                         ActivateOutput(pActInfo, HIT, (bool)true);
  387.                                         ActivateOutput(pActInfo, DIROUT, direction);
  388.                                         ActivateOutput(pActInfo, DISTANCE, hit.dist);
  389.                                         ActivateOutput(pActInfo, HITPOINT, hit.pt);
  390.                                         ActivateOutput(pActInfo, NORMAL, hit.n);
  391.                                         ActivateOutput(pActInfo, SURFTYPE, (int)hit.surface_idx);
  392.                                         ActivateOutput(pActInfo, HIT_ENTITY, pEntity ? pEntity->GetId() : 0);
  393.                                 }
  394.                                 else
  395.                                         ActivateOutput(pActInfo, NOHIT, false);
  396.                         }
  397.                 }
  398.         }
  399. };
  400.  
  401. class CFlowNode_RaycastCamera : public CFlowBaseNode<eNCT_Singleton>
  402. {
  403. public:
  404.         CFlowNode_RaycastCamera(SActivationInfo* pActInfo) {}
  405.  
  406.         enum EInPorts
  407.         {
  408.                 GO = 0,
  409.                 POS,
  410.                 MAXLENGTH,
  411.         };
  412.         enum EOutPorts
  413.         {
  414.                 NOHIT = 0,
  415.                 HIT,
  416.                 DIROUT,
  417.                 DISTANCE,
  418.                 HITPOINT,
  419.                 NORMAL,
  420.                 SURFTYPE,
  421.                 PARTID,
  422.                 HIT_ENTITY,
  423.                 HIT_ENTITY_PHID,
  424.         };
  425.  
  426.         virtual void GetMemoryUsage(ICrySizer* s) const
  427.         {
  428.                 s->Add(*this);
  429.         }
  430.  
  431.         virtual void GetConfiguration(SFlowNodeConfig& config)
  432.         {
  433.                 static const SInputPortConfig in_config[] = {
  434.                         InputPortConfig<SFlowSystemVoid>("go", SFlowSystemVoid(), _HELP("Perform Raycast")),
  435.                         InputPortConfig<Vec3>("offset",        Vec3(0,            0,                                  0),_HELP("Ray start position, relative to camera")),
  436.                         InputPortConfig<float>("maxLength",    10.0f,             _HELP("Maximum length of Raycast")),
  437.                         { 0 }
  438.                 };
  439.                 static const SOutputPortConfig out_config[] = {
  440.                         OutputPortConfig<SFlowSystemVoid>("nohit", _HELP("Triggered if NO object was hit by raycast")),
  441.                         OutputPortConfig<SFlowSystemVoid>("hit",   _HELP("Triggered if an object was hit by raycast")),
  442.                         OutputPortConfig<Vec3>("direction",        _HELP("Actual direction of the cast ray (transformed by entity rotation")),
  443.                         OutputPortConfig<float>("distance",        _HELP("Distance to object hit")),
  444.                         OutputPortConfig<Vec3>("hitpoint",         _HELP("Position the ray hit")),
  445.                         OutputPortConfig<Vec3>("normal",           _HELP("Normal of the surface at the hitpoint")),
  446.                         OutputPortConfig<int>("surfacetype",       _HELP("Surface type index at the hit point")),
  447.                         OutputPortConfig<int>("partid",            _HELP("Hit part id")),
  448.                         OutputPortConfig<EntityId>("entity",       _HELP("Entity which was hit")),
  449.                         OutputPortConfig<EntityId>("entityPhysId", _HELP("Id of the physical entity that was hit")),
  450.                         { 0 }
  451.                 };
  452.                 config.sDescription = _HELP("Perform a raycast relative to the camera");
  453.                 config.pInputPorts = in_config;
  454.                 config.pOutputPorts = out_config;
  455.                 config.SetCategory(EFLN_APPROVED);
  456.         }
  457.  
  458.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  459.         {
  460.                 if (event == eFE_Activate && IsPortActive(pActInfo, GO))
  461.                 {
  462.                         IEntity* pEntity = pActInfo->pEntity;
  463.                         // if (pEntity)
  464.                         {
  465.                                 ray_hit hit;
  466.                                 CCamera& cam = GetISystem()->GetViewCamera();
  467.                                 Vec3 pos = cam.GetPosition() + cam.GetViewdir();
  468.                                 Vec3 direction = cam.GetViewdir();
  469.                                 IPhysicalWorld* pWorld = gEnv->pPhysicalWorld;
  470.                                 //                              IPhysicalEntity *pSkip = 0; // pEntity->GetPhysics();
  471.                                 int numHits = pWorld->RayWorldIntersection(
  472.                                   pos + GetPortVec3(pActInfo, POS),
  473.                                   direction * GetPortFloat(pActInfo, MAXLENGTH),
  474.                                   ent_all,
  475.                                   rwi_stop_at_pierceable | rwi_colltype_any,
  476.                                   &hit, 1
  477.                                   /* ,&pSkip, 1 */);
  478.                                 if (numHits)
  479.                                 {
  480.                                         pEntity = (IEntity*)hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY);
  481.                                         ActivateOutput(pActInfo, HIT, (bool)true);
  482.                                         ActivateOutput(pActInfo, DIROUT, direction);
  483.                                         ActivateOutput(pActInfo, DISTANCE, hit.dist);
  484.                                         ActivateOutput(pActInfo, HITPOINT, hit.pt);
  485.                                         ActivateOutput(pActInfo, NORMAL, hit.n);
  486.                                         ActivateOutput(pActInfo, SURFTYPE, (int)hit.surface_idx);
  487.                                         ActivateOutput(pActInfo, PARTID, hit.partid);
  488.                                         ActivateOutput(pActInfo, HIT_ENTITY, pEntity ? pEntity->GetId() : 0);
  489.                                         ActivateOutput(pActInfo, HIT_ENTITY_PHID, gEnv->pPhysicalWorld->GetPhysicalEntityId(hit.pCollider));
  490.                                 }
  491.                                 else
  492.                                         ActivateOutput(pActInfo, NOHIT, false);
  493.                         }
  494.                 }
  495.         }
  496. };
  497.  
  498. //////////////////////////////////////////////////////////////////////////
  499. // Enable/Disable AI for an entity/
  500. //////////////////////////////////////////////////////////////////////////
  501. class CFlowNode_PhysicsEnable : public CFlowBaseNode<eNCT_Singleton>
  502. {
  503. public:
  504.         enum EInputs
  505.         {
  506.                 IN_ENABLE,
  507.                 IN_DISABLE,
  508.                 IN_ENABLE_AI,
  509.                 IN_DISABLE_AI,
  510.         };
  511.         CFlowNode_PhysicsEnable(SActivationInfo* pActInfo) {};
  512.  
  513.         /*
  514.            IFlowNodePtr Clone( SActivationInfo * pActInfo )
  515.            {
  516.            return this;
  517.            }
  518.          */
  519.  
  520.         virtual void GetConfiguration(SFlowNodeConfig& config)
  521.         {
  522.                 static const SInputPortConfig in_config[] = {
  523.                         InputPortConfig_Void("Enable",     _HELP("Enable Physics for target entity")),
  524.                         InputPortConfig_Void("Disable",    _HELP("Disable Physics for target entity")),
  525.                         InputPortConfig_Void("AI_Enable",  _HELP("Enable AI for target entity")),
  526.                         InputPortConfig_Void("AI_Disable", _HELP("Disable AI for target entity")),
  527.                         { 0 }
  528.                 };
  529.                 config.sDescription = _HELP("Enables/Disables Physics");
  530.                 config.nFlags |= EFLN_TARGET_ENTITY;
  531.                 config.pInputPorts = in_config;
  532.                 config.pOutputPorts = 0;
  533.                 config.SetCategory(EFLN_ADVANCED);
  534.         }
  535.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  536.         {
  537.                 switch (event)
  538.                 {
  539.                 case eFE_Activate:
  540.                         {
  541.                                 if (!pActInfo->pEntity)
  542.                                         return;
  543.  
  544.                                 if (IsPortActive(pActInfo, IN_ENABLE))
  545.                                 {
  546.                                         pActInfo->pEntity->EnablePhysics(true);
  547.                                 }
  548.                                 if (IsPortActive(pActInfo, IN_DISABLE))
  549.                                 {
  550.                                         pActInfo->pEntity->EnablePhysics(false);
  551.                                 }
  552.  
  553.                                 if (IsPortActive(pActInfo, IN_ENABLE_AI))
  554.                                 {
  555.                                         if (IAIObject* aiObject = pActInfo->pEntity->GetAI())
  556.                                                 aiObject->Event(AIEVENT_ENABLE, 0);
  557.                                 }
  558.                                 if (IsPortActive(pActInfo, IN_DISABLE_AI))
  559.                                 {
  560.                                         if (IAIObject* aiObject = pActInfo->pEntity->GetAI())
  561.                                                 aiObject->Event(AIEVENT_DISABLE, 0);
  562.                                 }
  563.                                 break;
  564.                         }
  565.  
  566.                 case eFE_Initialize:
  567.                         break;
  568.                 }
  569.         }
  570.  
  571.         virtual void GetMemoryUsage(ICrySizer* s) const
  572.         {
  573.                 s->Add(*this);
  574.         }
  575. };
  576.  
  577. class CFlowNode_CameraProxy : public CFlowBaseNode<eNCT_Singleton>
  578. {
  579. public:
  580.         enum EInputs
  581.         {
  582.                 IN_CREATE,
  583.                 IN_ID
  584.         };
  585.         enum EOutputs
  586.         {
  587.                 OUT_ID
  588.         };
  589.         CFlowNode_CameraProxy(SActivationInfo* pActInfo) {};
  590.  
  591.         virtual void GetConfiguration(SFlowNodeConfig& config)
  592.         {
  593.                 static const SInputPortConfig in_config[] = {
  594.                         InputPortConfig<SFlowSystemVoid>("Create", SFlowSystemVoid(), _HELP("Create the proxy if it doesnt exist yet")),
  595.                         InputPortConfig<EntityId>("EntityHost",    0,                 _HELP("Activate to sync proxy rotation with the current view camera")),
  596.                         { 0 }
  597.                 };
  598.                 static const SOutputPortConfig out_config[] = {
  599.                         OutputPortConfig<int>("EntityCamera", _HELP("")),
  600.                         { 0 }
  601.                 };
  602.                 config.sDescription = _HELP("Retrieves or creates a physicalized camera proxy attached to EntityHost");
  603.                 config.pInputPorts = in_config;
  604.                 config.pOutputPorts = out_config;
  605.                 config.SetCategory(EFLN_ADVANCED);
  606.         }
  607.  
  608.         IEntity* GetCameraEnt(IEntity* pHost, bool bCreate)
  609.         {
  610.                 if (!pHost->GetPhysics())
  611.                         return bCreate ? pHost : 0;
  612.  
  613.                 pe_params_articulated_body pab;
  614.                 IEntityLink* plink = pHost->GetEntityLinks();
  615.                 for (; plink && strcmp(plink->name, "CameraProxy"); plink = plink->next);
  616.                 if (plink)
  617.                 {
  618.                         IEntity* pCam = gEnv->pEntitySystem->GetEntity(plink->entityId);
  619.                         if (!pCam)
  620.                         {
  621.                                 pHost->RemoveEntityLink(plink);
  622.                                 if (bCreate)
  623.                                         goto CreateCam;
  624.                                 return 0;
  625.                         }
  626.                         pab.qHostPivot = !pHost->GetRotation() * Quat(Matrix33(GetISystem()->GetViewCamera().GetMatrix()));
  627.                         pCam->GetPhysics()->SetParams(&pab);
  628.                         return pCam;
  629.                 }
  630.                 else if (bCreate)
  631.                 {
  632. CreateCam:
  633.                         CCamera& cam = GetISystem()->GetViewCamera();
  634.                         Quat qcam = Quat(Matrix33(cam.GetMatrix()));
  635.                         SEntitySpawnParams esp;
  636.                         esp.sName = "CameraProxy";
  637.                         esp.nFlags = 0;
  638.                         esp.pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("Default");
  639.                         IEntity* pCam = gEnv->pEntitySystem->SpawnEntity(esp);
  640.                         pCam->SetPos(cam.GetPosition());
  641.                         pCam->SetRotation(qcam);
  642.                         pHost->AddEntityLink("CameraProxy", pCam->GetId());
  643.                         SEntityPhysicalizeParams epp;
  644.                         epp.type = PE_ARTICULATED;
  645.                         pCam->Physicalize(epp);
  646.                         pe_geomparams gp;
  647.                         gp.flags = 0;
  648.                         gp.flagsCollider = 0;
  649.                         primitives::sphere sph;
  650.                         sph.r = 0.1f;
  651.                         sph.center.zero();
  652.                         IGeometry* psph = gEnv->pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::sphere::type, &sph);
  653.                         phys_geometry* pGeom = gEnv->pPhysicalWorld->GetGeomManager()->RegisterGeometry(psph);
  654.                         psph->Release();
  655.                         pCam->GetPhysics()->AddGeometry(pGeom, &gp);
  656.                         pGeom->nRefCount--;
  657.                         pe_params_pos pp;
  658.                         pp.iSimClass = 2;
  659.                         pCam->GetPhysics()->SetParams(&pp);
  660.                         pab.pHost = pHost->GetPhysics();
  661.                         pab.posHostPivot = (cam.GetPosition() - pHost->GetPos()) * pHost->GetRotation();
  662.                         pab.qHostPivot = !pHost->GetRotation() * qcam;
  663.                         pCam->GetPhysics()->SetParams(&pab);
  664.                         return pCam;
  665.                 }
  666.                 return 0;
  667.         }
  668.  
  669.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  670.         {
  671.                 if (event == eFE_Activate)
  672.                 {
  673.                         bool bCreate = IsPortActive(pActInfo, IN_CREATE);
  674.                         if (IEntity* pHost = gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, IN_ID)))
  675.                                 if (IEntity* pCam = GetCameraEnt(pHost, bCreate))
  676.                                         if (bCreate)
  677.                                                 ActivateOutput(pActInfo, OUT_ID, pCam->GetId());
  678.                 }
  679.         }
  680.  
  681.         virtual void GetMemoryUsage(ICrySizer* s) const
  682.         {
  683.                 s->Add(*this);
  684.         }
  685. };
  686.  
  687. class CFlowNode_Constraint : public CFlowBaseNode<eNCT_Instanced>
  688. {
  689. public:
  690.         enum EInputs
  691.         {
  692.                 IN_CREATE,
  693.                 IN_BREAK,
  694.                 IN_ID,
  695.                 IN_ENTITY0,
  696.                 IN_PARTID0,
  697.                 IN_ENTITY1,
  698.                 IN_PARTID1,
  699.                 IN_TYPE,
  700.                 IN_POINT,
  701.                 IN_POINTB,
  702.                 IN_LOCAL_FRAMES,
  703.                 IN_IGNORE_COLLISIONS,
  704.                 IN_BREAKABLE,
  705.                 IN_FORCE_AWAKE,
  706.                 IN_FORCE_MOVE,
  707.                 IN_MAX_FORCE,
  708.                 IN_MAX_TORQUE,
  709.                 IN_MAX_FORCE_REL,
  710.                 IN_AXIS,
  711.                 IN_MIN_ROT,
  712.                 IN_MAX_ROT,
  713.                 IN_MAX_BEND,
  714.                 IN_AREA,
  715.         };
  716.         enum EOutputs
  717.         {
  718.                 OUT_ID,
  719.                 OUT_BROKEN,
  720.         };
  721.         CFlowNode_Constraint(SActivationInfo* pActInfo) : m_id(1000) {};
  722.         ~CFlowNode_Constraint() {}
  723.  
  724.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  725.         {
  726.                 return new CFlowNode_Constraint(pActInfo);
  727.         }
  728.  
  729.         struct SConstraintRec
  730.         {
  731.                 SConstraintRec() : next(0), prev(0), pent(0), pNode(0), idConstraint(-1), bBroken(0), minEnergy(0), minEnergyRagdoll(0.0f) {}
  732.                 ~SConstraintRec() { Free(); }
  733.                 void Free()
  734.                 {
  735.                         if (idConstraint >= 0)
  736.                         {
  737.                                 if (minEnergy > 0)
  738.                                 {
  739.                                         pe_simulation_params sp;
  740.                                         sp.minEnergy = minEnergy;
  741.                                         pe_params_articulated_body pab;
  742.                                         pab.minEnergyLyingMode = minEnergyRagdoll;
  743.                                         pent->SetParams(&sp);
  744.                                         pent->SetParams(&pab);
  745.                                 }
  746.                                 if (pent)
  747.                                         pent->Release();
  748.                                 idConstraint = -1;
  749.                                 pent = 0;
  750.                                 (prev ? prev->next : g_pConstrRec0) = next;
  751.                                 if (next) next->prev = prev;
  752.                         }
  753.                 }
  754.                 SConstraintRec*       next, * prev;
  755.                 IPhysicalEntity*      pent;
  756.                 CFlowNode_Constraint* pNode;
  757.                 int                   idConstraint;
  758.                 int                   bBroken;
  759.                 float                 minEnergy, minEnergyRagdoll;
  760.         };
  761.         static SConstraintRec* g_pConstrRec0;
  762.         int                    m_id;
  763.  
  764.         static int OnConstraintBroken(const EventPhysJointBroken* ejb)
  765.         {
  766.                 for (SConstraintRec* pRec = g_pConstrRec0; pRec; pRec = pRec->next)
  767.                         if (pRec->pent == ejb->pEntity[0] && pRec->idConstraint == ejb->idJoint)
  768.                                 pRec->bBroken = 1;
  769.                 return 1;
  770.         }
  771.  
  772.         virtual void GetConfiguration(SFlowNodeConfig& config)
  773.         {
  774.                 static const SInputPortConfig in_config[] = {
  775.                         InputPortConfig<SFlowSystemVoid>("Create", SFlowSystemVoid(),        _HELP("Creates the constraint")),
  776.                         InputPortConfig<SFlowSystemVoid>("Break",  SFlowSystemVoid(),        _HELP("Breaks a constraint Id from EntityA if EntityA is activated, or a previously created one")),
  777.                         InputPortConfig<int>("Id",                 1000,                     _HELP("Requested constraint Id; -1 to auto-generate, -2 to auto-generate and remember")),
  778.                         InputPortConfig<EntityId>("EntityA",       0,                        _HELP("Constraint owner entity (can't be an actor; should be lighter than EntityB for best results)")),
  779.                         InputPortConfig<int>("PartIdA",            -1,                       _HELP("Part id to attach to; -1 to use default")),
  780.                         InputPortConfig<EntityId>("EntityB",       0,                        _HELP("Constrained entity (can be an actor)")),
  781.                         InputPortConfig<int>("PartIdB",            -1,                       _HELP("Part id to attach to; -1 to use default")),
  782.                         InputPortConfig<int>("Type",               _HELP("Constraint type"), _HELP("Type"),                                                                                         _UICONFIG("enum_int:Point=0,RotOnly=1,Line=2,Plane=3")),
  783.                         InputPortConfig<Vec3>("Point",             Vec3(ZERO),               _HELP("Connection point in world space")),
  784.                         InputPortConfig<Vec3>("PointB",            Vec3(ZERO),               _HELP("Connection point on entity B in world space (if not set, assumed same as Point)")),
  785.                         InputPortConfig<bool>("LocalFrames",       false,                    _HELP("Means Point and PointB are specified in Entity and EntityB's local frames, respectively (instead of the world)")),
  786.                         InputPortConfig<bool>("IgnoreCollisions",  true,                     _HELP("Disables collisions between constrained entities")),
  787.                         InputPortConfig<bool>("Breakable",         false,                    _HELP("Break if force limit is reached")),
  788.                         InputPortConfig<bool>("ForceAwake",        false,                    _HELP("Make EntityB always awake; restore previous sleep params on Break")),
  789.                         InputPortConfig<bool>("MoveEnforcement",   true,                     _HELP("Teleport one enity if the other has its position updated from outside the physics")),
  790.                         InputPortConfig<float>("MaxForce",         0.0f,                     _HELP("Force limit")),
  791.                         InputPortConfig<float>("MaxTorque",        0.0f,                     _HELP("Rotational force (torque) limit")),
  792.                         InputPortConfig<bool>("MaxForceRelative",  true,                     _HELP("Make limits relative to EntityB's mass")),
  793.                         InputPortConfig<Vec3>("TwistAxis",         Vec3(0,                   0,                                                                                                     1), _HELP("Main rotation axis in world space")),
  794.                         InputPortConfig<float>("MinTwist",         0.0f,                     _HELP("Lower rotation limit around TwistAxis. Linear limit for line constraints")),
  795.                         InputPortConfig<float>("MaxTwist",         0.0f,                     _HELP("Upper rotation limit around TwistAxis. Linear limit for line constraints")),
  796.                         InputPortConfig<float>("MaxBend",          0.0f,                     _HELP("Maximum bend of the TwistAxis")),
  797.                         InputPortConfig<EntityId>("Area",          0,                        _HELP("Optional physical area entity to define the constraint surface")),
  798.  
  799.                         { 0 }
  800.                 };
  801.                 static const SOutputPortConfig out_config[] = {
  802.                         OutputPortConfig<int>("Id",      _HELP("Constraint Id")),
  803.                         OutputPortConfig<bool>("Broken", _HELP("Activated when the constraint breaks")),
  804.                         { 0 }
  805.                 };
  806.                 config.sDescription = _HELP("Creates a physical constraint between EntityA and EntityB");
  807.                 config.pInputPorts = in_config;
  808.                 config.pOutputPorts = out_config;
  809.                 config.SetCategory(EFLN_ADVANCED);
  810.         }
  811.  
  812.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  813.         {
  814.                 SConstraintRec* pRec = 0, * pRecNext;
  815.                 if (event == eFE_Update)
  816.                 {
  817.                         pe_status_pos sp;
  818.                         for (pRec = g_pConstrRec0; pRec; pRec = pRecNext)
  819.                         {
  820.                                 pRecNext = pRec->next;
  821.                                 if (pRec->pNode == this && (pRec->bBroken || pRec->pent->GetStatus(&sp) && sp.iSimClass == 7))
  822.                                 {
  823.                                         ActivateOutput(pActInfo, OUT_BROKEN, true);
  824.                                         ActivateOutput(pActInfo, OUT_ID, pRec->idConstraint);
  825.                                         delete pRec;
  826.                                 }
  827.                         }
  828.                         if (!g_pConstrRec0)
  829.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  830.                 }
  831.                 else if (event == eFE_Activate)
  832.                 {
  833.                         if (IsPortActive(pActInfo, IN_ID))
  834.                                 m_id = GetPortInt(pActInfo, IN_ID);
  835.                         if (IsPortActive(pActInfo, IN_CREATE))
  836.                         {
  837.                                 IEntity* pent[3] = {
  838.                                         gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, IN_ENTITY0)), gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, IN_ENTITY1)),
  839.                                         gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, IN_AREA))
  840.                                 };
  841.                                 if (!pent[0] || !pent[0]->GetPhysics())
  842.                                         return;
  843.                                 IPhysicalEntity* pentPhys = pent[0]->GetPhysics();
  844.                                 pe_action_add_constraint aac;
  845.                                 int i;
  846.                                 float f;
  847.                                 aac.pBuddy = pent[1] && pent[1]->GetPhysics() ? pent[1]->GetPhysics() : WORLD_ENTITY;
  848.                                 if (pent[2] && pent[2]->GetPhysics())
  849.                                         aac.pConstraintEntity = pent[2]->GetPhysics();
  850.                                 if (m_id >= 0)
  851.                                         aac.id = m_id;
  852.                                 for (int iop = 0; iop < 2; iop++)
  853.                                         if ((i = GetPortInt(pActInfo, IN_PARTID0 + iop * 2)) >= 0)
  854.                                                 aac.partid[iop] = i;
  855.                                 aac.pt[0] = GetPortVec3(pActInfo, IN_POINT);
  856.                                 Vec3 ptB = GetPortVec3(pActInfo, IN_POINTB);
  857.                                 if (ptB.len2())
  858.                                         aac.pt[1] = ptB;
  859.                                 aac.flags = GetPortBool(pActInfo, IN_LOCAL_FRAMES) ? local_frames : world_frames;
  860.                                 aac.flags |= (GetPortBool(pActInfo, IN_IGNORE_COLLISIONS) ? constraint_ignore_buddy : 0) | (GetPortBool(pActInfo, IN_BREAKABLE) ? 0 : constraint_no_tears);
  861.                                 aac.flags |= GetPortBool(pActInfo, IN_FORCE_MOVE) ? 0 : constraint_no_enforcement;
  862.                                 const int cflags[] = { 0, constraint_free_position, constraint_line, constraint_plane };
  863.                                 aac.flags |= cflags[i = GetPortInt(pActInfo, IN_TYPE)];
  864.                                 pe_status_dynamics sd;
  865.                                 sd.mass = 1.0f;
  866.                                 if (GetPortBool(pActInfo, IN_MAX_FORCE_REL))
  867.                                         pentPhys->GetStatus(&sd);
  868.                                 if ((f = GetPortFloat(pActInfo, IN_MAX_FORCE)) > 0)
  869.                                         aac.maxPullForce = f * sd.mass;
  870.                                 if ((f = GetPortFloat(pActInfo, IN_MAX_TORQUE)) > 0)
  871.                                         aac.maxBendTorque = f * sd.mass;
  872.                                 float conv = i == 2 ? 1.0f : gf_PI / 180.0f;
  873.                                 for (int iop = 0; iop < 2; iop++)
  874.                                         aac.xlimits[iop] = GetPortFloat(pActInfo, IN_MIN_ROT + iop) * conv;
  875.                                 aac.yzlimits[0] = 0;
  876.                                 aac.yzlimits[1] = DEG2RAD(GetPortFloat(pActInfo, IN_MAX_BEND));
  877.                                 if (aac.xlimits[1] <= aac.xlimits[0] && aac.yzlimits[1] <= aac.yzlimits[0])
  878.                                         aac.flags |= constraint_no_rotation;
  879.                                 else if (aac.xlimits[0] < gf_PI * -1.01f && aac.xlimits[1] > gf_PI * 1.01f && aac.yzlimits[1] > gf_PI * 0.51f)
  880.                                         MARK_UNUSED aac.xlimits[0], aac.xlimits[1], aac.yzlimits[0], aac.yzlimits[1];
  881.                                 aac.qframe[0] = aac.qframe[1] = Quat::CreateRotationV0V1(Vec3(1, 0, 0), GetPortVec3(pActInfo, IN_AXIS));
  882.                                 if (GetPortBool(pActInfo, IN_FORCE_AWAKE))
  883.                                 {
  884.                                         pRec = new SConstraintRec;
  885.                                         pe_simulation_params sp;
  886.                                         sp.minEnergy = 0;
  887.                                         pentPhys->GetParams(&sp);
  888.                                         pRec->minEnergy = pRec->minEnergyRagdoll = sp.minEnergy;
  889.                                         new(&sp)pe_simulation_params;
  890.                                         sp.minEnergy = 0;
  891.                                         pentPhys->SetParams(&sp);
  892.                                         pe_params_articulated_body pab;
  893.                                         if (pentPhys->GetParams(&pab))
  894.                                         {
  895.                                                 pRec->minEnergyRagdoll = pab.minEnergyLyingMode;
  896.                                                 new(&pab)pe_params_articulated_body;
  897.                                                 pab.minEnergyLyingMode = 0;
  898.                                                 pentPhys->SetParams(&pab);
  899.                                         }
  900.                                         pe_action_awake aa;
  901.                                         aa.minAwakeTime = 0.1f;
  902.                                         pentPhys->Action(&aa);
  903.                                         if (aac.pBuddy != WORLD_ENTITY)
  904.                                                 aac.pBuddy->Action(&aa);
  905.                                 }
  906.                                 pe_params_flags pf;
  907.                                 int queued = aac.pBuddy == WORLD_ENTITY ? 0 : aac.pBuddy->SetParams(&pf) - 1, id = pentPhys->Action(&aac, -queued >> 31);
  908.                                 if (m_id == -2)
  909.                                         m_id = id;
  910.                                 ActivateOutput(pActInfo, OUT_ID, id);
  911.                                 if (!is_unused(aac.maxPullForce || !is_unused(aac.maxBendTorque)) && !(aac.flags & constraint_no_tears))
  912.                                 {
  913.                                         if (!pRec)
  914.                                                 pRec = new SConstraintRec;
  915.                                         gEnv->pPhysicalWorld->AddEventClient(EventPhysJointBroken::id, (int (*)(const EventPhys*))OnConstraintBroken, 1);
  916.                                 }
  917.                                 if (pRec)
  918.                                 {
  919.                                         (pRec->pent = pentPhys)->AddRef();
  920.                                         pRec->idConstraint = id;
  921.                                         pRec->pNode = this;
  922.                                         if (g_pConstrRec0)
  923.                                                 g_pConstrRec0->prev = pRec;
  924.                                         pRec->next = g_pConstrRec0;
  925.                                         g_pConstrRec0 = pRec;
  926.                                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  927.                                 }
  928.                                 return;
  929.                         }
  930.  
  931.                         if (IsPortActive(pActInfo, IN_BREAK) || IsPortActive(pActInfo, IN_POINT))
  932.                                 if (IEntity* pent = gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, IN_ENTITY0)))
  933.                                         if (IPhysicalEntity* pentPhys = pent->GetPhysics())
  934.                                         {
  935.                                                 pe_action_update_constraint auc;
  936.                                                 auc.idConstraint = GetPortInt(pActInfo, IN_ID);
  937.                                                 if (IsPortActive(pActInfo, IN_BREAK))
  938.                                                         auc.bRemove = 1;
  939.                                                 if (IsPortActive(pActInfo, IN_POINT))
  940.                                                         auc.pt[1] = GetPortVec3(pActInfo, IN_POINT);
  941.                                                 auc.flags = GetPortBool(pActInfo, IN_LOCAL_FRAMES) ? local_frames : world_frames;
  942.                                                 pentPhys->Action(&auc);
  943.                                                 if (auc.bRemove)
  944.                                                 {
  945.                                                         for (pRec = g_pConstrRec0; pRec; pRec = pRecNext)
  946.                                                         {
  947.                                                                 pRecNext = pRec->next;
  948.                                                                 if (pRec->pent == pentPhys && pRec->idConstraint == auc.idConstraint)
  949.                                                                         delete pRec;
  950.                                                         }
  951.                                                         ActivateOutput(pActInfo, OUT_BROKEN, true);
  952.                                                         ActivateOutput(pActInfo, OUT_ID, auc.idConstraint);
  953.                                                         if (!g_pConstrRec0)
  954.                                                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  955.                                                 }
  956.                                         }
  957.                 }
  958.         }
  959.  
  960.         virtual void GetMemoryUsage(ICrySizer* s) const
  961.         {
  962.                 s->Add(*this);
  963.         }
  964. };
  965.  
  966. CFlowNode_Constraint::SConstraintRec* CFlowNode_Constraint::g_pConstrRec0 = 0;
  967.  
  968. class CFlowNode_Collision : public CFlowBaseNode<eNCT_Instanced>
  969. {
  970. public:
  971.         enum EInputs
  972.         {
  973.                 IN_ADD_ID,
  974.                 IN_MAX_COLLISIONS,
  975.                 IN_IGNORE_SIBLINGS,
  976.                 IN_ONLY_SIBLINGS,
  977.                 IN_REMOVE_ID,
  978.                 IN_REMOVE_ALL,
  979.         };
  980.         enum EOutputs
  981.         {
  982.                 OUT_ID_A,
  983.                 OUT_PART_ID_A,
  984.                 OUT_ID_B,
  985.                 OUT_PART_ID_B,
  986.                 OUT_POINT,
  987.                 OUT_NORMAL,
  988.                 OUT_SURFACETYPE_A,
  989.                 OUT_SURFACETYPE_B,
  990.                 OUT_IMPULSE,
  991.         };
  992.  
  993.         struct SCollListener
  994.         {
  995.                 EntityId             id;
  996.                 CFlowNode_Collision* pNode;
  997.         };
  998.         static std::map<EntityId, SCollListener*> g_listeners;
  999.         SActivationInfo                           m_actInfo;
  1000.  
  1001.         CFlowNode_Collision(SActivationInfo* pActInfo) {}
  1002.         virtual ~CFlowNode_Collision()
  1003.         {
  1004.                 for (auto iter = g_listeners.begin(); iter != g_listeners.end(); )
  1005.                         if (iter->second->pNode == this)
  1006.                         {
  1007.                                 delete iter->second;
  1008.                                 g_listeners.erase(iter++);
  1009.                         }
  1010.                         else iter++;
  1011.         }
  1012.  
  1013.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  1014.         {
  1015.                 return new CFlowNode_Collision(pActInfo);
  1016.         }
  1017.  
  1018.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1019.         {
  1020.                 static const SInputPortConfig in_config[] = {
  1021.                         InputPortConfig<EntityId>("AddListener",      0,                 _HELP("Register entity id as collision listener")),
  1022.                         InputPortConfig<int>("CollisionsPerFrame",    0,                 _HELP("Set the maximum amount of reported collisions per frame (0 = don't change)")),
  1023.                         InputPortConfig<bool>("IgnoreSameNode",       false,             _HELP("Suppress events if both colliders are registered via the same node")),
  1024.                         InputPortConfig<bool>("OnlySameNode",         false,             _HELP("Only send events if both colliders are registered via the same node")),
  1025.                         InputPortConfig<EntityId>("RemoveListener",   0,                 _HELP("Unregister entity id from collision listeners")),
  1026.                         InputPortConfig<SFlowSystemVoid>("RemoveAll", SFlowSystemVoid(), _HELP("Remove all registered listeners")),
  1027.                         { 0 }
  1028.                 };
  1029.  
  1030.                 static const SOutputPortConfig out_config[] = {
  1031.                         OutputPortConfig<EntityId>("IdA",        _HELP("Id of the first colliding entity (one that is registered as a listener)")),
  1032.                         OutputPortConfig<int>("PartIdA",         _HELP("Part id inside the first colliding entity")),
  1033.                         OutputPortConfig<EntityId>("IdB",        _HELP("Id of the second colliding entity")),
  1034.                         OutputPortConfig<int>("PartIdB",         _HELP("Part id inside the second colliding entity")),
  1035.                         OutputPortConfig<Vec3>("Point",          _HELP("Collision point in world space")),
  1036.                         OutputPortConfig<Vec3>("Normal",         _HELP("Collision normal in world space")),
  1037.                         OutputPortConfig<string>("SurfacetypeA", _HELP("Name of the surfacetype of the first colliding entity")),
  1038.                         OutputPortConfig<string>("SurfacetypeB", _HELP("Name of the surfacetype of the second colliding entity")),
  1039.                         OutputPortConfig<float>("HitImpulse",    _HELP("Collision impulse along the normal")),
  1040.                         { 0 }
  1041.                 };
  1042.                 config.pInputPorts = in_config;
  1043.                 config.pOutputPorts = out_config;
  1044.                 config.sDescription = _HELP("Set up collision listeners");
  1045.                 config.SetCategory(EFLN_APPROVED); // POLICY CHANGE: Maybe an Enable/Disable Port
  1046.         }
  1047.  
  1048.         virtual void GetMemoryUsage(ICrySizer* s) const { s->Add(*this); }
  1049.  
  1050.         static int   OnCollision(const EventPhysCollision* pColl)
  1051.         {
  1052.                 std::map<EntityId, SCollListener*>::iterator iter;
  1053.                 SCollListener* coll[2] = { 0, 0 };
  1054.                 for (int i = 0; i < 2; i++)
  1055.                         if (pColl->iForeignData[i] == PHYS_FOREIGN_ID_ENTITY && (iter = g_listeners.find(((IEntity*)pColl->pForeignData[i])->GetId())) != g_listeners.end())
  1056.                                 coll[i] = iter->second;
  1057.                 if (coll[0] && coll[1] && coll[0]->pNode == coll[1]->pNode && GetPortBool(&coll[0]->pNode->m_actInfo, IN_IGNORE_SIBLINGS))
  1058.                         return 1;
  1059.                 for (int i = 0; i < 2; i++)
  1060.                         if (coll[i] && GetPortBool(&coll[i]->pNode->m_actInfo, IN_ONLY_SIBLINGS) && (!coll[i ^ 1] || coll[i]->pNode != coll[i ^ 1]->pNode))
  1061.                                 return 1;
  1062.                 for (int i = 0; i < 2; i++)
  1063.                         if (coll[i])
  1064.                         {
  1065.                                 SActivationInfo* pActInfo = &coll[i]->pNode->m_actInfo;
  1066.                                 ActivateOutput(pActInfo, OUT_PART_ID_A, pColl->partid[i]);
  1067.                                 ActivateOutput(pActInfo, OUT_ID_B, pColl->iForeignData[i ^ 1] == PHYS_FOREIGN_ID_ENTITY ? ((IEntity*)pColl->pForeignData[i ^ 1])->GetId() : 0);
  1068.                                 ActivateOutput(pActInfo, OUT_PART_ID_B, pColl->partid[i ^ 1]);
  1069.                                 ActivateOutput(pActInfo, OUT_POINT, pColl->pt);
  1070.                                 ActivateOutput(pActInfo, OUT_NORMAL, pColl->n * (1.0f - i * 2));
  1071.                                 ActivateOutput(pActInfo, OUT_IMPULSE, pColl->normImpulse);
  1072.                                 if (ISurfaceType* pSurf = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceTypeManager()->GetSurfaceType(pColl->idmat[i]))
  1073.                                         ActivateOutput(pActInfo, OUT_SURFACETYPE_A, string(pSurf->GetName()));
  1074.                                 if (ISurfaceType* pSurf = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceTypeManager()->GetSurfaceType(pColl->idmat[i ^ 1]))
  1075.                                         ActivateOutput(pActInfo, OUT_SURFACETYPE_B, string(pSurf->GetName()));
  1076.                                 ActivateOutput(pActInfo, OUT_ID_A, coll[i]->id);
  1077.                         }
  1078.                 return 1;
  1079.         }
  1080.  
  1081.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1082.         {
  1083.                 if (event == eFE_Initialize)
  1084.                         m_actInfo = *pActInfo;
  1085.                 else if (event == eFE_Activate)
  1086.                 {
  1087.                         IEntity* pent;
  1088.                         if (IsPortActive(pActInfo, IN_ADD_ID))
  1089.                         {
  1090.                                 SCollListener cl;
  1091.                                 cl.id = GetPortEntityId(pActInfo, IN_ADD_ID);
  1092.                                 cl.pNode = this;
  1093.                                 if (g_listeners.find(cl.id) == g_listeners.end() && (pent = gEnv->pEntitySystem->GetEntity(cl.id)) && pent->GetPhysics())
  1094.                                 {
  1095.                                         if (g_listeners.empty())
  1096.                                                 gEnv->pPhysicalWorld->AddEventClient(EventPhysCollision::id, (int (*)(const EventPhys*))OnCollision, 1);
  1097.                                         pe_simulation_params sp;
  1098.                                         if (sp.maxLoggedCollisions = GetPortInt(pActInfo, IN_MAX_COLLISIONS))
  1099.                                                 pent->GetPhysics()->SetParams(&sp);
  1100.                                         pe_params_flags pf;
  1101.                                         pf.flagsOR = pef_log_collisions;
  1102.                                         pent->GetPhysics()->SetParams(&pf);
  1103.                                         g_listeners.insert(std::pair<EntityId, SCollListener*>(cl.id, new SCollListener(cl)));
  1104.                                 }
  1105.                         }
  1106.  
  1107.                         std::map<EntityId, SCollListener*>::iterator iter;
  1108.                         if (IsPortActive(pActInfo, IN_REMOVE_ID) && (iter = g_listeners.find(GetPortEntityId(pActInfo, IN_REMOVE_ID))) != g_listeners.end())
  1109.                         {
  1110.                                 delete iter->second;
  1111.                                 g_listeners.erase(iter);
  1112.                                 if (g_listeners.empty())
  1113.                                         gEnv->pPhysicalWorld->RemoveEventClient(EventPhysCollision::id, (int (*)(const EventPhys*))OnCollision, 1);
  1114.                         }
  1115.  
  1116.                         if (IsPortActive(pActInfo, IN_REMOVE_ALL))
  1117.                         {
  1118.                                 for (auto iter : g_listeners) delete iter.second;
  1119.                                 g_listeners.clear();
  1120.                                 gEnv->pPhysicalWorld->RemoveEventClient(EventPhysCollision::id, (int (*)(const EventPhys*))OnCollision, 1);
  1121.                         }
  1122.                 }
  1123.         }
  1124. };
  1125.  
  1126. std::map<EntityId, CFlowNode_Collision::SCollListener*> CFlowNode_Collision::g_listeners;
  1127.  
  1128. class CFlowNode_PhysId : public CFlowBaseNode<eNCT_Singleton>
  1129. {
  1130. public:
  1131.         CFlowNode_PhysId(SActivationInfo* pActInfo) {}
  1132.  
  1133.         enum EInPorts
  1134.         {
  1135.                 IN_ENTITY_ID,
  1136.         };
  1137.         enum EOutPorts
  1138.         {
  1139.                 OUT_PHYS_ID,
  1140.         };
  1141.  
  1142.         virtual void GetMemoryUsage(ICrySizer* s) const
  1143.         {
  1144.                 s->Add(*this);
  1145.         }
  1146.  
  1147.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1148.         {
  1149.                 static const SInputPortConfig in_config[] = {
  1150.                         InputPortConfig<EntityId>("EntityId", EntityId(0), _HELP("Entity id")),
  1151.                         { 0 }
  1152.                 };
  1153.                 static const SOutputPortConfig out_config[] = {
  1154.                         OutputPortConfig<int>("PhysId", _HELP("Physical entity id")),
  1155.                         { 0 }
  1156.                 };
  1157.                 config.sDescription = _HELP("Return id of a physical entity associated with EntityId (-1 if none)");
  1158.                 config.pInputPorts = in_config;
  1159.                 config.pOutputPorts = out_config;
  1160.                 config.SetCategory(EFLN_APPROVED);
  1161.         }
  1162.  
  1163.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1164.         {
  1165.                 if (event == eFE_Activate)
  1166.                         if (IEntity* pent = gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, IN_ENTITY_ID)))
  1167.                                 ActivateOutput(pActInfo, OUT_PHYS_ID, gEnv->pPhysicalWorld->GetPhysicalEntityId(pent->GetPhysics()));
  1168.         }
  1169. };
  1170.  
  1171. class CFlowNode_Awake : public CFlowBaseNode<eNCT_Singleton>
  1172. {
  1173. public:
  1174.         CFlowNode_Awake(SActivationInfo* pActInfo) {}
  1175.  
  1176.         enum EInPorts
  1177.         {
  1178.                 IN_AWAKE,
  1179.         };
  1180.  
  1181.         virtual void GetMemoryUsage(ICrySizer* s) const
  1182.         {
  1183.                 s->Add(*this);
  1184.         }
  1185.  
  1186.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1187.         {
  1188.                 static const SInputPortConfig in_config[] = {
  1189.                         InputPortConfig<bool>("Awake", true, _HELP("Awake or send to sleep flag")),
  1190.                         { 0 }
  1191.                 };
  1192.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1193.                 config.sDescription = _HELP("Awakes an entity or sends it to rest");
  1194.                 config.pInputPorts = in_config;
  1195.                 config.pOutputPorts = 0;
  1196.                 config.SetCategory(EFLN_APPROVED);
  1197.         }
  1198.  
  1199.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1200.         {
  1201.                 if (event == eFE_Activate && pActInfo->pEntity && pActInfo->pEntity->GetPhysics())
  1202.                 {
  1203.                         pe_action_awake aa;
  1204.                         aa.bAwake = GetPortBool(pActInfo, IN_AWAKE) ? 1 : 0;
  1205.                         pActInfo->pEntity->GetPhysics()->Action(&aa);
  1206.                 }
  1207.         }
  1208. };
  1209.  
  1210. class CFlowNode_PhysParams : public CFlowBaseNode<eNCT_Singleton>
  1211. {
  1212. public:
  1213.         CFlowNode_PhysParams(SActivationInfo*) {}
  1214.         virtual void GetMemoryUsage(ICrySizer* s) const { s->Add(*this); }
  1215.  
  1216.         enum EInPorts
  1217.         {
  1218.                 IN_SET, IN_TYPE, IN_NAME0, IN_VAL0
  1219.         };
  1220.  
  1221.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1222.         {
  1223.                 static const SInputPortConfig in_config[] = {
  1224.                         InputPortConfig_Void("Set",  _HELP("Activate it when all values are ready")),
  1225.                         InputPortConfig<int>("Type", _HELP("Type of the parameters to set"),         _HELP("Type"),_UICONFIG("enum_int:\
  1226. Particle=1,Vehicle=2,PlayerDynamics=3,PlayerSize=4,Simulation=5,Articulated=6,Joint=7,Rope=8,Buoyancy=9,Constraint=10,\
  1227. Flags=12,CarWheel=13,SoftBody=14,Velocity=15,PartFlags=16,AutoDetachment=20,CollisionClass=21")),
  1228. #define VAL(i)                                                                                        \
  1229.   InputPortConfig<string>("Name" # i "", _HELP("Will set parameter with this name to Value" # i "")), \
  1230.   InputPortConfig_AnyType("Value" # i "", _HELP("Sets the value 'Name" # i "' (must have correct type)")),
  1231.                         VAL(0) VAL(1) VAL(2) VAL(3) VAL(4) VAL(5) VAL(6) VAL(7) VAL(8) VAL(9)
  1232.                         { 0 }
  1233.                 };
  1234.                 static const SOutputPortConfig out_config[] = {
  1235.                         OutputPortConfig<int>("Result", _HELP("Param-specific result")),
  1236.                         { 0 }
  1237.                 };
  1238.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1239.                 config.sDescription = _HELP("Sets various physical parameters that are exposed to scripts");
  1240.                 config.pInputPorts = in_config;
  1241.                 config.pOutputPorts = out_config;
  1242.                 config.SetCategory(EFLN_APPROVED);
  1243.         }
  1244.  
  1245.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1246.         {
  1247.                 if (event == eFE_Activate && IsPortActive(pActInfo, IN_SET) && pActInfo->pEntity && pActInfo->pEntity->GetPhysics())
  1248.                 {
  1249.                         HSCRIPTFUNCTION SetParams = 0;
  1250.                         IScriptTable* pEntityTable = pActInfo->pEntity->GetScriptTable();
  1251.                         if (pEntityTable->GetValue("SetPhysicParams", SetParams) && SetParams)
  1252.                         {
  1253.                                 static IScriptTable* pParams = 0;
  1254.                                 if (!pParams)
  1255.                                         (pParams = gEnv->pScriptSystem->CreateTable())->AddRef();
  1256.                                 pParams->Clear();
  1257.                                 for (int i = 0; i < 10; i++)
  1258.                                 {
  1259.                                         string name = GetPortString(pActInfo, IN_NAME0 + i * 2);
  1260.                                         if (name.empty())
  1261.                                                 continue;
  1262.                                         switch (GetPortType(pActInfo, IN_VAL0 + i * 2))
  1263.                                         {
  1264.                                         case eFDT_Int:
  1265.                                                 pParams->SetValue(name, GetPortInt(pActInfo, IN_VAL0 + i * 2));
  1266.                                                 break;
  1267.                                         case eFDT_Float:
  1268.                                                 pParams->SetValue(name, GetPortFloat(pActInfo, IN_VAL0 + i * 2));
  1269.                                                 break;
  1270.                                         case eFDT_EntityId:
  1271.                                                 pParams->SetValue(name, GetPortEntityId(pActInfo, IN_VAL0 + i * 2));
  1272.                                                 break;
  1273.                                         case eFDT_Vec3:
  1274.                                                 pParams->SetValue(name, GetPortVec3(pActInfo, IN_VAL0 + i * 2));
  1275.                                                 break;
  1276.                                         case eFDT_Bool:
  1277.                                                 pParams->SetValue(name, GetPortBool(pActInfo, IN_VAL0 + i * 2) ? 1 : 0);
  1278.                                                 break;
  1279.                                         case eFDT_String:
  1280.                                                 pParams->SetValue(name, GetPortString(pActInfo, IN_VAL0 + i * 2).c_str());
  1281.                                                 break;
  1282.                                         }
  1283.                                 }
  1284.                                 gEnv->pScriptSystem->BeginCall(SetParams);
  1285.                                 gEnv->pScriptSystem->PushFuncParam(pEntityTable);
  1286.                                 gEnv->pScriptSystem->PushFuncParam(GetPortInt(pActInfo, IN_TYPE));
  1287.                                 gEnv->pScriptSystem->PushFuncParam(pParams);
  1288.                                 int res;
  1289.                                 gEnv->pScriptSystem->EndCall(res);
  1290.                                 gEnv->pScriptSystem->ReleaseFunc(SetParams);
  1291.                                 ActivateOutput(pActInfo, 0, res);
  1292.                         }
  1293.                 }
  1294.         }
  1295. };
  1296.  
  1297. class CFlowNode_CharSkel : public CFlowBaseNode<eNCT_Singleton>, public IEntitySystemSink
  1298. {
  1299. public:
  1300.         CFlowNode_CharSkel(SActivationInfo* pActInfo) {}
  1301.         ~CFlowNode_CharSkel()
  1302.         {
  1303.                 g_mapSkels.clear();
  1304.                 if (gEnv->pEntitySystem)
  1305.                         gEnv->pEntitySystem->RemoveSink(this); 
  1306.         }
  1307.  
  1308.         enum EInPorts
  1309.         {
  1310.                 IN_GET,
  1311.                 IN_ENT_SLOT,
  1312.                 IN_CHAR_SLOT,
  1313.         };
  1314.         enum EOutPorts
  1315.         {
  1316.                 OUT_SKEL_ENT,
  1317.         };
  1318.  
  1319.         virtual void GetMemoryUsage(ICrySizer* s) const
  1320.         {
  1321.                 s->Add(*this);
  1322.         }
  1323.  
  1324.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1325.         {
  1326.                 static const SInputPortConfig in_config[] = {
  1327.                         InputPortConfig_Void("Get", _HELP("Trigger the output")),
  1328.                         InputPortConfig<int>("EntitySlot", 0, _HELP("Entity slot that contains the character")),
  1329.                         InputPortConfig<int>("PhysIndex", -1, _HELP("Index of the character physics (-1 - the main skeleton, >= 0 - auxiliary, such as ropes or cloth)")),
  1330.                         { 0 }
  1331.                 };
  1332.                 static const SOutputPortConfig out_config[] = {
  1333.                         OutputPortConfig<EntityId>("SkeletonEntId", _HELP("Entity id of the skeleton")),
  1334.                         { 0 }
  1335.                 };
  1336.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1337.                 config.sDescription = _HELP("Returns a temporary entity id that can be used to access character skeleton physics");
  1338.                 config.pInputPorts = in_config;
  1339.                 config.pOutputPorts = out_config;
  1340.                 config.SetCategory(EFLN_APPROVED);
  1341.         }
  1342.  
  1343.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1344.         {
  1345.                 if (event == eFE_Activate && pActInfo->pEntity)
  1346.                         if (ICharacterInstance *pChar = pActInfo->pEntity->GetCharacter(GetPortInt(pActInfo, IN_ENT_SLOT)))
  1347.                                 if (IPhysicalEntity *pent = pChar->GetISkeletonPose()->GetCharacterPhysics(GetPortInt(pActInfo, IN_CHAR_SLOT)))
  1348.                                 {
  1349.                                         int id = gEnv->pPhysicalWorld->GetPhysicalEntityId(pent);
  1350.                                         IEntity *pSkel;
  1351.                                         auto iter = g_mapSkels.find(id);
  1352.                                         if (iter != g_mapSkels.end())
  1353.                                                 pSkel = iter->second;
  1354.                                         else
  1355.                                         {
  1356.                                                 pe_status_pos sp;
  1357.                                                 pent->GetStatus(&sp);
  1358.                                                 pe_params_flags pf;
  1359.                                                 pent->GetParams(&pf);
  1360.                                                 SEntitySpawnParams esp;
  1361.                                                 esp.sName = "SkeletonTmp";
  1362.                                                 esp.nFlags = ENTITY_FLAG_NO_SAVE | ENTITY_FLAG_CLIENT_ONLY | ENTITY_FLAG_PROCEDURAL | ENTITY_FLAG_SPAWNED;
  1363.                                                 esp.pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("Default");
  1364.                                                 esp.vPosition = sp.pos;
  1365.                                                 esp.qRotation = sp.q;
  1366.                                                 pSkel = gEnv->pEntitySystem->SpawnEntity(esp);
  1367.                                                 pSkel->AssignPhysicalEntity(pent);
  1368.                                                 pe_params_foreign_data pfd;
  1369.                                                 pfd.pForeignData = pActInfo->pEntity;
  1370.                                                 pent->SetParams(&pfd); // revert the changes done in AssignPhysicalEntity
  1371.                                                 pent->SetParams(&pf);
  1372.                                                 if (g_mapSkels.empty())
  1373.                                                         gEnv->pEntitySystem->AddSink(this, IEntitySystem::OnRemove, 0);
  1374.                                                 g_mapSkels.emplace(id, pSkel);
  1375.                                         }
  1376.                                         ActivateOutput(pActInfo, OUT_SKEL_ENT, pSkel->GetId());
  1377.                                 }
  1378.         }
  1379.  
  1380.         virtual bool OnBeforeSpawn(SEntitySpawnParams& params) { return true; }
  1381.         virtual void OnSpawn(IEntity* pEntity, SEntitySpawnParams& params) {}
  1382.         virtual void OnReused(IEntity* pEntity, SEntitySpawnParams& params) {}
  1383.         virtual void OnEvent(IEntity* pEntity, SEntityEvent& event) {}
  1384.         virtual bool OnRemove(IEntity* pEntity)
  1385.         {
  1386.                 if (pEntity->GetFlags() & ENTITY_FLAG_PROCEDURAL)
  1387.                         if (IPhysicalEntity *pent = pEntity->GetPhysics())
  1388.                         {
  1389.                                 auto iter = g_mapSkels.find(gEnv->pPhysicalWorld->GetPhysicalEntityId(pent));
  1390.                                 if (iter!=g_mapSkels.end())
  1391.                                 {
  1392.                                         // during entity deletion, make sure the physics is reset to 0 to save it from deletion
  1393.                                         pEntity->AssignPhysicalEntity(0);
  1394.                                         g_mapSkels.erase(iter);
  1395.                                         if (g_mapSkels.empty())
  1396.                                                 gEnv->pEntitySystem->RemoveSink(this);
  1397.                                 }
  1398.                         }
  1399.                 return true;
  1400.         }
  1401.  
  1402.         std::map<int,IEntity*> g_mapSkels;
  1403. };
  1404.  
  1405. REGISTER_FLOW_NODE("Physics:Dynamics", CFlowNode_Dynamics);
  1406. REGISTER_FLOW_NODE("Physics:ActionImpulse", CFlowNode_ActionImpulse);
  1407. REGISTER_FLOW_NODE("Physics:RayCast", CFlowNode_Raycast);
  1408. REGISTER_FLOW_NODE("Physics:RayCastCamera", CFlowNode_RaycastCamera);
  1409. REGISTER_FLOW_NODE("Physics:PhysicsEnable", CFlowNode_PhysicsEnable);
  1410. REGISTER_FLOW_NODE("Physics:PhysicsSleepQuery", CFlowNode_PhysicsSleepQuery);
  1411. REGISTER_FLOW_NODE("Physics:Constraint", CFlowNode_Constraint);
  1412. REGISTER_FLOW_NODE("Physics:CameraProxy", CFlowNode_CameraProxy);
  1413. REGISTER_FLOW_NODE("Physics:CollisionListener", CFlowNode_Collision);
  1414. REGISTER_FLOW_NODE("Physics:GetPhysId", CFlowNode_PhysId);
  1415. REGISTER_FLOW_NODE("Physics:Awake", CFlowNode_Awake);
  1416. REGISTER_FLOW_NODE("Physics:SetParams", CFlowNode_PhysParams);
  1417. REGISTER_FLOW_NODE("Physics:GetSkeleton", CFlowNode_CharSkel);
  1418.  
downloadFlowPhysicsNodes.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top