Added more UE4 blueprint support

Added blueprint support for JoinRequest() and Respond, added latent
blueprint node for getting Discord profile images
This commit is contained in:
cyberblaststudios
2017-11-19 19:29:39 -06:00
parent 49b7703334
commit 48850065ee
3 changed files with 251 additions and 75 deletions

View File

@@ -1,7 +1,7 @@
#include "DiscordRpcBlueprint.h"
#include "Blueprint/AsyncTaskDownloadImage.h"
#include "discord-rpc.h"
DEFINE_LOG_CATEGORY(Discord)
@@ -53,6 +53,29 @@ static void SpectateGameHandler(const char* spectateSecret)
}
}
static void JoinRequestReceiveHandler(const DiscordJoinRequest* joinRequestPayload)
{
if (!joinRequestPayload)
{
UE_LOG(Discord, Log, TEXT("received invalid Discord join request payload"));
return;
}
// wrap the payload with USTRUCT
FDiscordJoinRequestPayload payloadContainer(joinRequestPayload);
UE_LOG(Discord, Log, TEXT("Discord join request from username: %s, UserID: %s, Avatar: %s"), *payloadContainer.Username,
*payloadContainer.UserID,
*payloadContainer.Avatar);
if (self) {
// add to pending requests map
self->PendingJoinRequests.Add(payloadContainer.UserID, payloadContainer);
self->OnJoinRequest.Broadcast(payloadContainer);
}
}
void UDiscordRpc::Initialize(const FString& applicationId,
bool autoRegister,
const FString& optionalSteamId)
@@ -63,6 +86,10 @@ void UDiscordRpc::Initialize(const FString& applicationId,
handlers.ready = ReadyHandler;
handlers.disconnected = DisconnectHandler;
handlers.errored = ErroredHandler;
if (OnJoinRequest.IsBound())
{
handlers.joinRequest = JoinRequestReceiveHandler;
}
if (OnJoin.IsBound()) {
handlers.joinGame = JoinGameHandler;
}
@@ -128,3 +155,65 @@ void UDiscordRpc::UpdatePresence()
Discord_UpdatePresence(&rp);
}
void UDiscordRpc::RespondToDiscordJoinRequest(FString DiscordUserID, EDiscordJoinRequestResponse response)
{
// send the response to discord
Discord_Respond(TCHAR_TO_ANSI(*DiscordUserID), static_cast<int>(response));
// remove userID entry from current join requests map
PendingJoinRequests.FindAndRemoveChecked(DiscordUserID);
}
UAsyncDiscordFetchAvatar::UAsyncDiscordFetchAvatar(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
if (HasAnyFlags(RF_ClassDefaultObject) == false)
{
AddToRoot();
}
}
UAsyncDiscordFetchAvatar* UAsyncDiscordFetchAvatar::DiscordFetchAvatar(FString UserID, FString Avatar)
{
FString userProfileUrl = FString("http://cdn.discordapp.com/avatars/") + UserID + FString("/") + Avatar + FString(".jpg?size=512");
UE_LOG(Discord, Log, TEXT("Pulling Discord profile avatar image from %s"), *userProfileUrl);
// create the download image async task
UAsyncTaskDownloadImage* asyncImageDl = UAsyncTaskDownloadImage::DownloadImage(userProfileUrl);
UAsyncDiscordFetchAvatar* fetchAsyncTask = NewObject<UAsyncDiscordFetchAvatar>();
if (fetchAsyncTask)
{
fetchAsyncTask->BindDelegates(asyncImageDl);
fetchAsyncTask->ImageTask = asyncImageDl;
}
return fetchAsyncTask;
}
void UAsyncDiscordFetchAvatar::BindDelegates(UAsyncTaskDownloadImage* imageTask)
{
if (imageTask)
{
imageTask->OnSuccess.AddDynamic(this, &UAsyncDiscordFetchAvatar::OnImageDownloadSuccess);
imageTask->OnFail.AddDynamic(this, &UAsyncDiscordFetchAvatar::OnImageDownloadFailed);
}
}
void UAsyncDiscordFetchAvatar::OnImageDownloadSuccess(UTexture2DDynamic* texture)
{
Successful.Broadcast(texture, UserID);
RemoveFromRoot();
}
void UAsyncDiscordFetchAvatar::OnImageDownloadFailed(UTexture2DDynamic* texture)
{
Failed.Broadcast(texture, UserID);
RemoveFromRoot();
}

