Feedback via Discord in UE4
You can just download the class here if you're lazy. mbpfl.h and mbpfl.cpp
- Create a BlueprintFunctionLibrary class in C++ and add these includes and defines.
#if PLATFORM_WINDOWS #include "Windows/WindowsPlatformMisc.h" #elif PLATFORM_LINUX #include "Linux/LinuxPlatformMisc.h" #elif PLATFORM_MAC #include "Mac/MacPlatformMisc.h" #endif
#include “GameFramework/GameUserSettings.h”
#define BUG_REPORT_WEBHOOK_URL “YOURWEBHOOKURLHERE” #define MYGAME_VERSION “v1.0-pre-alpha” #define DEFAULT_ICON_URL “https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"
- Add the following enums and structs to the header.
UENUM(BlueprintType) enum class EBugReportCategory : uint8 { Map, Weapon, Other };
UENUM(BlueprintType) enum class EBugReportPriority : uint8 { Crash, High, Med, Low };
USTRUCT() struct FDiscordMessageField { GENERATED_BODY()
UPROPERTY() FString name; UPROPERTY() FString value; UPROPERTY() bool binline;
};
USTRUCT() struct FDiscordMessageEmbedAuthor { GENERATED_BODY()
UPROPERTY() FString name; UPROPERTY() FString url; UPROPERTY() FString icon_url; FDiscordMessageEmbedAuthor() : url("https://trdwll.com"), icon_url(DEFAULT_ICON_URL) {}
};
USTRUCT() struct FDiscordMessageEmbedFooter { GENERATED_BODY()
UPROPERTY() FString text; UPROPERTY() FString icon_url; FDiscordMessageEmbedFooter() : icon_url(DEFAULT_ICON_URL) {}
};
USTRUCT() struct FDiscordMessageEmbed { GENERATED_BODY()
UPROPERTY() FString title; UPROPERTY() FString description; UPROPERTY() uint32 color; UPROPERTY() TArray<FDiscordMessageField> fields; UPROPERTY() FDiscordMessageEmbedAuthor author; UPROPERTY() FDiscordMessageEmbedFooter footer; UPROPERTY() FString timestamp; FDiscordMessageEmbed() : color(720640), timestamp(FDateTime::Now().ToIso8601()) {} uint32 GetColor(const EBugReportPriority Priority) { switch (Priority) { case EBugReportPriority::Crash: return 16711680; case EBugReportPriority::High: return 12389388; case EBugReportPriority::Med: return 16742912; default: case EBugReportPriority::Low: return 720640; } }
};
USTRUCT() struct FDiscordMessage { GENERATED_BODY()
UPROPERTY() FString username; UPROPERTY() FString avatar_url; UPROPERTY() FString content; UPROPERTY() TArray<FDiscordMessageEmbed> embeds; FDiscordMessage() : avatar_url(DEFAULT_ICON_URL) {}
};
USTRUCT(BlueprintType) struct FBugReportUserData { GENERATED_BODY()
UPROPERTY(BlueprintReadWrite) FString Author; UPROPERTY(BlueprintReadWrite) FVector Location; UPROPERTY(BlueprintReadWrite) FString MapName; UPROPERTY(BlueprintReadWrite) FString Message;
};
- Add the following to your header file.
// Thanks to Rama for this method // GetEnumValueAsString<EEnumType>("EEnumType", Value); template<typename TEnum> static FString GetEnumValueAsString(const FString& Name, TEnum Value) { const UEnum* enumPtr = FindObject<UEnum>(ANY_PACKAGE, *Name, true); if (!enumPtr) { return FString("Invalid"); } return enumPtr->GetNameByValue((int64)Value).ToString(); }
UFUNCTION(BlueprintCallable, Category = "Discord") static void SubmitBugReport(const EBugReportCategory Category, const EBugReportPriority Priority, const FBugReportUserData& AuthorData, FString& ReportID, bool bIncludeSpecs = true); /** * Gets the number of RAM on the system */ UFUNCTION(BlueprintPure) static FORCEINLINE int32 GetTotalRAM() { const FPlatformMemoryConstants& MemoryConstants = FPlatformMemory::GetConstants(); return MemoryConstants.TotalPhysicalGB; } UFUNCTION(BlueprintPure) static FString GetGameResolution() { return *FString::Printf(TEXT("%dx%d"), UGameUserSettings::GetGameUserSettings()->GetScreenResolution().X, UGameUserSettings::GetGameUserSettings()->GetScreenResolution().Y); } /** * Gets the CPU Brand Name information. */ UFUNCTION(BlueprintPure) static FString GetCPUBrandName() {
#if PLATFORM_WINDOWS return FWindowsPlatformMisc::GetCPUBrand(); #elif PLATFORM_LINUX return FLinuxPlatformMisc::GetCPUBrand(); #elif PLATFORM_MAC return FMacPlatformMisc::GetCPUBrand(); #endif }
/** * Gets the CPU Vendor Name information. */ UFUNCTION(BlueprintPure) static FString GetCPUVendorName() {
#if PLATFORM_WINDOWS return FWindowsPlatformMisc::GetCPUVendor(); #elif PLATFORM_LINUX return FLinuxPlatformMisc::GetCPUVendor(); #elif PLATFORM_MAC return FMacPlatformMisc::GetCPUVendor(); #endif }
/** * Gets the GPU Brand Name information. */ UFUNCTION(BlueprintPure) static FString GetGPUBrandName() {
#if PLATFORM_WINDOWS return FWindowsPlatformMisc::GetPrimaryGPUBrand(); #elif PLATFORM_LINUX return FLinuxPlatformMisc::GetPrimaryGPUBrand(); #elif PLATFORM_MAC return FMacPlatformMisc::GetPrimaryGPUBrand(); #endif }
/** * Gets the GPU Driver information. */ UFUNCTION(BlueprintPure) static FORCEINLINE FString GetGPUDriverInfo() { return GRHIAdapterUserDriverVersion; }</code></pre>
In your BPFL source file add includes.
#include "Http.h" #include "Interfaces/IHttpRequest.h" #include "JsonObjectConverter.h"
- The implementation for
SubmitBugReport
.void UMBPFL::SubmitBugReport(const EBugReportCategory Category, const EBugReportPriority Priority, const FBugReportUserData& AuthorData, FString& ReportID, bool bIncludeSpecs) { // Just some quick checks to prevent spamming if (AuthorData.Author == "" || AuthorData.MapName == "" || AuthorData.Message == "") { return; }
if (FHttpModule* http = &FHttpModule::Get()) { TSharedRef<IHttpRequest> request = http->CreateRequest(); request->SetVerb("POST"); request->SetHeader("Content-Type", "application/json"); request->SetURL(BUG_REPORT_WEBHOOK_URL); ReportID = FGuid::NewGuid().ToString(); // Create the embed for the report FDiscordMessageEmbed embed; embed.title = GetEnumValueAsString<EBugReportCategory>("EBugReportCategory", Category); embed.author.icon_url = ""; embed.author.name = AuthorData.Author; embed.description = AuthorData.Message; embed.color = embed.GetColor(Priority); embed.fields.Add({ "Priority", GetEnumValueAsString<EBugReportPriority>("EBugReportPriority", Priority) }); embed.fields.Add({ "Location", AuthorData.Location.ToString(), true }); embed.fields.Add({ "Map", AuthorData.MapName, true }); embed.footer.text = FString::Printf(TEXT("MYGame %s | %s"), *FString(MYGAME_VERSION), *ReportID); FDiscordMessage data; data.username = "Bug Reporter"; data.embeds.Add(embed); // Don't show "private" information unless the player wants to if (bIncludeSpecs) { // Create another embed for the users pc specs FDiscordMessageEmbed embed2; embed2.title = FString::Printf(TEXT("%s PC Specs"), *AuthorData.Author); embed2.color = embed.GetColor(Priority); embed2.fields.Add({ "Resolution", GetGameResolution(), true }); embed2.fields.Add({ "RAM", FString::Printf(TEXT("%dGB"), GetTotalRAM()), true }); embed2.fields.Add({ "CPU", GetCPUBrandName(), true }); embed2.fields.Add({ "GPU", GetGPUBrandName(), true }); embed2.fields.Add({ "GPU Driver", GetGPUDriverInfo(), true }); data.embeds.Add(embed2); } FString OutputString; FJsonObjectConverter::UStructToJsonObjectString(data, OutputString); OutputString = OutputString.Replace(TEXT("binline"), TEXT("inline")); request->SetContentAsString(OutputString); request->ProcessRequest(); }
}
- Add
"Http", "Json", "JsonUtilities", "RHI"
to your Project.Build.cs under PublicDependencyModuleNames. - Head on over to your discord server Server Settings -> Integrations -> Create Webhook. Then replace the URL for BUG_REPORT_WEBHOOK_URL with the one it gives you.