// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #pragma once // Standard Library #include <functional> // GameKit #include "GameSaving/AwsGameKitGameSaving.h" #include "Models/AwsGameKitGameSavingModels.h" // Unreal #include "Containers/UnrealString.h" #include "GameFramework/Actor.h" #include "Widgets/Layout/SScrollBox.h" // Unreal forward declarations class SCheckBox; class SEditableTextBox; class SMultiLineEditableTextBox; #include "AwsGameKitGameSavingExamples.generated.h" // Last include (Unreal requirement) enum class InitializationStatus { NOT_STARTED, IN_PROGRESS, FAILED, SUCCESSFUL }; DECLARE_DELEGATE(ZeroParamDelegate); /** * This class demonstrates how to call the GameKit Game Saving APIs through C++ code. * * This Actor's Details Panel let's you call the GameKit Game Saving APIs against your deployed AWS resources (see AWS Command Center). * * The Output Log shows any errors that may occur (example: calling SaveGame() with a SlotName that's malformed). * Enable the Output Log in Unreal by selecting: Window -> Developer Tools -> Output Log * * Copy/paste snippets of the code into your own game in order to integrate your game with GameKit Game Saving. */ UCLASS(DisplayName = "AWS GameKit Game State Cloud Saving Examples") class AWSGAMEKITEDITOR_API AAwsGameKitGameSavingExamples : public AActor { GENERATED_BODY() public: AAwsGameKitGameSavingExamples(); virtual void Destroyed() override; virtual bool IsEditorOnly() const override; private: /** * The initialization status of the Game Saving library. * * This is static because the Game Saving library should only be initialized once in the lifetime of a running game. * * For example, it should only be initialized once, no matter how many AAwsGameKitGameSavingExamples Actors are created or destroyed. */ static InitializationStatus gameSavingInitializationStatus; /** * The most recent set of cached slots returned by any Game Saving API. * * This is an optimization for the LoadSlot() API. See OnLoadGameButtonClicked() for details. */ static FGameSavingSlots cachedSlotsCopy; // Initialization typedef void (AAwsGameKitGameSavingExamples::* OnButtonClickFromDetailsPanel)(void); typedef FReply(AAwsGameKitGameSavingExamples::* OnButtonClickFromPopupWindow)(void); void InitializeGameSavingLibrary(const OnButtonClickFromDetailsPanel postInitCallback, FString* postInitStatusCode); void InitializeGameSavingLibrary(const OnButtonClickFromPopupWindow postInitCallback, FString* postInitStatusCode); void InitializeGameSavingLibrary(const TFunction<void()> postInitCallback, FString* postInitStatusCode); void OnAddLocalSlotsComplete(const IntResult& result); void OnGetAllSlotSyncStatusesForInitializationComplete(const IntResult& result, const TArray<FGameSavingSlot>& cachedSlots); TFunction<void()> postInitializationCallback; FString* postInitializationStatusCode; bool IsIdentityDeployed() const; bool IsGameSavingDeployed() const; bool IsFeatureDeployed(FeatureType featureType, FString featureName) const; bool ReloadSettings(FeatureType featureType) const; // Utility Functions static FString GetSaveInfoFilePath(const FString& slotName); static FString GetResultMessage(unsigned int errorCode); // Popout Window UI TSharedRef<SVerticalBox> SlotToResultUI(const FGameSavingSlot& slot) const; TSharedPtr<SWindow> GetPopoutWindow(const FString& action, bool metadataShown, TSharedPtr<SEditableTextBox>& slotName, TSharedPtr<SCheckBox>& overrideBox, TSharedPtr<SEditableTextBox>& filePath, bool savingFile, TSharedPtr<SVerticalBox>& slotSection, const FString* statusCode, std::function<FReply()> handler); /* * GameKit APIs: */ // Identity Login API UFUNCTION(CallInEditor, Category = "1. Login") void CallLoginApi(); void OnLoginComplete(const IntResult& result); // Inputs UPROPERTY(Transient, EditInstanceOnly, Category = "1. Login", DisplayName = "User Name:") FString LoginUserName; UPROPERTY(Transient, EditInstanceOnly, Category = "1. Login", DisplayName = "Password:") FString LoginPassword; // Outputs UPROPERTY(Transient, VisibleInstanceOnly, Category = "1. Login", DisplayName = "Return Value:") FString LoginReturnValue; // GetAllSlotSyncStatuses API UFUNCTION(CallInEditor, Category = "2. Get All Game Save Statuses") void CallGetAllGameSaveStatusesApi(); void OnGetAllGameSaveStatusesComplete(const IntResult& result, const TArray<FGameSavingSlot>& cachedSlots); // Inputs // (none) // Outputs UPROPERTY(Transient, VisibleInstanceOnly, Category = "2. Get All Game Save Statuses", DisplayName = "Return Value:") FString GetAllSlotSyncStatusesReturnValue; UPROPERTY(Transient, VisibleInstanceOnly, Category = "2. Get All Game Save Statuses", DisplayName = "Response (Cached Saves):") TArray<FGameSavingSlot> GetAllSlotSyncStatusesResponseCachedSlots; // SaveSlot API UFUNCTION(CallInEditor, Category = "3. Save Game") void CallSaveApi(); FReply OnSaveGameButtonClicked(); void OnSaveGameComplete(const IntResult& result, const FGameSavingSlotActionResults& slotActionResults); // Popout Window TSharedPtr<SWindow> SaveSlotWindow; bool savePopoutOpen; // Inputs TSharedPtr<SEditableTextBox> SaveFromFileSlotName; TSharedPtr<SEditableTextBox> SaveFromFileMetadata; TSharedPtr<SCheckBox> SaveFromFileOverride; TSharedPtr<SEditableTextBox> SaveFromFilePath; // Outputs TSharedPtr<SVerticalBox> SaveSlotSection; UPROPERTY(Transient, VisibleInstanceOnly, Category = "3. Save Game", DisplayName = "Return Value:") FString SaveSlotReturnValue; // LoadSlot API UFUNCTION(CallInEditor, Category = "4. Load Game") void CallLoadApi(); FReply OnLoadGameButtonClicked(); void OnLoadGameComplete(const IntResult& result, const FGameSavingDataResults& dataResults); // Popout Window TSharedPtr<SWindow> LoadSlotWindow; bool loadPopoutOpen; // Inputs TSharedPtr<SEditableTextBox> LoadToFileSlotName; TSharedPtr<SCheckBox> LoadToFileOverride; TSharedPtr<SEditableTextBox> LoadToFilePath; // Outputs TSharedPtr<SVerticalBox> LoadSlotSection; UPROPERTY(Transient, VisibleInstanceOnly, Category = "4. Load Game", DisplayName = "Return Value:") FString LoadSlotReturnValue; // DeleteSlot API UFUNCTION(CallInEditor, Category = "5. Delete Game Save") void CallDeleteGameSaveApi(); void OnDeleteGameSaveComplete(const IntResult& result, const FGameSavingSlotActionResults& slotActionResults); // Inputs UPROPERTY(Transient, EditInstanceOnly, Category = "5. Delete Game Save", DisplayName = "Save Name:") FString DeleteSlotSlotName; // Outputs UPROPERTY(Transient, VisibleInstanceOnly, Category = "5. Delete Game Save", DisplayName = "Return Value:") FString DeleteSlotReturnValue; UPROPERTY(Transient, VisibleInstanceOnly, Category = "5. Delete Game Save", DisplayName = "Response (Deleted Save):") FGameSavingSlot DeleteSlotResponseDeletedSlot; UPROPERTY(Transient, VisibleInstanceOnly, Category = "5. Delete Game Save", DisplayName = "Response (Cached Saves):") TArray<FGameSavingSlot> DeleteSlotResponseCachedSlots; };