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.
    #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"

     

  2. 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;
    
    

    };

  3. 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&amp; AuthorData, FString&amp; ReportID, bool bIncludeSpecs = true);
    
    
    
    /**
    
     * Gets the number of RAM on the system
    
     */
    
    UFUNCTION(BlueprintPure)
    
    static FORCEINLINE int32 GetTotalRAM()
    
    {
    
    	const FPlatformMemoryConstants&amp; MemoryConstants = FPlatformMemory::GetConstants();
    
    	return MemoryConstants.TotalPhysicalGB;
    
    }
    
    
    
    UFUNCTION(BlueprintPure)
    
    static FString GetGameResolution() { return *FString::Printf(TEXT("%dx%d"), UGameUserSettings::GetGameUserSettings()-&gt;GetScreenResolution().X, UGameUserSettings::GetGameUserSettings()-&gt;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>
    
    

     

  4. In your BPFL source file add includes.

  5. #include "Http.h"
    
    #include "Interfaces/IHttpRequest.h"
    
    #include "JsonObjectConverter.h"
  6. 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 = &amp;FHttpModule::Get())
    
    {
    
    	TSharedRef&lt;IHttpRequest&gt; request = http-&gt;CreateRequest();
    
    	request-&gt;SetVerb("POST");
    
    	request-&gt;SetHeader("Content-Type", "application/json");
    
    	request-&gt;SetURL(BUG_REPORT_WEBHOOK_URL);
    
    
    
    	ReportID = FGuid::NewGuid().ToString();
    
    
    
    	// Create the embed for the report
    
    	FDiscordMessageEmbed embed;
    
    	embed.title = GetEnumValueAsString&lt;EBugReportCategory&gt;("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&lt;EBugReportPriority&gt;("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-&gt;SetContentAsString(OutputString);
    
    	request-&gt;ProcessRequest();
    
    }
    
    

    }

  7. Add "Http", "Json", "JsonUtilities", "RHI" to your Project.Build.cs under PublicDependencyModuleNames.
  8. 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