Add Recent Blueprint Plugin

This commit is contained in:
Philip W 2024-04-26 03:30:26 +01:00
parent a5e8a8db13
commit b62d7d75de
9 changed files with 307 additions and 0 deletions

View File

@ -68,6 +68,11 @@
"Name": "AsyncLoadingScreen", "Name": "AsyncLoadingScreen",
"Enabled": true, "Enabled": true,
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/01f39767dc6b4290877f38365787cbf8" "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/01f39767dc6b4290877f38365787cbf8"
},
{
"Name": "RecentBlueprintMenu",
"Enabled": true,
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/484f72297c144cf9b5c35fea3359500c"
} }
] ]
} }

View File

@ -0,0 +1,28 @@
{
"FileVersion": 3,
"Version": 101,
"VersionName": "1.01",
"FriendlyName": "Recent Blueprints Menu",
"Description": "A simple but time saving plugin that adds a \"Recent Blueprints\" menu to the blueprint editor. Giving you one click access to blueprints recently opened, and avoid having to constantly search for them.",
"Category": "Blueprint Editor",
"CreatedBy": "The Tool Shed",
"CreatedByURL": "https://unrealengine.com/marketplace/en-US/profile/The%20Tool%20Shed",
"DocsURL": "https://docs.google.com/presentation/d/10Gp1y-EPkBW8myvR-Lzd3viMDU5xovd0fSzJLOFm4NI/edit?usp=sharing",
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/484f72297c144cf9b5c35fea3359500c",
"SupportURL": "https://forums.unrealengine.com/t/support-recent-blueprints-menu/532808",
"EngineVersion": "5.1.0",
"CanContainContent": false,
"Installed": true,
"Modules": [
{
"Name": "RecentBlueprintMenu",
"Type": "Editor",
"LoadingPhase": "PostEngineInit",
"PlatformAllowList": [
"Win64",
"Mac",
"Linux"
]
}
]
}

Binary file not shown.

View File

