Feedback via Discord in UE4

 

You can just download the class here if you’re lazy. mbpfl.h and mbpfl.cpp

 

  1. Create a BlueprintFunctionLibrary class in C++ and add these includes and defines.
C++
#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"

 

  1. Add the following enums and structs to the header.
C++
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;
};
  1. Add the following to your header file.
C++
 // 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; }

 

In your BPFL source file add includes.

C++
#include "Http.h"
#include "Interfaces/IHttpRequest.h"
#include "JsonObjectConverter.h"
  1. The implementation for SubmitBugReport.
C++
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();
    }
}
  1. Add "Http", "Json", "JsonUtilities", "RHI" to your Project.Build.cs under PublicDependencyModuleNames.
  2. 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.   until next time