Unresolved public when trying to create an editor plugin

I’m using UE4.27

Hi, I’m trying to create my own editor for dialogue in my game but I’ve run into a problem. I’m following this reference: Asset Editor

I have followed everything that is said but I still get an error saying I have unresolved public dependencies related to my AssetAction. This is the error:

Error        CompilerResultsLog          DialogueEditor.cpp.obj : error LNK2019: unresolved external symbol "public: __cdecl DialogueAssetAction::DialogueAssetAction(enum EAssetTypeCategories::Type)" (??0DialogueAssetAction@@QEAA@W4Type@EAssetTypeCategories@@@Z) referenced in function "public: virtual void __cdecl FDialogueEditorModule::StartupModule(void)" (?StartupModule@FDialogueEditorModule@@UEAAXXZ)
Error        CompilerResultsLog          C:\Users\Sarlack\Documents\Unreal Projects\RPGFrameworkV2\Plugins\DialogueEditor\Binaries\Win64\UE4Editor-DialogueEditor-0277.dll : fatal error LNK1120: 1 unresolved externals

Here’s the code:

AssetAction.h

#pragma once

#include "CoreMinimal.h"
#include "AssetTypeActions_Base.h"
#include "AssetTypeCategories.h"

class DialogueAssetAction : public FAssetTypeActions_Base {

public:
	DialogueAssetAction(EAssetTypeCategories::Type category);

public: // FAssetTypeActions_Base interface
	virtual FText GetName() const override;
	virtual FColor GetTypeColor() const override;
	virtual UClass* GetSupportedClass() const override;
	virtual void OpenAssetEditor(const TArray<UObject*>& inObjects, TSharedPtr<class IToolkitHost> editWithinLevelEditor = TSharedPtr<IToolkitHost>()) override;
	virtual uint32 GetCategories() override;

private:
	EAssetTypeCategories::Type _assetCategory;
};

AssetAction .cpp

#include "AssetTypeCategories.h"
#include "DialogueAssetAction.h"
#include "DialogueAsset.h"

DialogueAssetAction::DialogueAssetAction(EAssetTypeCategories::Type category) {
	_assetCategory = category;
}

FText DialogueAssetAction::GetName() const {
	return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_MyCustomAsset", "My Custom Asset");
}

FColor DialogueAssetAction::GetTypeColor() const {
	return FColor::Cyan;
}

UClass* DialogueAssetAction::GetSupportedClass() const {
	return UDialogueAsset::StaticClass();
}

void DialogueAssetAction::OpenAssetEditor(const TArray<UObject*>& inObjects, TSharedPtr<class IToolkitHost> editWithinLevelEditor) {
}

uint32 DialogueAssetAction::GetCategories() {
	return _assetCategory;
}

Editor.hpp

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class DialogueAssetAction;

class FDialogueEditorModule : public IModuleInterface
{
public:

	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};

Editor.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "DialogueEditor.h"

#include "IAssetTools.h"
#include "AssetToolsModule.h"
#include "DialogueAssetAction.h"

#define LOCTEXT_NAMESPACE "FDialogueEditorModule"


void FDialogueEditorModule::StartupModule()
{
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
	IAssetTools& assetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
	EAssetTypeCategories::Type assetType = assetToolsModule.RegisterAdvancedAssetCategory(FName(TEXT("CustomAssets")), LOCTEXT("CustomAssets", "Custom Assets"));
	TSharedPtr<DialogueAssetAction> customAssetAction = MakeShareable(new DialogueAssetAction(assetType));
	assetToolsModule.RegisterAssetTypeActions(customAssetAction.ToSharedRef());
}

void FDialogueEditorModule::ShutdownModule()
{
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
	// we call this function before unloading the module.
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FDialogueEditorModule, DialogueEditor)

Here are the build files:

Editor:

using UnrealBuildTool;

public class DialogueEditor : ModuleRules
{
	public DialogueEditor(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",
				"DialogueRuntime",
				"AssetTools",
				"UnrealEd",
				"PropertyEditor"
			}
		);
		
		
		DynamicallyLoadedModuleNames.AddRange(
			new string[]
			{
				// ... add any modules that your module loads dynamically here ...
			}
		);
	}
}

Runtime:

using UnrealBuildTool;

public class DialogueRuntime : ModuleRules
{
	public DialogueRuntime(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", "UnrealEd",
				// ... add other public dependencies that you statically link with here ...
			}
		);
			
		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"CoreUObject",
				"Engine",
				"Slate",
				"SlateCore",
				// ... add private dependencies that you statically link with here ...	
			}
		);
		
		
		DynamicallyLoadedModuleNames.AddRange(
			new string[]
			{
				// ... add any modules that your module loads dynamically here ...
			}
		);
	}
}

This is driving me nuts. I have tried everything, including all I can think of, changing the name of the constructor. Adding different things to the build.cs. Rebuilding the vs files. To my eyes, there should be nothing wrong. I don’t quite understand what the problem is. Why can’t the linker find the function?

Is DialogueAssetAction in that DialogueRuntime module? If so, you’re missing the DIALOGUERUNTIME_API macro on your class declaration of DialogueAssetAction.