My current goal is to create an editor for displaying debugging information. The editor itself by default supports certain categories like AI, Navigation and Perception and I wish to extend those to display my own subsystems.
I took the AIModule as an example of how to extend the gameplay debugger system, so excuse me for that mess, but for some reason I can’t get around a LNK2020/2019 error; “unresolved external symbol “public: __cdecl FVisualLoggerExtension::FVisualLoggerExtension(void)” (??0FVisualLoggerExtension@@QEAA@XZ) referenced in function InitializeModule”
The error I’m getting only occurs when I am attempting to use the “FVisualLoggerExtension” class from my editor module. My first thought was that I had to include a dependency but it doesn’t make any difference so far.
I am very confused why this is happening and I hope someone could tell me what the problem is or if I’m actually missing a dependency?
For reference I am adding source code of the current state.
GameCoreEditor.Build.cs
using System.IO;
using UnrealBuildTool;
public class GameCoreEditor : ModuleRules
{
public GameCoreEditor(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
OptimizeCode = CodeOptimization.InShippingBuildsOnly;
IncludeSubDirectoriesRecursive(ModuleDirectory + "\\Private", true);
IncludeSubDirectoriesRecursive(ModuleDirectory + "\\Public", false);
PrivateDependencyModuleNames.AddRange(new string[] {
"Engine",
"Core",
"CoreUObject",
"ApplicationCore",
"AIModule",
"AssetTools",
"PropertyEditor",
"LevelEditor",
"DetailCustomizations",
});
PublicDependencyModuleNames.AddRange(new string[] {
"Engine",
"Core",
"CoreUObject",
"ApplicationCore",
"AIModule",
"AssetTools",
"PropertyEditor",
"LevelEditor",
"DetailCustomizations",
"GameCore",
});
if (Target.bBuildEditor == true) {
PrivateDependencyModuleNames.Add("UnrealEd");
}
if (Target.bBuildDeveloperTools || (Target.Configuration != UnrealTargetConfiguration.Shipping && Target.Configuration != UnrealTargetConfiguration.Test)) {
PrivateDependencyModuleNames.Add("GameplayDebugger");
PublicDefinitions.Add("WITH_GAMEPLAY_DEBUGGER=1");
}
else {
PublicDefinitions.Add("WITH_GAMEPLAY_DEBUGGER=0");
}
}
private void IncludeSubDirectoriesRecursive(string DirectoryPathToSearch, bool bIsPrivate) {
foreach (string DirectoryPath in Directory.GetDirectories(DirectoryPathToSearch)) {
if (bIsPrivate) {
PrivateIncludePaths.Add(DirectoryPath);
}
else {
PublicIncludePaths.Add(DirectoryPath);
}
IncludeSubDirectoriesRecursive(DirectoryPath, bIsPrivate);
}
}
}
GameCoreEditor.h
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#if WITH_EDITOR
#include "Developer/AssetTools/Public/AssetTypeCategories.h"
#endif // WITH_EDITOR
class IGameCoreEditorModule : public IModuleInterface {
public:
static inline IGameCoreEditorModule& Get() {
return FModuleManager::LoadModuleChecked<IGameCoreEditorModule>("GameCoreEditor");
}
static inline bool IsAvailable() {
return FModuleManager::Get().IsModuleLoaded("GameCoreEditor");
}
#if WITH_EDITOR
virtual EAssetTypeCategories::Type GetEcoSAssetCategoryBit() const = 0;
#endif // WITH_EDITOR
};
GameCoreEditor.cpp
#include "GameCoreEditor.h"
#include "AIModule.h"
#include "EngineDefines.h"
#include "Templates/SubclassOf.h"
#include "AISystem.h"
#include "VisualLogger/VisualLogger.h"
#include "GameFramework/WorldSettings.h"
#include "DefaultManagerInstanceTracker.h"
#if WITH_EDITOR
#include "Developer/AssetTools/Public/IAssetTools.h"
#include "Developer/AssetTools/Public/AssetToolsModule.h"
#if ENABLE_VISUAL_LOG
#include "VisualLoggerExtension.h"
#endif // ENABLE_VISUAL_LOG
#endif // WITH_EDITOR
#if WITH_GAMEPLAY_DEBUGGER
#include "GameplayDebugger.h"
#include "DebuggerCategory_EcoSubsystem.h"
#endif // WITH_GAMEPLAY_DEBUGGER
#define LOCTEXT_NAMESPACE "GameCoreEditor"
DEFINE_LOG_CATEGORY_STATIC(GameCoreEditor, Log, All);
//DEFINE_LOG_CATEGORY(LogManagerInstanceTracker);
class FGameCoreEditorModule : public IGameCoreEditorModule {
// Begin IModuleInterface
virtual void StartupModule() override;
virtual void ShutdownModule() override;
// End IModuleInterface
#if WITH_EDITOR
virtual EAssetTypeCategories::Type GetEcoSAssetCategoryBit() const override { return EcoSAssetCategoryBit; }
protected:
EAssetTypeCategories::Type EcoSAssetCategoryBit;
#if ENABLE_VISUAL_LOG
FVisualLoggerExtension VisualLoggerExtension;
#endif // ENABLE_VISUAL_LOG
#endif // WITH_EDITOR
};
IMPLEMENT_MODULE(FGameCoreEditorModule, GameCoreEditor)
void FGameCoreEditorModule::StartupModule() {
#if WITH_EDITOR
if (GIsEditor) {
// Register asset types
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
//EcoSAssetCategoryBit = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("EcoSubsystem")), LOCTEXT("AIAssetCategory", "Artificial Intelligence"));
EcoSAssetCategoryBit = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("EcoSubsystem")), FText::FromString("EcoSubsystem"));
}
#endif // WITH_EDITOR
#if WITH_EDITOR && ENABLE_VISUAL_LOG
FVisualLogger::Get().RegisterExtension(*EVisLogTags::TAG_EQS, &VisualLoggerExtension);
#endif
#if WITH_GAMEPLAY_DEBUGGER
IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get();
GameplayDebuggerModule.RegisterCategory("EcoSubsystem", IGameplayDebugger::FOnGetCategory::CreateStatic(&FGameplayDebuggerCategory_EcoSubsystem::MakeInstance), EGameplayDebuggerCategoryState::EnabledInGameAndSimulate, 1);
GameplayDebuggerModule.NotifyCategoriesChanged();
#endif
}
void FGameCoreEditorModule::ShutdownModule() {
#if WITH_EDITOR && ENABLE_VISUAL_LOG
FVisualLogger::Get().UnregisterExtension(*EVisLogTags::TAG_EQS, &VisualLoggerExtension);
#endif
#if WITH_GAMEPLAY_DEBUGGER
if (IGameplayDebugger::IsAvailable()) {
IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get();
GameplayDebuggerModule.UnregisterCategory("EcoSubsystem");
GameplayDebuggerModule.NotifyCategoriesChanged();
}
#endif
}
#undef LOCTEXT_NAMESPACE