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; +};