Page MenuHomeFeedback Tracker

FindContextualContinuousAction & FindContextualSingleUseAction are not reading from all available sources
Closed, ResolvedPublic

Description

Both FindContextualContinuousAction and FindContextualSingleUseAction only look for the action ids found on the player or the target item.
For example, general "Objects" can also have single use actions. So I highly suggest adding the same interface that is used on GetContextualInteractActions.
I attached a ready to use implementation under additional information.

Details

Severity
Feature
Resolution
Open
Reproducibility
Always
Operating System
Windows 10 x64
Category
Modding
Additional Information
protected ActionBase FindContextualContinuousAction(ActionTarget target, ItemBase item)
{
    Object targetObject;
    Object targetParent;

    if( target )
    {
        targetObject = target.GetObject();
        targetParent = target.GetParent();
    }
    
    ref TIntArray primary_action_ids = new TIntArray;
    ActionBase picked_action;
    
    primary_action_ids.Insert(AT_WORLD_CRAFT);
    
    if (targetParent)
    {
        targetParent.GetContinuousActions(primary_action_ids);
    }

    // Adding interact actions of items in the world
    if ( targetObject )
    {
        targetObject.GetContinuousActions(primary_action_ids);
    }
    
    if ( item )
    {
        item.GetContinuousActions(primary_action_ids);
    }
    
    // Adding default continuous actions of player
    if ( m_Player ) 
    {
        m_Player.GetContinuousActions(primary_action_ids);
    }

    // Adding actions of item

    // Looking for first possible continuous action 
    if ( primary_action_ids && primary_action_ids.Count() > 0  )
    {
        for ( int i = 0; i < primary_action_ids.Count(); i++ )
        {
            picked_action = GetAction(primary_action_ids.Get(i));
            if ( picked_action && picked_action.Can(m_Player,target, item) )
            {
                return picked_action;
            }
        }
    }
    return NULL;
}

protected ActionBase FindContextualSingleUseAction(ActionTarget target, ItemBase item)
{
    Object targetObject;
    Object targetParent;

    if( target )
    {
        targetObject = target.GetObject();
        targetParent = target.GetParent();
    }
    
    ref TIntArray secondary_action_ids = new TIntArray;
    ActionBase picked_action;

    secondary_action_ids.Insert(AT_WORLD_CRAFT_SWITCH);
    
    if (targetParent)
    {
        targetParent.GetSingleUseActions(secondary_action_ids);
    }

    // Adding interact actions of items in the world
    if ( targetObject )
    {
        targetObject.GetSingleUseActions(secondary_action_ids);
    }
    
    // Adding actions of item
    if ( item )
    {
        item.GetSingleUseActions(secondary_action_ids);
    }
    // Adding default single use actions of player
    if ( m_Player ) 
    {
        m_Player.GetSingleUseActions(secondary_action_ids);
    }
    
    // Looking for first possible single use action 
    if ( secondary_action_ids  && secondary_action_ids.Count() > 0 )
    {
        for ( int i = 0; i < secondary_action_ids.Count(); i++ )
        {
            picked_action = GetAction(secondary_action_ids.Get(i));		
            if ( picked_action && picked_action.Can(m_Player, target, item) ) 
            {
                return picked_action;
            }
        }
    }
    return NULL;
}

Event Timeline

Arkensor edited Steps To Reproduce. (Show Details)
Arkensor edited Additional Information. (Show Details)
Geez changed the task status from New to Reviewed.Dec 17 2018, 11:14 AM
Geez added a subscriber: Geez.

Hello Arkensor and thank you for your feedback.
Your suggestion has been forwarded to the developers responsible and will be taken into account.
Regards,
Geez

rVn changed the task status from Reviewed to Need More Info.Apr 3 2019, 12:45 PM
rVn added a subscriber: rVn.

Hi, I asked our action scripter about this

There are reasons why contextual actions and interact actions work differently:
Contextual(single use/continuous) actions are used for item in your hand ( animation and action condition expect specific item in hand - same as action execution )
On the other hand interact actions are used for interaction in world ignoring what you have in hands (take items, drink from pound, open door, etc.)

