Download

[Solved] What could possibly prevent unreal from calling my extender delegates?

I am new to unreal (Just over 2 weeks) but not programming and recently made the switch from unity. The editor programming is a black box despite visible code from the source file. I have spent 2 days going through every bit of my code and it is identical to all the samples that inspired it but no result.
The code is structured the same way as the online learning tutorial on plugin best practices, I was able to re-implement that tutorial with extra features no problem but my attempts at creating a viewport has been disastrous.
Debugging the program shows that this is where all the madness happens


    
TSharedPtr<FExtender> FExtensibilityManager::GetAllExtenders(const TSharedRef<FUICommandList>& CommandList, const TArray<UObject*>& ContextSensitiveObjects)
{
    auto OutExtenders = Extenders;
    for (int32 i = 0; i < ExtenderDelegates.Num(); ++i)
    {
        if (ExtenderDelegates*.IsBound())
        {
            OutExtenders.Add(ExtenderDelegates*.Execute(CommandList, ContextSensitiveObjects));  // <-- here delegates are nomally call
        }
    }
    return FExtender::Combine(OutExtenders);
}

Register



void FMotionSetEditorToolkit::RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager)
{
    WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_MotionSetEditor", "MotionSet Editor"));
    auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();

    FAssetEditorToolkit::RegisterTabSpawners(InTabManager);


    InTabManager->RegisterTabSpawner(MotionSetEditor::Tabs::ViewportID, FOnSpawnTab::CreateSP(this, &FMotionSetEditorToolkit::SpawnTab_Viewport))
        .SetDisplayName(LOCTEXT("ViewportTab", "Viewport"))
        .SetGroup(WorkspaceMenuCategoryRef)
        .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports"));


    InTabManager->RegisterTabSpawner(MotionSetEditor::Tabs::DetailsID, FOnSpawnTab::CreateSP(this, &FMotionSetEditorToolkit::SpawnTab_Details))
        .SetDisplayName(LOCTEXT("DetailsTabLabel", "Details"))
        .SetGroup(WorkspaceMenuCategoryRef)
        .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.ContentBrowser"));



    /*
    //Allternative
    InTabManager->RegisterTabSpawner(MotionSetEditor::Tabs::ViewportID, FOnSpawnTab::CreateSP(this, &FMotionSetEditorToolkit::SpawnTab_Viewport, MotionSetEditor::Tabs::ViewportID))
        .SetDisplayName(LOCTEXT("ViewportTab", "Viewport"))
        .SetGroup(WorkspaceMenuCategoryRef)
        .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports"));

    InTabManager->RegisterTabSpawner(MotionSetEditor::Tabs::DetailsID, FOnSpawnTab::CreateSP(this, &FMotionSetEditorToolkit::SpawnTab_Details, MotionSetEditor::Tabs::DetailsID))
        .SetDisplayName(LOCTEXT("DetailsTabLabel", "Details"))
        .SetGroup(WorkspaceMenuCategoryRef)
        .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.ContentBrowser"));
    */

}



Initialize



