Locating the Content Folder independently if it's a ProjectPlugin or an EnginePlugin

Guys, i have added icons for slate brushes on my plugin, but i have the following issue:

If i try to use
Style->SetContentRoot(FPaths::ProjectPluginsDir() / PATH_TO_MY_PLUGIN / “Content” / PATH_TO_MY_ICONS);

works well when the plugin is, well, a Project Plugin. If the user would download this from the Marketplace, i would have to change this to EnginePluginsDir() (AFAIK).
Given that users could use the plugin as a ProjectPlugin or a EnginePlugin… how would i be able to distinguish the correct path?

Could i just use a relative path from the file ITSELF? or do i have to use FPaths?.


Get the plugin module directory then append path to icons.

The way you it there will never work on packaged game.

“Content” folder won’t exist in that context.

Yeah but the Module is an Editor module, FPaths is used for checking some images for creating SlateBrushed via a Custom Editor style.
How would i get the plugin module directory though?

For Editor-only or runtime modules it’s pretty much the same process as you shouldn’t hardcode paths to resources in code.
I often do it like this on my Editor/Runtime modules:

class FMyStyle {
    static TSharedPtr<FSlateStyleSet> StyleSet;
    static FString InContent(const FString &RelativePath, const ANSICHAR* Extension);


    static FName GetStyleSetName();

    static const ISlateStyle& IGet();
    static TSharedPtr<ISlateStyle> Get();

#define PLUGIN_BRUSH(RelativePath,...) FSlateImageBrush(FMyStyle::InContent(RelativePath,".png"),__VA_ARGS__)

FString FMyStyle::InContent(const FString &RelativePath, const ANSICHAR* Extension) {

    static FString Content = IPluginManager::Get().FindPlugin(TEXT("MyPluginNamedInterface"))->GetContentDir();

    return (Content/RelativePath)+Extension;


FName FMyStyle::GetStyleSetName() {
    static FName StyleName(TEXT("MyStyle"));
    return StyleName;

void FMyStyle::Initialize() {

    if (StyleSet.IsValid()) {return;}

    const FVector2D Icon16x16(16.0f,16.0f);
    const FVector2D Icon128x128(128.0f,128.0f);

    StyleSet = MakeShareable(new FSlateStyleSet(GetStyleSetName()));

    StyleSet->Set("ClassIcon.MyObject", new PLUGIN_BRUSH(TEXT("Icons/MyIcon_16x"),Icon16x16));
    StyleSet->Set("ClassThumbnail.MyObject", new PLUGIN_BRUSH(TEXT("Icons/MyIcon_128x"),Icon128x128));



That works where “Icons/MyIcon_128x” is inside “MyPlugin\Content\Icons” folder; doesn’t really matter then if the plugin is in Marketplace Launcher or inside a project, or engine folder, etc.



The plugin manager finds the plugin using the name you set on your Module interface:

class IMyPlugin : public IModuleInterface {


    static inline IMyPlugin& Get() {
        return FModuleManager::LoadModuleChecked<IMyPlugin>("***MyPluginNamedInterface***");

    static inline bool IsAvailable() {
        return FModuleManager::Get().IsModuleLoaded("MyPluginNamedInterface");

I ended up solving it… what i was missing was the fact that IPluginManager Exists… so, instead of using FPaths to get the ProjectPlugin or EnginePlugin Directory, i simply had to do this.

FString ContentDir = IPluginManager::Get().FindPlugin(“PaperZD”)->GetBaseDir(); // <= THIS
Style->SetContentRoot(ContentDir / “Content” / “Editor” / “Slate”);

I’m finishing testing, but it all seems dandy so far.

P.S. Thanks Bruno, just read your response… was actually checking Paper2D and they use the ::InContent method too… going to modify my solution to be more in line with that.


A Question that i do have is the following:

Why would be needed to set the StyleSet content Directory like this:

And then on the ::InContent method do the same?

On Paper2D case it makes sense, because they set the content root to be on the EngineDirectory:

StyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT(“Editor/Slate”));

that is used by other stuff down the lines… not needed for the brush.

Thanks a lot, worked like charm.