Announcement

Collapse
No announcement yet.

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

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

    [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


    Code:
        
    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[i].IsBound())
            {
                OutExtenders.Add(ExtenderDelegates[i].Execute(CommandList, ContextSensitiveObjects));  // <-- here delegates are nomally call
            }
        }
        return FExtender::Combine(OutExtenders);
    }
    Register
    Code:
    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
    Code:
    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
    Last edited by JohnHudeski; 06-05-2019, 04:38 AM.

    #2
    How code setup in your asset factory and type actions class look like?
    | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

    Comment


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

      Code:
      
      /**
       * 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);
      };
      Last edited by JohnHudeski; 06-03-2019, 10:03 PM.

      Comment


        #4
        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:

        https://api.unrealengine.com/INT/API...tor/index.html


        then register it with this:

        https://api.unrealengine.com/INT/API...ons/index.html



        Did you do that?
        | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

        Comment


          #5
          Code:
          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;
          };

          Code:
          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())));
          }
          Code:
          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
          Last edited by JohnHudeski; 06-04-2019, 06:45 AM.

          Comment


            #6
            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:

            Code:
            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);
                    }
                }
            
            }
            | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

            Comment


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

              Code:
              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

              Comment


                #8
                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:







                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:
                Code:
                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
                Last edited by BrUnO XaVIeR; 06-04-2019, 10:34 AM.
                | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                Comment


                  #9
                  I must have done something strange when i added the viewport

                  Comment


                    #10
                    Dear unreal.
                    Please fix this bug
                    https://answers.unrealengine.com/que...-variable.html

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

                    Code:
                     Windows -> Layout -> Reset Layout

                    Comment

                    Working...
                    X