void FMotionSetEditorToolkit::Initialize(UMotionSet* InMotionSet, const EToolkitMode::Type InMode, const TSharedPtr<IToolkitHost>& InToolkitHost)
{
    // Ensure asset exclusivity
    FAssetEditorManager::Get().CloseOtherEditors(InMotionSet, this);
    MotionSet = InMotionSet;
    // ?
    CurrentExtractionContextIndex = INDEX_NONE;


    // Support undo/redo
    //RF_Standalone    Keep object around for editing even if unreferenced.
    //MotionSet->SetFlags(RF_Transactional); // We set this already in CreateNew
    //GEditor->RegisterForUndo(this);

    FMotionSetEditorCommands::Register();

    BindCommands();
    TSharedPtr<FMotionSetEditorToolkit> MotionSetEditorPtr = SharedThis(this);
    ViewportPtr = SNew(SMotionSetEditorViewport, MotionSetEditorPtr).MotionSet(this, &FMotionSetEditorToolkit::GetMotionSetBeingEdited);

    // create Default tab layout
    const TSharedRef<FTabManager::FLayout> Layout = FTabManager::NewLayout("Standalone_MotionSetEditor")
        ->AddArea
        (
            FTabManager::NewPrimaryArea()
            ->SetOrientation(Orient_Vertical)
            ->Split
            (
                FTabManager::NewStack()
                ->SetSizeCoefficient(0.1f)
                ->SetHideTabWell(true)
                ->AddTab(GetToolbarTabId(), ETabState::OpenedTab)
            )
            ->Split
            (
                FTabManager::NewSplitter()
                ->SetOrientation(Orient_Horizontal)
                ->SetSizeCoefficient(0.9f)
                ->Split
                (
                    FTabManager::NewStack()
                    ->SetSizeCoefficient(1.f)
                    ->SetHideTabWell(true)
                    ->AddTab(MotionSetEditor::Tabs::ViewportID, ETabState::OpenedTab)
                )
                ->Split
                (
                    FTabManager::NewStack()
                    ->SetSizeCoefficient(0.75f)
                    ->SetHideTabWell(true)
                    ->AddTab(MotionSetEditor::Tabs::DetailsID, ETabState::OpenedTab)
                )
            )
        );


    //Frustration hack to force generation, doesnt work
    //TSharedRef<class FGlobalTabmanager> tm = FGlobalTabmanager::Get();
    //tm->InvokeTab(MotionSetEditor::Tabs::ViewportID);
    //tm->InvokeTab(MotionSetEditor::Tabs::DetailsID);


    // Initialize the asset editor and spawn nothing (dummy layout)
    FAssetEditorToolkit::InitAssetEditor(
        InMode,
        InToolkitHost,
        MotionSetEditor::AppIdentifier,
        Layout, // The Slate us we created above
        true /*bCreateDefaultStandaloneMenu*/,
        true /*bCreateDefaultToolbar*/,
        InMotionSet
    );


    //const FSpawnTabArgs* Dummy = nullptr;
    //SpawnTab_Viewport(*Dummy);
    //SpawnTab_Details(*Dummy);

    // Extend things
    ExtendMenu();
    ExtendToolbar();
    RegenerateMenusAndToolbars();


    if(TagTimelineBoxPtr)
        RebuildTagTimelines();
}



Link to post on Answers

How code setup in your asset factory and type actions class look like?

I can successfully create the asset. The problem comes when i try to edit it





/**
 * Implements a factory for UMotionSet objects.
 * Context browser Right click (No drag drop support)
 */
UCLASS(hidecategories=Object)
class UMotionSetAssetFactoryNew : public UFactory
{
    GENERATED_UCLASS_BODY()

public:
    virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
    virtual bool ShouldShowInNewMenu() const override;

    //Bone Picker dialog
    virtual bool ConfigureProperties() override;
    UPROPERTY(EditAnywhere)
    class USkeleton* TargetSkeleton;
    UPROPERTY(EditAnywhere)
    TArray <FName> UserSelectedBones;
};



#include "Widgets/SMatchTargetsCreationDialog.h"


#define LOCTEXT_NAMESPACE "FMotionSetAssetFactoryNew"

//////////////////////////////////////////////////////////
// UMotionSetAssetFactoryNew implementation.
//////////////////////////////////////////////////////////

// Register self
UMotionSetAssetFactoryNew::UMotionSetAssetFactoryNew(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
    //Enable editor support for class
    SupportedClass = UMotionSet::StaticClass();
    bCreateNew = true; //creates news instance rather than drag drop
    bEditAfterNew = true; //Editable after creation (Name)
}


// UFactory overrides

//Generate new (Add the skeleton)
UObject* UMotionSetAssetFactoryNew::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
    //Is this the best place to set the flags?
    UMotionSet* newMotionSet = NewObject<UMotionSet>(InParent, InClass, InName, Flags | RF_Transactional);

    if (newMotionSet && TargetSkeleton)
    {
        newMotionSet->PopulateFromSkeleton(TargetSkeleton, UserSelectedBones);

        return newMotionSet;
    }

    return NULL;
}

// Show up in menu
bool UMotionSetAssetFactoryNew::ShouldShowInNewMenu() const
{
    return true;
}

