AddMenuEntry to right click on UObject

hello,

So I have been trying to extend some engine code to allow me to add custom menu entries upon right clicking my custom Actor objects in the Editor.

I can now correctly receive a functioncall to my Actor that has been selected and the right mouse button has been clicked on in the object browser.

Here is the body of my method that is being called :

void AMyCustomActor::AddCustomMenuEntries(class FMenuBuilder& MenuBuilder)  
{  
	FMyCustomEditorCommands::Get().MapActions(this);

	FMyCustomEditorCommands::Get().AddToMenu(MenuBuilder);
}

where FMyCustomEditorCommands is defined as

class FMyCustomEditorCommands : public TCommands < FMyCustomEditorCommands >
{
public:
	FMyCustomEditorCommands ();

	virtual void RegisterCommands() override;

	static void MapActions(AActor* InActor);

	static void AddToMenu(class FMenuBuilder& MenuBuilder);

protected:

public:
	TSharedPtr< FUICommandInfo > DoSomethingCustom;

private:
	TSharedPtr< FUICommandList > MyCommandsList;
};

and implemented as

FMyCustomEditorCommands::FMyCustomEditorCommands() : 
TCommands<FMyCustomEditorCommands>(TEXT("MyCustomEditorCommands"), NSLOCTEXT("MyEditor", "FMyCustomEditorCommands", "My-Editor"), NAME_None, FEditorStyle::GetStyleSetName()),
MyCommandsList(new FUICommandList())
{
	
}

void FMyCustomEditorCommands::RegisterCommands()
{
	UI_COMMAND(DoSomethingCustom, "My Custom Entry", "Does something really awesome..", EUserInterfaceActionType::Button, FInputGesture());
}

void FMyCustomEditorCommands::MapActions(AActor* InActor)
{
	Register();

	AMyCustomActor* pMyActor = Cast<AMyCustomActor>(InActor);

	if (pMyCustomActor)
	{
		Get().MyCommandsList->MapAction(
			Get().DoSomethingCustom, FExecuteAction::CreateStatic(&AMyCustomActor::SomeStaticMethod));
	}
}

void FMyCustomEditorCommands::AddToMenu(class FMenuBuilder& MenuBuilder)
{
	MenuBuilder.BeginSection("MyCustomStuff", FText::FromString("Custom")); 
	{
		MenuBuilder.AddMenuEntry(Get().DoSomethingCustom);
	}
	MenuBuilder.EndSection();
}

so then I just make sure I register FMyCustomEditorCommands once at startup of the editor and I can now see my custom menu added to the existing actor menu. (it works because i added a virtual function call on Actor and i call it from where in the engine it builds the menu for all selected actors.)

but I have one problem… even though i can see and click on my custom menu entry, it doesnt actually execute any code.

I have put breakpoints in each step of the code and it always hits right up to the point where it registers the static method to the menu. But the static method is never called. Am I missing something ? I can post also the code for where i call the “AddCustomMenuEntries” but it is fairly trivial.

Any idea why my function even though it is registered isnt being called ?

Investigating this further I found that my command is being executed but it failed to find the correct action

const FUIAction* FUICommandList::GetActionForCommand(TSharedPtr<const FUICommandInfo> Command) const
{
	// Make sure the command is valid
	if ( !ensure(Command.IsValid()) )
	{
		return NULL;
	}

	// Check in my own binding map. This should not be prevented by CanProduceActionForCommand.
	// Any action directly requested from a command list should be returned if it actually exists in the list.
	const FUIAction* Action = UICommandBindingMap.Find( Command );

	if ( !Action )
	{

I will keep looking and post if I find the reason for this.

some more info :
I looked at how my command is being added via the MapAction

void FUICommandList::MapAction( const TSharedPtr< const FUICommandInfo > InUICommandInfo, const FUIAction& InUIAction )
{
	check( InUICommandInfo.IsValid() );

	// Check against already mapped actions
	checkSlow( !UICommandBindingMap.Contains( InUICommandInfo ) );

	ContextsInList.Add( InUICommandInfo->GetBindingContext() );
	UICommandBindingMap.Add( InUICommandInfo, InUIAction );
}

it looks like it doesnt get added correctly to the lists .
The data passed in
InUICommandInfo
InUIAction
both look alright (I can see the string names telling me the variables look alright) then inside the “Add” when it comes to

template
FSetElementId Emplace(ArgsType&& Args,bool* bIsAlreadyInSetPtr = NULL)
{
// Create a new element.
FSparseArrayAllocationInfo ElementAllocation = Elements.AddUninitialized();
FSetElementId ElementId(ElementAllocation.Index);
auto& Element = *new(ElementAllocation) SetElementType(Forward(Args));

		bool bIsAlreadyInSet = false;
		if (!KeyFuncs::bAllowDuplicateKeys)
		{
			// If the set doesn't allow duplicate keys, check for an existing element with the same key as the element being added.
			FSetElementId ExistingId = FindId(KeyFuncs::GetSetKey(Element.Value));
			bIsAlreadyInSet = ExistingId.IsValidId();
			if (bIsAlreadyInSet)
			{
				// If there's an existing element with the same key as the new element, replace the existing element with the new element.
				MoveByRelocate(Elements[ExistingId].Value, Element.Value);

				// Then remove the new element.
				Elements.RemoveAtUninitialized(ElementId);

				// Then point the return value at the replaced element.
				ElementId = ExistingId;
			}
		}

		if (!bIsAlreadyInSet)
		{
			// Check if the hash needs to be resized.
			if(!ConditionalRehash(Elements.Num()))
			{
				// If the rehash didn't add the new element to the hash, add it.
				HashElement(ElementId,Element);
			}
		}

		if (bIsAlreadyInSetPtr)
		{
			*bIsAlreadyInSetPtr = bIsAlreadyInSet;
		}

		return ElementId;
	}

it actially says that apparently “bIsAlreadyInSet” is true and that it hence tries to replace the command, but there is only one place in code where i map my action and even when it being called for the first time it says that my entry already is in the list. I think I might need some advice from and engine guy.

so when it then comes to try and execute my command , it looks for my command in the list mentioned above but it returns an ElementId of -1 , so it didn’t find my command even though it should be in that list.

So yesterday I build a debug version of my project and was able to dig down into the logic , et voila’ , I found the cause.
Basically the debug variables I saw werent correct 100% , long story short, I was adding my commands to my own custom command list but the engine code was only looking for commands to be executed in its own list. I have fixed this now and I am able to have my own custom right click menu entries on editor Actor objects. Its pretty neat. I will add a tutorial for this on the code wiki oif UE4 so others can use it.

So for completness sake , I have created a tutorial on how to have custom context menus in the editor for your custom actors. It can be found here
UE4 Wiki : Custom Context Menu for Actors in Editor

I ran into this issue too. I didn’t see an easy way to add my commands to the editor’s list though.
It turns out you can use “AddMenuEntryWithCommandList” to provide your own command list when you create the menu command, but it does kind of mingle objects that would be isolated otherwise.

I wonder if there’s a better approach to add your commands to the source where it’s looking more easily?

How did you solve the problem? The wiki is gone now.