From fc2976b13c60ef282d1027ed300fb84e9bfac693 Mon Sep 17 00:00:00 2001 From: Mike Seese Date: Thu, 7 Dec 2023 14:25:32 -0800 Subject: [PATCH 1/2] add initial support for AppV1 GetApps call --- .../Source/HathoraSDK/HathoraSDK.Build.cs | 2 +- .../Source/HathoraSDK/Private/HathoraSDK.cpp | 8 ++ .../HathoraSDK/Private/HathoraSDKAPI.cpp | 5 + .../HathoraSDK/Private/HathoraSDKAppV1.cpp | 101 +++++++++++++++++ .../Source/HathoraSDK/Public/HathoraSDK.h | 7 ++ .../Source/HathoraSDK/Public/HathoraSDKAPI.h | 2 + .../HathoraSDK/Public/HathoraSDKAppV1.h | 105 ++++++++++++++++++ 7 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAppV1.cpp create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAppV1.h diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/HathoraSDK.Build.cs b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/HathoraSDK.Build.cs index eb016d7..f72c601 100644 --- a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/HathoraSDK.Build.cs +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/HathoraSDK.Build.cs @@ -1,4 +1,4 @@ -// Copyright Epic Games, Inc. All Rights Reserved. +// Copyright 2023 Hathora, Inc. using UnrealBuildTool; diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDK.cpp b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDK.cpp index 092a531..b8de17e 100644 --- a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDK.cpp +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDK.cpp @@ -3,6 +3,7 @@ #include "HathoraSDK.h" #include "HathoraSDKModule.h" #include "HathoraSDKConfig.h" +#include "HathoraSDKAppV1.h" #include "HathoraSDKAuthV1.h" #include "HathoraSDKDiscoveryV1.h" #include "HathoraSDKLobbyV3.h" @@ -32,6 +33,7 @@ void UHathoraSDK::GetRegionalPings(const FHathoraOnGetRegionalPings& OnComplete, UHathoraSDK* UHathoraSDK::CreateHathoraSDK() { UHathoraSDK* SDK = NewObject(); + SDK->AppV1 = NewObject(); SDK->AuthV1 = NewObject(); SDK->DiscoveryV1 = NewObject(); SDK->LobbyV3 = NewObject(); @@ -129,6 +131,11 @@ void UHathoraSDK::SetAuthToken(FString Token) SetCredentials(Config->GetAppId(), Security); } +FString UHathoraSDK::GetAuthToken() +{ + return AuthV1->GetAuthToken(); +} + bool UHathoraSDK::IsLoggedIn() { return AuthV1->IsLoggedIn(); @@ -136,6 +143,7 @@ bool UHathoraSDK::IsLoggedIn() void UHathoraSDK::SetCredentials(FString AppId, FHathoraSDKSecurity Security) { + AppV1->SetCredentials(AppId, Security); AuthV1->SetCredentials(AppId, Security); DiscoveryV1->SetCredentials(AppId, Security); LobbyV3->SetCredentials(AppId, Security); diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAPI.cpp b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAPI.cpp index 34cdb40..c68721e 100644 --- a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAPI.cpp +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAPI.cpp @@ -19,6 +19,11 @@ void UHathoraSDKAPI::SetCredentials(FString InAppId, FHathoraSDKSecurity InSecur this->Security = InSecurity; } +FString UHathoraSDKAPI::GetAuthToken() +{ + return Security.AuthToken; +} + void UHathoraSDKAPI::SendRequest( FString Method, FString Endpoint, diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAppV1.cpp b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAppV1.cpp new file mode 100644 index 0000000..0afe013 --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Private/HathoraSDKAppV1.cpp @@ -0,0 +1,101 @@ +// Copyright 2023 Hathora, Inc. + +#include "HathoraSDKAppV1.h" +#include "HathoraSDKModule.h" +#include "HathoraSDK.h" +#include "Serialization/JsonSerializer.h" +#include "Dom/JsonObject.h" +#include "Misc/DateTime.h" + +FHathoraApplication UHathoraSDKAppV1::ParseApplication(TSharedPtr Object) +{ + FHathoraApplication Application; + + TSharedPtr DeletedBy = Object->TryGetField(TEXT("deletedBy")); + + Application.bDeleted = DeletedBy.IsValid() && !DeletedBy->IsNull(); + + if (Application.bDeleted) + { + Application.DeletedBy = DeletedBy->AsString(); + + FDateTime::ParseIso8601( + *Object->GetStringField(TEXT("deletedAt")), + Application.DeletedAt + ); + } + + FDateTime::ParseIso8601( + *Object->GetStringField(TEXT("createdAt")), + Application.CreatedAt + ); + + Application.CreatedBy = Object->GetStringField(TEXT("createdBy")); + Application.OrgId = Object->GetStringField(TEXT("orgId")); + + Application.AuthConfiguration.bGoogleEnabled = Object->HasField(TEXT("google")); + Application.AuthConfiguration.bNicknameEnabled = Object->HasField(TEXT("nickname")); + Application.AuthConfiguration.bAnonymousEnabled = Object->HasField(TEXT("anonymous")); + + if (Application.AuthConfiguration.bGoogleEnabled) + { + TSharedPtr Google = Object->GetObjectField(TEXT("google")); + Application.AuthConfiguration.Google.ClientId = Google->GetStringField(TEXT("clientId")); + } + + Application.AppSecret = Object->GetStringField(TEXT("appSecret")); + Application.AppId = Object->GetStringField(TEXT("appId")); + Application.AppName = Object->GetStringField(TEXT("appName")); + + // TODO: deployment? + + return Application; +} + +void UHathoraSDKAppV1::GetApps(FHathoraOnGetApps OnComplete) +{ + SendRequest( + TEXT("GET"), + TEXT("/apps/v1/list"), + [OnComplete](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bSuccess) mutable + { + FHathoraGetAppsResult Result; + if (bSuccess && Response.IsValid()) + { + Result.StatusCode = Response->GetResponseCode(); + FString Content = Response->GetContentAsString(); + + if (Result.StatusCode == 200) + { + TArray> OutArray; + TSharedRef> Reader = TJsonReaderFactory<>::Create(Content); + FJsonSerializer::Deserialize(Reader, OutArray); + + for (TSharedPtr Value : OutArray) + { + TSharedPtr Object = Value->AsObject(); + Result.Data.Add(ParseApplication(Object)); + } + } + else + { + Result.ErrorMessage = UHathoraSDK::ParseErrorMessage(Content); + } + } + else + { + Result.ErrorMessage = TEXT("[GetApps] Error: unknown error"); + } + + if (!Result.ErrorMessage.IsEmpty()) + { + UE_LOG(LogHathoraSDK, Error, TEXT("[GetApps] Error: %s"), *Result.ErrorMessage); + } + + if (!OnComplete.ExecuteIfBound(Result)) + { + UE_LOG(LogHathoraSDK, Warning, TEXT("[GetApps] function pointer was not valid, so OnComplete will not be called")); + } + } + ); +} diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDK.h b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDK.h index 310ffea..2fe5370 100644 --- a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDK.h +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDK.h @@ -8,6 +8,7 @@ #include "Kismet/BlueprintFunctionLibrary.h" #include "HathoraSDK.generated.h" +class UHathoraSDKAppV1; class UHathoraSDKAuthV1; class UHathoraSDKDiscoveryV1; class UHathoraSDKLobbyV3; @@ -53,9 +54,15 @@ class HATHORASDK_API UHathoraSDK : public UBlueprintFunctionLibrary UFUNCTION(BlueprintCallable, Category = "HathoraSDK") void SetAuthToken(FString Token); + UFUNCTION(BlueprintPure, Category = "HathoraSDK") + FString GetAuthToken(); + UFUNCTION(BlueprintPure, Category = "HathoraSDK") bool IsLoggedIn(); + UPROPERTY(BlueprintReadOnly, Category="HathoraSDK") + UHathoraSDKAppV1* AppV1; + UPROPERTY(BlueprintReadOnly, Category="HathoraSDK") UHathoraSDKAuthV1* AuthV1; diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAPI.h b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAPI.h index f271145..f97a78e 100644 --- a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAPI.h +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAPI.h @@ -18,6 +18,8 @@ class HATHORASDK_API UHathoraSDKAPI : public UBlueprintFunctionLibrary public: void SetCredentials(FString AppId, FHathoraSDKSecurity Security); + FString GetAuthToken(); + protected: void SendRequest( FString Method, diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAppV1.h b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAppV1.h new file mode 100644 index 0000000..dbde5ac --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDK/Public/HathoraSDKAppV1.h @@ -0,0 +1,105 @@ +// Copyright 2023 Hathora, Inc. + +#pragma once + +#include "CoreMinimal.h" +#include "HathoraSDKAPI.h" +#include "HathoraTypes.h" +#include "Misc/DateTime.h" +#include "HathoraSDKAppV1.generated.h" + +USTRUCT(BlueprintType) +struct FHathoraGoogleAuthConfiguration +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString ClientId; +}; + +USTRUCT(BlueprintType) +struct FHathoraApplicationAuthConfiguration +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadOnly, Category = "Default") + bool bGoogleEnabled = false; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + bool bNicknameEnabled = false; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + bool bAnonymousEnabled = false; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FHathoraGoogleAuthConfiguration Google; +}; + +USTRUCT(BlueprintType) +struct FHathoraApplication +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadOnly, Category = "Default") + bool bDeleted = false; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString DeletedBy; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FDateTime DeletedAt; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FDateTime CreatedAt; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString CreatedBy; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString OrgId; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FHathoraApplicationAuthConfiguration AuthConfiguration; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString AppSecret; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString AppId; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString AppName; + + // TODO: deployment? +}; + +USTRUCT(BlueprintType) +struct FHathoraGetAppsResult +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadOnly, Category = "Default") + int32 StatusCode = 0; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + FString ErrorMessage; + + UPROPERTY(BlueprintReadOnly, Category = "Default") + TArray Data; +}; + +UCLASS(BlueprintType) +class HATHORASDK_API UHathoraSDKAppV1 : public UHathoraSDKAPI +{ + GENERATED_BODY() + +public: + typedef TDelegate FHathoraOnGetApps; + + // Returns an unsorted list of your organization’s applications. + // An application is uniquely identified by an appId. + void GetApps(FHathoraOnGetApps OnComplete); + +private: + static FHathoraApplication ParseApplication(TSharedPtr Object); +}; From ce1a4a77bd9196655fb915f8944c14dbbd3bae9c Mon Sep 17 00:00:00 2001 From: Mike Seese Date: Thu, 7 Dec 2023 14:27:02 -0800 Subject: [PATCH 2/2] initial implementation of the plugin ui --- SDKDemo/Plugins/HathoraSDK/HathoraSDK.uplugin | 5 + .../HathoraSDKEditor.Build.cs | 54 ++++++ .../Private/HathoraSDKEditorModule.cpp | 60 +++++++ .../Private/SHathoraSDKWidget.cpp | 166 ++++++++++++++++++ .../Public/HathoraSDKEditorCommands.h | 32 ++++ .../Public/HathoraSDKEditorModule.h | 28 +++ .../Public/SHathoraSDKWidget.h | 35 ++++ 7 files changed, 380 insertions(+) create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/HathoraSDKEditor.Build.cs create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/HathoraSDKEditorModule.cpp create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/SHathoraSDKWidget.cpp create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorCommands.h create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorModule.h create mode 100644 SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/SHathoraSDKWidget.h diff --git a/SDKDemo/Plugins/HathoraSDK/HathoraSDK.uplugin b/SDKDemo/Plugins/HathoraSDK/HathoraSDK.uplugin index 849e722..a907a6a 100644 --- a/SDKDemo/Plugins/HathoraSDK/HathoraSDK.uplugin +++ b/SDKDemo/Plugins/HathoraSDK/HathoraSDK.uplugin @@ -19,6 +19,11 @@ "Name": "HathoraSDK", "Type": "Runtime", "LoadingPhase": "Default" + }, + { + "Name": "HathoraSDKEditor", + "Type": "Editor", + "LoadingPhase": "PostDefault" } ] } \ No newline at end of file diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/HathoraSDKEditor.Build.cs b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/HathoraSDKEditor.Build.cs new file mode 100644 index 0000000..b364d23 --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/HathoraSDKEditor.Build.cs @@ -0,0 +1,54 @@ +// Copyright 2023 Hathora, Inc. + +using UnrealBuildTool; + +public class HathoraSDKEditor : ModuleRules +{ + public HathoraSDKEditor(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + "WorkspaceMenuStructure", + "InputCore", + "HathoraSDK", + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/HathoraSDKEditorModule.cpp b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/HathoraSDKEditorModule.cpp new file mode 100644 index 0000000..904c248 --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/HathoraSDKEditorModule.cpp @@ -0,0 +1,60 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "HathoraSDKEditorModule.h" +#include "HathoraSDKEditorCommands.h" +#include "Framework/Docking/TabManager.h" +#include "Widgets/Docking/SDockTab.h" +#include "ToolMenus.h" +#include "WorkspaceMenuStructure.h" +#include "WorkspaceMenuStructureModule.h" +#include "SHathoraSDKWidget.h" + +#define LOCTEXT_NAMESPACE "FHathoraSDKEditorModule" + +DEFINE_LOG_CATEGORY(LogHathoraSDKEditorModule) +IMPLEMENT_MODULE(FHathoraSDKEditorModule, HathoraSDKEditorModule) + +FName FHathoraSDKEditorModule::TabNameOpenTab(TEXT("HathoraSDKOpenTab")); + +void FHathoraSDKEditorModule::StartupModule() +{ + FHathoraSDKEditorCommands::Register(); + + PluginCommands = MakeShareable(new FUICommandList); + + PluginCommands->MapAction( + FHathoraSDKEditorCommands::Get().OpenWindow, + FExecuteAction::CreateRaw(this, &FHathoraSDKEditorModule::ButtonClicked), + FCanExecuteAction() + ); + + FGlobalTabmanager::Get()->RegisterNomadTabSpawner(TabNameOpenTab,FOnSpawnTab::CreateRaw(this, &FHathoraSDKEditorModule::CreatePluginTab)) + .SetDisplayName(LOCTEXT("FHathoraSDKTabTitle", "Hathora SDK")) + .SetTooltipText(LOCTEXT("FHathoraSDKTooltipText", "Open the Hathora SDK development tools.")) + .SetGroup(WorkspaceMenu::GetMenuStructure().GetToolsCategory()); + +} + +void FHathoraSDKEditorModule::ShutdownModule() +{ + if (FSlateApplication::IsInitialized()) + { + FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(TabNameOpenTab); + } +} + +void FHathoraSDKEditorModule::ButtonClicked() +{ + FGlobalTabmanager::Get()->TryInvokeTab(TabNameOpenTab); +} + +TSharedRef FHathoraSDKEditorModule::CreatePluginTab(const FSpawnTabArgs& SpawnTabArgs) +{ + return SNew(SDockTab) + .TabRole(ETabRole::NomadTab) + [ + SNew(SHathoraSDKWidget) + ]; +} + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/SHathoraSDKWidget.cpp b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/SHathoraSDKWidget.cpp new file mode 100644 index 0000000..03206d9 --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Private/SHathoraSDKWidget.cpp @@ -0,0 +1,166 @@ +// Copyright 2023 Hathora, Inc. + +#include "SHathoraSDKWidget.h" +#include "HathoraSDK.h" +#include "HathoraSDKAppV1.h" +#include "SlateBasics.h" +#include "Styling/AppStyle.h" +#include "Widgets/Layout/SWidgetSwitcher.h" +#include "Widgets/Layout/SScaleBox.h" + +#define LOCTEXT_NAMESPACE "SHathoraSDKWidget" + +void SHathoraSDKWidget::Construct(const FArguments& InArgs) +{ + TSharedRef LoggedInWidget = SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Text(LOCTEXT("DeveloperTokenLabel", "Developer Token")) + ] + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SAssignNew(DeveloperTokenTextBox, SEditableTextBox) + .IsPassword(true) + ] + ] + // + SVerticalBox::Slot() + // .AutoHeight() + // [ + // SNew(SButton) + // .Text(LOCTEXT("LoggedInButtonText", "[Logged In] Log in with another account")) + // ] + ]; + + TSharedRef Applications = SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Text(LOCTEXT("ApplicationsLabel", "Target Application")) + ] + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SAssignNew(ApplicationComboBox, SApplicationComboBox) + .OptionsSource(&ApplicationsList) + .OnSelectionChanged(this, &SHathoraSDKWidget::ApplicationSelected) + .OnGenerateWidget(this, &SHathoraSDKWidget::GenerateApplicationComboBoxItem) + [ + SNew(SBox) + ] + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SButton) + .OnClicked(this, &SHathoraSDKWidget::RefreshApplications) + [ + SNew(SImage) + .Image(FAppStyle::GetBrush("GenericCommands.Redo")) + ] + ] + ] + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Text(LOCTEXT("ApplicationIdLabel", "AppId")) + ] + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SAssignNew(AppIdTextBlock, STextBlock) + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SButton) + [ + SNew(SImage) + .Image(FAppStyle::GetBrush("DataTableEditor.Copy.Small")) + ] + ] + ]; + + ChildSlot + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + [ + LoggedInWidget + ] + + SVerticalBox::Slot() + .AutoHeight() + [ + Applications + ] + ]; +} + +TSharedRef SHathoraSDKWidget::GenerateApplicationComboBoxItem(FHathoraApplicationPtr Item) const +{ + return SNew(STextBlock) + .Text(FText::FromString(Item->AppName)) + .Font(FCoreStyle::GetDefaultFontStyle("Regular", 16)); +} + +FReply SHathoraSDKWidget::RefreshApplications() +{ + UHathoraSDK* SDK = UHathoraSDK::CreateHathoraSDK(); + SDK->SetAuthToken(DeveloperTokenTextBox->GetText().ToString()); + if (SDK->IsLoggedIn()) + { + SDK->AppV1->GetApps( + UHathoraSDKAppV1::FHathoraOnGetApps::CreateLambda( + [this](const FHathoraGetAppsResult Result) + { + ApplicationsList.Empty(); + + if (!Result.ErrorMessage.IsEmpty()) + { + return; + } + + for (FHathoraApplication Application : Result.Data) + { + ApplicationsList.Add(MakeShareable(new FHathoraApplication(Application))); + } + + ApplicationComboBox->RefreshOptions(); + } + ) + ); + } + + return FReply::Handled(); +} + +void SHathoraSDKWidget::ApplicationSelected(FHathoraApplicationPtr ProposedSelection, ESelectInfo::Type SelectInfo) +{ + if (ProposedSelection.IsValid()) + { + AppIdTextBlock->SetText(FText::FromString(*ProposedSelection->AppId)); + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorCommands.h b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorCommands.h new file mode 100644 index 0000000..4c761cd --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorCommands.h @@ -0,0 +1,32 @@ +// Copyright 2023 Hathora, Inc. + +#pragma once + +#include "CoreMinimal.h" +#include "Framework/Commands/Commands.h" + +#define LOCTEXT_NAMESPACE "FHathoraSDKEditorCommands" + +class FHathoraSDKEditorCommands : public TCommands< FHathoraSDKEditorCommands > { +public: + FHathoraSDKEditorCommands() : + TCommands< FHathoraSDKEditorCommands >( + TEXT("HathoraSDK"), + FText::FromString("Hathora SDK"), + NAME_None, + "HathoraSDKEditorCommandsStyle" + ) {} + + TSharedPtr< FUICommandInfo > OpenWindow; + + virtual void RegisterCommands() override { + UI_COMMAND( + OpenWindow, + "HathoraSDK", + "Open the Hathora SDK window", + EUserInterfaceActionType::Button, + FInputChord()); + } +}; + +#undef LOCTEXT_NAMESPACE diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorModule.h b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorModule.h new file mode 100644 index 0000000..0925c66 --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/HathoraSDKEditorModule.h @@ -0,0 +1,28 @@ +// Copyright 2023 Hathora, Inc. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +class SDockTab; +class FSpawnTabArgs; + +DECLARE_LOG_CATEGORY_EXTERN(LogHathoraSDKEditorModule, Log, All) + +class FHathoraSDKEditorModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; + +private: + TSharedPtr PluginCommands; + + static FName TabNameOpenTab; + + void ButtonClicked(); + TSharedRef CreatePluginTab(const FSpawnTabArgs& SpawnTabArgs); +}; diff --git a/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/SHathoraSDKWidget.h b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/SHathoraSDKWidget.h new file mode 100644 index 0000000..e2315bd --- /dev/null +++ b/SDKDemo/Plugins/HathoraSDK/Source/HathoraSDKEditor/Public/SHathoraSDKWidget.h @@ -0,0 +1,35 @@ +// Copyright 2023 Hathora, Inc. + +#pragma once + +#include "CoreMinimal.h" +#include "Widgets/SCompoundWidget.h" +#include "HathoraSDKAppV1.h" +#include "Widgets/Input/SComboBox.h" +#include "Widgets/Input/SEditableTextBox.h" +// #include "Widgets/Layout/SGridPanel.h" + +class SHathoraSDKWidget : public SCompoundWidget +{ +public: + typedef TSharedPtr FHathoraApplicationPtr; + typedef SComboBox SApplicationComboBox; + + SLATE_BEGIN_ARGS(SHathoraSDKWidget) + { + } + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs); + +private: + TSharedRef GenerateApplicationComboBoxItem(FHathoraApplicationPtr Item) const; + void ApplicationSelected(FHathoraApplicationPtr ProposedSelection, ESelectInfo::Type SelectInfo); + + FReply RefreshApplications(); + + TSharedPtr DeveloperTokenTextBox; + TSharedPtr ApplicationComboBox; + TArray ApplicationsList; + TSharedPtr AppIdTextBlock; +};