//Calls the Picker
bool UMotionSetAssetFactoryNew::ConfigureProperties()
{
    TSharedRef<SMatchTargetsCreationDialog> Dialog = SNew(SMatchTargetsCreationDialog, true);
    return Dialog->ConfigureProperties(this);
};


Yes, but now that you have a factory registered, did you create and register the necessary “type actions” class?

You should have a class from “FAssetTypeActions_Base” which overrides the default OpenAsset() function to use your custom Toolkit:

then register it with this:

Did you do that?


s ISlateStyle;

/**
 * Implements an action for UMotionSet assets.
 */
class FMotionSetActions : public FAssetTypeActions_Base //For context menus (Manually registered)
{


    // this is what displays the multiline text editor, replace to change what is shown insteadead of default details editor
    virtual void OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<IToolkitHost> EditWithinLevelEditor = TSharedPtr<IToolkitHost>()) override;

private:

    /** Pointer to the style set to use for toolkits. */
    TSharedRef<ISlateStyle> Style;
};





void FMMEditorModule::RegisterAssetTools()
{
    IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
    // Register motion set actions to the context menu
    RegisterAssetTypeAction(AssetTools, MakeShareable(new FMotionSetActions(Style.ToSharedRef())));
}






void FMMEditorModule::RegisterAssetTypeAction(IAssetTools& AssetTools, TSharedRef<IAssetTypeActions> Action)
{
    AssetTools.RegisterAssetTypeActions(Action);
    RegisteredAssetTypeActions.Add(Action);
}


​​​​​​​Should i send you the entire project? Maybe my eyes have stopped working

No need. If your Type Actions is working correctly then your “RegisterTabSpawners()” function should be called when an asset is open.
The “OpenAssetEditor()” override should be doing something like this:



void FMyAssetTypeActions::OpenAssetEditor (const TArray<UObject*>& InObjects, TSharedPtr<IToolkitHost> EditWithinLevelEditor) {

    EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;

    for (auto IT = InObjects.CreateConstIterator(); IT; ++IT) {
        if (UMyObjectClass* TargetObject = Cast<UMyObjectClass>(*IT)) {
            TSharedRef<FMyToolkit> MyAssetToolkitEditor (new FMyToolkit());
            MyAssetToolkitEditor->***Initialize ***(Mode, EditWithinLevelEditor, TargetObject);
        }
    }

}


Thank you for your continued feedback but i swear this has me really confused



void FMotionSetActions::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<IToolkitHost> EditWithinLevelEditor)
{
    const EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;

    for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt)
    {
        //cast to our desired object, if it succeeds draw
        if (UMotionSet* MotionSet = Cast<UMotionSet>(*ObjIt))
        {
            // AssetEditor and Toolkit are interchangeable names
            TSharedRef<FMotionSetEditorToolkit> EditorToolkit(new FMotionSetEditorToolkit(Style)); //create
            EditorToolkit->Initialize(MotionSet, Mode, EditWithinLevelEditor); //init
        }
    }
}

//Too long posted above
void FMotionSetEditorToolkit::Initialize(UMotionSet* InMotionSet, const EToolkitMode::Type InMode, const TSharedPtr<IToolkitHost>& InToolkitHost)
{
      //..
}



I am starting again from scratch. No functionality just the viewport

There must be something fundamental you’re missing.
I’ve built a custom toolkit a few minutes ago for a custom UObject class to test a few things, specially toolkit menu extensibility with custom section actions, and it seems to be working fine:

[HR][/HR]

BTW, whenever you change the Layout of your tabs, it’s good idea to change the string identifier to avoid weird behavior.
For example, I start with:


const TSharedRef<FTabManager::FLayout>FMyEditorLayout = FTabManager::NewLayout("MyKitEditorLayout_V001")

Then whenever I create more tabs or remove layout structure I go incrementing the “Vxxx” string :slight_smile:

I must have done something strange when i added the viewport

Dear unreal.
Please fix this bug
https://answers.unrealengine.com/questions/552456/unrecognized-tab-opens-when-creating-new-variable.html

I rewrote my code 5 times but it was never me. It was always you


 Windows -> Layout -> Reset Layout