Utilizing Joint Management
Joint Management is an extensible editor tab that lets you add your own joint related tools.
In this document, We're going to cover both what it has by default, and how to extend it with your own tools.
Opening Joint Management
To open Joint Management, go to Tools -> Joint Management on the toolbar of the Unreal Editor.

Default Provided Tools
By default, Joint provides "Editor Utility" and "Node Class Management" tabs for the easy iteration over your project.
Editor Utility Tab
The Editor Utility tab provides you with a set of utilities that let you perform some very specific tasks related to joints in your project.
For example, we mostly add some compatibility related features here, that automatically fix issues that may arise when you update Joint or Unreal Engine versions.
And also we provide reset Editor preference setting here - just in case you messed up something and want to go back to default settings.

We also provide a "developer mode" toggle here, that makes some hidden properties visible in Joint editors - useful for debugging or development purposes - we might want you to turn this on when you report issues to us, so that we can get more information about your setup.
Node Class Management Tab
The Node Class Management tab provides you some functionalities to manage issues for the nodes.

Redirecting Missing Node Class
When you delete or rename a node class that is being used in your project, the nodes that were using that class will become broken, and you will see errors like below when you open the graph editor.
Joint provides a way to redirect those missing node classes to new ones, so that you can quickly fix those broken nodes without having to manually fix each of them.
If your project has any missing node classes, they will be listed on the view if you click the Refresh List button.

And if you click the Apply button, and press ok to the dialog, it will redirect the node class to the new one.

The change will be applied after you restart the editor.

You can remove each redirection whenever you need by clicking the Remove Redirection button of them here, or you can visit the JointEditorSettings to remove them manually (it hold the redirection data).
Node Class Swap (BETA)
You can now swap the node class of existing nodes to another one! You can either swap editor nodes or node instances.
It will try to maintain the node's properties, but it may not be able to maintain all of them depending on the node class.
This feature is still in BETA and extremely experimental. So it may not work as expected. We recommend you to backup your project before using this feature.

Extending Joint Management
This part is only for the advanced user; You have to have some knowledge about Unreal Engine Editor module development and Slate UI framework to follow this section.
You may want to add your own tools to Joint Management for your own workflow - and Joint provides an easy and elegant way to do that.
To add your own tool to Joint Management, you need to create a new class that inherits from IJointManagementSubTab and implement the required functions. This class will be used as an interface to register your tab to Joint Management.
Here are the important functions you need to look at for IJointManagementSubTab implementation:
- GetTabId: You have to return a unique FName for your tab here - this will be used to identify your tab in the tab manager.
- RegisterTabSpawner: This is where you actually register your tab contents to the Joint Management tab manager. You can use the
TabManager->RegisterTabSpawnerfunction to register your tab, and provide a lambda function that returns the contents of your tab.
And after that, you need to register your tab class to Joint Management Tab Handler during your module startup or elsewhere appropriate.
Example
Here's an example of how Joint Native Editor adds the "Joint Native Utility" tab to Joint Management:
In this example, we didn't actually implement the contents of the tab - you can use your own editor slate for it (in this example, we used external SJointNativeTab slate for the tab content).
In header file:
#include "Editor/Management/JointManagement.h"
class JOINTNATIVEEDITOR_API FJointManagementTab_JointNativeUtility: public IJointManagementSubTab
{
public:
FJointManagementTab_JointNativeUtility();
virtual ~FJointManagementTab_JointNativeUtility() override;
public:
static TSharedRef<IJointManagementSubTab> MakeInstance();
public:
virtual void RegisterTabSpawner(const TSharedPtr<FTabManager>& TabManager) override;
public:
virtual const FName GetTabId() override;
virtual const ETabState::Type GetInitialTabState() override;
};
In source file:
FJointManagementTab_JointNativeUtility::FJointManagementTab_JointNativeUtility() : IJointManagementSubTab()
{
}
FJointManagementTab_JointNativeUtility::~FJointManagementTab_JointNativeUtility()
{
}
TSharedRef<IJointManagementSubTab> FJointManagementTab_JointNativeUtility::MakeInstance()
{
return MakeShareable(new FJointManagementTab_JointNativeUtility);
}
void FJointManagementTab_JointNativeUtility::RegisterTabSpawner(const TSharedPtr<FTabManager>& TabManager)
{
TSharedPtr<FWorkspaceItem> JointNativeEditorGroup = GetParentTabHandler().Pin()->GetActiveGroupFor("JointNativeEditor");
if(!JointNativeEditorGroup)
{
JointNativeEditorGroup = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("JointNativeEditorGroupName", "Joint Native Editor"));
GetParentTabHandler().Pin()->AddActiveGroup("JointNativeEditor", JointNativeEditorGroup);
}
TabManager->RegisterTabSpawner(
GetTabId()
, FOnSpawnTab::CreateLambda(
[=](const FSpawnTabArgs&)
{
return SNew(SDockTab)
.TabRole(ETabRole::PanelTab)
.Label(LOCTEXT("JointYggdrasilUtility", "Joint Native Utility"))
[
SNew(SJointNativeTab)
];
}
)
)
.SetDisplayName(LOCTEXT("EditorUtilityTabTitle", "Joint Native Utility"))
.SetTooltipText(LOCTEXT("EditorUtilityTooltipText", "Open the Joint Native Utility tab."))
.SetGroup(JointNativeEditorGroup.ToSharedRef())
.SetIcon(FSlateIcon(FJointEditorStyle::GetUEEditorSlateStyleSetName(), "ExternalImagePicker.GenerateImageButton"));
}
const FName FJointManagementTab_JointNativeUtility::GetTabId()
{
return "TAB_JointNativeUtility";
}
const ETabState::Type FJointManagementTab_JointNativeUtility::GetInitialTabState()
{
return IJointManagementSubTab::GetInitialTabState();
}
Then, you need to register your tab class to Joint Management module during the module startup:
void FJointNativeEditorModule::StartupModule()
{
if (FJointEditorModule* EditorModule = FJointEditorModule::Get())
{
EditorModule->JointManagementTabHandler->AddSubTab(FJointManagementTab_JointNativeUtility::MakeInstance());
}
RegisterClassLayout();
}
Once you added and registered your tab class, you will see your tab in the Joint Management tab's 'Window' menu!