View File

@@ -3,19 +3,57 @@
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "discord-rpc.h"
#include "DiscordRpcBlueprint.generated.h"
#include "Engine.h"
// unreal's header tool hates clang-format
// clang-format off
DECLARE_LOG_CATEGORY_EXTERN(Discord, Log, All);
USTRUCT(BlueprintType)
struct FDiscordJoinRequestPayload
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite)
FString UserID;
UPROPERTY(BlueprintReadWrite)
FString Username;
UPROPERTY(BlueprintReadWrite)
FString Avatar;
FDiscordJoinRequestPayload()
{
}
FDiscordJoinRequestPayload(const DiscordJoinRequest* request)
{
if (request)
{
UserID = FString(ANSI_TO_TCHAR(request->userId));
Username = FString(ANSI_TO_TCHAR(request->username));
Avatar = FString(ANSI_TO_TCHAR(request->avatar));
}
}
};
UENUM(BlueprintType)
enum class EDiscordJoinRequestResponse : uint8
{
DJR_NO = DISCORD_REPLY_NO UMETA(DisplayName = "Yes"),
DJR_YES = DISCORD_REPLY_YES UMETA(DisplayName = "No"),
DJR_IGNORE = DISCORD_REPLY_IGNORE UMETA(DisplayName = "Ignore")
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDiscordConnected);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordDisconnected, int, errorCode, const FString&, errorMessage);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordErrored, int, errorCode, const FString&, errorMessage);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordJoin, const FString&, joinSecret);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordSpectate, const FString&, spectateSecret);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordJoinRequest, FDiscordJoinRequestPayload, request);
// clang-format on
@@ -114,6 +152,12 @@ public:
Category = "Discord")
FDiscordJoin OnJoin;
// when a user presses ask to join, this will trigger on the user that is getting the request
UPROPERTY(BlueprintAssignable,
meta = (DisplayName = "When Discord user presses Ask to join, this will be called on the client requested", Keywords = "Discord rpc"),
Category = "Discord")
FDiscordJoinRequest OnJoinRequest;
UPROPERTY(BlueprintAssignable,
meta = (DisplayName = "When Discord user presses spectate", Keywords = "Discord rpc"),
Category = "Discord")
@@ -123,4 +167,46 @@ public:
meta = (DisplayName = "Rich presence info", Keywords = "Discord rpc"),
Category = "Discord")
FDiscordRichPresence RichPresence;
/** This map stores all of the current pending join requests*/
UPROPERTY(BlueprintReadOnly, meta = (Keywords = "Discord rpc"), Category = "Discord")
TMap<FString, FDiscordJoinRequestPayload> PendingJoinRequests;
UFUNCTION(BlueprintCallable, meta = (Keywords = "Discord rpc"), Category = "Discord")
void RespondToDiscordJoinRequest(FString DiscordUserID, EDiscordJoinRequestResponse response);
};
class UTexture2DDynamic;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordFetchAvatarCompleted, UTexture2DDynamic*, Texture, FString, UserID);
UCLASS()
class DISCORDRPC_API UAsyncDiscordFetchAvatar : public UBlueprintAsyncActionBase
{
GENERATED_UCLASS_BODY()
public:
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", Keywords = "Discord rpc"), Category = "Discord")
static UAsyncDiscordFetchAvatar* DiscordFetchAvatar(FString UserID, FString Avatar);
UFUNCTION()
void BindDelegates(UAsyncTaskDownloadImage* imageTask);
UPROPERTY(BlueprintAssignable)
FDiscordFetchAvatarCompleted Successful;
UPROPERTY(BlueprintAssignable)
FDiscordFetchAvatarCompleted Failed;
UPROPERTY()
UAsyncTaskDownloadImage* ImageTask;
UPROPERTY()
FString UserID;
UFUNCTION()
void OnImageDownloadSuccess(UTexture2DDynamic* texture);
UFUNCTION()
void OnImageDownloadFailed(UTexture2DDynamic* texture);
};

View File

@@ -41,7 +41,8 @@ public class discordrpc : ModuleRules
"SlateCore",
"Core",
"discordrpcLibrary",
"Projects"
"Projects",
"UMG"
// ... add other public dependencies that you statically link with here ...
}
);