Your solution would create issues in the overlap of these two systems. However it is unclear to us what exactly are you having trouble with, maybe use a specific example of what you are trying to accomplish?
Do note that the actions will have a bit of an overhaul in the 1.03 and things such as continuous interact actions will be possible

Arkensor added a comment.EditedApr 3 2019, 1:04 PM

The active interactions checks rely on the the action id. The pool of id's that will be iterated in a particular case depends on the actions available on the player, the actions from the item in hand, as well as the world objects that the player is in proximity / looking at.

Only the function GetContextualInteractActions actually asks world objects for if they have any interactions available. FindContextualContinuousAction and FindContextualSingleUseAction do not do that.
So because of that, it's not possible to add a ContinuousAction or SingleUseAction to a world object.
The reason for that will most likely be - as you said - that Contextual actions are only meant to be used for item in hands and on the player, and thus there was no reason to include the world objects into the check.

Contextual interactions are implemented differently in regards to how they appear in the hud (not trying to translate the interactions world pos to screen pos), and that's why I and other modders want to use them. Right now we simply mod the PlayerBase class to make the player interaction check include the target interactions. So far this has not created any issues because of any overlap of the systems. I don't see how this can create an issue really since the worst thing that can happen is that a world interaction is available at the same time as an item interaction in which case both actions would be part of the static bottom left hud selection.

Let me know what kind of issue the scripter sees in having Contextual interactions on world objects because I don't see any at the moment.

This is what I need to do at the moment in order to add my single use interaction from a world object to the list of actions the user can choose from:

modded class PlayerBase
{
	override void GetSingleUseActions( out TIntArray actions )
	{
	    super.GetSingleUseActions( actions );
		actions.Insert( HYPETRAIN_TURN_ENGINE_ON );
		actions.Insert( HYPETRAIN_TURN_ENGINE_OFF );
	}
};

I add them to the player since the player will be checked for actions for all 3 categories. This is a rather unpleasant solution, as it would be much easier to use the existing config entries from the object class definition or the object interactions functions as you would do for InteractAction.

Another example:

class MyCfgVehicle
{
    InteractActions[] = { 11111, 11112, 11115, 11116, 11117 };
    SingleUseActions[] = { 11118, 11119 };

InteractActions ids will be included from the action system, SingleUseActions are ignored. It would be a cleaner to have all 3 interaction types defined the same way.

rVn added a comment.Apr 3 2019, 4:17 PM

Doing this by modding PlayerBase is the intended way to go about this and yes, it might seem cleaner to look at if they operated the same way but they are two distinct systems.

An example of where this wouldn't work, although they are probably better ones:
You have a knife in hand and a new 'object' action - lets say drinking from bottle on the ground, using it would cause you to drink your knife instead. Situations like these would be avoidable only by checking for item in hand on each of these actions, but the system for them was written with mind of being tied to specific item in hands.

Just going to repeat again that the action systems will change a bit in 1.03, although this action type split will likely stay the same - maybe the real issue here is why do you consider the overrides in PlayerBase as an unpleasant solution?

I consider it unpleasant because I am not sure how the modded player instance is handled when multiple mods want to override the same function. If two mods, want to override GetSingleUseActions() - from my current experience - the modded versions will most likely fight each other over which instance will be used.
This can be avoided if the interactions are defined in the config or object class directly, where is less likely two mods are in conflict, then the PlayerBase. I think nearly every mod on the workshop right now has a different PlayerBase implementation, and many of which will advance at one point to use interactions in mods ...

I get your example though. I think it's less likely than two mods conflicting tbh, but I guess the vanilla experience has priority over modded content

I'll have a look at the refactor in the upcoming version, and see if that helps/eliminates the need to do this workaround at the moment.

rVn added a comment.Apr 3 2019, 5:23 PM

Multiple mods of the same class work similar to inheritance, it would be kinda like this:

class Vanila
class ModA: Vanilla
class ModB: ModA

In case of the overridden method, one of the mods not calling a super() could 'break' the chain and stop the call from being propagated to the next one, but that would be a mistake of the mod in question.

rVn closed this task as Resolved.Apr 4 2019, 10:05 AM
rVn claimed this task.