Best practices for integrating with Interactive Tools Framework and Persona toolkit

Hi,

I am developing a plugin from scratch for an animation-based system. I want to visualize animations using IK Rigs inside a Persona viewport in my own plugin editor window.

I am thinking deeply about the architecture choices I make right now as I want to lay a solid foundation for the plugin. I found about Interactive Tools Framework (here and here). I am wondering how to approach using it, as I failed to find information about some other classes that I have seen throughout the UE codebase (mostly built-in editors and plugins). I am wondering about the following, primarily:

  • UAssetEditor
  • UEdMode (or FEdMode)
  • FBaseAssetToolkit
  • FPersonaAssetEditorToolkit (FWorkflowCentricApplication)
  • FApplicationMode
  • FModeToolkit

Following some of the comments from the UVEditor plugin, it seems that UAssetEditor and UEdMode are recommended. This also requires the use of FBaseAssetToolkit, which is what UAssetEditor works with. Hence, My toolkit cannot be a workflow centric application with multiple FApplicationModes. This is probably not an issue right now, but in the future the plugin might need new “editor modes”, maybe similar to how Persona does it with the Animation, Skeleton, Physics Asset and Blueprint editors. The only workaround I see is that I would create and destroy UAssetEditors, each with its own FBaseAssetToolkit. However, this would not act as a central toolkit, which FWorkflowApplicationMode seems to be. Alternatively, I use UEdMode / FModeToolkits? Also, I notice that very few plugins use the UEdMode and UAssetEditor classes, maybe because they are new. As for why I mentioned the Persona toolkit, it is because I wish to reuse its viewport, as it has nice functionality for live previewing animation assets. It seems to use its own toolkit (FPersonaAssetEditorToolkit) that extends from FWorkflowCentricApplication, but all it does differently is creating/injecting its own editor mode manager into child toolkits.

Ultimately, I am not sure whether to take the approach of UAssetEditor vs FWorkflowCentricApplication (or something else). I cannot find much documentation on this besides the 2 blog posts I mentioned above, and some articles from here.

I wish to hear some opinions on what I said above. Some prodding questions:

  • What are the (in-house) best practices and recommendations when building such plugins, and using the above classes?
  • Should toolkits be mixed (e.g. Toolkit A contains pointer to Toolkit B, both used by the plugin at the same time)? This seems reasonable, as persona exposes IHasPersonaToolkit interface, supposedly to go in other toolkits.
  • How to handle multiple layouts (e.g. FApplicationMode) using UAssetEditor?
  • Should my toolkit inherit from FPersonaAssetEditorToolkit (like most Persona editors), or FBaseAssetToolkit instead with IHasPersonaToolkit and a pointer to Persona toolkit?
  • Overall thoughts on the matter?

I will deeply appreciate any insight that you can shed on the matter!

As additional info, I mainly referenced the following plugins/editors: UVEditor, AnimationEditor, IKRigEditor / IKRetargetEditor, and other Persona Editors.

I can’t really answer most of your questions, but I can just point out that some of these things are not mutually exclusive. For example the Skeletal Mesh Editor appears to be/use FPersonaAssetEditorToolkit, but it also can host UEdModes that use the ITF. If you look at USkeletalMeshModelingToolsEditorMode, this is a plugin you can enable that adds some modeling tools to the Skeletal Mesh Editor, via ITF/UEdMode.

(I was not involved in this and can’t say quite how the classes/etc are set up, though. I’m not familiar at all w/ the Persona or WorkflowCentricApplication systems)

I believe a UAssetEditor can also host multiple UEdModes, similar to the main level editor. This is (relatively) new functionality and has not been heavily exercised though, and I can’t think of any Asset Editors where I’m sure it was done this way.

Sorry I can’t be more helpful. The things you are trying to do are quite complex and not something that a large number of people have had to figure out how to do, unfortunately that means it can be quite hard to get solid information.

Thanks for the feedback Ryan, much appreciated! It seems that indeed, not much work has been done using these classes yet, but there will likely be more in the future for sure.

For reference (and to help others), I decided to go down the path of least resistance and mimic the setup of built-in editors like the Animation Editor. Specifically, subclassing FPersonaAsseEditorToolkit and FApplicationMode classes. This is a rough pseudo-boilerplate:

MyPluginApplicationMode.cpp (extends FApplicationMode):

  • Register the Persona viewport tab factory (subclass of FWorkflowTabFactory)
    FPersonaModule& PersonaModule = FModuleManager::LoadModuleChecked<FPersonaModule>("Persona"); TabFactories.RegisterFactory(PersonaModule.CreatePersonaViewportTabFactory(InHostingApp, ViewportArgs));
  • Similarly, register other tabs needed for the plugin editor (refer to the Persona tab factories for how to do so)
  • Remember to include Persona as a project dependency (MyPlugin.Build.cs)

MyPluginToolkit.cpp (extends FPersonaAssetEditorToolkit and IHasPersonaToolkit):

  • Stores a reference to IPersonaToolkit:
    TSharedPtr<IPersonaToolkit> PersonaToolkit = nullptr;
  • Defnies a custom void InitAssetEditor( const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost); function which further calls
    FAssetEditorToolkit::InitAssetEditor( Mode, InitToolkitHost, MyPluginAppName, FTabManager::FLayout::NullLayout, true, false, DummyAsset); - in this case, Mode is EToolkitMode::Standalone because the plugin uses its own editor window, rather than being EToolkitMode::WorldCentric and bound to the Level Editor.
  • IPersonaToolkit is initialized using
    const FPersonaModule& PersonaModule = FModuleManager::LoadModuleChecked<FPersonaModule>("Persona"); PersonaToolkit = PersonaModule.CreatePersonaToolkit(DummyAsset, PersonaToolkitArgs); in InitAssetEditor; where DummyAsset is a UAnimationAsset in my case.

MyPluginModule.cpp (extends IModuleInterface):

  • Primarily used to initialize the toolkit:
    TSharedRef<FMyPluginToolkit> MyPlugin(new FMyPluginToolkit()); MyPlugin->InitAssetEditor(EToolkitMode::Standalone, TSharedPtr<IToolkitHost>());

Hope this is useful for others! And of course, if someone wishes to give feedback on this process in the future, it will be more than welcome :slight_smile:

1 Like