How to get a DeviceIndex from an input

#1
Hi,

I'm trying to create a simple flowgraph node that reacts on controllers input and outputs deviceIndex of the controller.
I know it can be reached by creating my own input listener and there is actually a member deviceIndex that contains info about the id of used device (as it is here: http://apprize.info/game/cryengine/3.html)
However, this can't be reached from flowgraph so I need to write my own node.
But I'm not that familiar with programming so I need your help or advice.

The idea of getting a device index is to support multiple players playing the same level.

Any suggestions would be great help.

Also, If someone knows how to do that, we can talk about a paid job for implementing this

Re: How to get a DeviceIndex from an input

#2
Anyone?

In short, all I need is to avoid a situation where 2 plugged in controllers control one player.
Then I need to have a possibility to know the source of input (was it controller 2 or controller 1?) - for this I want to have a flowgraph node.

Any help would be great. As I said before, I can pay for implementing this task on GameSDK project base.

Re: How to get a DeviceIndex from an input

#3
Hi
Try adding this to a flow node cpp file, before all those lines starting with "REGISTER_FLOW_NODE" . I added it to "MPNodes.cpp".

Code: Select all

class CFlowNode_MyInputActionListener : public CFlowBaseNode<eNCT_Instanced>, public IInputEventListener { enum EInputs { EIP_ENABLE = 0, EIP_DISABLE, EIP_ACTION }; enum EOutputs { EOP_ENABLED, EOP_DISABLED, EOP_PRESSED, EOP_RELEASED, EOP_VALUE, EOP_DEVICEINDEX, EOP_DEVICEUNIQUEID }; public: CFlowNode_MyInputActionListener(SActivationInfo* pActInfo) : m_bActive(false) { } ~CFlowNode_MyInputActionListener() { Register(false, 0); } IFlowNodePtr Clone(SActivationInfo* pActInfo) { return new CFlowNode_MyInputActionListener(pActInfo); } virtual void GetMemoryUsage(ICrySizer* s) const { s->Add(*this); } void GetConfiguration(SFlowNodeConfig& config) { static const SInputPortConfig in_ports[] = { InputPortConfig_Void("Enable", _HELP("Trigger to enable")), InputPortConfig_Void("Disable", _HELP("Trigger to disable")), InputPortConfig<string>("actionMapActions_Action", _HELP("Action input to trigger"), _HELP("Action")), { 0 } }; static const SOutputPortConfig out_ports[] = { OutputPortConfig_Void("Enabled", _HELP("Action Listener set")), OutputPortConfig_Void("Disabled", _HELP("Action Listener removed")), OutputPortConfig<string>("Pressed", _HELP("Action trigger pressed.")), OutputPortConfig<string>("Released", _HELP("Action trigger released.")), OutputPortConfig<float>("Value", _HELP("Value associated with the event.")), OutputPortConfig<int>("DeviceIndex", _HELP("Local index of this particular controller type.")), OutputPortConfig<int>("DeviceUniqueID", _HELP("Process wide unique controller ID.")), { 0 } }; config.pInputPorts = in_ports; config.pOutputPorts = out_ports; config.sDescription = _HELP("Checks various Multiplayer states and conditions"); config.SetCategory(EFLN_APPROVED); } void Register(bool bRegister, SActivationInfo* pActInfo) { IInput* pInput = gEnv->pInput; if (pInput) { if (bRegister) pInput->AddEventListener(this); else pInput->RemoveEventListener(this); } m_bActive = bRegister; } void ProcessEvent(EFlowEvent ev, SActivationInfo *pActInfo) { switch (ev) { case eFE_Initialize: { m_pActInfo = *pActInfo; Register(false, pActInfo); break; } case eFE_Activate: { m_pActInfo = *pActInfo; if (IsPortActive(pActInfo, EIP_DISABLE)) { Register(false, pActInfo); } if (IsPortActive(pActInfo, EIP_ENABLE)) { Register(true, pActInfo); } break; } } } virtual bool OnInputEvent(const SInputEvent& event) { if (gEnv->pConsole->IsOpened()) return false; bool bActionFound = false; const string& eventKeyName = event.keyName.c_str(); const string& actionInput = GetPortString(&m_pActInfo, EIP_ACTION); const string& actionMapName = actionInput.substr(0, actionInput.find_first_of(":")); const string& actionName = actionInput.substr(actionInput.find_first_of(":") + 1, (actionInput.length() - actionInput.find_first_of(":"))); const EntityId filterEntityId = m_pActInfo.pEntity ? m_pActInfo.pEntity->GetId() : INVALID_ENTITYID; if (!actionMapName.empty() && !actionName.empty()) { IActionMapManager* pActionMapMgr = gEnv->pGame->GetIGameFramework()->GetIActionMapManager(); if (pActionMapMgr) { const IActionMap* pActionMap = pActionMapMgr->GetActionMap(actionMapName); if (pActionMap && (filterEntityId == INVALID_ENTITYID || filterEntityId == pActionMap->GetActionListener())) { const IActionMapAction* pAction = pActionMap->GetAction(ActionId(actionName)); if (pAction) { const int iNumInputData = pAction->GetNumActionInputs(); for (int i = 0; i < iNumInputData; ++i) { const SActionInput* pActionInput = pAction->GetActionInput(i); if (!stricmp(pActionInput->input, eventKeyName.c_str())) { bActionFound = true; break; } } } } } } if (bActionFound) { const bool nullInputValue = (fabs_tpl(event.value) < 0.02f); if ((event.state == eIS_Pressed) || ((event.state == eIS_Changed) && !nullInputValue)) { ActivateOutput(&m_pActInfo, EOP_PRESSED, eventKeyName); } else if ((event.state == eIS_Released) || ((event.state == eIS_Changed) && nullInputValue)) { ActivateOutput(&m_pActInfo, EOP_RELEASED, eventKeyName); } // for some unknown reason without this two variables, I gem compile errors int deviceIndex = event.deviceIndex; int deviceUniqueId = event.deviceUniqueID; if (!nullInputValue) { ActivateOutput(&m_pActInfo, EOP_VALUE, event.value); ActivateOutput(&m_pActInfo, EOP_DEVICEINDEX, deviceIndex); ActivateOutput(&m_pActInfo, EOP_DEVICEUNIQUEID, deviceUniqueId); } } // return false, so other listeners get notification as well return false; } SActivationInfo m_pActInfo; bool m_bActive; }; REGISTER_FLOW_NODE("Input:ActionMaps:MyActionListener", CFlowNode_MyInputActionListener);
And add this line to beginning of the file you chose, right after all those lines starting with "#include":

Code: Select all

#include "CryInput\IInput.h"
After you compile gamesdk, copy the dll file to "bin/win_x64" directory of gamesdk project.
The new node is present in "Input -> ActionMaps".

I hope this helps.
Last edited by game_dev5 on Fri May 05, 2017 6:48 pm, edited 2 times in total.

Re: How to get a DeviceIndex from an input

#4
Hi
adding this to a flow node cpp file, before all those lines starting with "REGISTER_FLOW_NODE" . I added it to "MPNodes.cpp".

Code: Select all

class CFlowNode_MyInputActionListener : public CFlowBaseNode<eNCT_Instanced>, public IInputEventListener { enum EInputs { EIP_ENABLE = 0, EIP_DISABLE, EIP_ACTION }; enum EOutputs { EOP_ENABLED, EOP_DISABLED, EOP_PRESSED, EOP_RELEASED, EOP_VALUE, EOP_DEVICEINDEX, EOP_DEVICEUNIQUEID }; public: CFlowNode_MyInputActionListener(SActivationInfo* pActInfo) : m_bActive(false) { } ~CFlowNode_MyInputActionListener() { Register(false, 0); } IFlowNodePtr Clone(SActivationInfo* pActInfo) { return new CFlowNode_MyInputActionListener(pActInfo); } virtual void GetMemoryUsage(ICrySizer* s) const { s->Add(*this); } void GetConfiguration(SFlowNodeConfig& config) { static const SInputPortConfig in_ports[] = { InputPortConfig_Void("Enable", _HELP("Trigger to enable")), InputPortConfig_Void("Disable", _HELP("Trigger to disable")), InputPortConfig<string>("actionMapActions_Action", _HELP("Action input to trigger"), _HELP("Action")), { 0 } }; static const SOutputPortConfig out_ports[] = { OutputPortConfig_Void("Enabled", _HELP("Action Listener set")), OutputPortConfig_Void("Disabled", _HELP("Action Listener removed")), OutputPortConfig<string>("Pressed", _HELP("Action trigger pressed.")), OutputPortConfig<string>("Released", _HELP("Action trigger released.")), OutputPortConfig<float>("Value", _HELP("Value associated with the event.")), OutputPortConfig<int>("DeviceIndex", _HELP("Local index of this particular controller type.")), OutputPortConfig<int>("DeviceUniqueID", _HELP("Process wide unique controller ID.")), { 0 } }; config.pInputPorts = in_ports; config.pOutputPorts = out_ports; config.sDescription = _HELP("Checks various Multiplayer states and conditions"); config.SetCategory(EFLN_APPROVED); } void Register(bool bRegister, SActivationInfo* pActInfo) { IInput* pInput = gEnv->pInput; if (pInput) { if (bRegister) pInput->AddEventListener(this); else pInput->RemoveEventListener(this); } m_bActive = bRegister; } void ProcessEvent(EFlowEvent ev, SActivationInfo *pActInfo) { switch (ev) { case eFE_Initialize: { m_pActInfo = *pActInfo; Register(false, pActInfo); break; } case eFE_Activate: { m_pActInfo = *pActInfo; if (IsPortActive(pActInfo, EIP_DISABLE)) { Register(false, pActInfo); } if (IsPortActive(pActInfo, EIP_ENABLE)) { Register(true, pActInfo); } break; } } } virtual bool OnInputEvent(const SInputEvent& event) { if (gEnv->pConsole->IsOpened()) return false; bool bActionFound = false; const string& eventKeyName = event.keyName.c_str(); const string& actionInput = GetPortString(&m_pActInfo, EIP_ACTION); const string& actionMapName = actionInput.substr(0, actionInput.find_first_of(":")); const string& actionName = actionInput.substr(actionInput.find_first_of(":") + 1, (actionInput.length() - actionInput.find_first_of(":"))); const EntityId filterEntityId = m_pActInfo.pEntity ? m_pActInfo.pEntity->GetId() : INVALID_ENTITYID; if (!actionMapName.empty() && !actionName.empty()) { IActionMapManager* pActionMapMgr = gEnv->pGame->GetIGameFramework()->GetIActionMapManager(); if (pActionMapMgr) { const IActionMap* pActionMap = pActionMapMgr->GetActionMap(actionMapName); if (pActionMap && (filterEntityId == INVALID_ENTITYID || filterEntityId == pActionMap->GetActionListener())) { const IActionMapAction* pAction = pActionMap->GetAction(ActionId(actionName)); if (pAction) { const int iNumInputData = pAction->GetNumActionInputs(); for (int i = 0; i < iNumInputData; ++i) { const SActionInput* pActionInput = pAction->GetActionInput(i); if (!stricmp(pActionInput->input, eventKeyName.c_str())) { bActionFound = true; break; } } } } } } if (bActionFound) { const bool nullInputValue = (fabs_tpl(event.value) < 0.02f); if ((event.state == eIS_Pressed) || ((event.state == eIS_Changed) && !nullInputValue)) { ActivateOutput(&m_pActInfo, EOP_PRESSED, eventKeyName); } else if ((event.state == eIS_Released) || ((event.state == eIS_Changed) && nullInputValue)) { ActivateOutput(&m_pActInfo, EOP_RELEASED, eventKeyName); } // for some unknown reason without this two variables, I gem compile errors int deviceIndex = event.deviceIndex; int deviceUniqueId = event.deviceUniqueID; if (!nullInputValue) { ActivateOutput(&m_pActInfo, EOP_VALUE, event.value); ActivateOutput(&m_pActInfo, EOP_DEVICEINDEX, deviceIndex); ActivateOutput(&m_pActInfo, EOP_DEVICEUNIQUEID, deviceUniqueId); } } // return false, so other listeners get notification as well return false; } SActivationInfo m_pActInfo; bool m_bActive; }; REGISTER_FLOW_NODE("Input:ActionMaps:MyActionListener", CFlowNode_MyInputActionListener);
And add this line to beginning of the file you chose, right after all those lines starting with "#include":

Code: Select all

#include "CryInput\IInput.h"
After you compile gamesdk, copy the dll file to bin directory of gamesdk project.
The new node is present in "Input -> ActionMaps".

I hope this helps.
Just to be clear, this is a slightly modified version of "CryAction"s "ActionListener" node.

Re: How to get a DeviceIndex from an input

#5
Thanks so much for helping!

Now one problem is solved.

There's another one left.

How to make only one gamepad control the player?

I mean, by default cryengine accepts input from gamepad 1 and gamepad 2, and all of them are controlling the same player.

I need to somehow set only one controller to control player.

(Second controller input will be held by a flowgraph and should not control the player)

How can I achieve this?

Again, thanks so much for helping out with the flowgraph node

Re: How to get a DeviceIndex from an input

#7
Thanks so much for helping!

Now one problem is solved.

There's another one left.

How to make only one gamepad control the player?

I mean, by default cryengine accepts input from gamepad 1 and gamepad 2, and all of them are controlling the same player.

I need to somehow set only one controller to control player.

(Second controller input will be held by a flowgraph and should not control the player)

How can I achieve this?

Again, thanks so much for helping out with the flowgraph node
Sorry, I don't think I can help you with this one. :(
But if your player character is not that complicated, I suggest you prototype your idea the way the robot player is implemented in amazon lumberyard's samplesproject. It's using flowgraphs.
Or you can wait for a few more weeks and use Cryengine 5.4 new schematyc nodes. The promised schematyc components look interesting.
Check "animation", "ai" and "physics" tabs in this page:
https://www.cryengine.com/roadmap
Last edited by game_dev5 on Sat May 06, 2017 6:06 am, edited 1 time in total.

Re: How to get a DeviceIndex from an input

#8
search

bool CBaseInput::SendEventToListeners(const SInputEvent& event)

and OnInputEvent(event)

actionInputNode->getAttr(ACTIONINPUT_INPUTBLOCKDEVICEINDEX_STR, iDeviceIndex);


int deviceIndex = event.deviceIndex;
int deviceUniqueId = event.deviceUniqueID;
combine them to filter


flow node need add deviceindex parameter
Last edited by mknmknmknjk on Sun May 07, 2017 12:08 am, edited 1 time in total.

Who is online

Users browsing this forum: No registered users and 1 guest