@ -0,0 +1,83 @@
// Copyright 2022 The Tool Shed (Chris Garnier)
#include "RecentBlueprintMenu.h"
#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION < 24
#include "Toolkits/AssetEditorManager.h"
#endif
#include "BlueprintEditor.h"
#include "RecentBlueprintMenuUtils.h"
#include "RecentBlueprintMenuSettings.h"
#include "EditorStyleSet.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Engine/LevelScriptBlueprint.h"
#define LOCTEXT_NAMESPACE "FRecentBlueprintMenuModule"
void FRecentBlueprintMenuModule::StartupModule()
{
///ADD NEW BLUEPRINT MENU
FBlueprintEditorModule& BlueprintEditorModule = FModuleManager::LoadModuleChecked<FBlueprintEditorModule>("Kismet");
if (const TSharedPtr<FExtensibilityManager> MenuExtender = BlueprintEditorModule.GetMenuExtensibilityManager())
{
BlueprintMenuExtender = MakeShareable(new FExtender);
BlueprintMenuExtender->AddMenuExtension("FileBlueprint",
EExtensionHook::Before,
nullptr,
FMenuExtensionDelegate::CreateRaw(this, &FRecentBlueprintMenuModule::OnBuildBlueprintMenu));
MenuExtender->AddExtender(BlueprintMenuExtender);
}
//SUBSCRIBE TO BLUEPRINT OPEN EVENTS
#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION < 24
FAssetEditorManager::Get().OnAssetEditorRequestedOpen().AddLambda([](UObject* Asset)
#else
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OnAssetEditorRequestedOpen().AddLambda([](UObject* Asset)
#endif
{
if (Asset && Asset->GetClass() == UBlueprint::StaticClass() && Asset->GetClass() != ULevelScriptBlueprint::StaticClass())
{
FRecentBlueprintMenuUtils::OnBlueprintOpened(Asset->GetPathName());
}
});
}
void FRecentBlueprintMenuModule::ShutdownModule()
{
}
void FRecentBlueprintMenuModule::OnBuildBlueprintMenu(FMenuBuilder& MenuBuilder)
{
MenuBuilder.BeginSection("RecentBlueprintMenuSection", FText::FromString("Quick Access"));
MenuBuilder.AddSubMenu(FText::FromString("Recent Blueprints..."),
FText::FromString("Select a Blueprint to edit from a list of recently opened ones."),
FNewMenuDelegate::CreateRaw(this, &FRecentBlueprintMenuModule::OnBuildRecentSubMenu),
false,
FSlateIcon(FEditorStyle::GetStyleSetName(),"GraphEditor.Timeline_16x"));
MenuBuilder.EndSection();
}
void FRecentBlueprintMenuModule::OnBuildRecentSubMenu(FMenuBuilder& MenuBuilder)
{
//purge first to ensure we have a list with no bad assets
FRecentBlueprintMenuUtils::PurgeList();
TArray<FString> RecentList = GetDefault<URecentBlueprintMenuSettings>()->RecentBlueprints;
for (FString Entry : RecentList)
{
MenuBuilder.AddMenuEntry(FText::FromString(FPackageName::ObjectPathToObjectName(Entry)),
FText::FromString(FPackageName::ObjectPathToPackageName(Entry)),
FSlateIcon(),
FUIAction(FExecuteAction::CreateLambda([Entry]()
{
#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION < 24
FAssetEditorManager::Get().OpenEditorForAsset(Entry);
#else
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(Entry);
#endif
})));
}
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FRecentBlueprintMenuModule, RecentBlueprintMenu)

View File

@ -0,0 +1,57 @@
// Copyright 2022 The Tool Shed (Chris Garnier)
#include "RecentBlueprintMenuUtils.h"
#include "RecentBlueprintMenuSettings.h"
void FRecentBlueprintMenuUtils::OnBlueprintOpened(FString BlueprintPath)
{
TArray<FString>& RecentList = GetMutableDefault<URecentBlueprintMenuSettings>()->RecentBlueprints;
const int32 Index = RecentList.Find(BlueprintPath);
if (Index != INDEX_NONE) //If it's already in the list we just need to move it to the top
{
if (Index == 0)
{
return; //already first
}
RecentList.RemoveAt(Index); //removes so we can re-add at the end
}
RecentList.EmplaceAt(0, BlueprintPath);
//Now that we've added, trim entries
const uint8 MaxBP = GetDefault<URecentBlueprintMenuSettings>()->MaxRecentBP;
if (RecentList.Num() > MaxBP)
{
TArray<FString> TrimmedList;
for (int i=0; i < RecentList.Num(); i++)
{
if (i < MaxBP)
{
TrimmedList.Add(RecentList[i]);
}
}
RecentList = TrimmedList;
}
GetMutableDefault<URecentBlueprintMenuSettings>()->SaveConfig();
}
void FRecentBlueprintMenuUtils::PurgeList()
{
TArray<FString>& List = GetMutableDefault<URecentBlueprintMenuSettings>()->RecentBlueprints;
TArray<FString> NewList;
for (int32 i = 0; i < List.Num(); i++)
{
if (FPackageName::DoesPackageExist(List[i]))
{
NewList.Add(List[i]);
}
}
List = NewList;
GetMutableDefault<URecentBlueprintMenuSettings>()->SaveConfig();
}

View File

@ -0,0 +1,28 @@
// Copyright 2022 The Tool Shed (Chris Garnier)
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FMenuBuilder;
class FExtender;
class FRecentBlueprintMenuModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
private:
//Delegate to generate new menu in BP
void OnBuildBlueprintMenu(FMenuBuilder&);
//Delegate to generate new menu in BP
void OnBuildRecentSubMenu(FMenuBuilder&);
//Pointer to the extender used for the new custom blueprint menu
TSharedPtr<FExtender> BlueprintMenuExtender;
};

View File

@ -0,0 +1,25 @@
// Copyright 2022 The Tool Shed (Chris Garnier)
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "RecentBlueprintMenuSettings.generated.h"
/**
* Settings class for RecentBlueprintMenu to save recent BPs and other info
*/
UCLASS(config=EditorPerProjectUserSettings)
class RECENTBLUEPRINTMENU_API URecentBlueprintMenuSettings : public UObject
{
GENERATED_BODY()
public:
//List of blueprints that were recently open to show in the Recent menu
UPROPERTY(Config)
TArray<FString> RecentBlueprints;
//How many Blueprints to remember max
UPROPERTY(Config) //not presented in a menu but users can modify in ini
uint8 MaxRecentBP = 15;
};

View File

@ -0,0 +1,23 @@
// Copyright 2022 The Tool Shed (Chris Garnier)
#pragma once
#include "CoreMinimal.h"
/**
* RecentBlueprintMenu class containing functions to use by the menus
*/
class RECENTBLUEPRINTMENU_API FRecentBlueprintMenuUtils
{
friend class FRecentBlueprintMenuModule; //TODO: Only friend the necessary classes
private:
//Called when a blueprint opens, so it can get saved to the recent list
static void OnBlueprintOpened(FString BlueprintPath);
//Remove files that do not exist anymore
static void PurgeList();
};

View File

@ -0,0 +1,55 @@
// Copyright 2022 The Tool Shed (Chris Garnier)
using UnrealBuildTool;
public class RecentBlueprintMenu : ModuleRules
{
public RecentBlueprintMenu(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"UnrealEd",
"EditorStyle"
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}