Skip to content

Instantly share code, notes, and snippets.

@gothicserpent
Created June 10, 2026 14:55
Show Gist options
  • Select an option

  • Save gothicserpent/4fb0d0daf57785d258b891354e0cae1a to your computer and use it in GitHub Desktop.

Select an option

Save gothicserpent/4fb0d0daf57785d258b891354e0cae1a to your computer and use it in GitHub Desktop.
EditorDiscordRichPresence
// Copyright Epic Games, Inc. All Rights Reserved.
#include "EditorDiscordRichPresence.h"
#include "discord-files/discord.h"
#include "Runtime/Launch/Resources/Version.h"
#include "Runtime/Core/Public/Misc/App.h"
#if WITH_EDITOR
#include "UnrealEd.h"
//#include "Toolkits/AssetEditorToolkit.h"
//#include "AssetEditorSubsystem.h"
#include "Interfaces/IPluginManager.h"
#include "Framework/Application/SlateApplication.h"
#endif
//#include "Editor/StaticMeshEditor/Public/StaticMeshEditorModule.h"
//#include "Editor/EditorFramework/Public/Tools/Modes.h"
#include "Editor/EditorFramework/Public/EditorModes.h"
#include "EditorModeManager.h"
#include "SlateBasics.h"
#include "SlateExtras.h"
#include "Editor/LevelEditor/Public/LevelEditor.h"
#include "Modules/ModuleManager.h"
#define LOCTEXT_NAMESPACE "FEditorDiscordRichPresenceModule"
discord::Core* fcore{};
void FEditorDiscordRichPresenceModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
// Get the base directory of this plugin
#if WITH_EDITOR
//new
UAssetEditorSubsystem* AssetSubsystem = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
if (AssetSubsystem)
{
AssetSubsystem->OnAssetEditorRequestedOpen().AddRaw(this, &FEditorDiscordRichPresenceModule::NotifyAssetOpened);
}
//ULevelEditorSubsystem* LevelSubsystem = GEditor->GetLevelEd
/*
IStaticMeshEditorModule* StaticMeshEditorModule = &FModuleManager::LoadModuleChecked<IStaticMeshEditorModule>("StaticMeshEditor");
{
FAssetEditorManager::Get().OnAssetOpenedInEditor().AddRaw(this, &FEditorDiscordRichPresenceModule::NotifyAssetOpened);
}*/
//old
FString BaseDir = IPluginManager::Get().FindPlugin("EditorDiscordRichPresence")->GetBaseDir();
// Add on the relative location of the third party dll and load it
FString LibraryPath;
#if PLATFORM_WINDOWS
LibraryPath = FPaths::Combine(*BaseDir, TEXT("ThirdParty/Discord/x64/Release/discord_game_sdk.dll"));
DLLHandle = FPlatformProcess::GetDllHandle(*LibraryPath);
#endif // PLATFORM_WINDOWS
#endif
/*
Grab that Client ID from earlier
Discord.CreateFlags.Default will require Discord to be running for the game to work
If Discord is not running, it will:
1. Close your game
2. Open Discord
3. Attempt to re-open your game
Step 3 will fail when running directly from the Unreal Engine editor
Therefore, always keep Discord running during tests, or use Discord.CreateFlags.NoRequireDiscord*/
auto result = discord::Core::Create(1023921525285457950, DiscordCreateFlags_NoRequireDiscord, &fcore);
//discord::Activity activity{};
activity.SetType(discord::ActivityType::Playing);
//Get project name from project settings, if blank get it from FApp (module name?)
//FString ProjectName;
//get project name from project config
GConfig->GetString(
TEXT("/Script/EngineSettings.GeneralProjectSettings"),
TEXT("ProjectName"),
ProjectName,
GGameIni
);
//check if its blank and use FApp to get it
if (ProjectName.IsEmpty())
{
ProjectName = FApp::GetProjectName();
if (ProjectName.IsEmpty())
{
ProjectName = "Untitled Project";
}
}
//get engine version
//FString VersionNum = "Engine Version: ";
VersionNum.AppendInt(ENGINE_MAJOR_VERSION);
VersionNum.Append(".").AppendInt(ENGINE_MINOR_VERSION);
VersionNum.Append(".").AppendInt(ENGINE_PATCH_VERSION);
//combine with engine ver
ProjectName.Append(" | ");
ProjectName.Append(VersionNum);
//ini status
EditorStatus = "Level";
activity.SetDetails(TCHAR_TO_ANSI(*ProjectName));
activity.SetState(TCHAR_TO_ANSI(*EditorStatus));
discord::Timestamp time = FDateTime::UtcNow().ToUnixTimestamp();
activity.GetTimestamps().SetStart(time);
activity.GetAssets().SetLargeImage("ue5");
if (fcore)
{
fcore->ActivityManager().UpdateActivity(activity, [](discord::Result result) {});
}
else
{
UE_LOG(LogTemp, Log, TEXT("Discord Error: fcore is null"));
}
//Tick for Discord update
TickDelegate = FTickerDelegate::CreateRaw(this, &FEditorDiscordRichPresenceModule::Tick);
//TickDelegateHandle = FTicker::GetCoreTicker().AddTicker(TickDelegate);
FTSTicker::GetCoreTicker().AddTicker(TickDelegate);
//FSlateApplication* SApp = &FSlateApplication::Get();
//FText WTitle = SApp->GetActiveTopLevelRegularWindow()->GetTitle();
FSlateApplication::Get().OnApplicationActivationStateChanged().AddRaw(
this, &FEditorDiscordRichPresenceModule::OnWindowFocusChanged
);
//if (SApp)
//{
//FString WTitle = SApp->GetTitle().ToString();
//UE_LOG(LogTemp, Log, TEXT("ProjectName: %s"), *WTitle);
//}
//else
//{
//UE_LOG(LogTemp, Log, TEXT("ProjectName: NULL"));
//}
//del tests
FEditorDelegates::BeginPIE.AddRaw(this, &FEditorDiscordRichPresenceModule::PlayInEditorBegin);
FEditorDelegates::EndPIE.AddRaw(this, &FEditorDiscordRichPresenceModule::PlayInEditorEnd);
//FEditorDelegates::selec.AddRaw(this, &FEditorDiscordRichPresenceModule::EditorModeIDExit);
//FName ModName = TEXT("LevelEditor");
FLevelEditorModule& levelEditor = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
levelEditor.OnActorSelectionChanged().AddRaw(this, &FEditorDiscordRichPresenceModule::OnSelectionChanged);
//FEditorDelegates::EditorModeIDEnter.AddRaw(this, &FEditorDiscordRichPresenceModule::EditorModeIDExit);
//AssetSubsystem->OnEditorModeRegistered().AddRaw(this,&FEditorDiscordRichPresenceModule::EditorModeIDExit);
/*
FEditorModeInfo ModeInfo;
AssetSubsystem->FindEditorModeInfo(FBuiltinEditorModes::EM_Level, ModeInfo);
ModeInfo.*/
}
void FEditorDiscordRichPresenceModule::OnWindowFocusChanged(bool bIsFocused)
{
bHasFocus = bIsFocused;
if (!bHasFocus)
{
DestroyDiscordCore();
}
else
{
InitDiscordCore();
}
}
void FEditorDiscordRichPresenceModule::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.
#if WITH_EDITOR
//FTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);
FTSTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);
FPlatformProcess::FreeDllHandle(DLLHandle);
if (FSlateApplication::IsInitialized())
{
FSlateApplication::Get().OnApplicationActivationStateChanged().RemoveAll(this);
}
DestroyDiscordCore();
#endif
}
bool FEditorDiscordRichPresenceModule::Tick(float DeltaTime)
{
//FEditorDiscordRichPresenceModule::Update(DeltaTime);
//UpdateFocusedWindowStatus();
UpdateDiscordStatus();
FSlateApplication* SApp = &FSlateApplication::Get();
if (SApp)
{
//FText WTitle = SApp->GetActiveTopLevelRegularWindow()->;
//UE_LOG(LogTemp, Log, TEXT("ProjectName: %s"), *WTitle.ToString());
}
if (::fcore)
{
::fcore->RunCallbacks();
}
return true;
}
void FEditorDiscordRichPresenceModule::UpdateFocusedWindowStatus()
{
//FAssetEditorManager assetEditorManager = FAssetEditorManager::Get();
//TArray<UObject*> editedAssets = assetEditorManager.GetAllEditedAssets();
//TArray<IAssetEditorInstance*> openedEditors
//IAssetEditorInstance* focusedEditor = nullptr;
UAssetEditorSubsystem* AssetSubsystem = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
if (AssetSubsystem)
{
TArray<UObject*> editedAssets = AssetSubsystem->GetAllEditedAssets();
TArray<IAssetEditorInstance*> openedEditors;
for (UObject* editedAsset : editedAssets)
{
if (editedAsset)
{
openedEditors.Add(AssetSubsystem->FindEditorForAsset(editedAsset, false));
}
}
double maxLastActivationTime = 0.0;
for (IAssetEditorInstance* openedEditor : openedEditors)
{
if (openedEditor && openedEditor->GetLastActivationTime() > maxLastActivationTime)
{
maxLastActivationTime = openedEditor->GetLastActivationTime();
FocusedEditor = openedEditor;
//UE_LOG(LogTemp, Log, TEXT("Discord: %f"), maxLastActivationTime);
}
}
if (!FocusedEditor)
{
EditorStatus = "Level";
activity.SetState(TCHAR_TO_ANSI(*EditorStatus));
activity.GetAssets().SetLargeImage("editor");
//UE_LOG(LogTemp, Log, TEXT("Discord: %s"), *EditorStatus);
}
else if (FocusedEditor)
{
FString AssetNameWithType = GetAssetNameForEditor(FocusedEditor);
if (!AssetNameWithType.IsEmpty())
{
EditorStatus = AssetNameWithType;
}
else
{
EditorStatus = GetFriendlyEditorName(FocusedEditor->GetEditorName());
}
activity.GetAssets().SetLargeImage(TCHAR_TO_ANSI(*GetImageKey(FocusedEditor->GetEditorName())));
activity.SetState(TCHAR_TO_ANSI(*EditorStatus));
//UE_LOG(LogTemp, Log, TEXT("Discord: %s"), *EditorStatus);
}
else/* if(FocusedEditor && !GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_Level))*/
{
FEditorModeID EID = FBuiltinEditorModes::EM_Level;
if (GLevelEditorModeTools().IsOnlyVisibleActiveMode(FBuiltinEditorModes::EM_Default) && EditorStatus != "Level")
{
EditorStatus = "Level";
activity.SetState(TCHAR_TO_ANSI(*EditorStatus));/**/
}
}
//clear
FocusedEditor = nullptr;
//UE_LOG(LogTemp, Log, TEXT("Discord: %s"), *EditorStatus);
//update
if (fcore)
{
fcore->ActivityManager().UpdateActivity(activity, [](discord::Result result) {});
}
}
}
void FEditorDiscordRichPresenceModule::UpdateDiscordStatus()
{
if (bIsInPIE)
{
EditorStatus = "Playing In Editor";
activity.SetState(TCHAR_TO_ANSI(*EditorStatus));
if (fcore && bHasFocus)
fcore->ActivityManager().UpdateActivity(activity, [](discord::Result result) {});
return;
}
UAssetEditorSubsystem* AssetSubsystem = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
if (!AssetSubsystem) return;
TArray<UObject*> editedAssets = AssetSubsystem->GetAllEditedAssets();
// Find the most recently activated asset editor (excluding level editor)
IAssetEditorInstance* MostRecentEditor = nullptr;
double MostRecentTime = 0.0;
for (UObject* editedAsset : editedAssets)
{
if (!editedAsset) continue;
IAssetEditorInstance* Editor = AssetSubsystem->FindEditorForAsset(editedAsset, false);
if (!Editor) continue;
if (Editor->GetEditorName() == FName("LevelEditor")) continue;
if (Editor->GetLastActivationTime() > MostRecentTime)
{
MostRecentTime = Editor->GetLastActivationTime();
MostRecentEditor = Editor;
}
}
// Get level editor activation time via the level editor module directly
double LevelEditorTime = 0.0;
FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr<FLevelEditorModule>("LevelEditor");
if (LevelEditorModule)
{
TSharedPtr<ILevelEditor> LevelEditor = LevelEditorModule->GetFirstLevelEditor();
if (LevelEditor.IsValid())
{
TSharedPtr<SWindow> LevelEditorWindow = FSlateApplication::Get().FindWidgetWindow(LevelEditor->AsShared());
if (LevelEditorWindow.IsValid() && FSlateApplication::Get().GetActiveTopLevelRegularWindow() == LevelEditorWindow)
{
// Level editor window is the active window, give it a very high time
LevelEditorTime = FPlatformTime::Seconds();
}
}
}
// Whichever was activated most recently wins
if (MostRecentEditor && MostRecentTime > LevelEditorTime)
{
FString AssetNameWithType = GetAssetNameForEditor(MostRecentEditor);
EditorStatus = AssetNameWithType.IsEmpty()
? GetFriendlyEditorName(MostRecentEditor->GetEditorName())
: AssetNameWithType;
activity.GetAssets().SetLargeImage(TCHAR_TO_ANSI(*GetImageKey(MostRecentEditor->GetEditorName())));
}
else
{
FString LevelName = GetCurrentLevelName();
EditorStatus = LevelName.IsEmpty() ? FString("Level") : FString(TEXT("Level - ")) + LevelName;
activity.GetAssets().SetLargeImage("editor");
}
activity.SetState(TCHAR_TO_ANSI(*EditorStatus));
if (fcore && bHasFocus)
fcore->ActivityManager().UpdateActivity(activity, [](discord::Result result) {});
FocusedEditor = nullptr;
}
void FEditorDiscordRichPresenceModule::NotifyAssetOpened(UObject* Asset/*, IAssetEditorInstance* InInstance*/)
{
//UE_LOG(LogTemp, Warning, TEXT("Discord Asset opened"));
}
FString FEditorDiscordRichPresenceModule::GetAssetNameForEditor(IAssetEditorInstance* Editor)
{
if (!Editor)
{
return FString();
}
// Check if we're in the level editor
if (Editor->GetEditorName() == FName("LevelEditor"))
{
FString LevelName = GetCurrentLevelName();
if (!LevelName.IsEmpty())
{
return TEXT("Level") + FString(TEXT(" - ")) + LevelName;
}
return TEXT("Level");
}
UAssetEditorSubsystem* AssetSubsystem = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
if (!AssetSubsystem)
{
return FString();
}
TArray<UObject*> EditedAssets = AssetSubsystem->GetAllEditedAssets();
for (UObject* Asset : EditedAssets)
{
if (!Asset)
{
continue;
}
IAssetEditorInstance* AssetEditor = AssetSubsystem->FindEditorForAsset(Asset, false);
if (AssetEditor == Editor)
{
FString AssetType = GetAssetTypeDisplayName(Asset);
FString AssetName = Asset->GetName();
if (!AssetType.IsEmpty())
{
return AssetType + FString(TEXT(" - ")) + AssetName;
}
return AssetName;
}
}
return FString();
}
FString FEditorDiscordRichPresenceModule::GetFriendlyEditorName(FName EditorName)
{
FString FriendlyName = FName::NameToDisplayString(EditorName.ToString(), false);
FriendlyName.RemoveFromEnd(TEXT(" Editor"));
return FriendlyName;
}
FString FEditorDiscordRichPresenceModule::GetAssetTypeDisplayName(UObject* Asset)
{
if (!Asset)
{
return FString();
}
UClass* AssetClass = Asset->GetClass();
if (!AssetClass)
{
return FString();
}
FString ClassName = AssetClass->GetName();
// Map common asset class names to friendly display names
if (ClassName == TEXT("Blueprint_GeneratedClass") || ClassName == TEXT("BlueprintGeneratedClass"))
{
return TEXT("Blueprint");
}
else if (ClassName == TEXT("WidgetBlueprintGeneratedClass"))
{
return TEXT("Widget");
}
else if (ClassName == TEXT("AnimBlueprint"))
{
return TEXT("Animation");
}
else if (ClassName == TEXT("SkeletalMesh"))
{
return TEXT("Skeletal Mesh");
}
else if (ClassName == TEXT("StaticMesh"))
{
return TEXT("Static Mesh");
}
else if (ClassName == TEXT("Texture2D"))
{
return TEXT("Texture");
}
else if (ClassName == TEXT("Material"))
{
return TEXT("Material");
}
else if (ClassName == TEXT("MaterialFunction"))
{
return TEXT("Material Function");
}
else if (ClassName == TEXT("MaterialParameterCollection"))
{
return TEXT("Material Parameters");
}
else if (ClassName == TEXT("Skeleton"))
{
return TEXT("Skeleton");
}
else if (ClassName == TEXT("PhysicsAsset"))
{
return TEXT("Physics Asset");
}
else if (ClassName == TEXT("AnimMontage"))
{
return TEXT("Montage");
}
else if (ClassName == TEXT("AnimSequence"))
{
return TEXT("Animation Sequence");
}
else if (ClassName == TEXT("SoundCue"))
{
return TEXT("Sound Cue");
}
else if (ClassName == TEXT("SoundWave"))
{
return TEXT("Sound Wave");
}
else if (ClassName == TEXT("SoundClass"))
{
return TEXT("Sound Class");
}
else if (ClassName == TEXT("SoundSubmix"))
{
return TEXT("Sound Submix");
}
else if (ClassName == TEXT("Particle"))
{
return TEXT("Particle");
}
else if (ClassName == TEXT("NiagaraSystem"))
{
return TEXT("Niagara System");
}
else if (ClassName == TEXT("NiagaraEmitter"))
{
return TEXT("Niagara Emitter");
}
else if (ClassName == TEXT("DataTable"))
{
return TEXT("Data Table");
}
else if (ClassName == TEXT("CurveTable"))
{
return TEXT("Curve Table");
}
else if (ClassName == TEXT("Curve"))
{
return TEXT("Curve");
}
else if (ClassName == TEXT("LevelSequence"))
{
return TEXT("Sequence");
}
else if (ClassName == TEXT("MetaHuman"))
{
return TEXT("MetaHuman");
}
else if (ClassName == TEXT("Enum"))
{
return TEXT("Enum");
}
else if (ClassName == TEXT("Structure"))
{
return TEXT("Structure");
}
else if (ClassName == TEXT("Dialogue"))
{
return TEXT("Dialogue");
}
else if (ClassName == TEXT("DialogueVoice"))
{
return TEXT("Dialogue Voice");
}
else if (ClassName == TEXT("Converter") || ClassName == TEXT("AssetActionUtility"))
{
return TEXT("Utility");
}
else if (ClassName == TEXT("DM_DataModel"))
{
return TEXT("Data Model");
}
else if (ClassName.Contains(TEXT("Blueprint")))
{
return TEXT("Blueprint");
}
// Remove trailing 'Class' if present and return as-is
if (ClassName.EndsWith(TEXT("Class")))
{
ClassName.RemoveFromEnd(TEXT("Class"));
}
return ClassName;
}
FString FEditorDiscordRichPresenceModule::GetCurrentLevelName()
{
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
if (!EditorWorld)
{
return FString();
}
FString MapName = EditorWorld->GetMapName();
if (MapName.IsEmpty())
{
return FString();
}
// Extract just the map filename without the path
// MapName is typically "/Game/Maps/MyLevel"
if (MapName.StartsWith(TEXT("/Game/")))
{
MapName.RemoveFromStart(TEXT("/Game/Maps/"));
if (!MapName.Contains(TEXT("/")))
{
return MapName;
}
// If still contains path, take the last part
int32 LastSlash = MapName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd);
if (LastSlash != INDEX_NONE)
{
return MapName.Mid(LastSlash + 1);
}
}
return MapName;
}
void FEditorDiscordRichPresenceModule::PlayInEditorBegin(bool bIsSimulating)
{
PrePIEStatus = EditorStatus;
//bIsLevelEditor = false;
bIsInPIE = true;
//UE_LOG(LogTemp, Warning, TEXT("Discord BeginPIE"));
}
void FEditorDiscordRichPresenceModule::PlayInEditorEnd(bool bIsSimulating)
{
//bIsLevelEditor = true;
bIsInPIE = false;
//UE_LOG(LogTemp, Warning, TEXT("Discord EndPIE"));
}
void FEditorDiscordRichPresenceModule::OnSelectionChanged(const TArray<UObject*>& Selection, bool MyBool)
{
//LastActiveTime += 1;
bIsLevelEditor = true;
//UE_LOG(LogTemp, Warning, TEXT("Discord Selection changed"));
}
FString FEditorDiscordRichPresenceModule::GetImageKey(FName EditorName)
{
FString KeyResult = "default";
//blueprint
if (EditorName == FName("BlueprintEditor"))
{
KeyResult = "bp";
}
else if (EditorName == FName("AnimBlueprint") || EditorName == FName("AnimBlueprintEditor"))
{
KeyResult = "anim";
}
else if (EditorName == FName("WidgetBlueprintEditor"))
{
KeyResult = "ui";
}
else if (EditorName == FName("StaticMeshEditor"))
{
KeyResult = "mesh";
}
else if (EditorName == FName("SkeletalMeshEditor"))
{
KeyResult = "mesh";
}
else if (EditorName == FName("TextureEditor"))
{
KeyResult = "texture";
}
else if (EditorName == FName("MaterialEditor") || EditorName == FName("MaterialInstanceEditor"))
{
KeyResult = "mat";
}
else if (EditorName == FName("MaterialFunctionEditor"))
{
KeyResult = "mat";
}
else if (EditorName == FName("EnumEditor"))
{
KeyResult = "bp";
}
else if (EditorName == FName("SoundCueEditor") || EditorName == FName("SoundSubmixEditor") || EditorName == FName("SoundClassEditor"))
{
KeyResult = "sound";
}
else if (EditorName == FName("SoundWaveEditor"))
{
KeyResult = "sound";
}
else if (EditorName == FName("DataTableEditor") || EditorName == FName("CurveTableEditor"))
{
KeyResult = "data";
}
else if (EditorName == FName("CurveEditor"))
{
KeyResult = "curve";
}
else if (EditorName == FName("SequenceRecorderEditor") || EditorName == FName("LevelSequenceEditor"))
{
KeyResult = "sequence";
}
else if (EditorName == FName("NiagaraSystemEditor") || EditorName == FName("NiagaraEmitterEditor"))
{
KeyResult = "niagara";
}
else if (EditorName == FName("GenericAssetEditor"))
{
KeyResult = "default";
}
else if (EditorName == FName("SpriteEditor"))
{
KeyResult = "sprite";
}
else if (EditorName == FName("LevelEditor"))
{
KeyResult = "editor";
}
//UE_LOG(LogTemp, Warning, TEXT("DiscordRP: Set to %s for %s"), *KeyResult, *EditorName.ToString());
return KeyResult;
}
void FEditorDiscordRichPresenceModule::InitDiscordCore()
{
discord::Core::Create(1023921525285457950, DiscordCreateFlags_NoRequireDiscord, &fcore);
if (fcore)
{
fcore->ActivityManager().UpdateActivity(activity, [](discord::Result result) {});
}
}
void FEditorDiscordRichPresenceModule::DestroyDiscordCore()
{
if (fcore)
{
delete fcore;
fcore = nullptr;
}
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FEditorDiscordRichPresenceModule, EditorDiscordRichPresence)
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
//#include "Modules/ModuleManager.h"
#include "Containers/Ticker.h"
#include "discord-files/discord.h"
#if WITH_EDITORONLY_DATA
#include "Editor/EditorFramework/Public/EditorModes.h"
#include "Interfaces/IPluginManager.h"
#endif
class FEditorDiscordRichPresenceModule : public IModuleInterface
{
public:
FTickerDelegate TickDelegate;
//FDelegateHandle TickDelegateHandle;
FTSTicker::FDelegateHandle TickDelegateHandle;
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
virtual bool Tick(float DeltaTime);
void UpdateFocusedWindowStatus();
void UpdateDiscordStatus();
private:
/** Handle to the test dll we will load */
void* DLLHandle;
//strings
FString EditorStatus;
FString ProjectName;
FString VersionNum;
IAssetEditorInstance* FocusedEditor = nullptr;
double LastActiveTime = 0.0f;
bool bIsInPIE = false;
bool bIsLevelEditor = true;
FString PrePIEStatus;
void NotifyAssetOpened(UObject* Asset/*, IAssetEditorInstance* InInstance*/);
FString GetFriendlyEditorName(FName EditorName);
FString GetAssetTypeDisplayName(UObject* Asset);
FString GetCurrentLevelName();
//UFUNCTION()
void PlayInEditorBegin(bool bIsSimulating);
void PlayInEditorEnd(bool bIsSimulating);
void OnSelectionChanged(const TArray<UObject*>& Selection, bool MyBool);
FString GetImageKey(FName EditorName);
FString GetAssetNameForEditor(IAssetEditorInstance* Editor);
discord::Activity activity{};
bool bHasFocus = true;
void OnWindowFocusChanged(bool bIsFocused);
void InitDiscordCore();
void DestroyDiscordCore();
};
{
"FileVersion": 3,
"Version": 2,
"VersionName": "1.3.0",
"FriendlyName": "EditorDiscordRichPresence",
"Description": "Adds Discord Rich Presence to Unreal Editor. Windows only ATM.",
"Category": "Other",
"CreatedBy": "Dane Nurse",
"CreatedByURL": "https://bsky.app/profile/dn2.bsky.social",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": false,
"Installed": true,
"Modules": [
{
"Name": "EditorDiscordRichPresence",
"Type": "Editor",
"LoadingPhase": "PostEngineInit"
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment