Re: Zoom & Rotation object

#11
Any chance of adapting this to a 5.6 template instead of the GameSDK?

What exactly is missing when using legacy entities and copying scripts.pak over? Any nodes?
Yes done, everything needed is below, and yes stuff is missing and I had to write some flownodes and make some code changes to the Player character as well.
If you are interested in the steps involved check the "Steps" part, if you just want the solution then scroll down to "Solution"

FPS Template 5.6:
Image

Steps:

The first thing that we need to change in the flowgraph this part:
Image
The entity components do not display any properties with the Entity:PropertyGet node so we need to work with something else.
We could just write our own "Inspectable" Component but tbh I was lazy so I thought why not just name the Entity "Inspectable" and use the node
Entity:EntityInfo get the name and put it through the String:Substring node
Image

String:Substring doesn't exist in the GameSDK and Templates, but you can easily get it by just copy pasting the C++
code in the documentation page I have written here:
https://docs.cryengine.com/pages/viewpa ... d=44958448
(I will also Paste the whole Player.h Player.cpp GamePlugin.h and GamePlugin.cpp including all changes and new flownodes so you would not need to worry about following the docs page)

The next issue would be the action maps / action filter which either have not been setup with the Player in the template or only work with the GameSDK character.
(I have not checked that system. I believe there were some XML files involved with that as well)
The quickest solution for me was just write my own code for it.

Player.h

Code: Select all

//We make a new variable
protected:
bool m_canMove = true;

// and the functions to access it
public:
void CanMove(bool canMove)
{
m_canMove = canMove;
}
Player.cpp (we only add the 2 last lines)
in case of the movement we just end the Update function early before it processes the movement.

Code: Select all


void CPlayerComponent::ProcessEvent(const SEntityEvent& event)
{
switch (event.event)
{
case Cry::Entity::EEvent::BecomeLocalPlayer:
{
InitializeLocalPlayer();
}
break;
case Cry::Entity::EEvent::Update:
{
// Don't update the player if we haven't spawned yet
if(!m_isAlive)
return;

// Don't handle input if movement is not allowed
if (!m_canMove)
return;
Player.cpp modify the revive function, add last line

Code: Select all

void CPlayerComponent::Revive(const Matrix34& transform)
{
m_isAlive = true;
m_canMove = true;

GamePlugin.h

Code: Select all

//Add inside the CGamePlugin class
PLUGIN_FLOWNODE_REGISTER
PLUGIN_FLOWNODE_UNREGISTER
GamePlugin.cpp we add the 3 new Flownodes:
Image Here We expose to CanMove function we have written in C++ to flowgraph.
Image (This one so during inspection the item does not suddenly drop to the ground due to physics.)
Image

The Player is made out of Entity Components which we will have to access and change the properties from.
Camera Component for the FOV. (Zoom) Since the Camera:View does not work with entity components. (Or should I say it has not been updated for the ECS system because ofc it's possible)

Code: Select all

class CFlowNode_PlayerSettings : public CFlowBaseNode<eNCT_Singleton>
{
enum class EInPorts : int
{
LockCamera = 0,
UnlockCamera,
OverrideFOV,
GetFOV
};

public:



CFlowNode_PlayerSettings(SActivationInfo* pActInfo) {}
virtual void GetConfiguration(SFlowNodeConfig& config)
{
static const SInputPortConfig in_config[] = {
InputPortConfig_Void("LockMovement", _HELP("Lock the Camera View and movement of the Player")),
InputPortConfig_Void("UnlockMovement", _HELP("Unlock the Camera View and movement of the Player")),
InputPortConfig<float>("OverrideFOV", _HELP("Override players FOV")),
InputPortConfig_Void("GetFOV", _HELP("Gets players FOV")),
{ 0 }
};
static const SOutputPortConfig out_config[] = {
OutputPortConfig<float>("FOV", _HELP("Field of View")),
{ 0 }
};
config.sDescription = _HELP("Locks and Unlocks the Camera View and movement of the Player");
config.nFlags |= EFLN_TARGET_ENTITY;
config.pInputPorts = in_config;
config.pOutputPorts = out_config;
config.SetCategory(EFLN_APPROVED);
}
virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
{
if (event != eFE_Activate)
return;
IEntity* pEntity = pActInfo->pEntity;
if (pEntity == 0)
return;
if (IsPortActive(pActInfo, (int)EInPorts::LockCamera))
{
if (CPlayerComponent* pCPlayerComponent = pEntity->GetComponent<CPlayerComponent>())
{
pCPlayerComponent->CanMove(false);
}
}

//Lock
if (IsPortActive(pActInfo, (int)EInPorts::UnlockCamera))
{
if (CPlayerComponent* pCPlayerComponent = pEntity->GetComponent<CPlayerComponent>())
{
pCPlayerComponent->CanMove(true);
}
}

if (IsPortActive(pActInfo, (int)EInPorts::OverrideFOV))
{
if (Cry::DefaultComponents::CCameraComponent* pCCameraComponent = pEntity->GetOrCreateComponent<Cry::DefaultComponents::CCameraComponent>())
{
pCCameraComponent->SetFieldOfView(CryTransform::CAngle::FromDegrees(GetPortFloat(pActInfo, (int)EInPorts::OverrideFOV)));

}
}

if (IsPortActive(pActInfo, (int)EInPorts::GetFOV))
{
if (Cry::DefaultComponents::CCameraComponent* pCCameraComponent = pEntity->GetOrCreateComponent<Cry::DefaultComponents::CCameraComponent>())
{
ActivateOutput(pActInfo, 0, pCCameraComponent->GetFieldOfView().ToDegrees());
}
}
/*
*/

}

virtual void GetMemoryUsage(ICrySizer* s) const
{
s->Add(*this);
}
};


class CFlowNode_EntityPhysics : public CFlowBaseNode<eNCT_Singleton>
{
public:



CFlowNode_EntityPhysics(SActivationInfo* pActInfo) {}
virtual void GetConfiguration(SFlowNodeConfig& config)
{
static const SInputPortConfig in_config[] = {
InputPortConfig_Void("Enable Physics", _HELP("Enable Physics of the Entity")),
InputPortConfig_Void("Disable Physics", _HELP("Disable Physics of the Entity")),
{ 0 }
};
static const SOutputPortConfig out_config[] = {
//OutputPortConfig<EntityId>("Id", _HELP("Entity Id")),
{ 0 }
};
config.sDescription = _HELP("Enable and disable the physics on the Entity");
config.nFlags |= EFLN_TARGET_ENTITY;
config.pInputPorts = in_config;
config.pOutputPorts = out_config;
config.SetCategory(EFLN_APPROVED);
}
virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
{
if (event != eFE_Activate)
return;
IEntity* pEntity = pActInfo->pEntity;
if (pEntity == 0)
return;

if (IsPortActive(pActInfo, 0))
{
pEntity->EnablePhysics(true);
}

if (IsPortActive(pActInfo, 1))
{
pEntity->EnablePhysics(false);
}
}

virtual void GetMemoryUsage(ICrySizer* s) const
{
s->Add(*this);
}
};

//Register Flownode (you will need to do this for every FlowNode once)
//The REGISTER_FLOW_NODE Macro takes 2 parameters, the name as first and the class as second parameter.
REGISTER_FLOW_NODE("String:Substring", CFlowSubstringNode)
REGISTER_FLOW_NODE("PlayerSettings:Settings", CFlowNode_PlayerSettings)
REGISTER_FLOW_NODE("Entity:Physics", CFlowNode_EntityPhysics)
I will not go into the details of where to use the rest of the nodes, you can check for yourself in the solution below


Solution Flowgraph (Solution part 1 of 2 due to )
Image

Flowgraph:

Code: Select all

<Graph Description="" Group="InspectFG">
<Nodes>
<Node Id="215" Class="Debug:InputKey" pos="486,1681.9526,0">
<Inputs entityId="0" Key="f" NonDevMode="0"/>
</Node>
<Node Id="217" Class="Physics:RayCastCamera" pos="1404,1699.9526,0">
<Inputs offset="0,0,0" maxLength="2" ObjTypes="287" IgnoredEntity="0"/>
</Node>
<Node Id="222" Class="Math:InRange" pos="1944,1753.9526,0">
<Inputs In="0" Min="-1" Max="0"/>
</Node>
<Node Id="226" Class="Mission:GameTokenSet" pos="5742,1861.9526,0">
<Inputs gametoken_Token="Level.State_Inspecting" Value="1"/>
</Node>
<Node Id="228" Class="Mission:GameTokenSet" pos="4446,1843.9526,0">
<Inputs gametoken_Token="Level.Item_ID" Value=""/>
</Node>
<Node Id="231" Class="Logic:Any" pos="1944,1861.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="233" Class="Mission:GameToken" pos="162,3463.9526,0">
<Inputs gametoken_Token="Level.State_Inspecting" compare_Value="1" FireOnStart="1" FireOnlyOnResultChange="1"/>
</Node>
<Node Id="234" Class="Input:MouseCoords" pos="3348,3553.9526,0">
<Inputs World="0" Screen="0" Delta="1"/>
</Node>
<Node Id="235" Class="Entity:BeamEntity" pos="5184,3517.9526,0">
<Inputs entityId="0" CoordSys="1" Position="0,0,0" Rotation="0,0,0" UseZeroRot="0" Scale="0,0,0"/>
</Node>
<Node Id="236" Class="Entity:GetPos" pos="4176,3481.9526,0">
<Inputs entityId="0" CoordSys="1"/>
</Node>
<Node Id="237" Class="Vec3:ToVec3" pos="3780,3625.9526,0">
<Inputs x="0" y="0" z="0"/>
</Node>
<Node Id="238" Class="Logic:Any" pos="3780,3499.9526,0" InHideMask="1023">
<Inputs />
</Node>
<Node Id="239" Class="Vec3:AddVec3" pos="4734,3589.9526,0">
<Inputs A="0,0,0" B="0,0,0"/>
</Node>
<Node Id="240" Class="Logic:Any" pos="4176,3625.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="242" Class="Logic:Any" pos="4734,3499.9526,0" InHideMask="1023">
<Inputs />
</Node>
<Node Id="245" Name="Inspecting" Class="_commentbox" pos="144,2954.3423,0">
<Inputs TextSize="1" Color="1,1,1" DisplayFilled="1" DisplayBox="1" SortPriority="16"/>
<ResizeBorder X="0" Y="0" Width="6570" Height="1044"/>
<NodeSize Width="6570" Height="1424.1879"/>
</Node>
<Node Id="248" Class="Mission:GameToken" pos="4176,3391.9526,0">
<Inputs gametoken_Token="Level.Item_ID" compare_Value="" FireOnStart="1" FireOnlyOnResultChange="1"/>
</Node>
<Node Id="251" Name="Item_Inspector_(Set_State)" Class="_commentbox" pos="180,1279.3829,0">
<Inputs TextSize="1" Color="1,1,1" DisplayFilled="1" DisplayBox="1" SortPriority="16"/>
<ResizeBorder X="0" Y="0" Width="5976" Height="846"/>
<NodeSize Width="5976" Height="1226.1879"/>
</Node>
<Node Id="256" Name="Passes_on_Level.Item_ID" Class="_comment" pos="4176,3373.9526,0"/>
<Node Id="264" Class="Mission:GameTokenGet" pos="774,1699.9526,0">
<Inputs gametoken_Token="Level.State_Inspecting"/>
</Node>
<Node Id="268" Class="Math:BooleanFrom" pos="1188,1699.9526,0">
<Inputs Value="0"/>
</Node>
<Node Id="274" Class="String:Compare" pos="4104,1782,0">
<Inputs A="" B="Inspect" IgnoreCase="1"/>
</Node>
<Node Id="275" Class="Logic:Any" pos="3744,1879.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="276" Class="Logic:Any" pos="4104,1879.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="277" Name="Check_if_Item_can_be_inspected" Class="_comment" pos="3672,1746,0"/>
<Node Id="278" Name="if_item_can_be_inspected" Class="_comment" pos="4104,1764,0"/>
<Node Id="279" Name="Trigger_the_Inspecting_State" Class="_comment" pos="5742,1843.9526,0"/>
<Node Id="280" Name="Check_if_the_Entity_ID_is_Valid" Class="_comment" pos="1944,1735.9526,0"/>
<Node Id="281" Name="Inspection_Key" Class="_comment" pos="486,1789.9526,0"/>
<Node Id="283" Class="Entity:PropertySet" pos="4446,1951.9526,0">
<Inputs entityId="0" entityProperties_Property="Properties:bUsable" Value="0" perArchetype="1"/>
</Node>
<Node Id="287" Name="Set_Inspecting_Level.Item_ID" Class="_comment" pos="4446,1825.9526,0"/>
<Node Id="288" Name="Disable_Inspecting_Text_on_Item_while_inspecting" Class="_comment" pos="4446,1933.9526,0"/>
<Node Id="290" Class="Image:EffectDepthOfField" pos="864,3841.9526,0">
<Inputs entityId="0" Enabled="0" Disabled="0" Dof_User_Active="1" Dof_User_FocusDistance="1" Dof_User_FocusRange="2" Dof_User_BlurAmount="2" Dof_MaxCoC="12" Dof_CenterWeight="1"/>
</Node>
<Node Id="292" Class="Actor:LocalPlayer" pos="864,3805.9526,0">
<Inputs />
</Node>
<Node Id="297" Name="Activate_/_Deactivate_DoF_Effect" Class="_comment" pos="864,3787.9526,0"/>
<Node Id="298" Class="Mission:GameToken" pos="5184,3427.9526,0">
<Inputs gametoken_Token="Level.Item_ID" compare_Value="" FireOnStart="1" FireOnlyOnResultChange="1"/>
</Node>
<Node Id="299" Name="Passes_on_Level.Item_ID" Class="_comment" pos="5184,3409.9526,0"/>
<Node Id="301" Class="Mission:GameTokenGet" pos="1062,3589.9526,0">
<Inputs gametoken_Token="Level.Item_Move_To_Camera_Speed"/>
</Node>
<Node Id="304" Class="Mission:GameToken" pos="2232,3535.9526,0">
<Inputs gametoken_Token="Level.Item_ID" compare_Value="" FireOnStart="1" FireOnlyOnResultChange="1"/>
</Node>
<Node Id="305" Name="Passes_on_Level.Item_ID" Class="_comment" pos="2232,3517.9526,0"/>
<Node Id="307" Class="Camera:GetTransform" pos="648,3481.9526,0">
<Inputs />
</Node>
<Node Id="311" Class="Vec3:AddVec3" pos="864,3481.9526,0">
<Inputs A="0,0,0" B="0,0,0"/>
</Node>
<Node Id="314" Class="Input:ActionMaps:ActionFilter" pos="648,3589.9526,0">
<Inputs actionFilter_Filter="no_move"/>
</Node>
<Node Id="315" Class="Input:ActionMaps:ActionFilter" pos="648,3679.9526,0">
<Inputs actionFilter_Filter="no_mouse"/>
</Node>
<Node Id="316" Name="Disable_Movement" Class="_comment" pos="648,3571.9526,0"/>
<Node Id="318" Name="Disable_Looking_Around" Class="_comment" pos="648,3661.9526,0"/>
<Node Id="323" Class="Game:Start" pos="2934,3355.9526,0">
<Inputs InGame="1" InEditor="1"/>
</Node>
<Node Id="325" Class="Logic:Any" pos="2934,3409.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="327" Class="Mission:GameToken" pos="1926,1969.9526,0">
<Inputs gametoken_Token="Level.Item_ID" compare_Value="" FireOnStart="1" FireOnlyOnResultChange="1"/>
</Node>
<Node Id="328" Name="Passes_on_Level.Item_ID" Class="_comment" pos="1926,1951.9526,0"/>
<Node Id="332" Class="Mission:GameTokenGet" pos="1350,2077.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Location"/>
</Node>
<Node Id="334" Class="Entity:GetPos" pos="4932,1843.9526,0">
<Inputs entityId="0" CoordSys="1"/>
</Node>
<Node Id="335" Class="Mission:GameTokenSet" pos="5220,1861.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Location" Value="1"/>
</Node>
<Node Id="336" Name="Set_Original_Item_Location_(so_we_know_where_to_put_it_back_later)" Class="_comment" pos="5220,1843.9526,0"/>
<Node Id="337" Class="Mission:GameTokenGet" pos="1350,2131.9526,0">
<Inputs gametoken_Token="Level.Item_Move_To_Camera_Speed"/>
</Node>
<Node Id="339" Class="Logic:Any" pos="648,3769.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="342" Class="Mission:GameTokenSet" pos="3744,2329.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Location" Value="0,0,0"/>
</Node>
<Node Id="344" Class="Mission:GameTokenSet" pos="3744,2257.9526,0">
<Inputs gametoken_Token="Level.Item_ID" Value="0"/>
</Node>
<Node Id="345" Class="Entity:PropertySet" pos="3744,2149.9526,0">
<Inputs entityId="0" entityProperties_Property="Properties:bUsable" Value="1" perArchetype="1"/>
</Node>
<Node Id="348" Class="Mission:GameToken" pos="3744,2059.9526,0">
<Inputs gametoken_Token="Level.Item_ID" compare_Value="" FireOnStart="1" FireOnlyOnResultChange="1"/>
</Node>
<Node Id="349" Name="Passes_on_Level.Item_ID" Class="_comment" pos="3744,2041.9526,0"/>
<Node Id="350" Name="Reset_all_values_to_zero_when_we_finish_inspecting" Class="_comment" pos="3744,2023.9526,0"/>
<Node Id="362" Class="Math:BooleanTo" pos="648,3859.9526,0">
<Inputs />
</Node>
<Node Id="394" Class="Mission:GameTokenSet" pos="3744,2401.9526,0">
<Inputs gametoken_Token="Level.State_Inspecting" Value="0"/>
</Node>
<Node Id="395" Class="Mission:GameTokenSet" pos="5220,1969.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Rotation" Value="1"/>
</Node>
<Node Id="396" Name="Same_with_Rotation" Class="_comment" pos="5220,1951.9526,0"/>
<Node Id="399" Class="Mission:GameTokenGet" pos="1350,2185.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Rotation"/>
</Node>
<Node Id="461" Class="Interpol:Vec3" pos="2394,2077.9526,0">
<Inputs StartValue="0,0,0" EndValue="1,1,1" Time="1" UpdateFrequency="0" Easing="0"/>
</Node>
<Node Id="463" Class="Entity:BeamEntity" pos="2790,2041.9526,0">
<Inputs entityId="0" CoordSys="1" Position="0,0,0" Rotation="0,0,0" UseZeroRot="0" Scale="0,0,0"/>
</Node>
<Node Id="465" Class="Entity:GetPos" pos="1926,2059.9526,0">
<Inputs entityId="0" CoordSys="1"/>
</Node>
<Node Id="466" Class="Mission:GameToken" pos="2790,1951.9526,0">
<Inputs gametoken_Token="Level.Item_ID" compare_Value="" FireOnStart="1" FireOnlyOnResultChange="1"/>
</Node>
<Node Id="467" Name="Passes_on_Level.Item_ID" Class="_comment" pos="2790,1933.9526,0"/>
<Node Id="468" Class="Interpol:Vec3" pos="2394,2221.9526,0">
<Inputs StartValue="0,0,0" EndValue="1,1,1" Time="1" UpdateFrequency="0" Easing="0"/>
</Node>
<Node Id="470" Class="Logic:Any" pos="1926,2203.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="472" Class="Logic:Any" pos="1926,2257.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="474" Class="Logic:Any" pos="1926,2311.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="476" Class="Logic:Any" pos="2790,2203.9526,0">
<Inputs />
</Node>
<Node Id="480" Class="Interpol:Vec3" pos="1764,3643.9526,0">
<Inputs StartValue="0,0,0" EndValue="1,1,1" Time="1" UpdateFrequency="0" Easing="0"/>
</Node>
<Node Id="487" Class="Logic:Any" pos="1062,3643.9526,0" InHideMask="1022" OutHideMask="1">
<Inputs />
</Node>
<Node Id="489" Class="Entity:BeamEntity" pos="2232,3625.9526,0">
<Inputs entityId="0" CoordSys="1" Position="0,0,0" Rotation="0,0,0" UseZeroRot="0" Scale="0,0,0"/>
</Node>
<Node Id="491" Class="Mission:GameTokenGet" pos="1062,3481.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Location"/>
</Node>
<Node Id="493" Class="Mission:GameTokenGet" pos="1062,3535.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Rotation"/>
</Node>
<Node Id="497" Class="Logic:Any" pos="1764,3787.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="499" Class="Logic:Any" pos="2232,3787.9526,0">
<Inputs />
</Node>
<Node Id="503" Class="Input:MouseButtonInfo" pos="648,4075.9526,0">
<Inputs MouseButton="0" MouseWheel="1"/>
</Node>
<Node Id="510" Name="Zoom_Function" Class="_comment" pos="648,4057.9526,0"/>
<Node Id="550" Class="Math:Calculate" pos="1134,4111.9526,0">
<Inputs Op="3" A="-120" B="-120"/>
</Node>
<Node Id="554" Class="Math:Add" pos="1602,4111.9526,0">
<Inputs A="0" B="0"/>
</Node>
<Node Id="559" Name="sensitivity" Class="_comment" pos="1422,4093.9526,0"/>
<Node Id="562" Class="Math:Mul" pos="1422,4111.9526,0">
<Inputs A="0" B="3"/>
</Node>
<Node Id="564" Class="Interpol:Float" pos="2898,2527.9526,0">
<Inputs StartValue="0" EndValue="55" Time="1" UpdateFrequency="0" Easing="0"/>
</Node>
<Node Id="568" Class="Mission:GameTokenGet" pos="2394,2599.9526,0">
<Inputs gametoken_Token="Level.Item_Move_To_Camera_Speed"/>
</Node>
<Node Id="570" Name="Settings_(Init)" Class="_commentbox" pos="180,609.88794,0">
<Inputs TextSize="1" Color="1,1,1" DisplayFilled="1" DisplayBox="1" SortPriority="16"/>
<ResizeBorder X="0" Y="0" Width="720" Height="414"/>
<NodeSize Width="1791.9929" Height="794.18787"/>
</Node>
<Node Id="573" Class="Game:Start" pos="198,1015.9526,0">
<Inputs InGame="1" InEditor="1"/>
</Node>
<Node Id="575" Class="Mission:GameTokenSet" pos="432,1015.9526,0">
<Inputs gametoken_Token="Level.Item_ID" Value="0"/>
</Node>
<Node Id="576" Class="Mission:GameTokenSet" pos="432,1087.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Location" Value="0"/>
</Node>
<Node Id="577" Class="Mission:GameTokenSet" pos="432,1159.9526,0">
<Inputs gametoken_Token="Level.State_Inspecting" Value="0"/>
</Node>
<Node Id="578" Class="Mission:GameTokenSet" pos="432,1231.9526,0">
<Inputs gametoken_Token="Level.Item_Move_To_Camera_Speed" Value="1"/>
</Node>
<Node Id="579" Class="Mission:GameTokenSet" pos="432,1303.9526,0">
<Inputs gametoken_Token="Level.Item_Original_Rotation" Value="0"/>
</Node>
<Node Id="581" Class="Entity:EntityInfo" pos="1764,1537.9526,0">
<Inputs entityId="0"/>
</Node>
<Node Id="583" Class="Logic:Any" pos="2016,1573.9526,0" InHideMask="1023" OutHideMask="1">
<Inputs />
</Node>
<Node Id="605" Class="Entity:EntityInfo" pos="3672,1764,0">
<Inputs entityId="0"/>
</Node>
<Node Id="609" Class="String:Substring" pos="3888,1782,0">
<Inputs String="" Int1="0" Int2="7"/>
</Node>
<Node Id="636" Class="Actor:LocalPlayer" pos="432,3798,0">
<Inputs />
</Node>
<Node Id="646" Class="Entity:Physics" pos="3744,2502,0">
<Inputs entityId="0"/>
</Node>
<Node Id="661" Class="Entity:Physics" pos="2538,4050,0">
<Inputs entityId="0"/>
</Node>
<Node Id="663" Class="Mission:GameTokenGet" pos="2232,4050,0">
<Inputs gametoken_Token="Level.Item_ID"/>
</Node>
<Node Id="667" Class="PlayerSettings:Settings" pos="432,3834,0">
<Inputs entityId="0" OverrideFOV="0"/>
</Node>
<Node Id="669" Class="PlayerSettings:Settings" pos="1836,4086,0">
<Inputs entityId="0" OverrideFOV="0"/>
</Node>
<Node Id="671" Class="Actor:LocalPlayer" pos="1836,4050,0">
<Inputs />
</Node>
<Node Id="685" Class="PlayerSettings:Settings" pos="1422,4248,0">
<Inputs entityId="0" OverrideFOV="0"/>
</Node>
<Node Id="687" Class="Actor:LocalPlayer" pos="1422,4212,0">
<Inputs />
</Node>
<Node Id="696" Class="PlayerSettings:Settings" pos="3942,2664,0">
<Inputs entityId="0" OverrideFOV="0"/>
</Node>
<Node Id="697" Class="Actor:LocalPlayer" pos="3942,2628,0">
<Inputs />
</Node>
<Node Id="699" Class="Math:SetNumber" pos="3762,2718,0">
<Inputs in="70"/>
</Node>
<Node Id="700" Name="Make_a_token_for_this_as_well" Class="_comment" pos="3762,2772,0"/>
<Node Id="701" Name="I_was_lazy" Class="_comment" pos="3762,2790,0"/>
<Node Id="702" Name="Make_sure_you_stop_inspecting_the_item_in_the_sandbox_editor_else_the_item_will_not_return_to_its_original_state" Class="_comment" pos="3744,2592,0"/>
<Node Id="703" Name="Make_sure_you_stop_inspecting_the_item_in_the_sandbox_editor_else_the_item_will_not_return_to_its_original_state" Class="_comment" pos="2538,4122,0"/>
</Nodes>
<Edges>
<Edge nodeIn="264" nodeOut="215" portIn="Trigger" portOut="Pressed" enabled="1"/>
<Edge nodeIn="222" nodeOut="217" portIn="In" portOut="entity" enabled="1"/>
<Edge nodeIn="231" nodeOut="217" portIn="in1" portOut="entity" enabled="1"/>
<Edge nodeIn="581" nodeOut="217" portIn="Get" portOut="entity" enabled="1"/>
<Edge nodeIn="581" nodeOut="217" portIn="entityId" portOut="entity" enabled="1"/>
<Edge nodeIn="605" nodeOut="222" portIn="Get" portOut="false" enabled="1"/>
<Edge nodeIn="334" nodeOut="228" portIn="Get" portOut="OutValue" enabled="1"/>
<Edge nodeIn="334" nodeOut="228" portIn="entityId" portOut="OutValue" enabled="1"/>
<Edge nodeIn="275" nodeOut="231" portIn="in1" portOut="out" enabled="1"/>
<Edge nodeIn="605" nodeOut="231" portIn="entityId" portOut="out" enabled="1"/>
<Edge nodeIn="307" nodeOut="233" portIn="Get" portOut="Equal True" enabled="1"/>
<Edge nodeIn="314" nodeOut="233" portIn="Disable" portOut="Equal False" enabled="1"/>
<Edge nodeIn="314" nodeOut="233" portIn="Enable" portOut="Equal True" enabled="1"/>
<Edge nodeIn="315" nodeOut="233" portIn="Disable" portOut="Equal False" enabled="1"/>
<Edge nodeIn="315" nodeOut="233" portIn="Enable" portOut="Equal True" enabled="1"/>
<Edge nodeIn="339" nodeOut="233" portIn="in1" portOut="Equal False" enabled="1"/>
<Edge nodeIn="362" nodeOut="233" portIn="false" portOut="Equal False" enabled="1"/>
<Edge nodeIn="362" nodeOut="233" portIn="true" portOut="Equal True" enabled="1"/>
<Edge nodeIn="503" nodeOut="233" portIn="Disable" portOut="Equal False" enabled="1"/>
<Edge nodeIn="503" nodeOut="233" portIn="Enable" portOut="Equal True" enabled="1"/>
<Edge nodeIn="667" nodeOut="233" portIn="UnlockMovement" portOut="Equal False" enabled="1"/>
<Edge nodeIn="667" nodeOut="233" portIn="LockMovement" portOut="Equal True" enabled="1"/>
<Edge nodeIn="237" nodeOut="234" portIn="z" portOut="DeltaScreenX" enabled="1"/>
<Edge nodeIn="237" nodeOut="234" portIn="x" portOut="DeltaScreenY" enabled="1"/>
<Edge nodeIn="238" nodeOut="234" portIn="in1" portOut="DeltaScreenX" enabled="1"/>
<Edge nodeIn="239" nodeOut="236" portIn="A" portOut="Rotate" enabled="1"/>
<Edge nodeIn="242" nodeOut="236" portIn="in1" portOut="Pos" enabled="1"/>
<Edge nodeIn="240" nodeOut="237" portIn="in1" portOut="vec3" enabled="1"/>
<Edge nodeIn="236" nodeOut="238" portIn="Get" portOut="out" enabled="1"/>
<Edge nodeIn="235" nodeOut="239" portIn="Beam" portOut="out" enabled="1"/>
<Edge nodeIn="235" nodeOut="239" portIn="Rotation" portOut="out" enabled="1"/>
<Edge nodeIn="239" nodeOut="240" portIn="B" portOut="out" enabled="1"/>
<Edge nodeIn="235" nodeOut="242" portIn="Position" portOut="out" enabled="1"/>
<Edge nodeIn="236" nodeOut="248" portIn="entityId" portOut="Out" enabled="1"/>
<Edge nodeIn="268" nodeOut="264" portIn="Value" portOut="OutValue" enabled="1"/>
<Edge nodeIn="217" nodeOut="268" portIn="go" portOut="False" enabled="1"/>
<Edge nodeIn="332" nodeOut="268" portIn="Trigger" portOut="True" enabled="1"/>
<Edge nodeIn="337" nodeOut="268" portIn="Trigger" portOut="True" enabled="1"/>
<Edge nodeIn="399" nodeOut="268" portIn="Trigger" portOut="True" enabled="1"/>
<Edge nodeIn="228" nodeOut="274" portIn="Trigger" portOut="True" enabled="1"/>
<Edge nodeIn="283" nodeOut="274" portIn="Set" portOut="True" enabled="1"/>
<Edge nodeIn="276" nodeOut="275" portIn="in1" portOut="out" enabled="1"/>
<Edge nodeIn="228" nodeOut="276" portIn="Value" portOut="out" enabled="1"/>
<Edge nodeIn="283" nodeOut="276" portIn="entityId" portOut="out" enabled="1"/>
<Edge nodeIn="290" nodeOut="292" portIn="entityId" portOut="entityId" enabled="1"/>
<Edge nodeIn="235" nodeOut="298" portIn="entityId" portOut="Out" enabled="1"/>
<Edge nodeIn="480" nodeOut="301" portIn="Time" portOut="OutValue" enabled="1"/>
<Edge nodeIn="489" nodeOut="304" portIn="entityId" portOut="Out" enabled="1"/>
<Edge nodeIn="311" nodeOut="307" portIn="B" portOut="Dir" enabled="1"/>
<Edge nodeIn="311" nodeOut="307" portIn="A" portOut="Pos" enabled="1"/>
<Edge nodeIn="301" nodeOut="311" portIn="Trigger" portOut="out" enabled="1"/>
<Edge nodeIn="487" nodeOut="311" portIn="in1" portOut="out" enabled="1"/>
<Edge nodeIn="491" nodeOut="311" portIn="Trigger" portOut="out" enabled="1"/>
<Edge nodeIn="493" nodeOut="311" portIn="Trigger" portOut="out" enabled="1"/>
<Edge nodeIn="325" nodeOut="323" portIn="in1" portOut="output" enabled="1"/>
<Edge nodeIn="234" nodeOut="325" portIn="Disable" portOut="out" enabled="1"/>
<Edge nodeIn="465" nodeOut="327" portIn="entityId" portOut="Out" enabled="1"/>
<Edge nodeIn="465" nodeOut="332" portIn="Get" portOut="OutValue" enabled="1"/>
<Edge nodeIn="470" nodeOut="332" portIn="in1" portOut="OutValue" enabled="1"/>
<Edge nodeIn="335" nodeOut="334" portIn="Trigger" portOut="Pos" enabled="1"/>
<Edge nodeIn="335" nodeOut="334" portIn="Value" portOut="Pos" enabled="1"/>
<Edge nodeIn="395" nodeOut="334" portIn="Trigger" portOut="Rotate" enabled="1"/>
<Edge nodeIn="395" nodeOut="334" portIn="Value" portOut="Rotate" enabled="1"/>
<Edge nodeIn="226" nodeOut="335" portIn="Trigger" portOut="OutValue" enabled="1"/>
<Edge nodeIn="474" nodeOut="337" portIn="in1" portOut="OutValue" enabled="1"/>
<Edge nodeIn="345" nodeOut="348" portIn="entityId" portOut="Out" enabled="1"/>
<Edge nodeIn="646" nodeOut="348" portIn="entityId" portOut="Out" enabled="1"/>
<Edge nodeIn="290" nodeOut="362" portIn="Enabled" portOut="out" enabled="1"/>
<Edge nodeIn="325" nodeOut="399" portIn="in3" portOut="OutValue" enabled="1"/>
<Edge nodeIn="472" nodeOut="399" portIn="in1" portOut="OutValue" enabled="1"/>
<Edge nodeIn="463" nodeOut="461" portIn="Beam" portOut="Value" enabled="1"/>
<Edge nodeIn="463" nodeOut="461" portIn="Position" portOut="Value" enabled="1"/>
<Edge nodeIn="476" nodeOut="461" portIn="in1" portOut="Done" enabled="1"/>
<Edge nodeIn="461" nodeOut="465" portIn="Start" portOut="Pos" enabled="1"/>
<Edge nodeIn="461" nodeOut="465" portIn="StartValue" portOut="Pos" enabled="1"/>
<Edge nodeIn="468" nodeOut="465" portIn="Start" portOut="Rotate" enabled="1"/>
<Edge nodeIn="468" nodeOut="465" portIn="StartValue" portOut="Rotate" enabled="1"/>
<Edge nodeIn="463" nodeOut="466" portIn="entityId" portOut="Out" enabled="1"/>
<Edge nodeIn="463" nodeOut="468" portIn="Rotation" portOut="Value" enabled="1"/>
<Edge nodeIn="461" nodeOut="470" portIn="EndValue" portOut="out" enabled="1"/>
<Edge nodeIn="468" nodeOut="472" portIn="EndValue" portOut="out" enabled="1"/>
<Edge nodeIn="461" nodeOut="474" portIn="Time" portOut="out" enabled="1"/>
<Edge nodeIn="468" nodeOut="474" portIn="Time" portOut="out" enabled="1"/>
<Edge nodeIn="568" nodeOut="474" portIn="Trigger" portOut="out" enabled="1"/>
<Edge nodeIn="342" nodeOut="476" portIn="Trigger" portOut="out" enabled="1"/>
<Edge nodeIn="344" nodeOut="476" portIn="Trigger" portOut="out" enabled="1"/>
<Edge nodeIn="345" nodeOut="476" portIn="Set" portOut="out" enabled="1"/>
<Edge nodeIn="394" nodeOut="476" portIn="Trigger" portOut="out" enabled="1"/>
<Edge nodeIn="646" nodeOut="476" portIn="Enable Physics" portOut="out" enabled="1"/>
<Edge nodeIn="699" nodeOut="476" portIn="set" portOut="out" enabled="1"/>
<Edge nodeIn="489" nodeOut="480" portIn="Beam" portOut="Value" enabled="1"/>
<Edge nodeIn="489" nodeOut="480" portIn="Position" portOut="Value" enabled="1"/>
<Edge nodeIn="499" nodeOut="480" portIn="in1" portOut="Done" enabled="1"/>
<Edge nodeIn="663" nodeOut="480" portIn="Trigger" portOut="Done" enabled="1"/>
<Edge nodeIn="480" nodeOut="487" portIn="EndValue" portOut="out" enabled="1"/>
<Edge nodeIn="480" nodeOut="487" portIn="Start" portOut="out" enabled="1"/>
<Edge nodeIn="480" nodeOut="491" portIn="StartValue" portOut="OutValue" enabled="1"/>
<Edge nodeIn="497" nodeOut="493" portIn="in1" portOut="OutValue" enabled="1"/>
<Edge nodeIn="489" nodeOut="497" portIn="Rotation" portOut="out" enabled="1"/>
<Edge nodeIn="234" nodeOut="499" portIn="Enable" portOut="out" enabled="1"/>
<Edge nodeIn="550" nodeOut="503" portIn="A" portOut="MouseWheel" enabled="1"/>
<Edge nodeIn="550" nodeOut="503" portIn="DoCalc" portOut="MouseWheel" enabled="1"/>
<Edge nodeIn="562" nodeOut="550" portIn="A" portOut="out" enabled="1"/>
<Edge nodeIn="685" nodeOut="550" portIn="GetFOV" portOut="out" enabled="1"/>
<Edge nodeIn="669" nodeOut="554" portIn="OverrideFOV" portOut="out" enabled="1"/>
<Edge nodeIn="554" nodeOut="562" portIn="A" portOut="out" enabled="1"/>
<Edge nodeIn="564" nodeOut="568" portIn="Time" portOut="OutValue" enabled="1"/>
<Edge nodeIn="575" nodeOut="573" portIn="Trigger" portOut="output" enabled="1"/>
<Edge nodeIn="576" nodeOut="573" portIn="Trigger" portOut="output" enabled="1"/>
<Edge nodeIn="577" nodeOut="573" portIn="Trigger" portOut="output" enabled="1"/>
<Edge nodeIn="578" nodeOut="573" portIn="Trigger" portOut="output" enabled="1"/>
<Edge nodeIn="579" nodeOut="573" portIn="Trigger" portOut="output" enabled="1"/>
<Edge nodeIn="583" nodeOut="581" portIn="in3" portOut="Archetype" enabled="1"/>
<Edge nodeIn="583" nodeOut="581" portIn="in2" portOut="Class" enabled="1"/>
<Edge nodeIn="583" nodeOut="581" portIn="in1" portOut="Name" enabled="1"/>
<Edge nodeIn="609" nodeOut="605" portIn="Get" portOut="Name" enabled="1"/>
<Edge nodeIn="609" nodeOut="605" portIn="String" portOut="Name" enabled="1"/>
<Edge nodeIn="274" nodeOut="609" portIn="A" portOut="Out" enabled="1"/>
<Edge nodeIn="274" nodeOut="609" portIn="Compare" portOut="Out" enabled="1"/>
<Edge nodeIn="667" nodeOut="636" portIn="entityId" portOut="entityId" enabled="1"/>
<Edge nodeIn="661" nodeOut="663" portIn="Disable Physics" portOut="OutValue" enabled="1"/>
<Edge nodeIn="661" nodeOut="663" portIn="entityId" portOut="OutValue" enabled="1"/>
<Edge nodeIn="669" nodeOut="671" portIn="entityId" portOut="entityId" enabled="1"/>
<Edge nodeIn="554" nodeOut="685" portIn="B" portOut="FOV" enabled="1"/>
<Edge nodeIn="685" nodeOut="687" portIn="entityId" portOut="entityId" enabled="1"/>
<Edge nodeIn="696" nodeOut="697" portIn="entityId" portOut="entityId" enabled="1"/>
<Edge nodeIn="696" nodeOut="699" portIn="OverrideFOV" portOut="out" enabled="1"/>
</Edges>
</Graph>
Last edited by Cry-Chris on Sat Jul 25, 2020 8:01 am, edited 4 times in total.

Re: Zoom & Rotation object

#12
Solution Code (Solution part 2 of 2 )

Player.h

Code: Select all

#pragma once

#include <array>
#include <numeric>

#include <CryEntitySystem/IEntityComponent.h>
#include <CryMath/Cry_Camera.h>

#include <ICryMannequin.h>
#include <CrySchematyc/Utils/EnumFlags.h>

#include <DefaultComponents/Cameras/CameraComponent.h>
#include <DefaultComponents/Physics/CharacterControllerComponent.h>
#include <DefaultComponents/Geometry/AdvancedAnimationComponent.h>
#include <DefaultComponents/Input/InputComponent.h>
#include <DefaultComponents/Audio/ListenerComponent.h>

////////////////////////////////////////////////////////
// Represents a player participating in gameplay
////////////////////////////////////////////////////////
class CPlayerComponent final : public IEntityComponent
{
enum class EInputFlagType
{
Hold = 0,
Toggle
};

enum class EInputFlag : uint8
{
MoveLeft = 1 << 0,
MoveRight = 1 << 1,
MoveForward = 1 << 2,
MoveBack = 1 << 3
};

static constexpr EEntityAspects InputAspect = eEA_GameClientD;

template<typename T, size_t SAMPLES_COUNT>
class MovingAverage
{
static_assert(SAMPLES_COUNT > 0, "SAMPLES_COUNT shall be larger than zero!");

public:

MovingAverage()
: m_values()
, m_cursor(SAMPLES_COUNT)
, m_accumulator()
{
}

MovingAverage& Push(const T& value)
{
if (m_cursor == SAMPLES_COUNT)
{
m_values.fill(value);
m_cursor = 0;
m_accumulator = std::accumulate(m_values.begin(), m_values.end(), T(0));
}
else
{
m_accumulator -= m_values[m_cursor];
m_values[m_cursor] = value;
m_accumulator += m_values[m_cursor];
m_cursor = (m_cursor + 1) % SAMPLES_COUNT;
}

return *this;
}

T Get() const
{
return m_accumulator / T(SAMPLES_COUNT);
}

void Reset()
{
m_cursor = SAMPLES_COUNT;
}

private:

std::array<T, SAMPLES_COUNT> m_values;
size_t m_cursor;

T m_accumulator;
};

public:
CPlayerComponent() = default;
virtual ~CPlayerComponent() = default;

// IEntityComponent
virtual void Initialize() override;

virtual Cry::Entity::EventFlags GetEventMask() const override;
virtual void ProcessEvent(const SEntityEvent& event) override;

virtual bool NetSerialize(TSerialize ser, EEntityAspects aspect, uint8 profile, int flags) override;
virtual NetworkAspectType GetNetSerializeAspectMask() const override { return InputAspect; }
// ~IEntityComponent

// Reflect type to set a unique identifier for this component
static void ReflectType(Schematyc::CTypeDesc<CPlayerComponent>& desc)
{
desc.SetGUID("{63F4C0C6-32AF-4ACB-8FB0-57D45DD14725}"_cry_guid);
}

void OnReadyForGameplayOnServer();
bool IsLocalClient() const { return (m_pEntity->GetFlags() & ENTITY_FLAG_LOCAL_PLAYER) != 0; }

void CanMove(bool canMove)
{
m_canMove = canMove;
}

protected:
void Revive(const Matrix34& transform);

void UpdateMovementRequest(float frameTime);
void UpdateLookDirectionRequest(float frameTime);
void UpdateAnimation(float frameTime);
void UpdateCamera(float frameTime);

void HandleInputFlagChange(CEnumFlags<EInputFlag> flags, CEnumFlags<EActionActivationMode> activationMode, EInputFlagType type = EInputFlagType::Hold);

// Called when this entity becomes the local player, to create client specific setup such as the Camera
void InitializeLocalPlayer();

// Start remote method declarations
protected:
// Parameters to be passed to the RemoteReviveOnClient function
struct RemoteReviveParams
{
// Called once on the server to serialize data to the other clients
// Then called once on the other side to deserialize
void SerializeWith(TSerialize ser)
{
// Serialize the position with the 'wrld' compression policy
ser.Value("pos", position, 'wrld');
// Serialize the rotation with the 'ori0' compression policy
ser.Value("rot", rotation, 'ori0');
}

Vec3 position;
Quat rotation;
};
// Remote method intended to be called on all remote clients when a player spawns on the server
bool RemoteReviveOnClient(RemoteReviveParams&& params, INetChannel* pNetChannel);

protected:
bool m_isAlive = false;
bool m_canMove = true;

Cry::DefaultComponents::CCameraComponent* m_pCameraComponent = nullptr;
Cry::DefaultComponents::CCharacterControllerComponent* m_pCharacterController = nullptr;
Cry::DefaultComponents::CAdvancedAnimationComponent* m_pAnimationComponent = nullptr;
Cry::DefaultComponents::CInputComponent* m_pInputComponent = nullptr;
Cry::Audio::DefaultComponents::CListenerComponent* m_pAudioListenerComponent = nullptr;

FragmentID m_idleFragmentId;
FragmentID m_walkFragmentId;
TagID m_rotateTagId;

CEnumFlags<EInputFlag> m_inputFlags;
Vec2 m_mouseDeltaRotation;
MovingAverage<Vec2, 10> m_mouseDeltaSmoothingFilter;

const float m_rotationSpeed = 0.002f;

int m_cameraJointId = -1;

FragmentID m_activeFragmentId;

Quat m_lookOrientation; //!< Should translate to head orientation in the future
float m_horizontalAngularVelocity;
MovingAverage<float, 10> m_averagedHorizontalAngularVelocity;
};
Player.cpp

Code: Select all

#include "StdAfx.h"
#include "Player.h"
#include "Bullet.h"
#include "SpawnPoint.h"
#include "GamePlugin.h"

#include <CryRenderer/IRenderAuxGeom.h>
#include <CrySchematyc/Env/Elements/EnvComponent.h>
#include <CryCore/StaticInstanceList.h>
#include <CryNetwork/Rmi.h>

#define MOUSE_DELTA_TRESHOLD 0.0001f

namespace
{
static void RegisterPlayerComponent(Schematyc::IEnvRegistrar& registrar)
{
Schematyc::CEnvRegistrationScope scope = registrar.Scope(IEntity::GetEntityScopeGUID());
{
Schematyc::CEnvRegistrationScope componentScope = scope.Register(SCHEMATYC_MAKE_ENV_COMPONENT(CPlayerComponent));
}
}

CRY_STATIC_AUTO_REGISTER_FUNCTION(&RegisterPlayerComponent);
}

void CPlayerComponent::Initialize()
{
// The character controller is responsible for maintaining player physics
m_pCharacterController = m_pEntity->GetOrCreateComponent<Cry::DefaultComponents::CCharacterControllerComponent>();
// Offset the default character controller up by one unit
m_pCharacterController->SetTransformMatrix(Matrix34::Create(Vec3(1.f), IDENTITY, Vec3(0, 0, 1.f)));

// Create the advanced animation component, responsible for updating Mannequin and animating the player
m_pAnimationComponent = m_pEntity->GetOrCreateComponent<Cry::DefaultComponents::CAdvancedAnimationComponent>();

// Set the player geometry, this also triggers physics proxy creation
m_pAnimationComponent->SetMannequinAnimationDatabaseFile("Animations/Mannequin/ADB/FirstPerson.adb");
m_pAnimationComponent->SetCharacterFile("Objects/Characters/SampleCharacter/firstperson.cdf");

m_pAnimationComponent->SetControllerDefinitionFile("Animations/Mannequin/ADB/FirstPersonControllerDefinition.xml");
m_pAnimationComponent->SetDefaultScopeContextName("FirstPersonCharacter");
// Queue the idle fragment to start playing immediately on next update
m_pAnimationComponent->SetDefaultFragmentName("Idle");

// Disable movement coming from the animation (root joint offset), we control this entirely via physics
m_pAnimationComponent->SetAnimationDrivenMotion(false);

// Load the character and Mannequin data from file
m_pAnimationComponent->LoadFromDisk();

// Acquire fragment and tag identifiers to avoid doing so each update
m_idleFragmentId = m_pAnimationComponent->GetFragmentId("Idle");
m_walkFragmentId = m_pAnimationComponent->GetFragmentId("Walk");
m_rotateTagId = m_pAnimationComponent->GetTagId("Rotate");

// Mark the entity to be replicated over the network
m_pEntity->GetNetEntity()->BindToNetwork();

// Register the RemoteReviveOnClient function as a Remote Method Invocation (RMI) that can be executed by the server on clients
SRmi<RMI_WRAP(&CPlayerComponent::RemoteReviveOnClient)>::Register(this, eRAT_NoAttach, false, eNRT_ReliableOrdered);
}

void CPlayerComponent::InitializeLocalPlayer()
{
// Create the camera component, will automatically update the viewport every frame
m_pCameraComponent = m_pEntity->GetOrCreateComponent<Cry::DefaultComponents::CCameraComponent>();
//m_pCameraComponent->

// Create the audio listener component.
m_pAudioListenerComponent = m_pEntity->GetOrCreateComponent<Cry::Audio::DefaultComponents::CListenerComponent>();

// Get the input component, wraps access to action mapping so we can easily get callbacks when inputs are triggered
m_pInputComponent = m_pEntity->GetOrCreateComponent<Cry::DefaultComponents::CInputComponent>();

// Register an action, and the callback that will be sent when it's triggered
m_pInputComponent->RegisterAction("player", "moveleft", [this](int activationMode, float value) { HandleInputFlagChange(EInputFlag::MoveLeft, (EActionActivationMode)activationMode); });
// Bind the 'A' key the "moveleft" action
m_pInputComponent->BindAction("player", "moveleft", eAID_KeyboardMouse, EKeyId::eKI_A);

m_pInputComponent->RegisterAction("player", "moveright", [this](int activationMode, float value) { HandleInputFlagChange(EInputFlag::MoveRight, (EActionActivationMode)activationMode); });
m_pInputComponent->BindAction("player", "moveright", eAID_KeyboardMouse, EKeyId::eKI_D);

m_pInputComponent->RegisterAction("player", "moveforward", [this](int activationMode, float value) { HandleInputFlagChange(EInputFlag::MoveForward, (EActionActivationMode)activationMode); });
m_pInputComponent->BindAction("player", "moveforward", eAID_KeyboardMouse, EKeyId::eKI_W);

m_pInputComponent->RegisterAction("player", "moveback", [this](int activationMode, float value) { HandleInputFlagChange(EInputFlag::MoveBack, (EActionActivationMode)activationMode); });
m_pInputComponent->BindAction("player", "moveback", eAID_KeyboardMouse, EKeyId::eKI_S);

m_pInputComponent->RegisterAction("player", "mouse_rotateyaw", [this](int activationMode, float value) { m_mouseDeltaRotation.x -= value; });
m_pInputComponent->BindAction("player", "mouse_rotateyaw", eAID_KeyboardMouse, EKeyId::eKI_MouseX);

m_pInputComponent->RegisterAction("player", "mouse_rotatepitch", [this](int activationMode, float value) { m_mouseDeltaRotation.y -= value; });
m_pInputComponent->BindAction("player", "mouse_rotatepitch", eAID_KeyboardMouse, EKeyId::eKI_MouseY);

// Register the shoot action
m_pInputComponent->RegisterAction("player", "shoot", [this](int activationMode, float value)
{
// Only fire on press, not release
if (activationMode == eAAM_OnPress)
{
if (ICharacterInstance *pCharacter = m_pAnimationComponent->GetCharacter())
{
IAttachment* pBarrelOutAttachment = pCharacter->GetIAttachmentManager()->GetInterfaceByName("barrel_out");

if (pBarrelOutAttachment != nullptr)
{
QuatTS bulletOrigin = pBarrelOutAttachment->GetAttWorldAbsolute();

SEntitySpawnParams spawnParams;
spawnParams.pClass = gEnv->pEntitySystem->GetClassRegistry()->GetDefaultClass();

spawnParams.vPosition = bulletOrigin.t;
spawnParams.qRotation = bulletOrigin.q;

const float bulletScale = 0.05f;
spawnParams.vScale = Vec3(bulletScale);

// Spawn the entity
if (IEntity* pEntity = gEnv->pEntitySystem->SpawnEntity(spawnParams))
{
// See Bullet.cpp, bullet is propelled in the rotation and position the entity was spawned with
pEntity->CreateComponentClass<CBulletComponent>();
}
}
}
}
});

// Bind the shoot action to left mouse click
m_pInputComponent->BindAction("player", "shoot", eAID_KeyboardMouse, EKeyId::eKI_Mouse1);
}

Cry::Entity::EventFlags CPlayerComponent::GetEventMask() const
{
return
Cry::Entity::EEvent::BecomeLocalPlayer |
Cry::Entity::EEvent::Update |
Cry::Entity::EEvent::Reset;
}

void CPlayerComponent::ProcessEvent(const SEntityEvent& event)
{
switch (event.event)
{
case Cry::Entity::EEvent::BecomeLocalPlayer:
{
InitializeLocalPlayer();
}
break;
case Cry::Entity::EEvent::Update:
{
// Don't update the player if we haven't spawned yet
if(!m_isAlive)
return;

// Don't handle input if movement is not allowed
if (!m_canMove)
return;

const float frameTime = event.fParam[0];

// Start by updating the movement request we want to send to the character controller
// This results in the physical representation of the character moving
UpdateMovementRequest(frameTime);

// Process mouse input to update look orientation.
UpdateLookDirectionRequest(frameTime);

// Update the animation state of the character
UpdateAnimation(frameTime);

if (IsLocalClient())
{
// Update the camera component offset
UpdateCamera(frameTime);
}
}
break;
case Cry::Entity::EEvent::Reset:
{
// Disable player when leaving game mode.
m_isAlive = event.nParam[0] != 0;
}
break;
}
}

bool CPlayerComponent::NetSerialize(TSerialize ser, EEntityAspects aspect, uint8 profile, int flags)
{
if(aspect == InputAspect)
{
ser.BeginGroup("PlayerInput");

const CEnumFlags<EInputFlag> prevInputFlags = m_inputFlags;

ser.Value("m_inputFlags", m_inputFlags.UnderlyingValue(), 'ui8');

if (ser.IsReading())
{
const CEnumFlags<EInputFlag> changedKeys = prevInputFlags ^ m_inputFlags;

const CEnumFlags<EInputFlag> pressedKeys = changedKeys & prevInputFlags;
if (!pressedKeys.IsEmpty())
{
HandleInputFlagChange(pressedKeys, eAAM_OnPress);
}

const CEnumFlags<EInputFlag> releasedKeys = changedKeys & prevInputFlags;
if (!releasedKeys.IsEmpty())
{
HandleInputFlagChange(pressedKeys, eAAM_OnRelease);
}
}

// Serialize the player look orientation
ser.Value("m_lookOrientation", m_lookOrientation, 'ori3');

ser.EndGroup();
}

return true;
}

void CPlayerComponent::UpdateMovementRequest(float frameTime)
{
// Don't handle input if we are in air
if (!m_pCharacterController->IsOnGround())
return;

Vec3 velocity = ZERO;

const float moveSpeed = 20.5f;

if (m_inputFlags & EInputFlag::MoveLeft)
{
velocity.x -= moveSpeed * frameTime;
}
if (m_inputFlags & EInputFlag::MoveRight)
{
velocity.x += moveSpeed * frameTime;
}
if (m_inputFlags & EInputFlag::MoveForward)
{
velocity.y += moveSpeed * frameTime;
}
if (m_inputFlags & EInputFlag::MoveBack)
{
velocity.y -= moveSpeed * frameTime;
}

m_pCharacterController->AddVelocity(GetEntity()->GetWorldRotation() * velocity);
}

void CPlayerComponent::UpdateLookDirectionRequest(float frameTime)
{
const float rotationSpeed = 0.002f;
const float rotationLimitsMinPitch = -0.84f;
const float rotationLimitsMaxPitch = 1.5f;

// Apply smoothing filter to the mouse input
m_mouseDeltaRotation = m_mouseDeltaSmoothingFilter.Push(m_mouseDeltaRotation).Get();

// Update angular velocity metrics
m_horizontalAngularVelocity = (m_mouseDeltaRotation.x * rotationSpeed) / frameTime;
m_averagedHorizontalAngularVelocity.Push(m_horizontalAngularVelocity);

if (m_mouseDeltaRotation.IsEquivalent(ZERO, MOUSE_DELTA_TRESHOLD))
return;

// Start with updating look orientation from the latest input
Ang3 ypr = CCamera::CreateAnglesYPR(Matrix33(m_lookOrientation));

// Yaw
ypr.x += m_mouseDeltaRotation.x * rotationSpeed;

// Pitch
// TODO: Perform soft clamp here instead of hard wall, should reduce rot speed in this direction when close to limit.
ypr.y = CLAMP(ypr.y + m_mouseDeltaRotation.y * rotationSpeed, rotationLimitsMinPitch, rotationLimitsMaxPitch);

// Roll (skip)
ypr.z = 0;

m_lookOrientation = Quat(CCamera::CreateOrientationYPR(ypr));

// Reset the mouse delta accumulator every frame
m_mouseDeltaRotation = ZERO;
}

void CPlayerComponent::UpdateAnimation(float frameTime)
{
const float angularVelocityTurningThreshold = 0.174; // [rad/s]

// Update tags and motion parameters used for turning
const bool isTurning = std::abs(m_averagedHorizontalAngularVelocity.Get()) > angularVelocityTurningThreshold;
m_pAnimationComponent->SetTagWithId(m_rotateTagId, isTurning);
if (isTurning)
{
// TODO: This is a very rough predictive estimation of eMotionParamID_TurnAngle that could easily be replaced with accurate reactive motion
// if we introduced IK look/aim setup to the character's model and decoupled entity's orientation from the look direction derived from mouse input.

const float turnDuration = 1.0f; // Expect the turning motion to take approximately one second.
m_pAnimationComponent->SetMotionParameter(eMotionParamID_TurnAngle, m_horizontalAngularVelocity * turnDuration);
}

// Update active fragment
const FragmentID& desiredFragmentId = m_pCharacterController->IsWalking() ? m_walkFragmentId : m_idleFragmentId;
if (m_activeFragmentId != desiredFragmentId)
{
m_activeFragmentId = desiredFragmentId;
m_pAnimationComponent->QueueFragmentWithId(m_activeFragmentId);
}

// Update entity rotation as the player turns
// We only want to affect Z-axis rotation, zero pitch and roll
Ang3 ypr = CCamera::CreateAnglesYPR(Matrix33(m_lookOrientation));
ypr.y = 0;
ypr.z = 0;
const Quat correctedOrientation = Quat(CCamera::CreateOrientationYPR(ypr));

// Send updated transform to the entity, only orientation changes
GetEntity()->SetPosRotScale(GetEntity()->GetWorldPos(), correctedOrientation, Vec3(1, 1, 1));
}

void CPlayerComponent::UpdateCamera(float frameTime)
{
// Start with updating look orientation from the latest input
Ang3 ypr = CCamera::CreateAnglesYPR(Matrix33(m_lookOrientation));

ypr.x += m_mouseDeltaRotation.x * m_rotationSpeed;

const float rotationLimitsMinPitch = -0.84f;
const float rotationLimitsMaxPitch = 1.5f;

// TODO: Perform soft clamp here instead of hard wall, should reduce rot speed in this direction when close to limit.
ypr.y = CLAMP(ypr.y + m_mouseDeltaRotation.y * m_rotationSpeed, rotationLimitsMinPitch, rotationLimitsMaxPitch);
// Skip roll
ypr.z = 0;

m_lookOrientation = Quat(CCamera::CreateOrientationYPR(ypr));

// Reset every frame
m_mouseDeltaRotation = ZERO;

// Ignore z-axis rotation, that's set by CPlayerAnimations
ypr.x = 0;

// Start with changing view rotation to the requested mouse look orientation
Matrix34 localTransform = IDENTITY;
localTransform.SetRotation33(CCamera::CreateOrientationYPR(ypr));

const float viewOffsetForward = 0.01f;
const float viewOffsetUp = 0.26f;

if (ICharacterInstance *pCharacter = m_pAnimationComponent->GetCharacter())
{
// Get the local space orientation of the camera joint
const QuatT &cameraOrientation = pCharacter->GetISkeletonPose()->GetAbsJointByID(m_cameraJointId);
// Apply the offset to the camera
localTransform.SetTranslation(cameraOrientation.t + Vec3(0, viewOffsetForward, viewOffsetUp));
}

m_pCameraComponent->SetTransformMatrix(localTransform);
m_pAudioListenerComponent->SetOffset(localTransform.GetTranslation());
}

void CPlayerComponent::OnReadyForGameplayOnServer()
{
CRY_ASSERT(gEnv->bServer, "This function should only be called on the server!");

const Matrix34 newTransform = CSpawnPointComponent::GetFirstSpawnPointTransform();

Revive(newTransform);

// Invoke the RemoteReviveOnClient function on all remote clients, to ensure that Revive is called across the network
SRmi<RMI_WRAP(&CPlayerComponent::RemoteReviveOnClient)>::InvokeOnOtherClients(this, RemoteReviveParams{ newTransform.GetTranslation(), Quat(newTransform) });

// Go through all other players, and send the RemoteReviveOnClient on their instances to the new player that is ready for gameplay
const int channelId = m_pEntity->GetNetEntity()->GetChannelId();
CGamePlugin::GetInstance()->IterateOverPlayers([this, channelId](CPlayerComponent& player)
{
// Don't send the event for the player itself (handled in the RemoteReviveOnClient event above sent to all clients)
if (player.GetEntityId() == GetEntityId())
return;

// Only send the Revive event to players that have already respawned on the server
if (!player.m_isAlive)
return;

// Revive this player on the new player's machine, on the location the existing player was currently at
const QuatT currentOrientation = QuatT(player.GetEntity()->GetWorldTM());
SRmi<RMI_WRAP(&CPlayerComponent::RemoteReviveOnClient)>::InvokeOnClient(&player, RemoteReviveParams{ currentOrientation.t, currentOrientation.q }, channelId);
});
}

bool CPlayerComponent::RemoteReviveOnClient(RemoteReviveParams&& params, INetChannel* pNetChannel)
{
// Call the Revive function on this client
Revive(Matrix34::Create(Vec3(1.f), params.rotation, params.position));

return true;
}

void CPlayerComponent::Revive(const Matrix34& transform)
{
m_isAlive = true;
m_canMove = true;

// Set the entity transformation, except if we are in the editor
// In the editor case we always prefer to spawn where the viewport is
if(!gEnv->IsEditor())
{
m_pEntity->SetWorldTM(transform);
}

// Apply the character to the entity and queue animations
m_pAnimationComponent->ResetCharacter();
m_pCharacterController->Physicalize();

// Reset input now that the player respawned
m_inputFlags.Clear();
NetMarkAspectsDirty(InputAspect);

m_mouseDeltaRotation = ZERO;
m_lookOrientation = IDENTITY;

m_mouseDeltaSmoothingFilter.Reset();

m_activeFragmentId = FRAGMENT_ID_INVALID;

m_horizontalAngularVelocity = 0.0f;
m_averagedHorizontalAngularVelocity.Reset();

if (ICharacterInstance *pCharacter = m_pAnimationComponent->GetCharacter())
{
// Cache the camera joint id so that we don't need to look it up every frame in UpdateView
m_cameraJointId = pCharacter->GetIDefaultSkeleton().GetJointIDByName("head");
}
}

void CPlayerComponent::HandleInputFlagChange(const CEnumFlags<EInputFlag> flags, const CEnumFlags<EActionActivationMode> activationMode, const EInputFlagType type)
{
switch (type)
{
case EInputFlagType::Hold:
{
if (activationMode == eAAM_OnRelease)
{
m_inputFlags &= ~flags;
}
else
{
m_inputFlags |= flags;
}
}
break;
case EInputFlagType::Toggle:
{
if (activationMode == eAAM_OnRelease)
{
// Toggle the bit(s)
m_inputFlags ^= flags;
}
}
break;
}

if(IsLocalClient())
{
NetMarkAspectsDirty(InputAspect);
}
}
GamePlugin.h

Code: Select all

#pragma once

#include <CrySystem/ICryPlugin.h>
#include <CryEntitySystem/IEntityClass.h>
#include <CryNetwork/INetwork.h>

class CPlayerComponent;

// The entry-point of the application
// An instance of CGamePlugin is automatically created when the library is loaded
// We then construct the local player entity and CPlayerComponent instance when OnClientConnectionReceived is first called.
class CGamePlugin
: public Cry::IEnginePlugin
, public ISystemEventListener
, public INetworkedClientListener
{
public:
CRYINTERFACE_SIMPLE(Cry::IEnginePlugin)
CRYGENERATE_SINGLETONCLASS_GUID(CGamePlugin, "FirstPersonShooter", "{FC9BD884-49DE-4494-9D64-191734BBB7E3}"_cry_guid)

virtual ~CGamePlugin();

// Cry::IEnginePlugin
virtual const char* GetCategory() const override { return "Game"; }
virtual bool Initialize(SSystemGlobalEnvironment& env, const SSystemInitParams& initParams) override;
// ~Cry::IEnginePlugin

// ISystemEventListener
virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) override;
// ~ISystemEventListener

// INetworkedClientListener
// Sent to the local client on disconnect
virtual void OnLocalClientDisconnected(EDisconnectionCause cause, const char* description) override {}

// Sent to the server when a new client has started connecting
// Return false to disallow the connection
virtual bool OnClientConnectionReceived(int channelId, bool bIsReset) override;
// Sent to the server when a new client has finished connecting and is ready for gameplay
// Return false to disallow the connection and kick the player
virtual bool OnClientReadyForGameplay(int channelId, bool bIsReset) override;
// Sent to the server when a client is disconnected
virtual void OnClientDisconnected(int channelId, EDisconnectionCause cause, const char* description, bool bKeepClient) override;
// Sent to the server when a client is timing out (no packets for X seconds)
// Return true to allow disconnection, otherwise false to keep client.
virtual bool OnClientTimingOut(int channelId, EDisconnectionCause cause, const char* description) override { return true; }
// ~INetworkedClientListener

// Helper function to call the specified callback for every player in the game
void IterateOverPlayers(std::function<void(CPlayerComponent& player)> func) const;

// Helper function to get the CGamePlugin instance
// Note that CGamePlugin is declared as a singleton, so the CreateClassInstance will always return the same pointer
static CGamePlugin* GetInstance()
{
return cryinterface_cast<CGamePlugin>(CGamePlugin::s_factory.CreateClassInstance().get());
}

PLUGIN_FLOWNODE_REGISTER
PLUGIN_FLOWNODE_UNREGISTER

protected:
// Map containing player components, key is the channel id received in OnClientConnectionReceived
std::unordered_map<int, EntityId> m_players;
};
GamePlugin.cpp

Code: Select all

#include "StdAfx.h"
#include "GamePlugin.h"

#include "Components/Player.h"

#include <CrySchematyc/Env/IEnvRegistry.h>
#include <CrySchematyc/Env/EnvPackage.h>
#include <CrySchematyc/Utils/SharedString.h>

#include <IGameObjectSystem.h>
#include <IGameObject.h>
#include <Components/Player.h>

// Included only once per DLL module.
#include <CryCore/Platform/platform_impl.inl>

CGamePlugin::~CGamePlugin()
{
// Remove any registered listeners before 'this' becomes invalid
if (gEnv->pGameFramework != nullptr)
{
gEnv->pGameFramework->RemoveNetworkedClientListener(*this);
}

gEnv->pSystem->GetISystemEventDispatcher()->RemoveListener(this);

if (gEnv->pSchematyc)
{
gEnv->pSchematyc->GetEnvRegistry().DeregisterPackage(CGamePlugin::GetCID());
}
}

bool CGamePlugin::Initialize(SSystemGlobalEnvironment& env, const SSystemInitParams& initParams)
{
// Register for engine system events, in our case we need ESYSTEM_EVENT_GAME_POST_INIT to load the map
gEnv->pSystem->GetISystemEventDispatcher()->RegisterListener(this, "CGamePlugin");

return true;
}

void CGamePlugin::OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam)
{
switch (event)
{
// Called when the game framework has initialized and we are ready for game logic to start
case ESYSTEM_EVENT_GAME_POST_INIT:
{
// Listen for client connection events, in order to create the local player
gEnv->pGameFramework->AddNetworkedClientListener(*this);

// Don't need to load the map in editor
if (!gEnv->IsEditor())
{
// Load the example map in client server mode
gEnv->pConsole->ExecuteString("map example s", false, true);
}
}
break;

case ESYSTEM_EVENT_REGISTER_SCHEMATYC_ENV:
{
// Register all components that belong to this plug-in
auto staticAutoRegisterLambda = [](Schematyc::IEnvRegistrar& registrar)
{
// Call all static callback registered with the CRY_STATIC_AUTO_REGISTER_WITH_PARAM
Detail::CStaticAutoRegistrar<Schematyc::IEnvRegistrar&>::InvokeStaticCallbacks(registrar);
};

if (gEnv->pSchematyc)
{
gEnv->pSchematyc->GetEnvRegistry().RegisterPackage(
stl::make_unique<Schematyc::CEnvPackage>(
CGamePlugin::GetCID(),
"EntityComponents",
"Crytek GmbH",
"Components",
staticAutoRegisterLambda
)
);
}
}
break;

case ESYSTEM_EVENT_LEVEL_UNLOAD:
{
m_players.clear();
}
break;
}
}

bool CGamePlugin::OnClientConnectionReceived(int channelId, bool bIsReset)
{
// Connection received from a client, create a player entity and component
SEntitySpawnParams spawnParams;
spawnParams.pClass = gEnv->pEntitySystem->GetClassRegistry()->GetDefaultClass();

// Set a unique name for the player entity
const string playerName = string().Format("Player%" PRISIZE_T, m_players.size());
spawnParams.sName = playerName;

// Set local player details
if (m_players.empty() && !gEnv->IsDedicated())
{
spawnParams.id = LOCAL_PLAYER_ENTITY_ID;
spawnParams.nFlags |= ENTITY_FLAG_LOCAL_PLAYER;
}

// Spawn the player entity
if (IEntity* pPlayerEntity = gEnv->pEntitySystem->SpawnEntity(spawnParams))
{
// Set the local player entity channel id, and bind it to the network so that it can support Multiplayer contexts
pPlayerEntity->GetNetEntity()->SetChannelId(channelId);

// Create the player component instance
CPlayerComponent* pPlayer = pPlayerEntity->GetOrCreateComponentClass<CPlayerComponent>();

if (pPlayer != nullptr)
{
// Push the component into our map, with the channel id as the key
m_players.emplace(std::make_pair(channelId, pPlayerEntity->GetId()));
}
}

return true;
}

bool CGamePlugin::OnClientReadyForGameplay(int channelId, bool bIsReset)
{
// Revive players when the network reports that the client is connected and ready for gameplay
auto it = m_players.find(channelId);
if (it != m_players.end())
{
if (IEntity* pPlayerEntity = gEnv->pEntitySystem->GetEntity(it->second))
{
if (CPlayerComponent* pPlayer = pPlayerEntity->GetComponent<CPlayerComponent>())
{
pPlayer->OnReadyForGameplayOnServer();
}
}
}

return true;
}

void CGamePlugin::OnClientDisconnected(int channelId, EDisconnectionCause cause, const char* description, bool bKeepClient)
{
// Client disconnected, remove the entity and from map
auto it = m_players.find(channelId);
if (it != m_players.end())
{
gEnv->pEntitySystem->RemoveEntity(it->second);

m_players.erase(it);
}
}

void CGamePlugin::IterateOverPlayers(std::function<void(CPlayerComponent& player)> func) const
{
for (const std::pair<int, EntityId>& playerPair : m_players)
{
if (IEntity* pPlayerEntity = gEnv->pEntitySystem->GetEntity(playerPair.second))
{
if (CPlayerComponent* pPlayer = pPlayerEntity->GetComponent<CPlayerComponent>())
{
func(*pPlayer);
}
}
}
}


class CFlowSubstringNode : public CFlowBaseNode<eNCT_Singleton>
{
public:
CFlowSubstringNode(SActivationInfo* pActInfo) {};

virtual void GetConfiguration(SFlowNodeConfig& config)
{
static const SInputPortConfig in_config[] = {
InputPortConfig_Void("Get", _HELP("Substring, retrieves letters from defined string.")),
InputPortConfig<string>("String", _HELP("String to retrieve letters from")),
InputPortConfig<int>("Int1", _HELP("Start retrieving from")),
InputPortConfig<int>("Int2", _HELP("Number of letters to retrieve")),
{ 0 }
};
static const SOutputPortConfig out_config[] = {
OutputPortConfig<string>("Out"),
{ 0 }
};
config.sDescription = _HELP("Substring");
config.pInputPorts = in_config;
config.pOutputPorts = out_config;
config.SetCategory(EFLN_APPROVED);
}
virtual void ProcessEvent(EFlowEvent evt, SActivationInfo* pActInfo)
{
switch (evt)
{
case eFE_Activate:
if (IsPortActive(pActInfo, 0))
{
string str1 = GetPortString(pActInfo, 1);
int int1 = GetPortInt(pActInfo, 2);
int int2 = GetPortInt(pActInfo, 3);

if (int1 + int2 > str1.length())
{
CryWarning(
VALIDATOR_MODULE_FLOWGRAPH,
VALIDATOR_WARNING,
"Failed to get %d characters starting from %d in a string %d characters long.",
int2, int1, str1.length());
}
ActivateOutput(pActInfo, 0, str1.substr(int1, int2));
}
break;
}
};

virtual void GetMemoryUsage(ICrySizer* s) const
{
s->Add(*this);
}
};


class CFlowNode_PlayerSettings : public CFlowBaseNode<eNCT_Singleton>
{
enum class EInPorts : int
{
LockCamera = 0,
UnlockCamera,
OverrideFOV,
GetFOV
};

public:



CFlowNode_PlayerSettings(SActivationInfo* pActInfo) {}
virtual void GetConfiguration(SFlowNodeConfig& config)
{
static const SInputPortConfig in_config[] = {
InputPortConfig_Void("LockMovement", _HELP("Lock the Camera View and movement of the Player")),
InputPortConfig_Void("UnlockMovement", _HELP("Unlock the Camera View and movement of the Player")),
InputPortConfig<float>("OverrideFOV", _HELP("Override players FOV")),
InputPortConfig_Void("GetFOV", _HELP("Gets players FOV")),
{ 0 }
};
static const SOutputPortConfig out_config[] = {
OutputPortConfig<float>("FOV", _HELP("Field of View")),
{ 0 }
};
config.sDescription = _HELP("Locks and Unlocks the Camera View and movement of the Player");
config.nFlags |= EFLN_TARGET_ENTITY;
config.pInputPorts = in_config;
config.pOutputPorts = out_config;
config.SetCategory(EFLN_APPROVED);
}
virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
{
if (event != eFE_Activate)
return;
IEntity* pEntity = pActInfo->pEntity;
if (pEntity == 0)
return;
if (IsPortActive(pActInfo, (int)EInPorts::LockCamera))
{
if (CPlayerComponent* pCPlayerComponent = pEntity->GetComponent<CPlayerComponent>())
{
pCPlayerComponent->CanMove(false);
}
}

//Lock
if (IsPortActive(pActInfo, (int)EInPorts::UnlockCamera))
{
if (CPlayerComponent* pCPlayerComponent = pEntity->GetComponent<CPlayerComponent>())
{
pCPlayerComponent->CanMove(true);
}
}

if (IsPortActive(pActInfo, (int)EInPorts::OverrideFOV))
{
if (Cry::DefaultComponents::CCameraComponent* pCCameraComponent = pEntity->GetOrCreateComponent<Cry::DefaultComponents::CCameraComponent>())
{
pCCameraComponent->SetFieldOfView(CryTransform::CAngle::FromDegrees(GetPortFloat(pActInfo, (int)EInPorts::OverrideFOV)));

}
}

if (IsPortActive(pActInfo, (int)EInPorts::GetFOV))
{
if (Cry::DefaultComponents::CCameraComponent* pCCameraComponent = pEntity->GetOrCreateComponent<Cry::DefaultComponents::CCameraComponent>())
{
ActivateOutput(pActInfo, 0, pCCameraComponent->GetFieldOfView().ToDegrees());
}
}
/*
*/

}

virtual void GetMemoryUsage(ICrySizer* s) const
{
s->Add(*this);
}
};


class CFlowNode_EntityPhysics : public CFlowBaseNode<eNCT_Singleton>
{
public:



CFlowNode_EntityPhysics(SActivationInfo* pActInfo) {}
virtual void GetConfiguration(SFlowNodeConfig& config)
{
static const SInputPortConfig in_config[] = {
InputPortConfig_Void("Enable Physics", _HELP("Enable Physics of the Entity")),
InputPortConfig_Void("Disable Physics", _HELP("Disable Physics of the Entity")),
{ 0 }
};
static const SOutputPortConfig out_config[] = {
//OutputPortConfig<EntityId>("Id", _HELP("Entity Id")),
{ 0 }
};
config.sDescription = _HELP("Enable and disable the physics on the Entity");
config.nFlags |= EFLN_TARGET_ENTITY;
config.pInputPorts = in_config;
config.pOutputPorts = out_config;
config.SetCategory(EFLN_APPROVED);
}
virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
{
if (event != eFE_Activate)
return;
IEntity* pEntity = pActInfo->pEntity;
if (pEntity == 0)
return;

if (IsPortActive(pActInfo, 0))
{
pEntity->EnablePhysics(true);
}

if (IsPortActive(pActInfo, 1))
{
pEntity->EnablePhysics(false);
}
}

virtual void GetMemoryUsage(ICrySizer* s) const
{
s->Add(*this);
}
};



//Register Flownode (you will need to do this for every FlowNode once)
//The REGISTER_FLOW_NODE Macro takes 2 parameters, the name as first and the class as second parameter.
REGISTER_FLOW_NODE("String:Substring", CFlowSubstringNode)
REGISTER_FLOW_NODE("PlayerSettings:Settings", CFlowNode_PlayerSettings)
REGISTER_FLOW_NODE("Entity:Physics", CFlowNode_EntityPhysics)


CRYREGISTER_SINGLETON_CLASS(CGamePlugin)

Who is online

Users browsing this forum: No registered users and 1 guest