2
0
Эх сурвалжийг харах

Merge 'gameliftfeature' branch into 'development' branch (#1534)

Vincent Liu 4 жил өмнө
parent
commit
149cb2e2f2
70 өөрчлөгдсөн 5914 нэмэгдсэн , 0 устгасан
  1. 1 0
      Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h
  2. 12 0
      Gems/AWSGameLift/CMakeLists.txt
  3. 89 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt
  4. 39 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h
  5. 42 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h
  6. 33 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h
  7. 42 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h
  8. 78 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/IAWSGameLiftRequests.h
  9. 360 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp
  10. 122 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h
  11. 49 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientModule.cpp
  12. 186 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp
  13. 56 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h
  14. 90 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp
  15. 39 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.h
  16. 80 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp
  17. 40 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h
  18. 112 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.cpp
  19. 54 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.h
  20. 38 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.cpp
  21. 27 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.h
  22. 130 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp
  23. 45 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.h
  24. 58 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp
  25. 63 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp
  26. 54 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp
  27. 69 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp
  28. 63 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientFixture.h
  29. 773 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp
  30. 86 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h
  31. 156 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientSystemComponentTest.cpp
  32. 15 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientTest.cpp
  33. 81 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp
  34. 79 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp
  35. 84 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp
  36. 126 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp
  37. 36 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake
  38. 14 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_shared_files.cmake
  39. 22 0
      Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake
  40. 24 0
      Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h
  41. 72 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt
  42. 319 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp
  43. 128 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h
  44. 49 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerModule.cpp
  45. 129 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerSystemComponent.cpp
  46. 57 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerSystemComponent.h
  47. 72 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.cpp
  48. 64 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.h
  49. 58 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerFixture.h
  50. 421 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp
  51. 127 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h
  52. 99 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerSystemComponentTest.cpp
  53. 15 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerTest.cpp
  54. 20 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_files.cmake
  55. 14 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_shared_files.cmake
  56. 18 0
      Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_tests_files.cmake
  57. 13 0
      Gems/AWSGameLift/Code/CMakeLists.txt
  58. 10 0
      Gems/AWSGameLift/cdk/.gitignore
  59. 99 0
      Gems/AWSGameLift/cdk/README.md
  60. 53 0
      Gems/AWSGameLift/cdk/app.py
  61. 10 0
      Gems/AWSGameLift/cdk/aws_gamelift/__init__.py
  62. 59 0
      Gems/AWSGameLift/cdk/aws_gamelift/aws_gamelift_construct.py
  63. 147 0
      Gems/AWSGameLift/cdk/aws_gamelift/fleet_configurations.py
  64. 184 0
      Gems/AWSGameLift/cdk/aws_gamelift/gamelift_stack.py
  65. 71 0
      Gems/AWSGameLift/cdk/aws_gamelift/support_stack.py
  66. 17 0
      Gems/AWSGameLift/cdk/cdk.json
  67. 4 0
      Gems/AWSGameLift/cdk/requirements.txt
  68. 14 0
      Gems/AWSGameLift/gem.json
  69. 3 0
      Gems/AWSGameLift/preview.png
  70. 1 0
      engine.json

+ 1 - 0
Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h

@@ -12,6 +12,7 @@
 
 #pragma once
 
+#include <AzCore/IO/Path/Path.h>
 #include <AzCore/RTTI/RTTI.h>
 #include <AzCore/std/string/string.h>
 

+ 12 - 0
Gems/AWSGameLift/CMakeLists.txt

@@ -0,0 +1,12 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+add_subdirectory(Code)

+ 89 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt

@@ -0,0 +1,89 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(awsgameliftclient_compile_definition $<IF:$<CONFIG:release>,AWSGAMELIFT_RELEASE,AWSGAMELIFT_DEV>)
+
+ly_add_target(
+    NAME AWSGameLift.Client.Static STATIC
+    NAMESPACE Gem
+    FILES_CMAKE
+        awsgamelift_client_files.cmake
+    INCLUDE_DIRECTORIES
+        PUBLIC
+            Include
+        PRIVATE
+            Source
+            ../AWSGameLiftCommon/Source
+    COMPILE_DEFINITIONS
+        PRIVATE
+            ${awsgameliftclient_compile_definition}
+    BUILD_DEPENDENCIES
+        PRIVATE
+            AZ::AzCore
+            AZ::AzFramework
+            Gem::AWSCore
+            3rdParty::AWSNativeSDK::GameLiftClient
+)
+
+ly_add_target(
+    NAME AWSGameLift.Clients ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
+    NAMESPACE Gem
+    FILES_CMAKE
+        awsgamelift_client_shared_files.cmake
+    INCLUDE_DIRECTORIES
+        PRIVATE
+            Source
+    BUILD_DEPENDENCIES
+        PRIVATE
+            AZ::AzCore
+            3rdParty::AWSNativeSDK::GameLiftClient
+        PUBLIC
+            Gem::AWSGameLift.Client.Static
+    RUNTIME_DEPENDENCIES
+        Gem::AWSCore
+)
+
+# Load the "Gem::AWSGameLift" module in all types of applications.
+if (PAL_TRAIT_BUILD_HOST_TOOLS)
+    ly_create_alias(NAME AWSGameLift.Tools NAMESPACE Gem TARGETS Gem::AWSGameLift.Clients)
+    ly_create_alias(NAME AWSGameLift.Builders NAMESPACE Gem TARGETS Gem::AWSGameLift.Clients)
+endif()
+
+################################################################################
+# Tests
+################################################################################
+if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
+    ly_add_target(
+        NAME AWSGameLift.Client.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
+        NAMESPACE Gem
+        FILES_CMAKE
+            awsgamelift_client_tests_files.cmake
+        INCLUDE_DIRECTORIES
+            PRIVATE
+                Include
+                Tests
+                Source
+                ../AWSGameLiftCommon/Source
+        BUILD_DEPENDENCIES
+            PRIVATE
+                AZ::AzCore
+                AZ::AzFramework
+                AZ::AzTest
+                Gem::AWSCore
+                Gem::AWSGameLift.Client.Static
+                3rdParty::AWSNativeSDK::GameLiftClient
+                AZ::AWSNativeSDKInit
+    )
+    # Add AWSGameLift.Client.Tests to googletest
+    ly_add_googletest(
+        NAME Gem::AWSGameLift.Client.Tests
+    )
+endif()

+ 39 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h

@@ -0,0 +1,39 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzFramework/Session/ISessionRequests.h>
+
+namespace AWSGameLift
+{
+    //! AWSGameLiftCreateSessionOnQueueRequest
+    //! GameLift create session on queue request which corresponds to Amazon GameLift
+    //! StartGameSessionPlacement
+    struct AWSGameLiftCreateSessionOnQueueRequest
+        : public AzFramework::CreateSessionRequest
+    {
+    public:
+        AZ_RTTI(AWSGameLiftCreateSessionOnQueueRequest, "{2B99E594-CE81-4EB0-8888-74EF4242B59F}", AzFramework::CreateSessionRequest);
+        static void Reflect(AZ::ReflectContext* context);
+
+        AWSGameLiftCreateSessionOnQueueRequest() = default;
+        virtual ~AWSGameLiftCreateSessionOnQueueRequest() = default;
+
+        // Name of the queue to use to place the new game session. You can use either the queue name or ARN value. 
+        AZStd::string m_queueName;
+
+        // A unique identifier to assign to the new game session placement. This value is developer-defined.
+        // The value must be unique across all Regions and cannot be reused unless you are resubmitting a canceled or timed-out placement request.
+        AZStd::string m_placementId;
+    };
+} // namespace AWSGameLift

+ 42 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h

@@ -0,0 +1,42 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzFramework/Session/ISessionRequests.h>
+
+namespace AWSGameLift
+{
+    //! AWSGameLiftCreateSessionRequest
+    //! GameLift create session on fleet request which corresponds to Amazon GameLift
+    //! CreateGameSessionRequest
+    struct AWSGameLiftCreateSessionRequest
+        : public AzFramework::CreateSessionRequest
+    {
+    public:
+        AZ_RTTI(AWSGameLiftCreateSessionRequest, "{69612D5D-F899-4DEB-AD63-4C497ABC5C0D}", AzFramework::CreateSessionRequest);
+        static void Reflect(AZ::ReflectContext* context);
+
+        AWSGameLiftCreateSessionRequest() = default;
+        virtual ~AWSGameLiftCreateSessionRequest() = default;
+
+        // A unique identifier for the alias associated with the fleet to create a game session in.
+        AZStd::string m_aliasId;
+
+        // A unique identifier for the fleet to create a game session in.
+        AZStd::string m_fleetId;
+
+        // Custom string that uniquely identifies the new game session request.
+        // This is useful for ensuring that game session requests with the same idempotency token are processed only once. 
+        AZStd::string m_idempotencyToken;
+    };
+} // namespace AWSGameLift

+ 33 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h

@@ -0,0 +1,33 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzFramework/Session/ISessionRequests.h>
+
+namespace AWSGameLift
+{
+    //! AWSGameLiftJoinSessionRequest
+    //! GameLift join session request which corresponds to Amazon GameLift CreatePlayerSessionRequest.
+    //! Once player session has been created successfully in game session, gamelift client manager will
+    //! signal Multiplayer Gem to setup networking connection.
+    struct AWSGameLiftJoinSessionRequest
+        : public AzFramework::JoinSessionRequest
+    {
+    public:
+        AZ_RTTI(AWSGameLiftJoinSessionRequest, "{6EED6D15-531A-4956-90D0-2EDA31AC9CBA}", AzFramework::JoinSessionRequest);
+        static void Reflect(AZ::ReflectContext* context);
+
+        AWSGameLiftJoinSessionRequest() = default;
+        virtual ~AWSGameLiftJoinSessionRequest() = default;
+    };
+} // namespace AWSGameLift

+ 42 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h

@@ -0,0 +1,42 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzFramework/Session/ISessionRequests.h>
+
+namespace AWSGameLift
+{
+    //! AWSGameLiftSearchSessionsRequest
+    //! GameLift search sessions request which corresponds to Amazon GameLift
+    //! SearchSessionsRequest
+    struct AWSGameLiftSearchSessionsRequest
+        : public AzFramework::SearchSessionsRequest
+    {
+    public:
+        AZ_RTTI(AWSGameLiftSearchSessionsRequest, "{864C91C0-CA53-4585-BF07-066C0DF3E198}", AzFramework::SearchSessionsRequest);
+        static void Reflect(AZ::ReflectContext* context);
+
+        AWSGameLiftSearchSessionsRequest() = default;
+        virtual ~AWSGameLiftSearchSessionsRequest() = default;
+
+        // A unique identifier for the alias associated with the fleet to search for active game sessions.
+        AZStd::string m_aliasId;
+
+        // A unique identifier for the fleet to search for active game sessions.
+        AZStd::string m_fleetId;
+
+        // A fleet location to search for game sessions.
+        AZStd::string m_location;
+    };
+} // namespace AWSGameLift
+

+ 78 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/IAWSGameLiftRequests.h

@@ -0,0 +1,78 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+ 
+#pragma once
+
+#include <AzCore/EBus/EBus.h>
+#include <AzCore/RTTI/BehaviorContext.h>
+#include <AzCore/std/string/string.h>
+#include <AzFramework/Session/ISessionRequests.h>
+
+namespace AWSGameLift
+{
+    //! IAWSGameLiftRequests
+    //! GameLift Gem interfaces to configure client manager
+    class IAWSGameLiftRequests
+    {
+    public:
+        AZ_RTTI(IAWSGameLiftRequests, "{494167AD-1185-4AF3-8BF9-C8C37FC9C199}");
+
+        IAWSGameLiftRequests() = default;
+        virtual ~IAWSGameLiftRequests() = default;
+
+        //! ConfigureGameLiftClient
+        //! Configure GameLift client to interact with Amazon GameLift service
+        //! @param region Specifies the AWS region to use
+        //! @return True if client configuration succeeds, false otherwise
+        virtual bool ConfigureGameLiftClient(const AZStd::string& region) = 0;
+
+        //! CreatePlayerId
+        //! Create a new, random ID number for every player in every new game session.
+        //! @param includeBrackets Whether includes brackets in player id
+        //! @param includeDashes Whether includes dashes in player id
+        //! @return The player id to use in game session
+        virtual AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) = 0;
+    };
+
+    // IAWSGameLiftRequests EBus wrapper for scripting
+    class AWSGameLiftRequests
+        : public AZ::EBusTraits
+    {
+    public:
+        using MutexType = AZStd::recursive_mutex;
+        static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+        static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+    };
+    using AWSGameLiftRequestBus = AZ::EBus<IAWSGameLiftRequests, AWSGameLiftRequests>;
+
+    // ISessionAsyncRequests EBus wrapper for scripting
+    class AWSGameLiftSessionAsyncRequests
+        : public AZ::EBusTraits
+    {
+    public:
+        using MutexType = AZStd::recursive_mutex;
+        static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+        static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+    };
+    using AWSGameLiftSessionAsyncRequestBus = AZ::EBus<AzFramework::ISessionAsyncRequests, AWSGameLiftSessionAsyncRequests>;
+
+    // ISessionRequests EBus wrapper for scripting
+    class AWSGameLiftSessionRequests
+        : public AZ::EBusTraits
+    {
+    public:
+        using MutexType = AZStd::recursive_mutex;
+        static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+        static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+    };
+    using AWSGameLiftSessionRequestBus = AZ::EBus<AzFramework::ISessionRequests, AWSGameLiftSessionRequests>;
+} // namespace AWSGameLift

+ 360 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp

@@ -0,0 +1,360 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Console/IConsole.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzCore/Jobs/JobFunction.h>
+#include <AzCore/std/smart_ptr/make_shared.h>
+#include <AzFramework/Session/SessionConfig.h>
+
+#include <AWSCoreBus.h>
+#include <Credential/AWSCredentialBus.h>
+#include <ResourceMapping/AWSResourceMappingBus.h>
+
+#include <AWSGameLiftClientManager.h>
+#include <Activity/AWSGameLiftCreateSessionActivity.h>
+#include <Activity/AWSGameLiftCreateSessionOnQueueActivity.h>
+#include <Activity/AWSGameLiftJoinSessionActivity.h>
+#include <Activity/AWSGameLiftLeaveSessionActivity.h>
+#include <Activity/AWSGameLiftSearchSessionsActivity.h>
+
+#include <aws/core/auth/AWSCredentialsProvider.h>
+
+namespace AWSGameLift
+{
+#if defined(AWSGAMELIFT_DEV)
+    AZ_CVAR(AZ::CVarFixedString, cl_gameliftLocalEndpoint, "", nullptr, AZ::ConsoleFunctorFlags::Null, "The local endpoint to test with GameLiftLocal SDK.");
+#endif
+
+    AWSGameLiftClientManager::AWSGameLiftClientManager()
+    {
+        m_gameliftClient.reset();
+    }
+
+    void AWSGameLiftClientManager::ActivateManager()
+    {
+        AZ::Interface<IAWSGameLiftRequests>::Register(this);
+        AWSGameLiftRequestBus::Handler::BusConnect();
+
+        AZ::Interface<AzFramework::ISessionAsyncRequests>::Register(this);
+        AWSGameLiftSessionAsyncRequestBus::Handler::BusConnect();
+
+        AZ::Interface<AzFramework::ISessionRequests>::Register(this);
+        AWSGameLiftSessionRequestBus::Handler::BusConnect();
+    }
+
+    void AWSGameLiftClientManager::DeactivateManager()
+    {
+        AWSGameLiftSessionRequestBus::Handler::BusDisconnect();
+        AZ::Interface<AzFramework::ISessionRequests>::Unregister(this);
+
+        AWSGameLiftSessionAsyncRequestBus::Handler::BusDisconnect();
+        AZ::Interface<AzFramework::ISessionAsyncRequests>::Unregister(this);
+
+        AWSGameLiftRequestBus::Handler::BusDisconnect();
+        AZ::Interface<IAWSGameLiftRequests>::Unregister(this);
+    }
+
+    bool AWSGameLiftClientManager::ConfigureGameLiftClient(const AZStd::string& region)
+    {
+        m_gameliftClient.reset();
+
+        Aws::Client::ClientConfiguration clientConfig;
+        // Set up client endpoint or region
+        AZStd::string localEndpoint = "";
+#if defined(AWSGAMELIFT_DEV)
+        localEndpoint = static_cast<AZ::CVarFixedString>(cl_gameliftLocalEndpoint);
+#endif
+        if (!localEndpoint.empty())
+        {
+            // The attribute needs to override to interact with GameLiftLocal
+            clientConfig.endpointOverride = localEndpoint.c_str();
+        }
+        else if (!region.empty())
+        {
+            clientConfig.region = region.c_str();
+        }
+        else
+        {
+            AZStd::string clientRegion;
+            AWSCore::AWSResourceMappingRequestBus::BroadcastResult(clientRegion, &AWSCore::AWSResourceMappingRequests::GetDefaultRegion);
+            if (clientRegion.empty())
+            {
+                AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientRegionMissingErrorMessage);
+                return false;
+            }
+            clientConfig.region = clientRegion.c_str();
+        }
+
+        // Fetch AWS credential for client
+        AWSCore::AWSCredentialResult credentialResult;
+        AWSCore::AWSCredentialRequestBus::BroadcastResult(credentialResult, &AWSCore::AWSCredentialRequests::GetCredentialsProvider);
+        if (!localEndpoint.empty())
+        {
+            credentialResult.result = std::make_shared<Aws::Auth::AnonymousAWSCredentialsProvider>();
+        }
+        else if (!credentialResult.result)
+        {
+            AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientCredentialMissingErrorMessage);
+            return false;
+        }
+        m_gameliftClient = AZStd::make_shared<Aws::GameLift::GameLiftClient>(credentialResult.result, clientConfig);
+        return true;
+    }
+
+    AZStd::string AWSGameLiftClientManager::CreatePlayerId(bool includeBrackets, bool includeDashes)
+    {
+        return AZ::Uuid::CreateRandom().ToString<AZStd::string>(includeBrackets, includeDashes);
+    }
+
+    AZStd::string AWSGameLiftClientManager::CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest)
+    {
+        AZStd::string result = "";
+        if (CreateSessionActivity::ValidateCreateSessionRequest(createSessionRequest))
+        {
+            const AWSGameLiftCreateSessionRequest& gameliftCreateSessionRequest =
+                static_cast<const AWSGameLiftCreateSessionRequest&>(createSessionRequest);
+            result = CreateSessionHelper(gameliftCreateSessionRequest);
+        }
+        else if (CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(createSessionRequest))
+        {
+            const AWSGameLiftCreateSessionOnQueueRequest& gameliftCreateSessionOnQueueRequest =
+                static_cast<const AWSGameLiftCreateSessionOnQueueRequest&>(createSessionRequest);
+            result = CreateSessionOnQueueHelper(gameliftCreateSessionOnQueueRequest);
+        }
+        else
+        {
+            AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftCreateSessionRequestInvalidErrorMessage);
+        }
+
+        return result;
+    }
+
+    void AWSGameLiftClientManager::CreateSessionAsync(const AzFramework::CreateSessionRequest& createSessionRequest)
+    {
+        if (CreateSessionActivity::ValidateCreateSessionRequest(createSessionRequest))
+        {
+            const AWSGameLiftCreateSessionRequest& gameliftCreateSessionRequest =
+                static_cast<const AWSGameLiftCreateSessionRequest&>(createSessionRequest);
+
+            AZ::JobContext* jobContext = nullptr;
+            AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
+            AZ::Job* createSessionJob = AZ::CreateJobFunction(
+                [this, gameliftCreateSessionRequest]()
+                {
+                    AZStd::string result = CreateSessionHelper(gameliftCreateSessionRequest);
+
+                    AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                        &AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result);
+                },
+                true, jobContext);
+            createSessionJob->Start();
+        }
+        else if (CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(createSessionRequest))
+        {
+            const AWSGameLiftCreateSessionOnQueueRequest& gameliftCreateSessionOnQueueRequest =
+                static_cast<const AWSGameLiftCreateSessionOnQueueRequest&>(createSessionRequest);
+
+            AZ::JobContext* jobContext = nullptr;
+            AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
+            AZ::Job* createSessionOnQueueJob = AZ::CreateJobFunction(
+                [this, gameliftCreateSessionOnQueueRequest]()
+                {
+                    AZStd::string result = CreateSessionOnQueueHelper(gameliftCreateSessionOnQueueRequest);
+
+                    AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                        &AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result);
+                },
+                true, jobContext);
+            createSessionOnQueueJob->Start();
+        }
+        else
+        {
+            AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftCreateSessionRequestInvalidErrorMessage);
+            AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                &AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, "");
+        }
+    }
+
+    AZStd::string AWSGameLiftClientManager::CreateSessionHelper(
+        const AWSGameLiftCreateSessionRequest& createSessionRequest)
+    {
+        AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameLiftClient = m_gameliftClient;
+        AZStd::string result = "";
+        if (!gameLiftClient)
+        {
+            AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
+        }
+        else
+        {
+            result = CreateSessionActivity::CreateSession(*gameLiftClient, createSessionRequest);
+        }
+        return result;
+    }
+
+    AZStd::string AWSGameLiftClientManager::CreateSessionOnQueueHelper(
+        const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest)
+    {
+        AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient = m_gameliftClient;
+        AZStd::string result;
+        if (!gameliftClient)
+        {
+            AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
+        }
+        else
+        {
+            result = CreateSessionOnQueueActivity::CreateSessionOnQueue(*gameliftClient, createSessionOnQueueRequest);
+        }
+        return result;
+    }
+
+    bool AWSGameLiftClientManager::JoinSession(const AzFramework::JoinSessionRequest& joinSessionRequest)
+    {
+        bool result = false;
+        if (JoinSessionActivity::ValidateJoinSessionRequest(joinSessionRequest))
+        {
+            const AWSGameLiftJoinSessionRequest& gameliftJoinSessionRequest =
+                static_cast<const AWSGameLiftJoinSessionRequest&>(joinSessionRequest);
+            result = JoinSessionHelper(gameliftJoinSessionRequest);
+        }
+
+        return result;
+    }
+
+    void AWSGameLiftClientManager::JoinSessionAsync(const AzFramework::JoinSessionRequest& joinSessionRequest)
+    {
+        if (!JoinSessionActivity::ValidateJoinSessionRequest(joinSessionRequest))
+        {
+            AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                &AzFramework::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, false);
+            return;
+        }
+
+        const AWSGameLiftJoinSessionRequest& gameliftJoinSessionRequest =
+            static_cast<const AWSGameLiftJoinSessionRequest&>(joinSessionRequest);
+
+        AZ::JobContext* jobContext = nullptr;
+        AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
+        AZ::Job* joinSessionJob = AZ::CreateJobFunction(
+            [this, gameliftJoinSessionRequest]()
+            {
+                bool result = JoinSessionHelper(gameliftJoinSessionRequest);
+
+                AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                    &AzFramework::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, result);
+            },
+            true, jobContext);
+
+        joinSessionJob->Start();
+    }
+
+    bool AWSGameLiftClientManager::JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest)
+    {
+        AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient = m_gameliftClient;
+        bool result = false;
+        if (!gameliftClient)
+        {
+            AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
+        }
+        else
+        {
+            auto createPlayerSessionOutcome = JoinSessionActivity::CreatePlayerSession(*gameliftClient, joinSessionRequest);
+
+            result = JoinSessionActivity::RequestPlayerJoinSession(createPlayerSessionOutcome);
+        }
+        return result;
+    }
+
+    void AWSGameLiftClientManager::LeaveSession()
+    {
+        AWSGameLift::LeaveSessionActivity::LeaveSession();
+    }
+
+    void AWSGameLiftClientManager::LeaveSessionAsync()
+    {
+        AZ::JobContext* jobContext = nullptr;
+        AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
+        AZ::Job* leaveSessionJob = AZ::CreateJobFunction(
+            [this]()
+            {
+                LeaveSession();
+                AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                    &AzFramework::SessionAsyncRequestNotifications::OnLeaveSessionAsyncComplete);
+            },
+            true, jobContext);
+
+        leaveSessionJob->Start();
+    }
+
+    AzFramework::SearchSessionsResponse AWSGameLiftClientManager::SearchSessions(
+        const AzFramework::SearchSessionsRequest& searchSessionsRequest) const
+    {
+        AzFramework::SearchSessionsResponse response;
+        if (SearchSessionsActivity::ValidateSearchSessionsRequest(searchSessionsRequest))
+        {
+            const AWSGameLiftSearchSessionsRequest& gameliftSearchSessionsRequest =
+                static_cast<const AWSGameLiftSearchSessionsRequest&>(searchSessionsRequest);
+            response = SearchSessionsHelper(gameliftSearchSessionsRequest);
+        }
+
+        return response;
+    }
+
+    void AWSGameLiftClientManager::SearchSessionsAsync(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const
+    {
+        if (!SearchSessionsActivity::ValidateSearchSessionsRequest(searchSessionsRequest))
+        {
+            AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                &AzFramework::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, AzFramework::SearchSessionsResponse());
+            return;
+        }
+
+        const AWSGameLiftSearchSessionsRequest& gameliftSearchSessionsRequest =
+            static_cast<const AWSGameLiftSearchSessionsRequest&>(searchSessionsRequest);
+
+        AZ::JobContext* jobContext = nullptr;
+        AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
+        AZ::Job* searchSessionsJob = AZ::CreateJobFunction(
+            [this, gameliftSearchSessionsRequest]()
+            {
+                AzFramework::SearchSessionsResponse response = SearchSessionsHelper(gameliftSearchSessionsRequest);
+
+                AzFramework::SessionAsyncRequestNotificationBus::Broadcast(
+                    &AzFramework::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, response);
+            },
+            true, jobContext);
+
+        searchSessionsJob->Start(); 
+    }
+
+    AzFramework::SearchSessionsResponse AWSGameLiftClientManager::SearchSessionsHelper(
+        const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) const
+    {
+        AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient = m_gameliftClient;
+
+        AzFramework::SearchSessionsResponse response;
+        if (!gameliftClient)
+        {
+            AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage);
+        }
+        else
+        {
+            response = SearchSessionsActivity::SearchSessions(*gameliftClient, searchSessionsRequest);
+        }
+        return response;
+    }
+
+    void AWSGameLiftClientManager::SetGameLiftClient(AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient)
+    {
+        m_gameliftClient.swap(gameliftClient);
+    }
+} // namespace AWSGameLift

+ 122 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h

@@ -0,0 +1,122 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzCore/std/smart_ptr/shared_ptr.h>
+#include <Request/IAWSGameLiftRequests.h>
+
+namespace Aws
+{
+    namespace GameLift
+    {
+        class GameLiftClient;
+    }
+}
+
+namespace AWSGameLift
+{
+    struct AWSGameLiftCreateSessionRequest;
+    struct AWSGameLiftCreateSessionOnQueueRequest;
+    struct AWSGameLiftJoinSessionRequest;
+    struct AWSGameLiftSearchSessionsRequest;
+
+    // SessionAsyncRequestNotificationBus EBus handler for scripting
+    class AWSGameLiftSessionAsyncRequestNotificationBusHandler
+        : public AzFramework::SessionAsyncRequestNotificationBus::Handler
+        , public AZ::BehaviorEBusHandler
+    {
+    public:
+        AZ_EBUS_BEHAVIOR_BINDER(
+            AWSGameLiftSessionAsyncRequestNotificationBusHandler,
+            "{6E13FC73-53DC-4B6B-AEA7-9038DE4C9635}",
+            AZ::SystemAllocator,
+            OnCreateSessionAsyncComplete,
+            OnSearchSessionsAsyncComplete,
+            OnJoinSessionAsyncComplete,
+            OnLeaveSessionAsyncComplete);
+
+        void OnCreateSessionAsyncComplete(const AZStd::string& createSessionReponse) override
+        {
+            Call(FN_OnCreateSessionAsyncComplete, createSessionReponse);
+        }
+
+        void OnSearchSessionsAsyncComplete(const AzFramework::SearchSessionsResponse& searchSessionsResponse) override
+        {
+            Call(FN_OnSearchSessionsAsyncComplete, searchSessionsResponse);
+        }
+
+        void OnJoinSessionAsyncComplete(bool joinSessionsResponse) override
+        {
+            Call(FN_OnJoinSessionAsyncComplete, joinSessionsResponse);
+        }
+
+        void OnLeaveSessionAsyncComplete() override
+        {
+            Call(FN_OnLeaveSessionAsyncComplete);
+        }
+    };
+
+    //! AWSGameLiftClientManager
+    //! GameLift client manager to support game and player session related client requests
+    class AWSGameLiftClientManager
+        : public AWSGameLiftRequestBus::Handler
+        , public AWSGameLiftSessionAsyncRequestBus::Handler
+        , public AWSGameLiftSessionRequestBus::Handler
+    {
+    public:
+        static constexpr const char AWSGameLiftClientManagerName[] = "AWSGameLiftClientManager";
+        static constexpr const char AWSGameLiftClientRegionMissingErrorMessage[] =
+            "Missing AWS region for GameLift client.";
+        static constexpr const char AWSGameLiftClientCredentialMissingErrorMessage[] =
+            "Missing AWS credential for GameLift client.";
+        static constexpr const char AWSGameLiftClientMissingErrorMessage[] =
+            "GameLift client is not configured yet.";
+
+        static constexpr const char AWSGameLiftCreateSessionRequestInvalidErrorMessage[] =
+            "Invalid GameLift CreateSession or CreateSessionOnQueue request.";
+
+        AWSGameLiftClientManager();
+        virtual ~AWSGameLiftClientManager() = default;
+
+        virtual void ActivateManager();
+        virtual void DeactivateManager();
+
+        // AWSGameLiftRequestBus interface implementation
+        bool ConfigureGameLiftClient(const AZStd::string& region) override;
+        AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) override;
+
+        // AWSGameLiftSessionAsyncRequestBus interface implementation
+        void CreateSessionAsync(const AzFramework::CreateSessionRequest& createSessionRequest) override;
+        void JoinSessionAsync(const AzFramework::JoinSessionRequest& joinSessionRequest) override;
+        void SearchSessionsAsync(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override;
+        void LeaveSessionAsync() override;
+
+        // AWSGameLiftSessionRequestBus interface implementation
+        AZStd::string CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest) override;
+        bool JoinSession(const AzFramework::JoinSessionRequest& joinSessionRequest) override;
+        AzFramework::SearchSessionsResponse SearchSessions(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override;
+        void LeaveSession() override;
+
+    protected:
+        // Use for automation tests only to inject mock objects. 
+        void SetGameLiftClient(AZStd::shared_ptr<Aws::GameLift::GameLiftClient> gameliftClient);
+
+    private:
+        AZStd::string CreateSessionHelper(const AWSGameLiftCreateSessionRequest& createSessionRequest);
+        AZStd::string CreateSessionOnQueueHelper(const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest);
+        bool JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest);
+        AzFramework::SearchSessionsResponse SearchSessionsHelper(const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) const;
+
+        AZStd::shared_ptr<Aws::GameLift::GameLiftClient> m_gameliftClient;
+    };
+} // namespace AWSGameLift

+ 49 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientModule.cpp

@@ -0,0 +1,49 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Memory/SystemAllocator.h>
+#include <AzCore/Module/Module.h>
+
+#include <AWSGameLiftClientSystemComponent.h>
+
+namespace AWSGameLift
+{
+    //! Provide the entry point for the gem and register the system component.
+    class AWSGameLiftClientModule
+        : public AZ::Module
+    {
+    public:
+        AZ_RTTI(AWSGameLiftClientModule, "{7b920f3e-2b23-482e-a1b6-16bd278d126c}", AZ::Module);
+        AZ_CLASS_ALLOCATOR(AWSGameLiftClientModule, AZ::SystemAllocator, 0);
+
+        AWSGameLiftClientModule()
+            : AZ::Module()
+        {
+            // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
+            m_descriptors.insert(m_descriptors.end(), {
+                AWSGameLiftClientSystemComponent::CreateDescriptor(),
+            });
+        }
+
+        /**
+         * Add required SystemComponents to the SystemEntity.
+         */
+        AZ::ComponentTypeList GetRequiredSystemComponents() const override
+        {
+            return AZ::ComponentTypeList {
+                azrtti_typeid<AWSGameLiftClientSystemComponent>(),
+            };
+        }
+    };
+}// namespace AWSGameLift
+
+AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Client, AWSGameLift::AWSGameLiftClientModule)

+ 186 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp

@@ -0,0 +1,186 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/EditContextConstants.inl>
+#include <AzFramework/Session/SessionConfig.h>
+
+#include <AWSGameLiftClientManager.h>
+#include <AWSGameLiftClientSystemComponent.h>
+#include <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
+#include <Request/AWSGameLiftCreateSessionRequest.h>
+#include <Request/AWSGameLiftJoinSessionRequest.h>
+#include <Request/AWSGameLiftSearchSessionsRequest.h>
+
+#include <aws/gamelift/GameLiftClient.h>
+
+namespace AWSGameLift
+{
+    AWSGameLiftClientSystemComponent::AWSGameLiftClientSystemComponent()
+    {
+        m_gameliftClientManager = AZStd::make_unique<AWSGameLiftClientManager>();
+    }
+
+    void AWSGameLiftClientSystemComponent::Reflect(AZ::ReflectContext* context)
+    {
+        ReflectCreateSessionRequest(context);
+        AWSGameLiftCreateSessionOnQueueRequest::Reflect(context);
+        AWSGameLiftCreateSessionRequest::Reflect(context);
+        AWSGameLiftJoinSessionRequest::Reflect(context);
+        AWSGameLiftSearchSessionsRequest::Reflect(context);
+        ReflectSearchSessionsResponse(context);
+
+        if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serialize->Class<AWSGameLiftClientSystemComponent, AZ::Component>()
+                ->Version(0)
+                ;
+
+            if (AZ::EditContext* editContext = serialize->GetEditContext())
+            {
+                editContext
+                    ->Class<AWSGameLiftClientSystemComponent>(
+                        "AWSGameLiftClient",
+                        "Create the GameLift client manager that handles communication between game clients and the GameLift service.")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                        ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
+                        ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+                    ;
+            }
+        }
+
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->EBus<AWSGameLiftRequestBus>("AWSGameLiftRequestBus")
+                ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
+                ->Event("ConfigureGameLiftClient", &AWSGameLiftRequestBus::Events::ConfigureGameLiftClient,
+                    {{{"Region", ""}}})
+                ->Event("CreatePlayerId", &AWSGameLiftRequestBus::Events::CreatePlayerId,
+                    {{{"IncludeBrackets", ""},
+                      {"IncludeDashes", ""}}})
+                ;
+            behaviorContext->EBus<AWSGameLiftSessionAsyncRequestBus>("AWSGameLiftSessionAsyncRequestBus")
+                ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
+                ->Event("CreateSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::CreateSessionAsync,
+                    {{{"CreateSessionRequest", ""}}})
+                ->Event("JoinSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::JoinSessionAsync,
+                    {{{"JoinSessionRequest", ""}}})
+                ->Event("SearchSessionsAsync", &AWSGameLiftSessionAsyncRequestBus::Events::SearchSessionsAsync,
+                    {{{"SearchSessionsRequest", ""}}})
+                ->Event("LeaveSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::LeaveSessionAsync)
+                ;
+            behaviorContext
+                ->EBus<AzFramework::SessionAsyncRequestNotificationBus>("AWSGameLiftSessionAsyncRequestNotificationBus")
+                ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
+                ->Handler<AWSGameLiftSessionAsyncRequestNotificationBusHandler>()
+                ;
+            behaviorContext->EBus<AWSGameLiftSessionRequestBus>("AWSGameLiftSessionRequestBus")
+                ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
+                ->Event("CreateSession", &AWSGameLiftSessionRequestBus::Events::CreateSession,
+                    {{{"CreateSessionRequest", ""}}})
+                ->Event("JoinSession", &AWSGameLiftSessionRequestBus::Events::JoinSession,
+                    {{{"JoinSessionRequest", ""}}})
+                ->Event("SearchSessions", &AWSGameLiftSessionRequestBus::Events::SearchSessions,
+                    {{{"SearchSessionsRequest", ""}}})
+                ->Event("LeaveSession", &AWSGameLiftSessionRequestBus::Events::LeaveSession)
+                ;
+        }
+    }
+
+    void AWSGameLiftClientSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("AWSGameLiftClientService"));
+    }
+
+    void AWSGameLiftClientSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC_CE("AWSGameLiftClientService"));
+    }
+
+    void AWSGameLiftClientSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        required.push_back(AZ_CRC_CE("AWSCoreService"));
+    }
+
+    void AWSGameLiftClientSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+        AZ_UNUSED(dependent);
+    }
+
+    void AWSGameLiftClientSystemComponent::Init()
+    {
+    }
+
+    void AWSGameLiftClientSystemComponent::Activate()
+    {
+        m_gameliftClientManager->ActivateManager();
+    }
+
+    void AWSGameLiftClientSystemComponent::Deactivate()
+    {
+        m_gameliftClientManager->DeactivateManager();
+    }
+
+    void AWSGameLiftClientSystemComponent::ReflectCreateSessionRequest(AZ::ReflectContext* context)
+    {
+        AzFramework::CreateSessionRequest::Reflect(context);
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<AzFramework::CreateSessionRequest>("CreateSessionRequest")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                // Expose base type to BehaviorContext, but hide it to be used directly
+                ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
+                ;
+        }
+    }
+
+    void AWSGameLiftClientSystemComponent::ReflectSearchSessionsResponse(AZ::ReflectContext* context)
+    {
+        // As it is a common response type, reflection could be moved to AzFramework to avoid duplication
+        AzFramework::SessionConfig::Reflect(context);
+        AzFramework::SearchSessionsResponse::Reflect(context);
+
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<AzFramework::SessionConfig>("SessionConfig")
+                ->Attribute(AZ::Script::Attributes::Category, "Session")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                ->Property("CreationTime", BehaviorValueProperty(&AzFramework::SessionConfig::m_creationTime))
+                ->Property("CreatorId", BehaviorValueProperty(&AzFramework::SessionConfig::m_creatorId))
+                ->Property("CurrentPlayer", BehaviorValueProperty(&AzFramework::SessionConfig::m_currentPlayer))
+                ->Property("DnsName", BehaviorValueProperty(&AzFramework::SessionConfig::m_dnsName))
+                ->Property("IpAddress", BehaviorValueProperty(&AzFramework::SessionConfig::m_ipAddress))
+                ->Property("MaxPlayer", BehaviorValueProperty(&AzFramework::SessionConfig::m_maxPlayer))
+                ->Property("Port", BehaviorValueProperty(&AzFramework::SessionConfig::m_port))
+                ->Property("SessionId", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionId))
+                ->Property("SessionName", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionName))
+                ->Property("SessionProperties", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionProperties))
+                ->Property("Status", BehaviorValueProperty(&AzFramework::SessionConfig::m_status))
+                ->Property("StatusReason", BehaviorValueProperty(&AzFramework::SessionConfig::m_statusReason))
+                ->Property("TerminationTime", BehaviorValueProperty(&AzFramework::SessionConfig::m_terminationTime))
+                ;
+            behaviorContext->Class<AzFramework::SearchSessionsResponse>("SearchSessionsResponse")
+                ->Attribute(AZ::Script::Attributes::Category, "Session")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                ->Property("NextToken", BehaviorValueProperty(&AzFramework::SearchSessionsResponse::m_nextToken))
+                ->Property("SessionConfigs", BehaviorValueProperty(&AzFramework::SearchSessionsResponse::m_sessionConfigs))
+                ;
+        }
+    }
+
+    void AWSGameLiftClientSystemComponent::SetGameLiftClientManager(AZStd::unique_ptr<AWSGameLiftClientManager> gameliftClientManager)
+    {
+        m_gameliftClientManager.reset();
+        m_gameliftClientManager = AZStd::move(gameliftClientManager);
+    }
+} // namespace AWSGameLift

+ 56 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h

@@ -0,0 +1,56 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <AzCore/std/smart_ptr/unique_ptr.h>
+
+namespace AWSGameLift
+{
+    class AWSGameLiftClientManager;
+
+    //! Gem client system component. Responsible for creating the gamelift client manager.
+    class AWSGameLiftClientSystemComponent
+        : public AZ::Component
+    {
+    public:
+        AZ_COMPONENT(AWSGameLiftClientSystemComponent, "{d481c15c-732a-4eea-9853-4965ed1bc2be}");
+
+        AWSGameLiftClientSystemComponent();
+        virtual ~AWSGameLiftClientSystemComponent() = default;
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+    protected:
+        ////////////////////////////////////////////////////////////////////////
+        // AZ::Component interface implementation
+        void Init() override;
+        void Activate() override;
+        void Deactivate() override;
+        ////////////////////////////////////////////////////////////////////////
+
+        void SetGameLiftClientManager(AZStd::unique_ptr<AWSGameLiftClientManager> gameliftClientManager);
+
+    private:
+        static void ReflectCreateSessionRequest(AZ::ReflectContext* context);
+        static void ReflectSearchSessionsResponse(AZ::ReflectContext* context);
+
+        AZStd::unique_ptr<AWSGameLiftClientManager> m_gameliftClientManager;
+    };
+
+} // namespace AWSGameLift

+ 90 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp

@@ -0,0 +1,90 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <Activity/AWSGameLiftCreateSessionActivity.h>
+#include <AWSGameLiftSessionConstants.h>
+
+namespace AWSGameLift
+{
+    namespace CreateSessionActivity
+    {
+        Aws::GameLift::Model::CreateGameSessionRequest BuildAWSGameLiftCreateGameSessionRequest(
+            const AWSGameLiftCreateSessionRequest& createSessionRequest)
+        {
+            Aws::GameLift::Model::CreateGameSessionRequest request;
+            // Optional attributes
+            if (!createSessionRequest.m_creatorId.empty())
+            {
+                request.SetCreatorId(createSessionRequest.m_creatorId.c_str());
+            }
+            if (!createSessionRequest.m_sessionName.empty())
+            {
+                request.SetName(createSessionRequest.m_sessionName.c_str());
+            }
+            if (!createSessionRequest.m_idempotencyToken.empty())
+            {
+                request.SetIdempotencyToken(createSessionRequest.m_idempotencyToken.c_str());
+            }
+            for (auto iter = createSessionRequest.m_sessionProperties.begin();
+                 iter != createSessionRequest.m_sessionProperties.end(); iter++)
+            {
+                Aws::GameLift::Model::GameProperty sessionProperty;
+                sessionProperty.SetKey(iter->first.c_str());
+                sessionProperty.SetValue(iter->second.c_str());
+                request.AddGameProperties(sessionProperty);
+            }
+
+            // Required attributes
+            if (!createSessionRequest.m_aliasId.empty())
+            {
+                request.SetAliasId(createSessionRequest.m_aliasId.c_str());
+            }
+            if (!createSessionRequest.m_fleetId.empty())
+            {
+                request.SetFleetId(createSessionRequest.m_fleetId.c_str());
+            }
+            request.SetMaximumPlayerSessionCount(createSessionRequest.m_maxPlayer);
+
+            return request;
+        }
+
+        AZStd::string CreateSession(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftCreateSessionRequest& createSessionRequest)
+        {
+            AZ_TracePrintf(AWSGameLiftCreateSessionActivityName, "Requesting CreateGameSession against Amazon GameLift service ...");
+
+            AZStd::string result = "";
+            Aws::GameLift::Model::CreateGameSessionRequest request = BuildAWSGameLiftCreateGameSessionRequest(createSessionRequest);
+            auto createSessionOutcome = gameliftClient.CreateGameSession(request);
+
+            if (createSessionOutcome.IsSuccess())
+            {
+                result = AZStd::string(createSessionOutcome.GetResult().GetGameSession().GetGameSessionId().c_str());
+            }
+            else
+            {
+                AZ_Error(AWSGameLiftCreateSessionActivityName, false, AWSGameLiftErrorMessageTemplate,
+                    createSessionOutcome.GetError().GetExceptionName().c_str(), createSessionOutcome.GetError().GetMessage().c_str());
+            }
+            return result;
+        }
+
+        bool ValidateCreateSessionRequest(const AzFramework::CreateSessionRequest& createSessionRequest)
+        {
+            auto gameliftCreateSessionRequest = azrtti_cast<const AWSGameLiftCreateSessionRequest*>(&createSessionRequest);
+
+            return gameliftCreateSessionRequest && gameliftCreateSessionRequest->m_maxPlayer >= 0 &&
+                (!gameliftCreateSessionRequest->m_aliasId.empty() || !gameliftCreateSessionRequest->m_fleetId.empty());
+        }
+    } // namespace CreateSessionActivity
+} // namespace AWSGameLift

+ 39 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.h

@@ -0,0 +1,39 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <Request/AWSGameLiftCreateSessionRequest.h>
+
+#include <aws/core/utils/Outcome.h>
+#include <aws/gamelift/GameLiftClient.h>
+#include <aws/gamelift/model/CreateGameSessionRequest.h>
+
+namespace AWSGameLift
+{
+    namespace CreateSessionActivity
+    {
+        static constexpr const char AWSGameLiftCreateSessionActivityName[] = "AWSGameLiftCreateSessionActivity";
+
+        // Build AWS GameLift CreateGameSessionRequest by using AWSGameLiftCreateSessionRequest
+        Aws::GameLift::Model::CreateGameSessionRequest BuildAWSGameLiftCreateGameSessionRequest(const AWSGameLiftCreateSessionRequest& createSessionRequest);
+
+        // Create CreateGameSessionRequest and make a CreateGameSession call through GameLift client
+        AZStd::string CreateSession(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftCreateSessionRequest& createSessionRequest);
+
+        // Validate CreateSessionRequest and check required request parameters
+        bool ValidateCreateSessionRequest(const AzFramework::CreateSessionRequest& createSessionRequest);
+
+    } // namespace CreateSessionActivity
+} // namespace AWSGameLift

+ 80 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp

@@ -0,0 +1,80 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AWSGameLiftSessionConstants.h>
+#include <Activity/AWSGameLiftCreateSessionOnQueueActivity.h>
+
+namespace AWSGameLift
+{
+    namespace CreateSessionOnQueueActivity
+    {
+        Aws::GameLift::Model::StartGameSessionPlacementRequest BuildAWSGameLiftStartGameSessionPlacementRequest(
+            const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest)
+        {
+            Aws::GameLift::Model::StartGameSessionPlacementRequest request;
+            // Optional attributes
+            if (!createSessionOnQueueRequest.m_sessionName.empty())
+            {
+                request.SetGameSessionName(createSessionOnQueueRequest.m_sessionName.c_str());
+            }
+            for (auto iter = createSessionOnQueueRequest.m_sessionProperties.begin();
+                 iter != createSessionOnQueueRequest.m_sessionProperties.end(); iter++)
+            {
+                Aws::GameLift::Model::GameProperty sessionProperty;
+                sessionProperty.SetKey(iter->first.c_str());
+                sessionProperty.SetValue(iter->second.c_str());
+                request.AddGameProperties(sessionProperty);
+            }
+
+            // Required attributes
+            request.SetGameSessionQueueName(createSessionOnQueueRequest.m_queueName.c_str());
+            request.SetMaximumPlayerSessionCount(createSessionOnQueueRequest.m_maxPlayer);
+            request.SetPlacementId(createSessionOnQueueRequest.m_placementId.c_str());
+
+            return request;
+        }
+
+        AZStd::string CreateSessionOnQueue(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest)
+        {
+            AZ_TracePrintf(AWSGameLiftCreateSessionOnQueueActivityName,
+                "Requesting StartGameSessionPlacement against Amazon GameLift service ...");
+
+            AZStd::string result = "";
+            Aws::GameLift::Model::StartGameSessionPlacementRequest request =
+                BuildAWSGameLiftStartGameSessionPlacementRequest(createSessionOnQueueRequest);
+            auto createSessionOnQueueOutcome = gameliftClient.StartGameSessionPlacement(request);
+
+            if (createSessionOnQueueOutcome.IsSuccess())
+            {
+                result = AZStd::string(createSessionOnQueueOutcome.GetResult().GetGameSessionPlacement().GetPlacementId().c_str());
+            }
+            else
+            {
+                AZ_Error(AWSGameLiftCreateSessionOnQueueActivityName, false, AWSGameLiftErrorMessageTemplate,
+                    createSessionOnQueueOutcome.GetError().GetExceptionName().c_str(),
+                    createSessionOnQueueOutcome.GetError().GetMessage().c_str());
+            }
+            return result;
+        }
+
+        bool ValidateCreateSessionOnQueueRequest(const AzFramework::CreateSessionRequest& createSessionRequest)
+        {
+            auto gameliftCreateSessionOnQueueRequest =
+                azrtti_cast<const AWSGameLiftCreateSessionOnQueueRequest*>(&createSessionRequest);
+
+            return gameliftCreateSessionOnQueueRequest && gameliftCreateSessionOnQueueRequest->m_maxPlayer >= 0 &&
+                !gameliftCreateSessionOnQueueRequest->m_queueName.empty() && !gameliftCreateSessionOnQueueRequest->m_placementId.empty();
+        }
+    } // namespace CreateSessionOnQueueActivity
+} // namespace AWSGameLift

+ 40 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h

@@ -0,0 +1,40 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
+
+#include <aws/core/utils/Outcome.h>
+#include <aws/gamelift/GameLiftClient.h>
+#include <aws/gamelift/model/StartGameSessionPlacementRequest.h>
+
+namespace AWSGameLift
+{
+    namespace CreateSessionOnQueueActivity
+    {
+        static constexpr const char AWSGameLiftCreateSessionOnQueueActivityName[] = "AWSGameLiftCreateSessionOnQueueActivity";
+
+        // Build AWS GameLift StartGameSessionPlacementRequest by using AWSGameLiftCreateSessionOnQueueRequest
+        Aws::GameLift::Model::StartGameSessionPlacementRequest BuildAWSGameLiftStartGameSessionPlacementRequest(
+            const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest);
+
+        // Create StartGameSessionPlacementRequest and make a CreateGameSession call through GameLift client
+        AZStd::string CreateSessionOnQueue(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest);
+
+        // Validate CreateSessionOnQueueRequest and check required request parameters
+        bool ValidateCreateSessionOnQueueRequest(const AzFramework::CreateSessionRequest& createSessionRequest);
+
+    } // namespace CreateSessionOnQueueActivity
+} // namespace AWSGameLift

+ 112 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.cpp

@@ -0,0 +1,112 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Interface/Interface.h>
+#include <AzFramework/Session/ISessionHandlingRequests.h>
+
+#include <Activity/AWSGameLiftJoinSessionActivity.h>
+#include <AWSGameLiftSessionConstants.h>
+
+namespace AWSGameLift
+{
+    namespace JoinSessionActivity
+    {
+        Aws::GameLift::Model::CreatePlayerSessionRequest BuildAWSGameLiftCreatePlayerSessionRequest(
+            const AWSGameLiftJoinSessionRequest& joinSessionRequest)
+        {
+            Aws::GameLift::Model::CreatePlayerSessionRequest request;
+            // Optional attributes
+            if (!joinSessionRequest.m_playerData.empty())
+            {
+                request.SetPlayerData(joinSessionRequest.m_playerData.c_str());
+            }
+            // Required attributes
+            request.SetPlayerId(joinSessionRequest.m_playerId.c_str());
+            request.SetGameSessionId(joinSessionRequest.m_sessionId.c_str());
+            return request;
+        }
+
+        AzFramework::SessionConnectionConfig BuildSessionConnectionConfig(
+            const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome)
+        {
+            AzFramework::SessionConnectionConfig sessionConnectionConfig;
+            auto createPlayerSessionResult = createPlayerSessionOutcome.GetResult();
+            // TODO: AWSNativeSDK needs to be updated to support this attribute, and it is a must have for TLS certificate enabled fleet
+            //sessionConnectionConfig.m_dnsName = createPlayerSessionResult.GetPlayerSession().GetDnsName().c_str();
+            sessionConnectionConfig.m_ipAddress = createPlayerSessionResult.GetPlayerSession().GetIpAddress().c_str();
+            sessionConnectionConfig.m_playerSessionId = createPlayerSessionResult.GetPlayerSession().GetPlayerSessionId().c_str();
+            sessionConnectionConfig.m_port = createPlayerSessionResult.GetPlayerSession().GetPort();
+            return sessionConnectionConfig;
+        }
+
+        Aws::GameLift::Model::CreatePlayerSessionOutcome CreatePlayerSession(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftJoinSessionRequest& joinSessionRequest)
+        {
+            AZ_TracePrintf(AWSGameLiftJoinSessionActivityName,
+                "Requesting CreatePlayerSession for player %s against Amazon GameLift service ...",
+                joinSessionRequest.m_playerId.c_str());
+
+            Aws::GameLift::Model::CreatePlayerSessionRequest request =
+                BuildAWSGameLiftCreatePlayerSessionRequest(joinSessionRequest);
+            auto createPlayerSessionOutcome = gameliftClient.CreatePlayerSession(request);
+
+            if (!createPlayerSessionOutcome.IsSuccess())
+            {
+                AZ_Error(AWSGameLiftJoinSessionActivityName, false, AWSGameLiftErrorMessageTemplate,
+                    createPlayerSessionOutcome.GetError().GetExceptionName().c_str(),
+                    createPlayerSessionOutcome.GetError().GetMessage().c_str());
+            }
+            return createPlayerSessionOutcome;
+        }
+
+        bool RequestPlayerJoinSession(const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome)
+        {
+            bool result = false;
+            if (createPlayerSessionOutcome.IsSuccess())
+            {
+                auto clientRequestHandler = AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Get();
+                if (clientRequestHandler)
+                {
+                    AZ_TracePrintf(AWSGameLiftJoinSessionActivityName, "Requesting player to connect to game session ...");
+
+                    AzFramework::SessionConnectionConfig sessionConnectionConfig =
+                        BuildSessionConnectionConfig(createPlayerSessionOutcome);
+                    result = clientRequestHandler->RequestPlayerJoinSession(sessionConnectionConfig);
+                }
+                else
+                {
+                    AZ_Error(AWSGameLiftJoinSessionActivityName, false, AWSGameLiftJoinSessionMissingRequestHandlerErrorMessage);
+                }
+            }
+            return result;
+        }
+
+        bool ValidateJoinSessionRequest(const AzFramework::JoinSessionRequest& joinSessionRequest)
+        {
+            auto gameliftJoinSessionRequest = azrtti_cast<const AWSGameLiftJoinSessionRequest*>(&joinSessionRequest);
+
+            if (gameliftJoinSessionRequest &&
+                !gameliftJoinSessionRequest->m_playerId.empty() &&
+                !gameliftJoinSessionRequest->m_sessionId.empty())
+            {
+                return true;
+            }
+            else
+            {
+                AZ_Error(AWSGameLiftJoinSessionActivityName, false, AWSGameLiftJoinSessionRequestInvalidErrorMessage);
+
+                return false;
+            }
+        }
+    } // namespace JoinSessionActivity
+} // namespace AWSGameLift

+ 54 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.h

@@ -0,0 +1,54 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzFramework/Session/ISessionHandlingRequests.h>
+
+#include <Request/AWSGameLiftJoinSessionRequest.h>
+
+#include <aws/core/utils/Outcome.h>
+#include <aws/gamelift/GameLiftClient.h>
+#include <aws/gamelift/model/CreatePlayerSessionRequest.h>
+
+namespace AWSGameLift
+{
+    namespace JoinSessionActivity
+    {
+        static constexpr const char AWSGameLiftJoinSessionActivityName[] = "AWSGameLiftJoinSessionActivity";
+        static constexpr const char AWSGameLiftJoinSessionRequestInvalidErrorMessage[] =
+            "Invalid GameLift JoinSession request.";
+        static constexpr const char AWSGameLiftJoinSessionMissingRequestHandlerErrorMessage[] =
+            "Missing GameLift JoinSession request handler, please make sure Multiplayer Gem is enabled and registered as handler.";
+
+        // Build AWS GameLift CreatePlayerSessionRequest by using AWSGameLiftJoinSessionRequest
+        Aws::GameLift::Model::CreatePlayerSessionRequest BuildAWSGameLiftCreatePlayerSessionRequest(
+            const AWSGameLiftJoinSessionRequest& joinSessionRequest);
+
+        // Build session connection config by using CreatePlayerSessionOutcome
+        AzFramework::SessionConnectionConfig BuildSessionConnectionConfig(
+            const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome);
+
+        // Create CreatePlayerSessionRequest and make a CreatePlayerSession call through GameLift client
+        Aws::GameLift::Model::CreatePlayerSessionOutcome CreatePlayerSession(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftJoinSessionRequest& joinSessionRequest);
+
+        // Request to setup networking connection for player
+        bool RequestPlayerJoinSession(
+            const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome);
+
+        // Validate JoinSessionRequest and check required request parameters
+        bool ValidateJoinSessionRequest(const AzFramework::JoinSessionRequest& joinSessionRequest);
+
+    } // namespace JoinSessionActivity
+} // namespace AWSGameLift

+ 38 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.cpp

@@ -0,0 +1,38 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <Activity/AWSGameLiftLeaveSessionActivity.h>
+
+#include <AzCore/Interface/Interface.h>
+#include <AzFramework/Session/ISessionHandlingRequests.h>
+
+namespace AWSGameLift
+{
+    namespace LeaveSessionActivity
+    {
+        void LeaveSession()
+        {
+            auto clientRequestHandler = AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Get();
+            if (clientRequestHandler)
+            {
+                AZ_TracePrintf(AWSGameLiftLeaveSessionActivityName, "Requesting to leave the current session...");
+
+                clientRequestHandler->RequestPlayerLeaveSession();
+            }
+            else
+            {
+                AZ_Error(AWSGameLiftLeaveSessionActivityName, false, AWSGameLiftLeaveSessionMissingRequestHandlerErrorMessage);
+            }
+        }
+
+    } // namespace LeaveSessionActivity
+} // namespace AWSGameLift

+ 27 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.h

@@ -0,0 +1,27 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+namespace AWSGameLift
+{
+    namespace LeaveSessionActivity
+    {
+        static constexpr const char AWSGameLiftLeaveSessionActivityName[] = "AWSGameLiftLeaveSessionActivity";
+        static constexpr const char AWSGameLiftLeaveSessionMissingRequestHandlerErrorMessage[] =
+            "Missing GameLift LeaveSession request handler, please make sure Multiplayer Gem is enabled and registered as handler.";
+
+        // Request to leave the current session
+        void LeaveSession();
+    } // namespace LeaveSessionActivity
+} // namespace AWSGameLift
+

+ 130 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp

@@ -0,0 +1,130 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzFramework/Session/SessionConfig.h>
+
+#include <Activity/AWSGameLiftSearchSessionsActivity.h>
+#include <AWSGameLiftSessionConstants.h>
+
+namespace AWSGameLift
+{
+    namespace SearchSessionsActivity
+    {
+        Aws::GameLift::Model::SearchGameSessionsRequest BuildAWSGameLiftSearchGameSessionsRequest(
+            const AWSGameLiftSearchSessionsRequest& searchSessionsRequest)
+        {
+            Aws::GameLift::Model::SearchGameSessionsRequest request;
+            // Optional attributes
+            if (!searchSessionsRequest.m_filterExpression.empty())
+            {
+                request.SetFilterExpression(searchSessionsRequest.m_filterExpression.c_str());
+            }
+            if (!searchSessionsRequest.m_sortExpression.empty())
+            {
+                request.SetSortExpression(searchSessionsRequest.m_sortExpression.c_str());
+            }
+            if (searchSessionsRequest.m_maxResult > 0)
+            {
+                request.SetLimit(searchSessionsRequest.m_maxResult);
+            }
+            if (!searchSessionsRequest.m_nextToken.empty())
+            {
+                request.SetNextToken(searchSessionsRequest.m_nextToken.c_str());
+            }
+            // Required attributes
+            if (!searchSessionsRequest.m_aliasId.empty())
+            {
+                request.SetAliasId(searchSessionsRequest.m_aliasId.c_str());
+            }
+            if (!searchSessionsRequest.m_fleetId.empty())
+            {
+                request.SetFleetId(searchSessionsRequest.m_fleetId.c_str());
+            }
+            // TODO: Update the AWS Native SDK to accept the new request parameter.
+            //request.SetLocation(searchSessionsRequest.m_location.c_str());
+            return request;
+        }
+
+        AzFramework::SearchSessionsResponse SearchSessions(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftSearchSessionsRequest& searchSessionsRequest)
+        {
+            AZ_TracePrintf(AWSGameLiftSearchSessionsActivityName, "Requesting SearchGameSessions against Amazon GameLift service ...");
+
+            AzFramework::SearchSessionsResponse response;
+            Aws::GameLift::Model::SearchGameSessionsRequest request = BuildAWSGameLiftSearchGameSessionsRequest(searchSessionsRequest);
+            Aws::GameLift::Model::SearchGameSessionsOutcome outcome = gameliftClient.SearchGameSessions(request);
+
+            if (outcome.IsSuccess())
+            {
+                response = SearchSessionsActivity::ParseResponse(outcome.GetResult());
+            }
+            else
+            {
+                AZ_Error(AWSGameLiftSearchSessionsActivityName, false, AWSGameLiftErrorMessageTemplate,
+                    outcome.GetError().GetExceptionName().c_str(), outcome.GetError().GetMessage().c_str());
+            }
+
+            return response;
+        }
+
+        AzFramework::SearchSessionsResponse ParseResponse(
+            const Aws::GameLift::Model::SearchGameSessionsResult& gameLiftSearchSessionsResult)
+        {
+            AzFramework::SearchSessionsResponse response;
+            response.m_nextToken = gameLiftSearchSessionsResult.GetNextToken().c_str();
+
+            for (const Aws::GameLift::Model::GameSession& gameSession : gameLiftSearchSessionsResult.GetGameSessions())
+            {
+                AzFramework::SessionConfig session;
+                session.m_creationTime = gameSession.GetCreationTime().Millis();
+                session.m_creatorId = gameSession.GetCreatorId().c_str();
+                session.m_currentPlayer = gameSession.GetCurrentPlayerSessionCount();
+                session.m_ipAddress = gameSession.GetIpAddress().c_str();
+                session.m_maxPlayer = gameSession.GetMaximumPlayerSessionCount();
+                session.m_port = gameSession.GetPort();
+                session.m_sessionId = gameSession.GetGameSessionId().c_str();
+                session.m_sessionName = gameSession.GetName().c_str();
+                session.m_status = AWSGameLiftSessionStatusNames[(int)gameSession.GetStatus()];
+                session.m_statusReason = AWSGameLiftSessionStatusReasons[(int)gameSession.GetStatusReason()];
+                session.m_terminationTime = gameSession.GetTerminationTime().Millis();
+                // TODO: Update the AWS Native SDK to get the new game session attributes.
+                //session.m_dnsName = gameSession.GetDnsName();
+
+                for (const auto& gameProperty : gameSession.GetGameProperties())
+                {
+                    session.m_sessionProperties[gameProperty.GetKey().c_str()] = gameProperty.GetValue().c_str();
+                }
+
+                response.m_sessionConfigs.emplace_back(AZStd::move(session));
+            }
+
+            return response;
+        };
+
+        bool ValidateSearchSessionsRequest(const AzFramework::SearchSessionsRequest& searchSessionsRequest)
+        {
+            auto gameliftSearchSessionsRequest = azrtti_cast<const AWSGameLiftSearchSessionsRequest*>(&searchSessionsRequest);
+            if (gameliftSearchSessionsRequest &&
+                (!gameliftSearchSessionsRequest->m_aliasId.empty() || !gameliftSearchSessionsRequest->m_fleetId.empty()))
+            {
+                return true;
+            }
+            else
+            {
+                AZ_Error(AWSGameLiftSearchSessionsActivityName, false, AWSGameLiftSearchSessionsRequestInvalidErrorMessage);
+
+                return false;
+            }
+        }
+    }
+} // namespace AWSGameLift

+ 45 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.h

@@ -0,0 +1,45 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <Request/AWSGameLiftSearchSessionsRequest.h>
+
+#include <aws/core/utils/Outcome.h>
+#include <aws/gamelift/GameLiftClient.h>
+#include <aws/gamelift/model/SearchGameSessionsRequest.h>
+
+namespace AWSGameLift
+{
+    namespace SearchSessionsActivity
+    {
+        static constexpr const char AWSGameLiftSearchSessionsActivityName[] = "AWSGameLiftSearchSessionsActivity";
+        static constexpr const char AWSGameLiftSearchSessionsRequestInvalidErrorMessage[] =
+            "Invalid GameLift SearchSessions request.";
+
+        // Build AWS GameLift SearchGameSessionsRequest by using AWSGameLiftSearchSessionsRequest
+        Aws::GameLift::Model::SearchGameSessionsRequest BuildAWSGameLiftSearchGameSessionsRequest(
+            const AWSGameLiftSearchSessionsRequest& searchSessionsRequest);
+
+        // Create SearchGameSessionsRequest and make a SeachGameSessions call through GameLift client
+        AzFramework::SearchSessionsResponse SearchSessions(
+            const Aws::GameLift::GameLiftClient& gameliftClient,
+            const AWSGameLiftSearchSessionsRequest& searchSessionsRequest);
+
+        // Convert from Aws::GameLift::Model::SearchGameSessionsResult to AzFramework::SearchSessionsResponse.
+        AzFramework::SearchSessionsResponse ParseResponse(
+            const Aws::GameLift::Model::SearchGameSessionsResult& gameLiftSearchSessionsResult);
+
+        // Validate SearchSessionsRequest and check required request parameters
+        bool ValidateSearchSessionsRequest(const AzFramework::SearchSessionsRequest& searchSessionsRequest);
+    } // namespace SearchSessionsActivity
+} // namespace AWSGameLift

+ 58 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp

@@ -0,0 +1,58 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+
+#include <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
+
+namespace AWSGameLift
+{
+    void AWSGameLiftCreateSessionOnQueueRequest::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<AWSGameLiftCreateSessionOnQueueRequest, AzFramework::CreateSessionRequest>()
+                ->Version(0)
+                ->Field("queueName", &AWSGameLiftCreateSessionOnQueueRequest::m_queueName)
+                ->Field("placementId", &AWSGameLiftCreateSessionOnQueueRequest::m_placementId)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<AWSGameLiftCreateSessionOnQueueRequest>("AWSGameLiftCreateSessionOnQueueRequest", "")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionOnQueueRequest::m_queueName, "QueueName (Required)",
+                        "Name of the queue to use to place the new game session")
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionOnQueueRequest::m_placementId, "PlacementId (Required)",
+                        "A unique identifier to assign to the new game session placement")
+                    ;
+            }
+        }
+
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<AWSGameLiftCreateSessionOnQueueRequest>("AWSGameLiftCreateSessionOnQueueRequest")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                ->Property("CreatorId", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_creatorId))
+                ->Property("SessionProperties", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_sessionProperties))
+                ->Property("SessionName", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_sessionName))
+                ->Property("MaxPlayer", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_maxPlayer))
+                ->Property("QueueName", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_queueName))
+                ->Property("PlacementId", BehaviorValueProperty(&AWSGameLiftCreateSessionOnQueueRequest::m_placementId))
+                ;
+        }
+    }
+} // namespace AWSGameLift

+ 63 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp

@@ -0,0 +1,63 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+
+#include <Request/AWSGameLiftCreateSessionRequest.h>
+
+namespace AWSGameLift
+{
+    void AWSGameLiftCreateSessionRequest::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<AWSGameLiftCreateSessionRequest, AzFramework::CreateSessionRequest>()
+                ->Version(0)
+                ->Field("aliasId", &AWSGameLiftCreateSessionRequest::m_aliasId)
+                ->Field("fleetId", &AWSGameLiftCreateSessionRequest::m_fleetId)
+                ->Field("idempotencyToken", &AWSGameLiftCreateSessionRequest::m_idempotencyToken)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<AWSGameLiftCreateSessionRequest>("AWSGameLiftCreateSessionRequest", "")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionRequest::m_aliasId, "AliasId (Required, or FleetId)",
+                        "A unique identifier for the alias associated with the fleet to create a game session in")
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionRequest::m_fleetId, "FleetId (Required, or AliasId)",
+                        "A unique identifier for the fleet to create a game session in")
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftCreateSessionRequest::m_idempotencyToken, "IdempotencyToken",
+                        "Custom string that uniquely identifies the new game session request")
+                    ;
+            }
+        }
+
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<AWSGameLiftCreateSessionRequest>("AWSGameLiftCreateSessionRequest")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                ->Property("CreatorId", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_creatorId))
+                ->Property("SessionProperties", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_sessionProperties))
+                ->Property("SessionName", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_sessionName))
+                ->Property("MaxPlayer", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_maxPlayer))
+                ->Property("AliasId", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_aliasId))
+                ->Property("FleetId", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_fleetId))
+                ->Property("IdempotencyToken", BehaviorValueProperty(&AWSGameLiftCreateSessionRequest::m_idempotencyToken))
+                ;
+        }
+    }
+} // namespace AWSGameLift

+ 54 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp

@@ -0,0 +1,54 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+
+#include <Request/AWSGameLiftJoinSessionRequest.h>
+
+namespace AWSGameLift
+{
+    void AWSGameLiftJoinSessionRequest::Reflect(AZ::ReflectContext* context)
+    {
+        AzFramework::JoinSessionRequest::Reflect(context);
+
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<AWSGameLiftJoinSessionRequest, AzFramework::JoinSessionRequest>()
+                ->Version(0)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<AWSGameLiftJoinSessionRequest>("AWSGameLiftJoinSessionRequest", "")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
+                    ;
+            }
+        }
+
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<AzFramework::JoinSessionRequest>("JoinSessionRequest")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                // Expose base type to BehaviorContext, but hide it to be used directly
+                ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
+                ;
+            behaviorContext->Class<AWSGameLiftJoinSessionRequest>("AWSGameLiftJoinSessionRequest")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                ->Property("PlayerData", BehaviorValueProperty(&AWSGameLiftJoinSessionRequest::m_playerData))
+                ->Property("PlayerId", BehaviorValueProperty(&AWSGameLiftJoinSessionRequest::m_playerId))
+                ->Property("SessionId", BehaviorValueProperty(&AWSGameLiftJoinSessionRequest::m_sessionId))
+                ;
+        }
+    }
+} // namespace AWSGameLift

+ 69 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp

@@ -0,0 +1,69 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzFramework/Session/SessionConfig.h>
+
+#include <Request/AWSGameLiftSearchSessionsRequest.h>
+#include <AWSGameLiftSessionConstants.h>
+
+namespace AWSGameLift
+{
+    void AWSGameLiftSearchSessionsRequest::Reflect(AZ::ReflectContext* context)
+    {
+        AzFramework::SearchSessionsRequest::Reflect(context);
+
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<AWSGameLiftSearchSessionsRequest, AzFramework::SearchSessionsRequest>()
+                ->Version(0)
+                ->Field("aliasId", &AWSGameLiftSearchSessionsRequest::m_aliasId)
+                ->Field("fleetId", &AWSGameLiftSearchSessionsRequest::m_fleetId)
+                ->Field("location", &AWSGameLiftSearchSessionsRequest::m_location);
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<AWSGameLiftSearchSessionsRequest>("AWSGameLiftSearchSessionsRequest", "")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftSearchSessionsRequest::m_aliasId, "AliasId (Required, or FleetId)",
+                        "A unique identifier for the alias associated with the fleet to search for active game sessions.")
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftSearchSessionsRequest::m_fleetId, "FleetId (Required, or AliasId)",
+                        "A unique identifier for the fleet to search for active game sessions.")
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default, &AWSGameLiftSearchSessionsRequest::m_location, "Location",
+                        "A fleet location to search for game sessions.");
+            }
+        }
+
+        if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<AzFramework::SearchSessionsRequest>("SearchSessionsRequest")
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                // Expose base type to BehaviorContext, but hide it to be used directly
+                ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All);
+            behaviorContext->Class<AWSGameLiftSearchSessionsRequest>("AWSGameLiftSearchSessionsRequest")
+
+                ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
+                ->Property("FilterExpression", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_filterExpression))
+                ->Property("SortExpression", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_sortExpression))
+                ->Property("MaxResult", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_maxResult))
+                ->Property("NextToken", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_nextToken))
+                ->Property("AliasId", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_aliasId))
+                ->Property("FleetId", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_fleetId))
+                ->Property("Location", BehaviorValueProperty(&AWSGameLiftSearchSessionsRequest::m_location));
+        }
+    }
+} // namespace AWSGameLift

+ 63 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientFixture.h

@@ -0,0 +1,63 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
+#include <AzCore/Jobs/JobManager.h>
+#include <AzCore/Jobs/JobManagerBus.h>
+#include <AzCore/Jobs/JobContext.h>
+#include <AzCore/Memory/PoolAllocator.h>
+#include <AzCore/UnitTest/TestTypes.h>
+
+class AWSGameLiftClientFixture
+    : public UnitTest::ScopedAllocatorSetupFixture
+{
+public:
+    AWSGameLiftClientFixture() {}
+    virtual ~AWSGameLiftClientFixture() = default;
+
+    void SetUp() override
+    {
+        AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
+        AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
+
+        AZ::JobManagerDesc jobManagerDesc;
+        AZ::JobManagerThreadDesc threadDesc;
+
+        m_jobManager.reset(aznew AZ::JobManager(jobManagerDesc));
+        m_jobCancelGroup.reset(aznew AZ::JobCancelGroup());
+        jobManagerDesc.m_workerThreads.push_back(threadDesc);
+        jobManagerDesc.m_workerThreads.push_back(threadDesc);
+        jobManagerDesc.m_workerThreads.push_back(threadDesc);
+        m_jobContext.reset(aznew AZ::JobContext(*m_jobManager, *m_jobCancelGroup));
+        AZ::JobContext::SetGlobalContext(m_jobContext.get());
+
+        AWSNativeSDKInit::InitializationManager::InitAwsApi();
+    }
+
+    void TearDown() override
+    {
+        AWSNativeSDKInit::InitializationManager::Shutdown();
+
+        AZ::JobContext::SetGlobalContext(nullptr);
+        m_jobContext.reset();
+        m_jobCancelGroup.reset();
+        m_jobManager.reset();
+        AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
+        AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
+    }
+
+    AZStd::unique_ptr<AZ::JobContext> m_jobContext;
+    AZStd::unique_ptr<AZ::JobCancelGroup> m_jobCancelGroup;
+    AZStd::unique_ptr<AZ::JobManager> m_jobManager;
+};

+ 773 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp

@@ -0,0 +1,773 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Component/ComponentApplication.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/std/smart_ptr/make_shared.h>
+#include <AzFramework/Session/SessionConfig.h>
+#include <Credential/AWSCredentialBus.h>
+#include <ResourceMapping/AWSResourceMappingBus.h>
+
+#include <AWSCoreBus.h>
+#include <AWSGameLiftClientFixture.h>
+#include <AWSGameLiftClientManager.h>
+#include <AWSGameLiftClientMocks.h>
+
+#include <Request/AWSGameLiftCreateSessionOnQueueRequest.h>
+#include <Request/AWSGameLiftCreateSessionRequest.h>
+#include <Request/AWSGameLiftJoinSessionRequest.h>
+#include <Request/AWSGameLiftSearchSessionsRequest.h>
+
+#include <aws/gamelift/GameLiftClient.h>
+
+using namespace AWSGameLift;
+
+MATCHER_P(SearchSessionsResponseMatcher, expectedResponse, "")
+{
+    // Custome matcher for checking the SearchSessionsResponse type argument.
+    AZ_UNUSED(result_listener);
+
+    bool result = arg.m_nextToken == expectedResponse.m_nextToken;
+    result &= arg.m_sessionConfigs.size() == expectedResponse.m_sessionConfigs.size();
+
+    for (int index = 0; index < arg.m_sessionConfigs.size(); ++index)
+    {
+        result &= arg.m_sessionConfigs[index].m_creationTime == expectedResponse.m_sessionConfigs[index].m_creationTime;
+        result &= arg.m_sessionConfigs[index].m_terminationTime == expectedResponse.m_sessionConfigs[index].m_terminationTime;
+        result &= arg.m_sessionConfigs[index].m_creatorId == expectedResponse.m_sessionConfigs[index].m_creatorId;
+        result &= arg.m_sessionConfigs[index].m_sessionProperties == expectedResponse.m_sessionConfigs[index].m_sessionProperties;
+        result &= arg.m_sessionConfigs[index].m_sessionId == expectedResponse.m_sessionConfigs[index].m_sessionId;
+        result &= arg.m_sessionConfigs[index].m_sessionName == expectedResponse.m_sessionConfigs[index].m_sessionName;
+        result &= arg.m_sessionConfigs[index].m_dnsName == expectedResponse.m_sessionConfigs[index].m_dnsName;
+        result &= arg.m_sessionConfigs[index].m_ipAddress == expectedResponse.m_sessionConfigs[index].m_ipAddress;
+        result &= arg.m_sessionConfigs[index].m_port == expectedResponse.m_sessionConfigs[index].m_port;
+        result &= arg.m_sessionConfigs[index].m_maxPlayer == expectedResponse.m_sessionConfigs[index].m_maxPlayer;
+        result &= arg.m_sessionConfigs[index].m_currentPlayer == expectedResponse.m_sessionConfigs[index].m_currentPlayer;
+        result &= arg.m_sessionConfigs[index].m_status == expectedResponse.m_sessionConfigs[index].m_status;
+        result &= arg.m_sessionConfigs[index].m_statusReason == expectedResponse.m_sessionConfigs[index].m_statusReason;
+    }
+
+    return result;
+}
+
+class AWSResourceMappingRequestsHandlerMock
+    : public AWSCore::AWSResourceMappingRequestBus::Handler
+{
+public:
+    AWSResourceMappingRequestsHandlerMock()
+    {
+        AWSCore::AWSResourceMappingRequestBus::Handler::BusConnect();
+    }
+
+    ~ AWSResourceMappingRequestsHandlerMock()
+    {
+        AWSCore::AWSResourceMappingRequestBus::Handler::BusDisconnect();
+    }
+
+    MOCK_CONST_METHOD0(GetDefaultRegion, AZStd::string());
+    MOCK_CONST_METHOD0(GetDefaultAccountId, AZStd::string());
+    MOCK_CONST_METHOD1(GetResourceAccountId, AZStd::string(const AZStd::string&));
+    MOCK_CONST_METHOD1(GetResourceNameId, AZStd::string(const AZStd::string&));
+    MOCK_CONST_METHOD1(GetResourceRegion, AZStd::string(const AZStd::string&));
+    MOCK_CONST_METHOD1(GetResourceType, AZStd::string(const AZStd::string&));
+    MOCK_CONST_METHOD1(GetServiceUrlByServiceName, AZStd::string(const AZStd::string&));
+    MOCK_CONST_METHOD2(GetServiceUrlByRESTApiIdAndStage, AZStd::string(const AZStd::string&, const AZStd::string&));
+    MOCK_METHOD1(ReloadConfigFile, void(bool));
+};
+
+class AWSCredentialRequestsHandlerMock
+    : public AWSCore::AWSCredentialRequestBus::Handler
+{
+public:
+    AWSCredentialRequestsHandlerMock()
+    {
+        AWSCore::AWSCredentialRequestBus::Handler::BusConnect();
+    }
+
+    ~AWSCredentialRequestsHandlerMock()
+    {
+        AWSCore::AWSCredentialRequestBus::Handler::BusDisconnect();
+    }
+
+    MOCK_CONST_METHOD0(GetCredentialHandlerOrder, int());
+    MOCK_METHOD0(GetCredentialsProvider, std::shared_ptr<Aws::Auth::AWSCredentialsProvider>());
+};
+
+class AWSCoreRequestsHandlerMock
+    : public AWSCore::AWSCoreRequestBus::Handler
+{
+public:
+    AWSCoreRequestsHandlerMock()
+    {
+        AWSCore::AWSCoreRequestBus::Handler::BusConnect();
+    }
+
+    ~AWSCoreRequestsHandlerMock()
+    {
+        AWSCore::AWSCoreRequestBus::Handler::BusDisconnect();
+    }
+
+    MOCK_METHOD0(GetDefaultJobContext, AZ::JobContext*());
+    MOCK_METHOD0(GetDefaultConfig, AWSCore::AwsApiJobConfig*());
+};
+
+class TestAWSGameLiftClientManager
+    : public AWSGameLiftClientManager
+{
+public:
+    TestAWSGameLiftClientManager()
+    {
+        m_gameliftClientMockPtr = nullptr;
+    }
+    ~TestAWSGameLiftClientManager()
+    {
+        m_gameliftClientMockPtr = nullptr;
+    }
+
+    void SetUpMockClient()
+    {
+        m_gameliftClientMockPtr = AZStd::make_shared<GameLiftClientMock>();
+        SetGameLiftClient(m_gameliftClientMockPtr);
+    }
+
+    AZStd::shared_ptr<GameLiftClientMock> m_gameliftClientMockPtr;
+};
+
+class AWSGameLiftClientManagerTest
+    : public AWSGameLiftClientFixture
+{
+protected:
+    void SetUp() override
+    {
+        AWSGameLiftClientFixture::SetUp();
+
+        m_gameliftClientManager = AZStd::make_unique<TestAWSGameLiftClientManager>();
+        m_gameliftClientManager->SetUpMockClient();
+        m_gameliftClientManager->ActivateManager();
+    }
+
+    void TearDown() override
+    {
+        m_gameliftClientManager->DeactivateManager();
+        m_gameliftClientManager.reset();
+
+        AWSGameLiftClientFixture::TearDown();
+    }
+
+    AWSGameLiftSearchSessionsRequest GetValidSearchSessionsRequest()
+    {
+        AWSGameLiftSearchSessionsRequest request;
+        request.m_aliasId = "dummyAliasId";
+        request.m_fleetId = "dummyFleetId";
+        request.m_location = "dummyLocation";
+        request.m_filterExpression = "dummyFilterExpression";
+        request.m_sortExpression = "dummySortExpression";
+        request.m_maxResult = 1;
+        request.m_nextToken = "dummyNextToken";
+
+        return request;
+    }
+
+    Aws::GameLift::Model::SearchGameSessionsOutcome GetValidSearchGameSessionsOutcome()
+    {
+        Aws::GameLift::Model::GameProperty gameProperty;
+        gameProperty.SetKey("dummyKey");
+        gameProperty.SetValue("dummyValue");
+        Aws::Vector<Aws::GameLift::Model::GameProperty> gameProperties = { gameProperty };
+
+        Aws::GameLift::Model::GameSession gameSession;
+        gameSession.SetCreationTime(Aws::Utils::DateTime(0.0));
+        gameSession.SetTerminationTime(Aws::Utils::DateTime(0.0));
+        gameSession.SetCreatorId("dummyCreatorId");
+        gameSession.SetGameProperties(gameProperties);
+        gameSession.SetGameSessionId("dummyGameSessionId");
+        gameSession.SetName("dummyGameSessionName");
+        gameSession.SetIpAddress("dummyIpAddress");
+        gameSession.SetPort(0);
+        gameSession.SetMaximumPlayerSessionCount(2);
+        gameSession.SetCurrentPlayerSessionCount(1);
+        gameSession.SetStatus(Aws::GameLift::Model::GameSessionStatus::TERMINATED);
+        gameSession.SetStatusReason(Aws::GameLift::Model::GameSessionStatusReason::INTERRUPTED);
+        // TODO: Update the AWS Native SDK to set the new game session attributes.
+        // gameSession.SetDnsName("dummyDnsName");
+
+        Aws::GameLift::Model::SearchGameSessionsResult result;
+        result.SetNextToken("dummyNextToken");
+        result.SetGameSessions({ gameSession });
+
+        return Aws::GameLift::Model::SearchGameSessionsOutcome(result);
+    }
+
+    AzFramework::SearchSessionsResponse GetValidSearchSessionsResponse()
+    {
+        AzFramework::SessionConfig sessionConfig;
+        sessionConfig.m_creationTime = 0;
+        sessionConfig.m_terminationTime = 0;
+        sessionConfig.m_creatorId = "dummyCreatorId";
+        sessionConfig.m_sessionProperties["dummyKey"] = "dummyValue";
+        sessionConfig.m_sessionId = "dummyGameSessionId";
+        sessionConfig.m_sessionName = "dummyGameSessionName";
+        sessionConfig.m_ipAddress = "dummyIpAddress";
+        sessionConfig.m_port = 0;
+        sessionConfig.m_maxPlayer = 2;
+        sessionConfig.m_currentPlayer = 1;
+        sessionConfig.m_status = "Terminated";
+        sessionConfig.m_statusReason = "Interrupted";
+        // TODO: Update the AWS Native SDK to set the new game session attributes.
+        // sessionConfig.m_dnsName = "dummyDnsName";
+
+        AzFramework::SearchSessionsResponse response;
+        response.m_nextToken = "dummyNextToken";
+        response.m_sessionConfigs = { sessionConfig };
+
+        return response;
+    }
+
+public:
+    AZStd::unique_ptr<TestAWSGameLiftClientManager> m_gameliftClientManager;
+};
+
+TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutRegion_GetFalseAsResult)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = m_gameliftClientManager->ConfigureGameLiftClient("");
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutCredential_GetFalseAsResult)
+{
+    AWSResourceMappingRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultRegion()).Times(1).WillOnce(::testing::Return("us-west-2"));
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = m_gameliftClientManager->ConfigureGameLiftClient("");
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithRegionAndCredential_GetTrueAsResult)
+{
+    AWSCredentialRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetCredentialsProvider())
+        .Times(1)
+        .WillOnce(::testing::Return(std::make_shared<Aws::Auth::SimpleAWSCredentialsProvider>("dummyAccess", "dummySecret", "")));
+    auto result = m_gameliftClientManager->ConfigureGameLiftClient("us-west-2");
+    EXPECT_TRUE(result);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithoutBracketsOrDashes_GetExpectedResult)
+{
+    auto result = m_gameliftClientManager->CreatePlayerId(false, false);
+    EXPECT_FALSE(result.starts_with("{"));
+    EXPECT_FALSE(result.ends_with("}"));
+    EXPECT_FALSE(result.contains("-"));
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithBrackets_GetExpectedResult)
+{
+    auto result = m_gameliftClientManager->CreatePlayerId(true, false);
+    EXPECT_TRUE(result.starts_with("{"));
+    EXPECT_TRUE(result.ends_with("}"));
+    EXPECT_FALSE(result.contains("-"));
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithDashes_GetExpectedResult)
+{
+    auto result = m_gameliftClientManager->CreatePlayerId(false, true);
+    EXPECT_FALSE(result.starts_with("{"));
+    EXPECT_FALSE(result.ends_with("}"));
+    EXPECT_TRUE(result.contains("-"));
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreatePlayerId_CreateWithBracketsAndDashes_GetExpectedResult)
+{
+    auto result = m_gameliftClientManager->CreatePlayerId(true, true);
+    EXPECT_TRUE(result.starts_with("{"));
+    EXPECT_TRUE(result.ends_with("}"));
+    EXPECT_TRUE(result.contains("-"));
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithoutClientSetup_GetEmptyResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->ConfigureGameLiftClient("");
+    AWSGameLiftCreateSessionRequest request;
+    request.m_aliasId = "dummyAlias";
+    auto response = m_gameliftClientManager->CreateSession(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message
+    EXPECT_TRUE(response == "");
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithInvalidRequest_GetEmptyResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto response = m_gameliftClientManager->CreateSession(AzFramework::CreateSessionRequest());
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+    EXPECT_TRUE(response == "");
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithValidRequest_GetSuccessOutcome)
+{
+    AWSGameLiftCreateSessionRequest request;
+    request.m_aliasId = "dummyAlias";
+    Aws::GameLift::Model::CreateGameSessionResult result;
+    result.SetGameSession(Aws::GameLift::Model::GameSession());
+    Aws::GameLift::Model::CreateGameSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    m_gameliftClientManager->CreateSession(request);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithValidRequest_GetErrorOutcome)
+{
+    AWSGameLiftCreateSessionRequest request;
+    request.m_aliasId = "dummyAlias";
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::CreateGameSessionOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->CreateSession(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithInvalidRequest_GetNotificationWithEmptyResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(AZStd::string())).Times(1);
+    m_gameliftClientManager->CreateSessionAsync(AzFramework::CreateSessionRequest());
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithValidRequest_GetNotificationWithSuccessOutcome)
+{
+    AWSCoreRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    AWSGameLiftCreateSessionRequest request;
+    request.m_aliasId = "dummyAlias";
+    Aws::GameLift::Model::CreateGameSessionResult result;
+    result.SetGameSession(Aws::GameLift::Model::GameSession());
+    Aws::GameLift::Model::CreateGameSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(::testing::_)).Times(1);
+    m_gameliftClientManager->CreateSessionAsync(request);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithValidRequest_GetNotificationWithErrorOutcome)
+{
+    AWSCoreRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    AWSGameLiftCreateSessionRequest request;
+    request.m_aliasId = "dummyAlias";
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::CreateGameSessionOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(AZStd::string(""))).Times(1);
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->CreateSessionAsync(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithoutClientSetup_GetEmptyResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->ConfigureGameLiftClient("");
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_queueName = "dummyQueue";
+    request.m_placementId = "dummyPlacementId";
+    auto response = m_gameliftClientManager->CreateSession(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message
+    EXPECT_TRUE(response == "");
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithValidRequest_GetSuccessOutcome)
+{
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_queueName = "dummyQueue";
+    request.m_placementId = "dummyPlacementId";
+    Aws::GameLift::Model::StartGameSessionPlacementResult result;
+    result.SetGameSessionPlacement(Aws::GameLift::Model::GameSessionPlacement());
+    Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    m_gameliftClientManager->CreateSession(request);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithValidRequest_GetErrorOutcome)
+{
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_queueName = "dummyQueue";
+    request.m_placementId = "dummyPlacementId";
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->CreateSession(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueueAsync_CallWithValidRequest_GetNotificationWithSuccessOutcome)
+{
+    AWSCoreRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_queueName = "dummyQueue";
+    request.m_placementId = "dummyPlacementId";
+    Aws::GameLift::Model::StartGameSessionPlacementResult result;
+    result.SetGameSessionPlacement(Aws::GameLift::Model::GameSessionPlacement());
+    Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(::testing::_)).Times(1);
+    m_gameliftClientManager->CreateSessionAsync(request);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueueAsync_CallWithValidRequest_GetNotificationWithErrorOutcome)
+{
+    AWSCoreRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_queueName = "dummyQueue";
+    request.m_placementId = "dummyPlacementId";
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(AZStd::string(""))).Times(1);
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->CreateSessionAsync(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithoutClientSetup_GetFalseResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->ConfigureGameLiftClient("");
+    AWSGameLiftJoinSessionRequest request;
+    request.m_playerId = "dummyPlayerId";
+    request.m_sessionId = "dummySessionId";
+    auto response = m_gameliftClientManager->JoinSession(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message
+    EXPECT_FALSE(response);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithInvalidRequest_GetFalseResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto response = m_gameliftClientManager->JoinSession(AzFramework::JoinSessionRequest());
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+    EXPECT_FALSE(response);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestButNoRequestHandler_GetSuccessOutcomeButFalseResponse)
+{
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::GameLift::Model::CreatePlayerSessionResult result;
+    result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto response = m_gameliftClientManager->JoinSession(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+    EXPECT_FALSE(response);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequest_GetErrorOutcomeAndFalseResponse)
+{
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto response = m_gameliftClientManager->JoinSession(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+    EXPECT_FALSE(response);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeButFalseResponse)
+{
+    SessionHandlingClientRequestsMock handlerMock;
+    EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(false));
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::GameLift::Model::CreatePlayerSessionResult result;
+    result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    auto response = m_gameliftClientManager->JoinSession(request);
+    EXPECT_FALSE(response);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeAndTrueResponse)
+{
+    SessionHandlingClientRequestsMock handlerMock;
+    EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(true));
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::GameLift::Model::CreatePlayerSessionResult result;
+    result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    auto response = m_gameliftClientManager->JoinSession(request);
+    EXPECT_TRUE(response);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithInvalidRequest_GetNotificationWithFalseResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
+    m_gameliftClientManager->JoinSessionAsync(AzFramework::JoinSessionRequest());
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestButNoRequestHandler_GetSuccessOutcomeButNotificationWithFalseResponse)
+{
+    AWSCoreRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::GameLift::Model::CreatePlayerSessionResult result;
+    result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->JoinSessionAsync(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequest_GetErrorOutcomeAndNotificationWithFalseResponse)
+{
+    AWSCoreRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->JoinSessionAsync(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeButNotificationWithFalseResponse)
+{
+    AWSCoreRequestsHandlerMock coreHandlerMock;
+    EXPECT_CALL(coreHandlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    SessionHandlingClientRequestsMock handlerMock;
+    EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(false));
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::GameLift::Model::CreatePlayerSessionResult result;
+    result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1);
+    m_gameliftClientManager->JoinSessionAsync(request);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestAndRequestHandler_GetSuccessOutcomeAndNotificationWithTrueResponse)
+{
+    AWSCoreRequestsHandlerMock coreHandlerMock;
+    EXPECT_CALL(coreHandlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+    SessionHandlingClientRequestsMock handlerMock;
+    EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(true));
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    request.m_playerId = "dummyPlayerId";
+    Aws::GameLift::Model::CreatePlayerSessionResult result;
+    result.SetPlayerSession(Aws::GameLift::Model::PlayerSession());
+    Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(true)).Times(1);
+    m_gameliftClientManager->JoinSessionAsync(request);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, SearchSessions_CallWithValidRequestAndErrorOutcome_GetErrorWithEmptyResponse)
+{
+    AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
+
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::SearchGameSessionsOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = m_gameliftClientManager->SearchSessions(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+    EXPECT_TRUE(result.m_sessionConfigs.size() == 0);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, SearchSessions_CallWithValidRequestAndSuccessOutcome_GetNotificationWithValidResponse)
+{
+    AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
+
+    Aws::GameLift::Model::SearchGameSessionsOutcome outcome = GetValidSearchGameSessionsOutcome();
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+
+    AzFramework::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse();
+    auto result = m_gameliftClientManager->SearchSessions(request);
+    EXPECT_TRUE(result.m_sessionConfigs.size() != 0);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithoutClientSetup_GetErrorWithEmptyResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    EXPECT_FALSE(m_gameliftClientManager->ConfigureGameLiftClient(""));
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+
+    AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
+
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock,
+        OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1);
+
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->SearchSessionsAsync(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithInvalidRequest_GetErrorWithEmptyResponse)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock,
+        OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1);
+
+    m_gameliftClientManager->SearchSessionsAsync(AzFramework::SearchSessionsRequest());
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAndErrorOutcome_GetErrorWithEmptyResponse)
+{
+    AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
+
+    AWSCoreRequestsHandlerMock handlerMock;
+    EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+
+    Aws::Client::AWSError<Aws::GameLift::GameLiftErrors> error;
+    Aws::GameLift::Model::SearchGameSessionsOutcome outcome(error);
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock,
+        OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1);
+
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->SearchSessionsAsync(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAndSuccessOutcome_GetNotificationWithValidResponse)
+{
+    AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest();
+
+    AWSCoreRequestsHandlerMock coreHandlerMock;
+    EXPECT_CALL(coreHandlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get()));
+
+    Aws::GameLift::Model::SearchGameSessionsOutcome outcome = GetValidSearchGameSessionsOutcome();
+    EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_))
+        .Times(1)
+        .WillOnce(::testing::Return(outcome));
+
+    AzFramework::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse();
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock,
+        OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(expectedResponse))).Times(1);
+
+    m_gameliftClientManager->SearchSessionsAsync(request);
+}
+
+TEST_F(AWSGameLiftClientManagerTest, LeaveSession_CallWithInterfaceNotRegistered_GetExpectedError)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->LeaveSession();
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, LeaveSession_CallWithInterfaceRegistered_LeaveSessionRequestSent)
+{
+    SessionHandlingClientRequestsMock handlerMock;
+    EXPECT_CALL(handlerMock, RequestPlayerLeaveSession).Times(1);
+
+    m_gameliftClientManager->LeaveSession();
+}
+
+TEST_F(AWSGameLiftClientManagerTest, LeaveSessionAsync_CallWithInterfaceNotRegistered_GetExpectedError)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    m_gameliftClientManager->LeaveSessionAsync();
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
+}
+
+TEST_F(AWSGameLiftClientManagerTest, LeaveSessionAsync_CallWithInterfaceRegistered_LeaveSessionAsyncRequestSentAndGetNotification)
+{
+    SessionHandlingClientRequestsMock handlerMock;
+    EXPECT_CALL(handlerMock, RequestPlayerLeaveSession).Times(1);
+    SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock;
+    EXPECT_CALL(sessionHandlerMock, OnLeaveSessionAsyncComplete()).Times(1);
+
+    m_gameliftClientManager->LeaveSessionAsync();
+}

+ 86 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h

@@ -0,0 +1,86 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Interface/Interface.h>
+#include <AzFramework/Session/ISessionRequests.h>
+#include <AzFramework/Session/ISessionHandlingRequests.h>
+#include <AzTest/AzTest.h>
+
+#include <aws/core/auth/AWSCredentialsProvider.h>
+#include <aws/core/utils/Outcome.h>
+#include <aws/gamelift/GameLiftClient.h>
+#include <aws/gamelift/GameLiftErrors.h>
+#include <aws/gamelift/model/CreateGameSessionRequest.h>
+#include <aws/gamelift/model/CreateGameSessionResult.h>
+#include <aws/gamelift/model/CreatePlayerSessionRequest.h>
+#include <aws/gamelift/model/CreatePlayerSessionResult.h>
+#include <aws/gamelift/model/SearchGameSessionsRequest.h>
+#include <aws/gamelift/model/SearchGameSessionsResult.h>
+#include <aws/gamelift/model/StartGameSessionPlacementRequest.h>
+#include <aws/gamelift/model/StartGameSessionPlacementResult.h>
+
+using namespace Aws::GameLift;
+
+class GameLiftClientMock
+    : public GameLiftClient
+{
+public:
+    GameLiftClientMock()
+        : GameLiftClient(Aws::Auth::AWSCredentials())
+    {
+    }
+
+    MOCK_CONST_METHOD1(CreateGameSession, Model::CreateGameSessionOutcome(const Model::CreateGameSessionRequest&));
+    MOCK_CONST_METHOD1(CreatePlayerSession, Model::CreatePlayerSessionOutcome(const Model::CreatePlayerSessionRequest&));
+    MOCK_CONST_METHOD1(SearchGameSessions, Model::SearchGameSessionsOutcome(const Model::SearchGameSessionsRequest&));
+    MOCK_CONST_METHOD1(StartGameSessionPlacement, Model::StartGameSessionPlacementOutcome(const Model::StartGameSessionPlacementRequest&));
+};
+
+class SessionAsyncRequestNotificationsHandlerMock
+    : public AzFramework::SessionAsyncRequestNotificationBus::Handler
+{
+public:
+    SessionAsyncRequestNotificationsHandlerMock()
+    {
+        AzFramework::SessionAsyncRequestNotificationBus::Handler::BusConnect();
+    }
+
+    ~SessionAsyncRequestNotificationsHandlerMock()
+    {
+        AzFramework::SessionAsyncRequestNotificationBus::Handler::BusDisconnect();
+    }
+
+    MOCK_METHOD1(OnCreateSessionAsyncComplete, void(const AZStd::string&));
+    MOCK_METHOD1(OnSearchSessionsAsyncComplete, void(const AzFramework::SearchSessionsResponse&));
+    MOCK_METHOD1(OnJoinSessionAsyncComplete, void(bool));
+    MOCK_METHOD0(OnLeaveSessionAsyncComplete, void());
+};
+
+class SessionHandlingClientRequestsMock
+    : public AzFramework::ISessionHandlingClientRequests
+{
+public:
+    SessionHandlingClientRequestsMock()
+    {
+        AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Register(this);
+    }
+
+    virtual ~SessionHandlingClientRequestsMock()
+    {
+        AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Unregister(this);
+    }
+
+    MOCK_METHOD1(RequestPlayerJoinSession, bool(const AzFramework::SessionConnectionConfig&));
+    MOCK_METHOD0(RequestPlayerLeaveSession, void());
+};

+ 156 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientSystemComponentTest.cpp

@@ -0,0 +1,156 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include <AzCore/Component/ComponentApplication.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/std/smart_ptr/unique_ptr.h>
+
+#include <AWSGameLiftClientFixture.h>
+#include <AWSGameLiftClientManager.h>
+#include <AWSGameLiftClientSystemComponent.h>
+
+#include <aws/gamelift/GameLiftClient.h>
+
+using namespace AWSGameLift;
+
+class AWSGameLiftClientManagerMock
+    : public AWSGameLiftClientManager
+{
+public:
+    AWSGameLiftClientManagerMock() = default;
+    ~AWSGameLiftClientManagerMock() = default;
+
+    MOCK_METHOD0(ActivateManager, void());
+    MOCK_METHOD0(DeactivateManager, void());
+};
+
+class TestAWSGameLiftClientSystemComponent
+    : public AWSGameLiftClientSystemComponent
+{
+public:
+    TestAWSGameLiftClientSystemComponent()
+    {
+        m_gameliftClientManagerMockPtr = nullptr;
+    }
+    ~TestAWSGameLiftClientSystemComponent()
+    {
+        m_gameliftClientManagerMockPtr = nullptr;
+    }
+
+    void SetUpMockManager()
+    {
+        AZStd::unique_ptr<AWSGameLiftClientManagerMock> gameliftClientManagerMock = AZStd::make_unique<AWSGameLiftClientManagerMock>();
+        m_gameliftClientManagerMockPtr = gameliftClientManagerMock.get();
+        SetGameLiftClientManager(AZStd::move(gameliftClientManagerMock));
+    }
+
+    AWSGameLiftClientManagerMock* m_gameliftClientManagerMockPtr;
+};
+
+class AWSCoreSystemComponentMock
+    : public AZ::Component
+{
+public:
+    AZ_COMPONENT(AWSCoreSystemComponentMock, "{52DB1342-30C6-412F-B7CC-B23F8B0629EA}");
+
+    static void Reflect(AZ::ReflectContext* context)
+    {
+        AZ_UNUSED(context);
+    }
+
+    static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("AWSCoreService"));
+    }
+    static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        AZ_UNUSED(incompatible);
+    }
+    static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        AZ_UNUSED(required);
+    }
+    static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+        AZ_UNUSED(dependent);
+    }
+
+    AWSCoreSystemComponentMock() = default;
+    ~AWSCoreSystemComponentMock() = default;
+
+    void Init() override {}
+    void Activate() override {}
+    void Deactivate() override {}
+};
+
+class AWSGameLiftClientSystemComponentTest
+    : public AWSGameLiftClientFixture
+{
+protected:
+    AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
+    AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
+    AZStd::unique_ptr<AZ::ComponentDescriptor> m_coreComponentDescriptor;
+    AZStd::unique_ptr<AZ::ComponentDescriptor> m_gameliftClientComponentDescriptor;
+
+    void SetUp() override
+    {
+        AWSGameLiftClientFixture::SetUp();
+
+        m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
+        m_serializeContext->CreateEditContext();
+        m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
+        m_coreComponentDescriptor.reset(AWSCoreSystemComponentMock::CreateDescriptor());
+        m_gameliftClientComponentDescriptor.reset(TestAWSGameLiftClientSystemComponent::CreateDescriptor());
+        m_gameliftClientComponentDescriptor->Reflect(m_serializeContext.get());
+        m_gameliftClientComponentDescriptor->Reflect(m_behaviorContext.get());
+
+        m_entity = aznew AZ::Entity();
+        m_coreSystemComponent = AZStd::make_unique<AWSCoreSystemComponentMock>();
+        m_entity->AddComponent(m_coreSystemComponent.get());
+        m_gameliftClientSystemComponent = AZStd::make_unique<TestAWSGameLiftClientSystemComponent>();
+        m_gameliftClientSystemComponent->SetUpMockManager();
+        m_entity->AddComponent(m_gameliftClientSystemComponent.get());
+    }
+
+    void TearDown() override
+    {
+        m_entity->RemoveComponent(m_gameliftClientSystemComponent.get());
+        m_gameliftClientSystemComponent.reset();
+        m_entity->RemoveComponent(m_coreSystemComponent.get());
+        m_coreSystemComponent.reset();
+        delete m_entity;
+        m_entity = nullptr;
+
+        m_gameliftClientComponentDescriptor.reset();
+        m_coreComponentDescriptor.reset();
+        m_behaviorContext.reset();
+        m_serializeContext.reset();
+
+        AWSGameLiftClientFixture::TearDown();
+    }
+
+public:
+    AZStd::unique_ptr<AWSCoreSystemComponentMock> m_coreSystemComponent;
+    AZStd::unique_ptr<TestAWSGameLiftClientSystemComponent> m_gameliftClientSystemComponent;
+    AZ::Entity* m_entity;
+};
+
+TEST_F(AWSGameLiftClientSystemComponentTest, ActivateDeactivate_Call_GameLiftClientManagerGetsInvoked)
+{
+    m_entity->Init();
+    EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientManagerMockPtr), ActivateManager()).Times(1);
+    m_entity->Activate();
+
+    EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientManagerMockPtr), DeactivateManager()).Times(1);
+    m_entity->Deactivate();
+}

+ 15 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientTest.cpp

@@ -0,0 +1,15 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzTest/AzTest.h>
+
+AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);

+ 81 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp

@@ -0,0 +1,81 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <Activity/AWSGameLiftCreateSessionActivity.h>
+#include <AWSGameLiftClientFixture.h>
+
+using namespace AWSGameLift;
+
+using AWSGameLiftCreateSessionActivityTest = AWSGameLiftClientFixture;
+
+TEST_F(AWSGameLiftCreateSessionActivityTest, BuildAWSGameLiftCreateGameSessionRequest_Call_GetExpectedResult)
+{
+    AWSGameLiftCreateSessionRequest request;
+    request.m_creatorId = "dummyCreatorId";
+    request.m_sessionName = "dummySessionName";
+    request.m_maxPlayer = 1;
+    request.m_sessionProperties.emplace("dummyKey", "dummyValue");
+    request.m_aliasId = "dummyAliasId";
+    request.m_fleetId = "dummyFleetId";
+    request.m_idempotencyToken = "dummyIdempotencyToken";
+    auto awsRequest = CreateSessionActivity::BuildAWSGameLiftCreateGameSessionRequest(request);
+
+    EXPECT_TRUE(strcmp(awsRequest.GetCreatorId().c_str(), request.m_creatorId.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetName().c_str(), request.m_sessionName.c_str()) == 0);
+    EXPECT_TRUE(awsRequest.GetMaximumPlayerSessionCount() == request.m_maxPlayer);
+    EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetKey().c_str(), request.m_sessionProperties.begin()->first.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetValue().c_str(), request.m_sessionProperties.begin()->second.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetAliasId().c_str(), request.m_aliasId.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetFleetId().c_str(), request.m_fleetId.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetIdempotencyToken().c_str(), request.m_idempotencyToken.c_str()) == 0);
+}
+
+TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithBaseType_GetFalseResult)
+{
+    auto result = CreateSessionActivity::ValidateCreateSessionRequest(AzFramework::CreateSessionRequest());
+    EXPECT_FALSE(result);   
+}
+
+TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithNegativeMaxPlayer_GetFalseResult)
+{
+    AWSGameLiftCreateSessionRequest request;
+    request.m_maxPlayer = -1;
+
+    auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithoutAliasOrFleetId_GetFalseResult)
+{
+    AWSGameLiftCreateSessionRequest request;
+    request.m_maxPlayer = 1;
+    auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithAliasId_GetTrueResult)
+{
+    AWSGameLiftCreateSessionRequest request;
+    request.m_maxPlayer = 1;
+    request.m_aliasId = "dummyAliasId";
+    auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
+    EXPECT_TRUE(result);
+}
+
+TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithFleetId_GetTrueResult)
+{
+    AWSGameLiftCreateSessionRequest request;
+    request.m_maxPlayer = 1;
+    request.m_fleetId = "dummyFleetId";
+    auto result = CreateSessionActivity::ValidateCreateSessionRequest(request);
+    EXPECT_TRUE(result);
+}

+ 79 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp

@@ -0,0 +1,79 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AWSGameLiftClientFixture.h>
+#include <Activity/AWSGameLiftCreateSessionOnQueueActivity.h>
+
+using namespace AWSGameLift;
+
+using AWSGameLiftCreateSessionOnQueueActivityTest = AWSGameLiftClientFixture;
+
+TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, BuildAWSGameLiftCreateGameSessionRequest_Call_GetExpectedResult)
+{
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_sessionName = "dummySessionName";
+    request.m_maxPlayer = 1;
+    request.m_sessionProperties.emplace("dummyKey", "dummyValue");
+    request.m_queueName = "dummyQueueName";
+    request.m_placementId = "dummyPlacementId";
+    auto awsRequest = CreateSessionOnQueueActivity::BuildAWSGameLiftStartGameSessionPlacementRequest(request);
+
+    EXPECT_TRUE(strcmp(awsRequest.GetGameSessionName().c_str(), request.m_sessionName.c_str()) == 0);
+    EXPECT_TRUE(awsRequest.GetMaximumPlayerSessionCount() == request.m_maxPlayer);
+    EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetKey().c_str(), request.m_sessionProperties.begin()->first.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetGameProperties()[0].GetValue().c_str(), request.m_sessionProperties.begin()->second.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetGameSessionQueueName().c_str(), request.m_queueName.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetPlacementId().c_str(), request.m_placementId.c_str()) == 0);
+}
+
+TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithBaseType_GetFalseResult)
+{
+    auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(AzFramework::CreateSessionRequest());
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithNegativeMaxPlayer_GetFalseResult)
+{
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_maxPlayer = -1;
+
+    auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithoutQueueName_GetFalseResult)
+{
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_maxPlayer = 1;
+    request.m_placementId = "dummyPlacementId";
+    auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithoutPlacementId_GetFalseResult)
+{
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_maxPlayer = 1;
+    request.m_queueName = "dummyQueueName";
+    auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithValidRequest_GetTrueResult)
+{
+    AWSGameLiftCreateSessionOnQueueRequest request;
+    request.m_maxPlayer = 1;
+    request.m_queueName = "dummyQueueName";
+    request.m_placementId = "dummyPlacementId";
+    auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(request);
+    EXPECT_TRUE(result);
+}

+ 84 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp

@@ -0,0 +1,84 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AWSGameLiftClientFixture.h>
+#include <Activity/AWSGameLiftJoinSessionActivity.h>
+
+using namespace AWSGameLift;
+
+using AWSGameLiftJoinSessionActivityTest = AWSGameLiftClientFixture;
+
+TEST_F(AWSGameLiftJoinSessionActivityTest, BuildAWSGameLiftCreatePlayerSessionRequest_Call_GetExpectedResult)
+{
+    AWSGameLiftJoinSessionRequest request;
+    request.m_playerData = "dummyPlayerData";
+    request.m_playerId = "dummyPlayerId";
+    request.m_sessionId = "dummySessionId";
+    auto awsRequest = JoinSessionActivity::BuildAWSGameLiftCreatePlayerSessionRequest(request);
+
+    EXPECT_TRUE(strcmp(awsRequest.GetPlayerData().c_str(), request.m_playerData.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetPlayerId().c_str(), request.m_playerId.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetGameSessionId().c_str(), request.m_sessionId.c_str()) == 0);
+}
+
+TEST_F(AWSGameLiftJoinSessionActivityTest, BuildSessionConnectionConfig_Call_GetExpectedResult)
+{
+    Aws::GameLift::Model::PlayerSession playerSession;
+    playerSession.SetIpAddress("dummyIpAddress");
+    playerSession.SetPlayerSessionId("dummyPlayerSessionId");
+    playerSession.SetPort(123);
+    Aws::GameLift::Model::CreatePlayerSessionResult createPlayerSessionResult;
+    createPlayerSessionResult.SetPlayerSession(playerSession);
+    Aws::GameLift::Model::CreatePlayerSessionOutcome createPlayerSessionOutcome(createPlayerSessionResult);
+    auto connectionConfig = JoinSessionActivity::BuildSessionConnectionConfig(createPlayerSessionOutcome);
+
+    EXPECT_TRUE(strcmp(connectionConfig.m_ipAddress.c_str(), playerSession.GetIpAddress().c_str()) == 0);
+    EXPECT_TRUE(strcmp(connectionConfig.m_playerSessionId.c_str(), playerSession.GetPlayerSessionId().c_str()) == 0);
+    EXPECT_TRUE(connectionConfig.m_port == playerSession.GetPort());
+}
+
+TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithBaseType_GetFalseResult)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = JoinSessionActivity::ValidateJoinSessionRequest(AzFramework::JoinSessionRequest());
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message 
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithEmptyPlayerId_GetFalseResult)
+{
+    AWSGameLiftJoinSessionRequest request;
+    request.m_sessionId = "dummySessionId";
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = JoinSessionActivity::ValidateJoinSessionRequest(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message   
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithEmptySessionId_GetFalseResult)
+{
+    AWSGameLiftJoinSessionRequest request;
+    request.m_playerId = "dummyPlayerId";
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = JoinSessionActivity::ValidateJoinSessionRequest(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message  
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithPlayerAndSessionId_GetTrueResult)
+{
+    AWSGameLiftJoinSessionRequest request;
+    request.m_playerId = "dummyPlayerId";
+    request.m_sessionId = "dummySessionId";
+    auto result = JoinSessionActivity::ValidateJoinSessionRequest(request);
+    EXPECT_TRUE(result);
+}

+ 126 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp

@@ -0,0 +1,126 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzFramework/Session/SessionConfig.h>
+
+#include <Activity/AWSGameLiftSearchSessionsActivity.h>
+#include <AWSGameLiftClientFixture.h>
+#include <AWSGameLiftSessionConstants.h>
+
+using namespace AWSGameLift;
+
+using AWSGameLiftSearchSessionsActivityTest = AWSGameLiftClientFixture;
+
+TEST_F(AWSGameLiftSearchSessionsActivityTest, BuildAWSGameLiftSearchGameSessionsRequest_Call_GetExpectedResult)
+{
+    AWSGameLiftSearchSessionsRequest request;
+    request.m_aliasId = "dummyAliasId";
+    request.m_fleetId = "dummyFleetId";
+    request.m_location = "dummyLocation";
+    request.m_filterExpression = "dummyFilterExpression";
+    request.m_sortExpression = "dummySortExpression";
+    request.m_maxResult = 1;
+    request.m_nextToken = "dummyNextToken";
+
+    auto awsRequest = SearchSessionsActivity::BuildAWSGameLiftSearchGameSessionsRequest(request);
+
+    EXPECT_TRUE(strcmp(awsRequest.GetFleetId().c_str(), request.m_fleetId.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetAliasId().c_str(), request.m_aliasId.c_str()) == 0);   
+    EXPECT_TRUE(strcmp(awsRequest.GetFilterExpression().c_str(), request.m_filterExpression.c_str()) == 0);
+    EXPECT_TRUE(strcmp(awsRequest.GetSortExpression().c_str(), request.m_sortExpression.c_str()) == 0);
+    EXPECT_TRUE(awsRequest.GetLimit() == request.m_maxResult);
+    EXPECT_TRUE(strcmp(awsRequest.GetNextToken().c_str(), request.m_nextToken.c_str()) == 0);
+    // TODO: Update the AWS Native SDK to get the new request attributes.
+    //EXPECT_TRUE(strcmp(awsRequest.GetLocation().c_str(), request.m_location.c_str()) == 0);
+}
+
+TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithBaseType_GetFalseResult)
+{
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(AzFramework::SearchSessionsRequest());
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message    
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithoutAliasOrFleetId_GetFalseResult)
+{
+    AWSGameLiftSearchSessionsRequest request;
+    AZ_TEST_START_TRACE_SUPPRESSION;
+    auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(request);
+    AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message    
+    EXPECT_FALSE(result);
+}
+
+TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithAliasId_GetTrueResult)
+{
+    AWSGameLiftSearchSessionsRequest request;
+    request.m_aliasId = "dummyAliasId";
+    auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(request);
+    EXPECT_TRUE(result);
+}
+
+TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithFleetId_GetTrueResult)
+{
+    AWSGameLiftSearchSessionsRequest request;
+    request.m_fleetId = "dummyFleetId";
+    auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(request);
+    EXPECT_TRUE(result);
+}
+
+TEST_F(AWSGameLiftSearchSessionsActivityTest, ParseResponse_Call_GetExpectedResult)
+{
+    Aws::GameLift::Model::GameProperty gameProperty;
+    gameProperty.SetKey("dummyKey");
+    gameProperty.SetValue("dummyValue");
+    Aws::Vector<Aws::GameLift::Model::GameProperty> gameProperties = { gameProperty };
+
+    Aws::GameLift::Model::GameSession gameSession;
+    gameSession.SetCreationTime(Aws::Utils::DateTime(0.0));
+    gameSession.SetTerminationTime(Aws::Utils::DateTime(0.0));
+    gameSession.SetCreatorId("dummyCreatorId");
+    gameSession.SetGameProperties(gameProperties);
+    gameSession.SetGameSessionId("dummyGameSessionId");
+    gameSession.SetName("dummyGameSessionName");
+    gameSession.SetIpAddress("dummyIpAddress");
+    gameSession.SetPort(0);
+    gameSession.SetMaximumPlayerSessionCount(2);
+    gameSession.SetCurrentPlayerSessionCount(1);
+    gameSession.SetStatus(Aws::GameLift::Model::GameSessionStatus::TERMINATED);
+    gameSession.SetStatusReason(Aws::GameLift::Model::GameSessionStatusReason::INTERRUPTED);
+    // TODO: Update the AWS Native SDK to set the new game session attributes.
+    //gameSession.SetDnsName("dummyDnsName");
+    Aws::Vector<Aws::GameLift::Model::GameSession> gameSessions = { gameSession };
+
+    Aws::GameLift::Model::SearchGameSessionsResult result;
+    result.SetNextToken("dummyNextToken");
+    result.SetGameSessions(gameSessions);
+
+    auto response = SearchSessionsActivity::ParseResponse(result);
+
+    EXPECT_TRUE(strcmp(response.m_nextToken.c_str(), result.GetNextToken().c_str()) == 0);
+    EXPECT_EQ(response.m_sessionConfigs.size(), 1);
+
+    const auto& sessionConfig = response.m_sessionConfigs[0];
+    EXPECT_EQ(gameSession.GetCreationTime().Millis(), sessionConfig.m_creationTime);
+    EXPECT_EQ(gameSession.GetTerminationTime().Millis(), sessionConfig.m_terminationTime);
+    EXPECT_TRUE(strcmp(gameSession.GetCreatorId().c_str(), sessionConfig.m_creatorId.c_str()) == 0);
+    EXPECT_TRUE(strcmp(gameSession.GetGameSessionId().c_str(), sessionConfig.m_sessionId.c_str()) == 0);
+    EXPECT_TRUE(strcmp(gameSession.GetName().c_str(), sessionConfig.m_sessionName.c_str()) == 0);
+    EXPECT_TRUE(strcmp(gameSession.GetIpAddress().c_str(), sessionConfig.m_ipAddress.c_str()) == 0);
+    EXPECT_EQ(gameSession.GetPort(), 0);
+    EXPECT_EQ(gameSession.GetMaximumPlayerSessionCount(), 2);
+    EXPECT_EQ(gameSession.GetCurrentPlayerSessionCount(), 1);
+    EXPECT_TRUE(strcmp(AWSGameLiftSessionStatusNames[(int)gameSession.GetStatus()], sessionConfig.m_status.c_str()) == 0);
+    EXPECT_TRUE(strcmp(AWSGameLiftSessionStatusReasons[(int)gameSession.GetStatusReason()], sessionConfig.m_statusReason.c_str()) == 0);
+    // TODO: Update the AWS Native SDK to get the new game session attributes.
+    // EXPECT_TRUE(strcmp(gameSession.GetDnsName().c_str(), sessionConfig.m_dnsName.c_str()) == 0);
+}

+ 36 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake

@@ -0,0 +1,36 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h
+    Include/Request/AWSGameLiftCreateSessionRequest.h
+    Include/Request/AWSGameLiftJoinSessionRequest.h
+    Include/Request/AWSGameLiftSearchSessionsRequest.h
+    Include/Request/IAWSGameLiftRequests.h
+    Source/Activity/AWSGameLiftCreateSessionActivity.cpp
+    Source/Activity/AWSGameLiftCreateSessionActivity.h
+    Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp
+    Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h
+    Source/Activity/AWSGameLiftJoinSessionActivity.cpp
+    Source/Activity/AWSGameLiftJoinSessionActivity.h
+    Source/Activity/AWSGameLiftLeaveSessionActivity.cpp
+    Source/Activity/AWSGameLiftLeaveSessionActivity.h
+    Source/Activity/AWSGameLiftSearchSessionsActivity.cpp
+    Source/Activity/AWSGameLiftSearchSessionsActivity.h
+    Source/AWSGameLiftClientManager.cpp
+    Source/AWSGameLiftClientManager.h
+    Source/AWSGameLiftClientSystemComponent.cpp
+    Source/AWSGameLiftClientSystemComponent.h
+    Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp
+    Source/Request/AWSGameLiftCreateSessionRequest.cpp
+    Source/Request/AWSGameLiftJoinSessionRequest.cpp
+    Source/Request/AWSGameLiftSearchSessionsRequest.cpp
+)

+ 14 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_shared_files.cmake

@@ -0,0 +1,14 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    Source/AWSGameLiftClientModule.cpp
+)

+ 22 - 0
Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake

@@ -0,0 +1,22 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp
+    Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp
+    Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp
+    Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp
+    Tests/AWSGameLiftClientFixture.h
+    Tests/AWSGameLiftClientManagerTest.cpp
+    Tests/AWSGameLiftClientMocks.h
+    Tests/AWSGameLiftClientSystemComponentTest.cpp
+    Tests/AWSGameLiftClientTest.cpp
+)

+ 24 - 0
Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h

@@ -0,0 +1,24 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+namespace AWSGameLift
+{
+    // Reference https://sdk.amazonaws.com/cpp/api/LATEST/_game_session_status_8h_source.html
+    static const char* AWSGameLiftSessionStatusNames[6] = { "NotSet", "Active", "Activating", "Terminated", "Terminating", "Error"};
+
+    // Reference https://sdk.amazonaws.com/cpp/api/LATEST/_game_session_status_reason_8h.html
+    static const char* AWSGameLiftSessionStatusReasons[2] = { "NotSet", "Interrupted" };
+
+    static constexpr const char AWSGameLiftErrorMessageTemplate[] = "Exception: %s, Message: %s";
+} // namespace AWSGameLift

+ 72 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt

@@ -0,0 +1,72 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+if (NOT PAL_TRAIT_BUILD_SERVER_SUPPORTED)
+    return()
+endif()
+
+ly_add_target(
+    NAME AWSGameLift.Server.Static STATIC
+    NAMESPACE Gem
+    FILES_CMAKE
+        awsgamelift_server_files.cmake
+    INCLUDE_DIRECTORIES
+        PRIVATE
+            ../AWSGameLiftCommon/Source
+            Source
+    BUILD_DEPENDENCIES
+        PRIVATE
+            AZ::AzCore
+            AZ::AzFramework
+            3rdParty::AWSGameLiftServerSDK
+    )
+
+ly_add_target(
+    NAME AWSGameLift.Servers ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
+    NAMESPACE Gem
+    FILES_CMAKE
+        awsgamelift_server_shared_files.cmake
+    INCLUDE_DIRECTORIES
+        PRIVATE
+            Source
+    BUILD_DEPENDENCIES
+        PUBLIC
+            AZ::AzCore
+            Gem::AWSGameLift.Server.Static
+            3rdParty::AWSGameLiftServerSDK
+)
+
+################################################################################
+# Tests
+################################################################################
+if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
+    ly_add_target(
+        NAME AWSGameLift.Server.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
+        NAMESPACE Gem
+        FILES_CMAKE
+            awsgamelift_server_tests_files.cmake
+        INCLUDE_DIRECTORIES
+            PRIVATE
+                Tests
+                Source
+        BUILD_DEPENDENCIES
+            PRIVATE
+                AZ::AzCore
+                AZ::AzFramework
+                AZ::AzTest
+                Gem::AWSGameLift.Server.Static
+                3rdParty::AWSGameLiftServerSDK
+    )
+    # Add AWSGameLift.Server.Tests to googletest
+    ly_add_googletest(
+        NAME Gem::AWSGameLift.Server.Tests
+    )
+endif()

+ 319 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp

@@ -0,0 +1,319 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AWSGameLiftServerManager.h>
+#include <AWSGameLiftSessionConstants.h>
+#include <GameLiftServerSDKWrapper.h>
+
+#include <AzCore/Debug/Trace.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzCore/Jobs/JobFunction.h>
+#include <AzCore/Jobs/JobManagerBus.h>
+#include <AzCore/std/bind/bind.h>
+#include <AzFramework/Session/SessionNotifications.h>
+
+namespace AWSGameLift
+{
+    AWSGameLiftServerManager::AWSGameLiftServerManager()
+        : m_serverSDKInitialized(false)
+        , m_gameLiftServerSDKWrapper(AZStd::make_unique<GameLiftServerSDKWrapper>())
+        , m_connectedPlayers()
+    {
+    }
+
+    AWSGameLiftServerManager::~AWSGameLiftServerManager()
+    {
+        m_gameLiftServerSDKWrapper.reset();
+        m_connectedPlayers.clear();
+    }
+
+    bool AWSGameLiftServerManager::AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
+    {
+        AZStd::lock_guard<AZStd::mutex> lock(m_gameliftMutex);
+        if (m_connectedPlayers.contains(playerConnectionConfig.m_playerConnectionId))
+        {
+            if (m_connectedPlayers[playerConnectionConfig.m_playerConnectionId] != playerConnectionConfig.m_playerSessionId)
+            {
+                AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerPlayerConnectionRegisteredErrorMessage,
+                    playerConnectionConfig.m_playerConnectionId, playerConnectionConfig.m_playerSessionId.c_str());
+            }
+            return false;
+        }
+        else
+        {
+            m_connectedPlayers.emplace(playerConnectionConfig.m_playerConnectionId, playerConnectionConfig.m_playerSessionId);
+            return true;
+        }
+    }
+
+    AzFramework::SessionConfig AWSGameLiftServerManager::BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession)
+    {
+        AzFramework::SessionConfig sessionConfig;
+
+        sessionConfig.m_dnsName = gameSession.GetDnsName().c_str();
+        AZStd::string propertiesOutput = "";
+        for (const auto& gameProperty : gameSession.GetGameProperties())
+        {
+            sessionConfig.m_sessionProperties.emplace(gameProperty.GetKey().c_str(), gameProperty.GetValue().c_str());
+            propertiesOutput += AZStd::string::format("{Key=%s,Value=%s},", gameProperty.GetKey().c_str(), gameProperty.GetValue().c_str());
+        }
+        if (!propertiesOutput.empty())
+        {
+            propertiesOutput = propertiesOutput.substr(0, propertiesOutput.size() - 1); // Trim last comma to fit array format
+        }
+        sessionConfig.m_sessionId = gameSession.GetGameSessionId().c_str();
+        sessionConfig.m_ipAddress = gameSession.GetIpAddress().c_str();
+        sessionConfig.m_maxPlayer = gameSession.GetMaximumPlayerSessionCount();
+        sessionConfig.m_sessionName = gameSession.GetName().c_str();
+        sessionConfig.m_port = gameSession.GetPort();
+        sessionConfig.m_status = AWSGameLiftSessionStatusNames[(int)gameSession.GetStatus()];
+
+        AZ_TracePrintf(AWSGameLiftServerManagerName,
+            "Built SessionConfig with Name=%s, Id=%s, Status=%s, DnsName=%s, IpAddress=%s, Port=%d, MaxPlayer=%d and Properties=%s",
+            sessionConfig.m_sessionName.c_str(),
+            sessionConfig.m_sessionId.c_str(),
+            sessionConfig.m_status.c_str(),
+            sessionConfig.m_dnsName.c_str(),
+            sessionConfig.m_ipAddress.c_str(),
+            sessionConfig.m_port,
+            sessionConfig.m_maxPlayer,
+            AZStd::string::format("[%s]", propertiesOutput.c_str()).c_str());
+
+        return sessionConfig;
+    }
+
+    AZ::IO::Path AWSGameLiftServerManager::GetExternalSessionCertificate()
+    {
+        // TODO: Add support to get TLS cert file path
+        return AZ::IO::Path();
+    }
+
+    AZ::IO::Path AWSGameLiftServerManager::GetInternalSessionCertificate()
+    {
+        // GameLift doesn't support it, return empty path
+        return AZ::IO::Path();
+    }
+
+    bool AWSGameLiftServerManager::InitializeGameLiftServerSDK()
+    {
+        if (m_serverSDKInitialized)
+        {
+            AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKAlreadyInitErrorMessage);
+            return false;
+        }
+
+        AZ_TracePrintf(AWSGameLiftServerManagerName, "Initiating Amazon GameLift Server SDK...");
+        Aws::GameLift::Server::InitSDKOutcome initOutcome = m_gameLiftServerSDKWrapper->InitSDK();
+        m_serverSDKInitialized = initOutcome.IsSuccess();
+
+        AZ_Error(AWSGameLiftServerManagerName, m_serverSDKInitialized,
+            AWSGameLiftServerInitSDKErrorMessage, initOutcome.GetError().GetErrorMessage().c_str());
+
+        return m_serverSDKInitialized;
+    }
+
+    void AWSGameLiftServerManager::HandleDestroySession()
+    {
+        // No further request should be handled by GameLift server manager at this point
+        if (AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
+        {
+            AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Unregister(this);
+        }
+
+        AZ_TracePrintf(AWSGameLiftServerManagerName, "Server process is scheduled to be shut down at %s",
+            m_gameLiftServerSDKWrapper->GetTerminationTime().c_str());
+
+        // Send notifications to handler(s) to gracefully shut down the server process.
+        bool destroySessionResult = true;
+        AZ::EBusReduceResult<bool&, AZStd::logical_and<bool>> result(destroySessionResult);
+        AzFramework::SessionNotificationBus::BroadcastResult(result, &AzFramework::SessionNotifications::OnDestroySessionBegin);
+
+        if (!destroySessionResult)
+        {
+            AZ_Error("AWSGameLift", destroySessionResult, AWSGameLiftServerGameSessionDestroyErrorMessage);
+            return;
+        }
+
+        AZ_TracePrintf(AWSGameLiftServerManagerName, "Notifying GameLift server process is ending...");
+        Aws::GameLift::GenericOutcome processEndingOutcome = m_gameLiftServerSDKWrapper->ProcessEnding();
+        bool processEndingIsSuccess = processEndingOutcome.IsSuccess();
+
+        AZ_Error(AWSGameLiftServerManagerName, processEndingIsSuccess, AWSGameLiftServerProcessEndingErrorMessage,
+            processEndingOutcome.GetError().GetErrorMessage().c_str());
+    }
+
+    void AWSGameLiftServerManager::HandlePlayerLeaveSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
+    {
+        AZStd::string playerSessionId = "";
+        RemoveConnectedPlayer(playerConnectionConfig.m_playerConnectionId, playerSessionId);
+        if (playerSessionId.empty())
+        {
+            return;
+        }
+
+        Aws::GameLift::GenericOutcome disconnectOutcome = m_gameLiftServerSDKWrapper->RemovePlayerSession(playerSessionId);
+        AZ_Error(AWSGameLiftServerManagerName, disconnectOutcome.IsSuccess(), AWSGameLiftServerRemovePlayerSessionErrorMessage,
+            playerSessionId.c_str(), disconnectOutcome.GetError().GetErrorMessage().c_str());
+    }
+
+    bool AWSGameLiftServerManager::NotifyGameLiftProcessReady(const GameLiftServerProcessDesc& desc)
+    {
+        if (!m_serverSDKInitialized)
+        {
+            AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKNotInitErrorMessage);
+            return false;
+        }
+
+        AZ_Warning(AWSGameLiftServerManagerName, desc.m_port != 0, AWSGameLiftServerTempPortErrorMessage);
+
+        AZ::JobContext* jobContext = nullptr;
+        AZ::JobManagerBus::BroadcastResult(jobContext, &AZ::JobManagerEvents::GetGlobalContext);
+        AZ::Job* processReadyJob = AZ::CreateJobFunction(
+            [this, desc]() {
+                // The GameLift ProcessParameters object expects an vector (std::vector) of standard strings (std::string) as the log paths.
+                std::vector<std::string> logPaths;
+                for (const AZStd::string& path : desc.m_logPaths)
+                {
+                    logPaths.push_back(path.c_str());
+                }
+
+                Aws::GameLift::Server::ProcessParameters processReadyParameter = Aws::GameLift::Server::ProcessParameters(
+                    AZStd::bind(&AWSGameLiftServerManager::OnStartGameSession, this, AZStd::placeholders::_1),
+                    AZStd::bind(&AWSGameLiftServerManager::OnUpdateGameSession, this),
+                    AZStd::bind(&AWSGameLiftServerManager::OnProcessTerminate, this),
+                    AZStd::bind(&AWSGameLiftServerManager::OnHealthCheck, this), desc.m_port,
+                    Aws::GameLift::Server::LogParameters(logPaths));
+
+                AZ_TracePrintf(AWSGameLiftServerManagerName, "Notifying GameLift server process is ready...");
+                auto processReadyOutcome = m_gameLiftServerSDKWrapper->ProcessReady(processReadyParameter);
+
+                if (!processReadyOutcome.IsSuccess())
+                {
+                    AZ_Error(AWSGameLiftServerManagerName, false,
+                        AWSGameLiftServerProcessReadyErrorMessage, processReadyOutcome.GetError().GetErrorMessage().c_str());
+                    this->HandleDestroySession();
+                }
+        }, true, jobContext);
+        processReadyJob->Start();
+        return true;
+    }
+
+    void AWSGameLiftServerManager::OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession)
+    {
+        AzFramework::SessionConfig sessionConfig = BuildSessionConfig(gameSession);
+
+        bool createSessionResult = true;
+        AZ::EBusReduceResult<bool&, AZStd::logical_and<bool>> result(createSessionResult);
+        AzFramework::SessionNotificationBus::BroadcastResult(
+            result, &AzFramework::SessionNotifications::OnCreateSessionBegin, sessionConfig);
+
+        if (createSessionResult)
+        {
+            AZ_TracePrintf(AWSGameLiftServerManagerName, "Activating GameLift game session...");
+            Aws::GameLift::GenericOutcome activationOutcome = m_gameLiftServerSDKWrapper->ActivateGameSession();
+
+            if (activationOutcome.IsSuccess())
+            {
+                // Register server manager as handler once game session has been activated
+                if (!AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
+                {
+                    AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Register(this);
+                }
+            }
+            else
+            {
+                AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerActivateGameSessionErrorMessage,
+                    activationOutcome.GetError().GetErrorMessage().c_str());
+                HandleDestroySession();
+            }
+        }
+        else
+        {
+            AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerGameInitErrorMessage);
+            HandleDestroySession();
+        }
+    }
+
+    void AWSGameLiftServerManager::OnProcessTerminate()
+    {
+        AZ_TracePrintf(AWSGameLiftServerManagerName, "GameLift is shutting down server process...");
+
+        HandleDestroySession();
+    }
+
+    bool AWSGameLiftServerManager::OnHealthCheck()
+    {
+        bool healthCheckResult = true;
+        AZ::EBusReduceResult<bool&, AZStd::logical_and<bool>> result(healthCheckResult);
+        AzFramework::SessionNotificationBus::BroadcastResult(result, &AzFramework::SessionNotifications::OnSessionHealthCheck);
+
+        return m_serverSDKInitialized && healthCheckResult;
+    }
+
+    void AWSGameLiftServerManager::OnUpdateGameSession()
+    {
+        // TODO: Perform game-specific tasks to prep for newly matched players
+        return;
+    }
+
+    bool AWSGameLiftServerManager::RemoveConnectedPlayer(uint32_t playerConnectionId, AZStd::string& outPlayerSessionId)
+    {
+        AZStd::lock_guard<AZStd::mutex> lock(m_gameliftMutex);
+        if (m_connectedPlayers.contains(playerConnectionId))
+        {
+            outPlayerSessionId = m_connectedPlayers[playerConnectionId];
+            m_connectedPlayers.erase(playerConnectionId);
+            return true;
+        }
+        else
+        {
+            outPlayerSessionId = "";
+            AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerPlayerConnectionMissingErrorMessage, playerConnectionId);
+            return false;
+        }
+    }
+
+    void AWSGameLiftServerManager::SetGameLiftServerSDKWrapper(AZStd::unique_ptr<GameLiftServerSDKWrapper> gameLiftServerSDKWrapper)
+    {
+        m_gameLiftServerSDKWrapper.reset();
+        m_gameLiftServerSDKWrapper = AZStd::move(gameLiftServerSDKWrapper);
+    }
+
+    bool AWSGameLiftServerManager::ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
+    {
+        uint32_t playerConnectionId = playerConnectionConfig.m_playerConnectionId;
+        AZStd::string playerSessionId = playerConnectionConfig.m_playerSessionId;
+        if (playerSessionId.empty())
+        {
+            AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerInvalidConnectionConfigErrorMessage,
+                playerConnectionId, playerSessionId.c_str());
+            return false;
+        }
+
+        if (!AddConnectedPlayer(playerConnectionConfig))
+        {
+            return false;
+        }
+
+        AZ_TracePrintf(AWSGameLiftServerManagerName, "Attempting to accept player session connection with Amazon GameLift service...");
+        auto acceptPlayerSessionOutcome = m_gameLiftServerSDKWrapper->AcceptPlayerSession(playerSessionId.c_str());
+
+        if (!acceptPlayerSessionOutcome.IsSuccess())
+        {
+            AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerAcceptPlayerSessionErrorMessage,
+                playerSessionId.c_str(), acceptPlayerSessionOutcome.GetError().GetErrorMessage().c_str());
+            RemoveConnectedPlayer(playerConnectionId, playerSessionId);
+            return false;
+        }
+        return true;
+    }
+} // namespace AWSGameLift

+ 128 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h

@@ -0,0 +1,128 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <aws/gamelift/server/GameLiftServerAPI.h>
+#include <aws/gamelift/server/model/GameSession.h>
+
+#include <AzCore/std/containers/vector.h>
+#include <AzCore/std/string/string.h>
+#include <AzCore/std/smart_ptr/unique_ptr.h>
+#include <AzFramework/Session/ISessionHandlingRequests.h>
+#include <AzFramework/Session/SessionConfig.h>
+
+namespace AWSGameLift
+{
+    class GameLiftServerSDKWrapper;
+
+    //! GameLift server process settings.
+    struct GameLiftServerProcessDesc
+    {
+        AZStd::vector<AZStd::string> m_logPaths; //!< Log paths the servers will write to. Both relative to the game root folder and absolute paths supported.
+
+        uint16_t m_port = 0; //!< The port the server will be listening on.
+    };
+
+    //! Manage the server process for hosting game sessions via GameLiftServerSDK.
+    class AWSGameLiftServerManager
+        : public AzFramework::ISessionHandlingProviderRequests
+    {
+    public:
+        static constexpr const char AWSGameLiftServerManagerName[] = "AWSGameLiftServerManager";
+        static constexpr const char AWSGameLiftServerSDKNotInitErrorMessage[] =
+            "Amazon GameLift Server SDK is not initialized yet.";
+        static constexpr const char AWSGameLiftServerSDKAlreadyInitErrorMessage[] =
+            "Amazon GameLift Server SDK has already been initialized.";
+        static constexpr const char AWSGameLiftServerTempPortErrorMessage[] =
+            "No server port specified, server will be listening on ephemeral port.";
+        static constexpr const char AWSGameLiftServerGameInitErrorMessage[] =
+            "Failed to process game dependent initialization during OnStartGameSession.";
+        static constexpr const char AWSGameLiftServerGameSessionDestroyErrorMessage[] =
+            "Failed to destroy game session during OnProcessTerminate.";
+        static constexpr const char AWSGameLiftServerPlayerConnectionRegisteredErrorMessage[] =
+            "Player connection id %d is already registered to player session id %s. Remove connected player first.";
+        static constexpr const char AWSGameLiftServerPlayerConnectionMissingErrorMessage[] =
+            "Player connection id %d does not exist.";
+
+        static constexpr const char AWSGameLiftServerInitSDKErrorMessage[] =
+            "Failed to initialize Amazon GameLift Server SDK. ErrorMessage: %s";
+        static constexpr const char AWSGameLiftServerProcessReadyErrorMessage[] =
+            "Failed to notify GameLift server process ready. ErrorMessage: %s";
+        static constexpr const char AWSGameLiftServerActivateGameSessionErrorMessage[] =
+            "Failed to activate GameLift game session. ErrorMessage: %s";
+        static constexpr const char AWSGameLiftServerProcessEndingErrorMessage[] =
+            "Failed to notify GameLift server process ending. ErrorMessage: %s";
+        static constexpr const char AWSGameLiftServerAcceptPlayerSessionErrorMessage[] =
+            "Failed to validate player session connection with id %s. ErrorMessage: %s";
+        static constexpr const char AWSGameLiftServerInvalidConnectionConfigErrorMessage[] =
+            "Invalid player connection config, player connection id: %d, player session id: %s";
+        static constexpr const char AWSGameLiftServerRemovePlayerSessionErrorMessage[] =
+            "Failed to notify GameLift that the player with the player session id %s has disconnected from the server process. ErrorMessage: %s";
+
+        AWSGameLiftServerManager();
+        virtual ~AWSGameLiftServerManager();
+
+        //! Initialize GameLift API client by calling InitSDK().
+        //! @return Whether the initialization is successful.
+        bool InitializeGameLiftServerSDK();
+
+        //! Notify GameLift that the server process is ready to host a game session.
+        //! @param desc GameLift server process settings.
+        //! @return Whether the ProcessReady notification is sent to GameLift.
+        bool NotifyGameLiftProcessReady(const GameLiftServerProcessDesc& desc);
+
+        // ISessionHandlingProviderRequests interface implementation
+        void HandleDestroySession() override;
+        bool ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) override;
+        void HandlePlayerLeaveSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) override;
+        AZ::IO::Path GetExternalSessionCertificate() override;
+        AZ::IO::Path GetInternalSessionCertificate() override;
+
+    protected:
+        void SetGameLiftServerSDKWrapper(AZStd::unique_ptr<GameLiftServerSDKWrapper> gameLiftServerSDKWrapper);
+
+        //! Add connected player session id.
+        bool AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig);
+
+    private:
+        //! Build session config by using AWS GameLift Server GameSession Model.
+        AzFramework::SessionConfig BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession);
+
+        //! Callback function that the GameLift service invokes to activate a new game session.
+        void OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession);
+
+        //! Callback function that the GameLift service invokes to pass an updated game session object to the server process.
+        void OnUpdateGameSession();
+
+        //! Callback function that the server process or GameLift service invokes to force the server process to shut down.
+        void OnProcessTerminate();
+
+        //! Callback function that the GameLift service invokes to request a health status report from the server process.
+        //! @return Whether the server process is healthy.
+        bool OnHealthCheck();
+
+        //! Remove connected player session id.
+        //! @param playerConnectionId Connection id of the player to remove.
+        //! @param outPlayerSessionId Session id of the removed player. Empty if the player cannot be removed.
+        //! @return Whether the player is removed successfully.
+        bool RemoveConnectedPlayer(uint32_t playerConnectionId, AZStd::string& outPlayerSessionId);
+
+        AZStd::unique_ptr<GameLiftServerSDKWrapper> m_gameLiftServerSDKWrapper;
+        bool m_serverSDKInitialized;
+
+        AZStd::mutex m_gameliftMutex;
+        using PlayerConnectionId = uint32_t;
+        using PlayerSessionId = AZStd::string;
+        AZStd::unordered_map<PlayerConnectionId, PlayerSessionId> m_connectedPlayers;
+    };
+} // namespace AWSGameLift

+ 49 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerModule.cpp

@@ -0,0 +1,49 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Memory/SystemAllocator.h>
+#include <AzCore/Module/Module.h>
+
+#include <AWSGameLiftServerSystemComponent.h>
+
+namespace AWSGameLift
+{
+    //! Provide the entry point for the gem and register the system component.
+    class AWSGameLiftServerModule
+        : public AZ::Module
+    {
+    public:
+        AZ_RTTI(AWSGameLiftServerModule, "{898416ca-dc11-4731-87de-afe285aedb04}", AZ::Module);
+        AZ_CLASS_ALLOCATOR(AWSGameLiftServerModule, AZ::SystemAllocator, 0);
+
+        AWSGameLiftServerModule()
+            : AZ::Module()
+        {
+            // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
+            m_descriptors.insert(m_descriptors.end(), {
+                AWSGameLiftServerSystemComponent::CreateDescriptor(),
+            });
+        }
+
+        /**
+         * Add required SystemComponents to the SystemEntity.
+         */
+        AZ::ComponentTypeList GetRequiredSystemComponents() const override
+        {
+            return AZ::ComponentTypeList {
+                azrtti_typeid<AWSGameLiftServerSystemComponent>(),
+            };
+        }
+    };
+}// namespace AWSGameLift
+
+AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Server, AWSGameLift::AWSGameLiftServerModule)

+ 129 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerSystemComponent.cpp

@@ -0,0 +1,129 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AWSGameLiftServerSystemComponent.h>
+#include <AWSGameLiftServerManager.h>
+
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/EditContextConstants.inl>
+#include <AzCore/Console/IConsole.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzCore/IO/FileIO.h>
+#include <AzCore/IO/SystemFile.h>
+
+namespace AWSGameLift
+{
+    AWSGameLiftServerSystemComponent::AWSGameLiftServerSystemComponent()
+        : m_gameLiftServerManager(AZStd::make_unique<AWSGameLiftServerManager>())
+    {
+    }
+
+    AWSGameLiftServerSystemComponent::~AWSGameLiftServerSystemComponent()
+    {
+        m_gameLiftServerManager.reset();
+    }
+
+    void AWSGameLiftServerSystemComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serialize->Class<AWSGameLiftServerSystemComponent, AZ::Component>()
+                ->Version(0)
+                ;
+
+            if (AZ::EditContext* ec = serialize->GetEditContext())
+            {
+                ec->Class<AWSGameLiftServerSystemComponent>("AWSGameLiftServer", "Create the GameLift server manager which manages the server process for hosting a game session via GameLiftServerSDK.")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                        ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
+                        ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+                    ;
+            }
+        }
+    }
+
+    void AWSGameLiftServerSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("AWSGameLiftServerService"));
+    }
+
+    void AWSGameLiftServerSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC_CE("AWSGameLiftServerService"));
+    }
+
+    void AWSGameLiftServerSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        AZ_UNUSED(required);
+    }
+
+    void AWSGameLiftServerSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+        AZ_UNUSED(dependent);
+    }
+
+    void AWSGameLiftServerSystemComponent::Init()
+    {
+    }
+
+    void AWSGameLiftServerSystemComponent::Activate()
+    {
+        if (m_gameLiftServerManager->InitializeGameLiftServerSDK())
+        {
+            GameLiftServerProcessDesc serverProcessDesc;
+            UpdateGameLiftServerProcessDesc(serverProcessDesc);
+            m_gameLiftServerManager->NotifyGameLiftProcessReady(serverProcessDesc);
+        }
+    }
+
+    void AWSGameLiftServerSystemComponent::Deactivate()
+    {
+        m_gameLiftServerManager->HandleDestroySession();
+    }
+
+    void AWSGameLiftServerSystemComponent::UpdateGameLiftServerProcessDesc(GameLiftServerProcessDesc& serverProcessDesc)
+    {
+        AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetDirectInstance();
+        if (fileIO)
+        {
+            const char pathToLogFolder[] = "@log@/";
+            char resolvedPath[AZ_MAX_PATH_LEN];
+            if (fileIO->ResolvePath(pathToLogFolder, resolvedPath, AZ_ARRAY_SIZE(resolvedPath)))
+            {
+                serverProcessDesc.m_logPaths.push_back(resolvedPath);
+            }
+            else
+            {
+                AZ_Error("AWSGameLift", false, "Failed to resolve the path to the log folder.");
+            }
+        }
+        else
+        {
+            AZ_Error("AWSGameLift", false, "Failed to get File IO.");
+        }
+
+        if (auto console = AZ::Interface<AZ::IConsole>::Get(); console != nullptr)
+        {
+            AZ::GetValueResult getCvarResult = console->GetCvarValue("sv_port", serverProcessDesc.m_port);
+            AZ_Error(
+                "AWSGameLift", getCvarResult == AZ::GetValueResult::Success, "Lookup of 'sv_port' console variable failed with error %s",
+                AZ::GetEnumString(getCvarResult));
+        }
+    }
+
+    void AWSGameLiftServerSystemComponent::SetGameLiftServerManager(AZStd::unique_ptr<AWSGameLiftServerManager> gameLiftServerManager)
+    {
+        m_gameLiftServerManager.reset();
+        m_gameLiftServerManager = AZStd::move(gameLiftServerManager);
+    }
+} // namespace AWSGameLift

+ 57 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerSystemComponent.h

@@ -0,0 +1,57 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+
+namespace AWSGameLift
+{
+    struct GameLiftServerProcessDesc;
+    class AWSGameLiftServerManager;
+
+    //! Gem server system component. Responsible for managing the server process for hosting game sessions via the GameLift server manager.
+    class AWSGameLiftServerSystemComponent
+        : public AZ::Component
+    {
+    public:
+        AZ_COMPONENT(AWSGameLiftServerSystemComponent, "{fa2b46d6-82a9-408d-abab-62bae5ab38c9}");
+
+        AWSGameLiftServerSystemComponent();
+        virtual ~AWSGameLiftServerSystemComponent();
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+    protected:
+        ////////////////////////////////////////////////////////////////////////
+        // AZ::Component interface implementation
+        void Init() override;
+        void Activate() override;
+        void Deactivate() override;
+        ////////////////////////////////////////////////////////////////////////
+
+        void SetGameLiftServerManager(AZStd::unique_ptr<AWSGameLiftServerManager> gameLiftServerManager);
+
+    private:
+        //! Update the serverProcessDesc with appropriate server port number and log paths.
+        //! @param serverProcessDesc Desc object to update.
+        void UpdateGameLiftServerProcessDesc(GameLiftServerProcessDesc& serverProcessDesc);
+
+        AZStd::unique_ptr<AWSGameLiftServerManager> m_gameLiftServerManager;
+    };
+
+} // namespace AWSGameLift

+ 72 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.cpp

@@ -0,0 +1,72 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <GameLiftServerSDKWrapper.h>
+
+#include <ctime>
+
+#pragma warning(disable : 4996)
+
+namespace AWSGameLift
+{
+    Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::AcceptPlayerSession(const std::string& playerSessionId)
+    {
+        return Aws::GameLift::Server::AcceptPlayerSession(playerSessionId);
+    }
+
+    Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::ActivateGameSession()
+    {
+        return Aws::GameLift::Server::ActivateGameSession();
+    }
+
+    Aws::GameLift::Server::InitSDKOutcome GameLiftServerSDKWrapper::InitSDK()
+    {
+        return Aws::GameLift::Server::InitSDK();
+    }
+
+    Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::ProcessReady(
+        const Aws::GameLift::Server::ProcessParameters& processParameters)
+    {
+        return Aws::GameLift::Server::ProcessReady(processParameters);
+    }
+
+    Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::ProcessEnding()
+    {
+        return Aws::GameLift::Server::ProcessEnding();
+    }
+
+    AZStd::string GameLiftServerSDKWrapper::GetTerminationTime()
+    {
+        // Timestamp format is using the UTC ISO8601 format
+        std::time_t terminationTime;
+        Aws::GameLift::AwsLongOutcome GetTerminationTimeOutcome = Aws::GameLift::Server::GetTerminationTime();
+        if (GetTerminationTimeOutcome.IsSuccess())
+        {
+            terminationTime = GetTerminationTimeOutcome.GetResult();
+        }
+        else
+        {
+            // Use the current system time if the termination time is not available from GameLift.
+            time(&terminationTime);
+        }
+
+        char buffer[50];
+        strftime(buffer, sizeof(buffer), "%FT%TZ", gmtime(&terminationTime));
+
+        return AZStd::string(buffer);
+    }
+
+    Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::RemovePlayerSession(const AZStd::string& playerSessionId)
+    {
+        return Aws::GameLift::Server::RemovePlayerSession(playerSessionId.c_str());
+    }
+} // namespace AWSGameLift

+ 64 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.h

@@ -0,0 +1,64 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <aws/gamelift/server/GameLiftServerAPI.h>
+
+#include <AzCore/std/string/string.h>
+
+namespace AWSGameLift
+{
+    /* Wrapper to use to GameLift Server SDK.
+     */
+    class GameLiftServerSDKWrapper
+    {
+    public:
+        GameLiftServerSDKWrapper() = default;
+        virtual ~GameLiftServerSDKWrapper() = default;
+
+        //! Processes and validates a player session connection.
+        //! This method should be called when a client requests a connection to the server.
+        //! @param playerSessionId the ID of the joining player's session.
+        //! @return Returns a generic outcome consisting of success or failure with an error message.
+        virtual Aws::GameLift::GenericOutcome AcceptPlayerSession(const std::string& playerSessionId);
+
+        //! Reports to GameLift that the server process is now ready to receive player sessions.
+        //! Should be called once all GameSession initialization has finished.
+        //! @return Returns a generic outcome consisting of success or failure with an error message.
+        virtual Aws::GameLift::GenericOutcome ActivateGameSession();
+
+        //! Initializes the GameLift SDK.
+        //! Should be called when the server starts, before any GameLift-dependent initialization happens.
+        //! @return If successful, returns an InitSdkOutcome object indicating that the server process is ready to call ProcessReady().
+        virtual Aws::GameLift::Server::InitSDKOutcome InitSDK();
+
+        //! Notifies the GameLift service that the server process is ready to host game sessions.
+        //! @param processParameters A ProcessParameters object communicating the names of callback methods, port number and game
+        //! session-specific log files about the server process.
+        //! @return Returns a generic outcome consisting of success or failure with an error message.
+        virtual Aws::GameLift::GenericOutcome ProcessReady(const Aws::GameLift::Server::ProcessParameters& processParameters);
+
+        //! Notifies the GameLift service that the server process is shutting down.
+        //! @return Returns a generic outcome consisting of success or failure with an error message.
+        virtual Aws::GameLift::GenericOutcome ProcessEnding();
+
+        //! Returns the time that a server process is scheduled to be shut down.
+        //! @return Timestamp using the UTC ISO8601 format.
+        virtual AZStd::string GetTerminationTime();
+
+        //! Notifies the GameLift service that a player with the specified player session ID has disconnected from the server process.
+        //! @param playerSessionId Unique ID issued by the Amazon GameLift service in response to a call to the AWS SDK Amazon GameLift API action CreatePlayerSession.
+        //! @return Returns a generic outcome consisting of success or failure with an error message.
+        virtual Aws::GameLift::GenericOutcome RemovePlayerSession(const AZStd::string& playerSessionId);
+    };
+} // namespace AWSGameLift

+ 58 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerFixture.h

@@ -0,0 +1,58 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Jobs/JobContext.h>
+#include <AzCore/Jobs/JobManager.h>
+#include <AzCore/Jobs/JobManagerBus.h>
+#include <AzCore/Memory/PoolAllocator.h>
+#include <AzCore/UnitTest/TestTypes.h>
+
+class AWSGameLiftServerFixture
+    : public UnitTest::ScopedAllocatorSetupFixture
+{
+public:
+    AWSGameLiftServerFixture() {}
+    virtual ~AWSGameLiftServerFixture() = default;
+
+    void SetUp() override
+    {
+        AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
+        AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
+
+        AZ::JobManagerDesc jobManagerDesc;
+        AZ::JobManagerThreadDesc threadDesc;
+
+        m_jobManager.reset(aznew AZ::JobManager(jobManagerDesc));
+        m_jobCancelGroup.reset(aznew AZ::JobCancelGroup());
+        jobManagerDesc.m_workerThreads.push_back(threadDesc);
+        jobManagerDesc.m_workerThreads.push_back(threadDesc);
+        jobManagerDesc.m_workerThreads.push_back(threadDesc);
+        m_jobContext.reset(aznew AZ::JobContext(*m_jobManager, *m_jobCancelGroup));
+        AZ::JobContext::SetGlobalContext(m_jobContext.get());
+    }
+
+    void TearDown() override
+    {
+        AZ::JobContext::SetGlobalContext(nullptr);
+        m_jobContext.reset();
+        m_jobCancelGroup.reset();
+        m_jobManager.reset();
+        AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
+        AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
+    }
+
+    AZStd::unique_ptr<AZ::JobContext> m_jobContext;
+    AZStd::unique_ptr<AZ::JobCancelGroup> m_jobCancelGroup;
+    AZStd::unique_ptr<AZ::JobManager> m_jobManager;
+};

+ 421 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp

@@ -0,0 +1,421 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AWSGameLiftServerFixture.h>
+#include <AWSGameLiftServerMocks.h>
+
+#include <AzCore/Interface/Interface.h>
+#include <AzFramework/Session/SessionConfig.h>
+#include <AzFramework/Session/SessionNotifications.h>
+
+namespace UnitTest
+{
+    class SessionNotificationsHandlerMock
+        : public AzFramework::SessionNotificationBus::Handler
+    {
+    public:
+        SessionNotificationsHandlerMock()
+        {
+            AzFramework::SessionNotificationBus::Handler::BusConnect();
+        }
+
+        ~SessionNotificationsHandlerMock()
+        {
+            AzFramework::SessionNotificationBus::Handler::BusDisconnect();
+        }
+
+        MOCK_METHOD0(OnSessionHealthCheck, bool());
+        MOCK_METHOD1(OnCreateSessionBegin, bool(const AzFramework::SessionConfig&));
+        MOCK_METHOD0(OnDestroySessionBegin, bool());
+    };
+
+    class GameLiftServerManagerTest
+        : public AWSGameLiftServerFixture
+    {
+    public:
+        void SetUp() override
+        {
+            AWSGameLiftServerFixture::SetUp();
+
+            GameLiftServerProcessDesc serverDesc;
+            m_serverManager = AZStd::make_unique<NiceMock<AWSGameLiftServerManagerMock>>();
+        }
+
+        void TearDown() override
+        {
+            m_serverManager.reset();
+
+            AWSGameLiftServerFixture::TearDown();
+        }
+
+        AZStd::unique_ptr<NiceMock<AWSGameLiftServerManagerMock>> m_serverManager;
+    };
+
+    TEST_F(GameLiftServerManagerTest, InitializeGameLiftServerSDK_InitializeTwice_InitSDKCalledOnce)
+    {
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), InitSDK()).Times(1);
+
+        EXPECT_TRUE(m_serverManager->InitializeGameLiftServerSDK());
+
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        EXPECT_FALSE(m_serverManager->InitializeGameLiftServerSDK());
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, NotifyGameLiftProcessReady_SDKNotInitialized_FailToNotifyGameLift)
+    {
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessReady(testing::_)).Times(0);
+
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        EXPECT_FALSE(m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc()));
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, NotifyGameLiftProcessReady_SDKInitialized_ProcessReadyNotificationSent)
+    {
+        EXPECT_TRUE(m_serverManager->InitializeGameLiftServerSDK());
+
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessReady(testing::_)).Times(1);
+
+        EXPECT_TRUE(m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc()));
+    }
+
+    TEST_F(GameLiftServerManagerTest, NotifyGameLiftProcessReady_ProcessReadyFails_TerminationNotificationSent)
+    {
+        EXPECT_TRUE(m_serverManager->InitializeGameLiftServerSDK());
+
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessReady(testing::_))
+            .Times(1)
+            .WillOnce(testing::Return(Aws::GameLift::GenericOutcome()));
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        EXPECT_TRUE(m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc()));
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnProcessTerminate_OnDestroySessionBeginReturnsFalse_FailToNotifyGameLift)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        if (!AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
+        {
+            AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Register(m_serverManager.get());
+        }
+
+        SessionNotificationsHandlerMock handlerMock;
+        EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(false));
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), GetTerminationTime()).Times(1);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(0);
+
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onProcessTerminateFunc();
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+
+        EXPECT_FALSE(AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get());
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnProcessTerminate_OnDestroySessionBeginReturnsTrue_TerminationNotificationSent)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        if (!AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get())
+        {
+            AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Register(m_serverManager.get());
+        }
+
+        SessionNotificationsHandlerMock handlerMock;
+        EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), GetTerminationTime()).Times(1);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
+
+        m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onProcessTerminateFunc();
+
+        EXPECT_FALSE(AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get());
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnHealthCheck_OnSessionHealthCheckReturnsTrue_CallbackFunctionReturnsTrue)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        SessionNotificationsHandlerMock handlerMock;
+        EXPECT_CALL(handlerMock, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(true));
+        EXPECT_TRUE(m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_healthCheckFunc());
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnHealthCheck_OnSessionHealthCheckReturnsFalseAndTrue_CallbackFunctionReturnsFalse)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        SessionNotificationsHandlerMock handlerMock1;
+        EXPECT_CALL(handlerMock1, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(false));
+        SessionNotificationsHandlerMock handlerMock2;
+        EXPECT_CALL(handlerMock2, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(true));
+        EXPECT_FALSE(m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_healthCheckFunc());
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnHealthCheck_OnSessionHealthCheckReturnsFalse_CallbackFunctionReturnsFalse)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        SessionNotificationsHandlerMock handlerMock;
+        EXPECT_CALL(handlerMock, OnSessionHealthCheck()).Times(1).WillOnce(testing::Return(false));
+        EXPECT_FALSE(m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_healthCheckFunc());
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnStartGameSession_OnCreateSessionBeginReturnsFalse_TerminationNotificationSent)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        SessionNotificationsHandlerMock handlerMock;
+        EXPECT_CALL(handlerMock, OnCreateSessionBegin(testing::_)).Times(1).WillOnce(testing::Return(false));
+        EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onStartGameSessionFunc(Aws::GameLift::Server::Model::GameSession());
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnStartGameSession_ActivateGameSessionSucceeds_RegisterAsHandler)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        SessionNotificationsHandlerMock handlerMock;
+        EXPECT_CALL(handlerMock, OnCreateSessionBegin(testing::_)).Times(1).WillOnce(testing::Return(true));
+        EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ActivateGameSession())
+            .Times(1)
+            .WillOnce(testing::Return(Aws::GameLift::GenericOutcome(nullptr)));
+        Aws::GameLift::Server::Model::GameSession testSession;
+        Aws::GameLift::Server::Model::GameProperty testProperty;
+        testProperty.SetKey("testKey");
+        testProperty.SetValue("testValue");
+        testSession.AddGameProperties(testProperty);
+        m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onStartGameSessionFunc(testSession);
+        EXPECT_TRUE(AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get());
+        m_serverManager->HandleDestroySession();
+    }
+
+    TEST_F(GameLiftServerManagerTest, OnStartGameSession_ActivateGameSessionFails_TerminationNotificationSent)
+    {
+        m_serverManager->InitializeGameLiftServerSDK();
+        m_serverManager->NotifyGameLiftProcessReady(GameLiftServerProcessDesc());
+        SessionNotificationsHandlerMock handlerMock;
+        EXPECT_CALL(handlerMock, OnCreateSessionBegin(testing::_)).Times(1).WillOnce(testing::Return(true));
+        EXPECT_CALL(handlerMock, OnDestroySessionBegin()).Times(1).WillOnce(testing::Return(true));
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ActivateGameSession())
+            .Times(1)
+            .WillOnce(testing::Return(Aws::GameLift::GenericOutcome()));
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), ProcessEnding()).Times(1);
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onStartGameSessionFunc(Aws::GameLift::Server::Model::GameSession());
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithInvalidConnectionConfig_GetFalseResultAndExpectedErrorLog)
+    {
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        auto result = m_serverManager->ValidatePlayerJoinSession(AzFramework::PlayerConnectionConfig());
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+        EXPECT_FALSE(result);
+    }
+
+    TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithDuplicatedConnectionId_GetFalseResultAndExpectedErrorLog)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig1;
+        connectionConfig1.m_playerConnectionId = 123;
+        connectionConfig1.m_playerSessionId = "dummyPlayerSessionId1";
+        GenericOutcome successOutcome(nullptr);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
+            .Times(1)
+            .WillOnce(Return(successOutcome));
+        m_serverManager->ValidatePlayerJoinSession(connectionConfig1);
+        AzFramework::PlayerConnectionConfig connectionConfig2;
+        connectionConfig2.m_playerConnectionId = 123;
+        connectionConfig2.m_playerSessionId = "dummyPlayerSessionId2";
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig2);
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+        EXPECT_FALSE(result);
+    }
+
+    TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithValidConnectionConfigButErrorOutcome_GetFalseResultAndExpectedErrorLog)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig;
+        connectionConfig.m_playerConnectionId = 123;
+        connectionConfig.m_playerSessionId = "dummyPlayerSessionId1";
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_)).Times(1);
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig);
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+        EXPECT_FALSE(result);
+    }
+
+    TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithValidConnectionConfigAndSuccessOutcome_GetTrueResult)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig;
+        connectionConfig.m_playerConnectionId = 123;
+        connectionConfig.m_playerSessionId = "dummyPlayerSessionId1";
+        GenericOutcome successOutcome(nullptr);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
+            .Times(1)
+            .WillOnce(Return(successOutcome));
+        auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig);
+        EXPECT_TRUE(result);
+    }
+
+    TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithFirstErrorSecondSuccess_GetFirstFalseSecondTrueResult)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig1;
+        connectionConfig1.m_playerConnectionId = 123;
+        connectionConfig1.m_playerSessionId = "dummyPlayerSessionId1";
+        GenericOutcome successOutcome(nullptr);
+        Aws::GameLift::GameLiftError error;
+        GenericOutcome errorOutcome(error);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
+            .Times(2)
+            .WillOnce(Return(errorOutcome))
+            .WillOnce(Return(successOutcome));
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig1);
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+        EXPECT_FALSE(result);
+        AzFramework::PlayerConnectionConfig connectionConfig2;
+        connectionConfig2.m_playerConnectionId = 123;
+        connectionConfig2.m_playerSessionId = "dummyPlayerSessionId2";
+        result = m_serverManager->ValidatePlayerJoinSession(connectionConfig2);
+        EXPECT_TRUE(result);
+    }
+
+    TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithMultithread_GetFirstTrueAndRestFalse)
+    {
+        int testThreadNumber = 5;
+        GenericOutcome successOutcome(nullptr);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_))
+            .Times(1)
+            .WillOnce(Return(successOutcome));
+        AZStd::vector<AZStd::thread> testThreadPool;
+        AZStd::atomic<int> trueCount = 0;
+        for (int index = 0; index < testThreadNumber; index++)
+        {
+            testThreadPool.emplace_back(AZStd::thread([&]() {
+                AzFramework::PlayerConnectionConfig connectionConfig;
+                connectionConfig.m_playerConnectionId = 123;
+                connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
+                auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig);
+                if (result)
+                {
+                    trueCount++;
+                }
+            }));
+        }
+        for (auto& testThread : testThreadPool)
+        {
+            testThread.join();
+        }
+        EXPECT_TRUE(trueCount == 1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithInvalidConnectionConfig_GetExpectedErrorLog)
+    {
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_)).Times(0);
+
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        m_serverManager->HandlePlayerLeaveSession(AzFramework::PlayerConnectionConfig());
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithNonExistentPlayerConnectionId_GetExpectedErrorLog)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig;
+        connectionConfig.m_playerConnectionId = 123;
+        connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
+        auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
+        EXPECT_TRUE(result);
+
+        AzFramework::PlayerConnectionConfig connectionConfig1;
+        connectionConfig1.m_playerConnectionId = 456;
+        connectionConfig1.m_playerSessionId = "dummyPlayerSessionId";
+
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_)).Times(0);
+
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        m_serverManager->HandlePlayerLeaveSession(connectionConfig1);
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithValidConnectionConfigButErrorOutcome_GetExpectedErrorLog)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig;
+        connectionConfig.m_playerConnectionId = 123;
+        connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
+        auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
+        EXPECT_TRUE(result);
+
+        Aws::GameLift::GameLiftError error;
+        GenericOutcome errorOutcome(error);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_))
+            .Times(1)
+            .WillOnce(Return(errorOutcome));
+
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        m_serverManager->HandlePlayerLeaveSession(connectionConfig);
+        AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+    }
+
+    TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithValidConnectionConfigAndSuccessOutcome_RemovePlayerSessionNotificationSent)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig;
+        connectionConfig.m_playerConnectionId = 123;
+        connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
+        auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
+        EXPECT_TRUE(result);
+
+        GenericOutcome successOutcome(nullptr);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_))
+            .Times(1)
+            .WillOnce(Return(successOutcome));
+
+        m_serverManager->HandlePlayerLeaveSession(connectionConfig);
+    }
+
+    TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithMultithread_OnlyOneNotificationIsSent)
+    {
+        AzFramework::PlayerConnectionConfig connectionConfig;
+        connectionConfig.m_playerConnectionId = 123;
+        connectionConfig.m_playerSessionId = "dummyPlayerSessionId";
+        auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig);
+        EXPECT_TRUE(result);
+
+        int testThreadNumber = 5;
+        GenericOutcome successOutcome(nullptr);
+        EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_))
+            .Times(1)
+            .WillOnce(Return(successOutcome));
+
+        AZStd::vector<AZStd::thread> testThreadPool;
+        AZStd::atomic<int> trueCount = 0;
+        AZ_TEST_START_TRACE_SUPPRESSION;
+        for (int index = 0; index < testThreadNumber; index++)
+        {
+            testThreadPool.emplace_back(AZStd::thread(
+                [&]()
+                {
+                    m_serverManager->HandlePlayerLeaveSession(connectionConfig);
+                }));
+        }
+        for (auto& testThread : testThreadPool)
+        {
+            testThread.join();
+        }
+        AZ_TEST_STOP_TRACE_SUPPRESSION(testThreadNumber - 1); // The player is only disconnected once.
+    }
+} // namespace UnitTest

+ 127 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h

@@ -0,0 +1,127 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#include <AWSGameLiftServerSystemComponent.h>
+#include <AWSGameLiftServerManager.h>
+#include <GameLiftServerSDKWrapper.h>
+#include <AzCore/UnitTest/TestTypes.h>
+#include <AzCore/std/smart_ptr/make_shared.h>
+
+using namespace Aws::GameLift;
+using namespace AWSGameLift;
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+using testing::NiceMock;
+using testing::Eq;
+
+namespace UnitTest
+{
+    class GameLiftServerSDKWrapperMock
+        : public GameLiftServerSDKWrapper
+    {
+    public:
+        GameLiftServerSDKWrapperMock()
+        {
+            GenericOutcome successOutcome(nullptr);
+            Server::InitSDKOutcome sdkOutcome(nullptr);
+
+            ON_CALL(*this, InitSDK()).WillByDefault(Return(sdkOutcome));
+            ON_CALL(*this, ProcessReady(_)).WillByDefault(Invoke(this, &GameLiftServerSDKWrapperMock::ProcessReadyMock));
+            ON_CALL(*this, ProcessEnding()).WillByDefault(Return(successOutcome));
+        }
+
+        MOCK_METHOD1(AcceptPlayerSession, GenericOutcome(const std::string&));
+        MOCK_METHOD0(ActivateGameSession, GenericOutcome());
+        MOCK_METHOD0(InitSDK, Server::InitSDKOutcome());
+        MOCK_METHOD1(ProcessReady, GenericOutcome(const Server::ProcessParameters& processParameters));
+        MOCK_METHOD0(ProcessEnding, GenericOutcome());
+        MOCK_METHOD1(RemovePlayerSession, GenericOutcome(const AZStd::string& playerSessionId));
+        MOCK_METHOD0(GetTerminationTime, AZStd::string());
+
+        GenericOutcome ProcessReadyMock(const Server::ProcessParameters& processParameters)
+        {
+            m_healthCheckFunc = processParameters.getOnHealthCheck();
+            m_onStartGameSessionFunc = processParameters.getOnStartGameSession();
+            m_onProcessTerminateFunc = processParameters.getOnProcessTerminate();
+
+            GenericOutcome successOutcome(nullptr);
+            return successOutcome;
+        }
+
+        AZStd::function<bool()> m_healthCheckFunc;
+        AZStd::function<void()> m_onProcessTerminateFunc;
+        AZStd::function<void(Aws::GameLift::Server::Model::GameSession)> m_onStartGameSessionFunc;
+    };
+
+    class AWSGameLiftServerManagerMock
+        : public AWSGameLiftServerManager
+    {
+    public:
+        AWSGameLiftServerManagerMock()
+        {
+            AZStd::unique_ptr<NiceMock<GameLiftServerSDKWrapperMock>> gameLiftServerSDKWrapper =
+                AZStd::make_unique<NiceMock<GameLiftServerSDKWrapperMock>>();
+            m_gameLiftServerSDKWrapperMockPtr = gameLiftServerSDKWrapper.get();
+            SetGameLiftServerSDKWrapper(AZStd::move(gameLiftServerSDKWrapper));
+        }
+
+        ~AWSGameLiftServerManagerMock()
+        {
+            m_gameLiftServerSDKWrapperMockPtr = nullptr;
+        }
+
+        bool AddConnectedTestPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig)
+        {
+            return AddConnectedPlayer(playerConnectionConfig);
+        }
+
+        NiceMock<GameLiftServerSDKWrapperMock>* m_gameLiftServerSDKWrapperMockPtr;
+    };
+
+    class AWSGameLiftServerSystemComponentMock
+        : public AWSGameLift::AWSGameLiftServerSystemComponent
+    {
+    public:
+        AWSGameLiftServerSystemComponentMock()
+        {
+            SetGameLiftServerManager(AZStd::make_unique<NiceMock<AWSGameLiftServerManagerMock>>());
+
+            ON_CALL(*this, Init()).WillByDefault(testing::Invoke(this, &AWSGameLiftServerSystemComponentMock::InitMock));
+            ON_CALL(*this, Activate()).WillByDefault(testing::Invoke(this, &AWSGameLiftServerSystemComponentMock::ActivateMock));
+            ON_CALL(*this, Deactivate()).WillByDefault(testing::Invoke(this, &AWSGameLiftServerSystemComponentMock::DeactivateMock));
+        }
+
+        void InitMock()
+        {
+            AWSGameLift::AWSGameLiftServerSystemComponent::Init();
+        }
+
+        void ActivateMock()
+        {
+            AWSGameLift::AWSGameLiftServerSystemComponent::Activate();
+        }
+
+        void DeactivateMock()
+        {
+            AWSGameLift::AWSGameLiftServerSystemComponent::Deactivate();
+        }
+
+        MOCK_METHOD0(Init, void());
+        MOCK_METHOD0(Activate, void());
+        MOCK_METHOD0(Deactivate, void());
+
+        GameLiftServerProcessDesc m_serverProcessDesc;
+    };
+};

+ 99 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerSystemComponentTest.cpp

@@ -0,0 +1,99 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include <AWSGameLiftServerFixture.h>
+#include <AWSGameLiftServerMocks.h>
+
+#include <AzCore/Component/Entity.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/UnitTest/TestTypes.h>
+#include <AzFramework/IO/LocalFileIO.h>
+#include <AzTest/AzTest.h>
+
+namespace UnitTest
+{
+    class AWSGameLiftServerSystemComponentTest
+        : public AWSGameLiftServerFixture
+    {
+    public:
+        void SetUp() override
+        {
+            AWSGameLiftServerFixture::SetUp();
+
+            m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
+            m_serializeContext->CreateEditContext();
+            m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
+            m_componentDescriptor.reset(AWSGameLift::AWSGameLiftServerSystemComponent::CreateDescriptor());
+            m_componentDescriptor->Reflect(m_serializeContext.get());
+            m_componentDescriptor->Reflect(m_behaviorContext.get());
+
+            m_entity = aznew AZ::Entity();
+
+            m_AWSGameLiftServerSystemsComponent = aznew NiceMock<AWSGameLiftServerSystemComponentMock>();
+            m_entity->AddComponent(m_AWSGameLiftServerSystemsComponent);
+
+            // Set up the file IO and alias
+            m_localFileIO = aznew AZ::IO::LocalFileIO();
+            m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
+
+            AZ::IO::FileIOBase::SetInstance(nullptr);
+            AZ::IO::FileIOBase::SetInstance(m_localFileIO);
+            m_localFileIO->SetAlias("@log@", AZ_TRAIT_TEST_ROOT_FOLDER);
+        }
+
+        void TearDown() override
+        {
+            AZ::IO::FileIOBase::SetInstance(nullptr);
+            delete m_localFileIO;
+            AZ::IO::FileIOBase::SetInstance(m_priorFileIO);
+
+            m_entity->RemoveComponent(m_AWSGameLiftServerSystemsComponent);
+            delete m_AWSGameLiftServerSystemsComponent;
+            delete m_entity;
+
+            m_componentDescriptor.reset();
+            m_behaviorContext.reset();
+            m_serializeContext.reset();
+
+            AWSGameLiftServerFixture::TearDown();
+        }
+
+        AZStd::unique_ptr<AZ::ComponentDescriptor> m_componentDescriptor;
+        AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
+        AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
+
+        AZ::Entity* m_entity;      
+        NiceMock<AWSGameLiftServerSystemComponentMock>* m_AWSGameLiftServerSystemsComponent;
+
+        AZ::IO::FileIOBase* m_priorFileIO;
+        AZ::IO::FileIOBase* m_localFileIO;
+    };
+
+    TEST_F(AWSGameLiftServerSystemComponentTest, ActivateDeactivateComponent_ExecuteInOrder_Success)
+    {
+        testing::Sequence s1, s2;
+
+        EXPECT_CALL(*m_AWSGameLiftServerSystemsComponent, Init()).Times(1).InSequence(s1);
+        EXPECT_CALL(*m_AWSGameLiftServerSystemsComponent, Activate()).Times(1).InSequence(s1);
+
+        EXPECT_CALL(*m_AWSGameLiftServerSystemsComponent, Deactivate()).Times(1).InSequence(s2);
+
+        // activate component
+        m_entity->Init();
+        m_entity->Activate();
+
+        // deactivate component
+        m_entity->Deactivate();
+    }
+
+} // namespace UnitTest

+ 15 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerTest.cpp

@@ -0,0 +1,15 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzTest/AzTest.h>
+
+AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);

+ 20 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_files.cmake

@@ -0,0 +1,20 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    ../AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h
+    Source/AWSGameLiftServerManager.cpp
+    Source/AWSGameLiftServerManager.h
+    Source/AWSGameLiftServerSystemComponent.cpp
+    Source/AWSGameLiftServerSystemComponent.h
+    Source/GameLiftServerSDKWrapper.cpp
+    Source/GameLiftServerSDKWrapper.h
+)

+ 14 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_shared_files.cmake

@@ -0,0 +1,14 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    Source/AWSGameLiftServerModule.cpp
+)

+ 18 - 0
Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_tests_files.cmake

@@ -0,0 +1,18 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    Tests/AWSGameLiftServerFixture.h
+    Tests/AWSGameLiftServerMocks.h
+    Tests/AWSGameLiftServerManagerTest.cpp
+    Tests/AWSGameLiftServerTest.cpp
+    Tests/AWSGameLiftServerSystemComponentTest.cpp
+)

+ 13 - 0
Gems/AWSGameLift/Code/CMakeLists.txt

@@ -0,0 +1,13 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+add_subdirectory(AWSGameLiftClient)
+add_subdirectory(AWSGameLiftServer)

+ 10 - 0
Gems/AWSGameLift/cdk/.gitignore

@@ -0,0 +1,10 @@
+*.swp
+package-lock.json
+__pycache__
+.pytest_cache
+.env
+*.egg-info
+
+# CDK asset staging directory
+.cdk.staging
+cdk.out

+ 99 - 0
Gems/AWSGameLift/cdk/README.md

@@ -0,0 +1,99 @@
+
+# Welcome to O3DE GameLift Sample Project!
+
+This is an optional CDK application that provides two stacks:
+
+  * A GameLift stack that contains all the GameLift resources required to host game servers
+  * An optional support stack which is used to upload local build files and create GameLift builds
+
+The `cdk.json` file tells the CDK Toolkit how to execute this application.
+
+This project is set up like a standard Python project.  The initialization
+process also creates a virtualenv within this project, stored under the `.env`
+directory.  To create the virtualenv it assumes that there is a `python3`
+(or `python` for Windows) (Python 3.7+) executable in your path with access to the `venv`
+package. If for any reason the automatic creation of the virtualenv fails,
+you can create the virtualenv manually.
+
+See https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html about for information about how to set up
+the prerequisites for CDK development.
+
+To manually create a virtualenv on MacOS and Linux:
+
+```
+$ python -m venv .env
+```
+
+Once the virtualenv is created, you can use the following step to activate your virtualenv.
+
+```
+$ source .env/bin/activate
+```
+
+If you are a Windows platform, you would activate the virtualenv like this:
+
+```
+% .env\Scripts\activate.bat
+```
+
+Once the virtualenv is activated, you can install the required dependencies.
+
+```
+$ pip install -r requirements.txt
+```
+
+## Set environment variables or accept defaults
+
+* O3DE_AWS_DEPLOY_REGION*: The region to deploy the stacks into, will default to CDK_DEFAULT_REGION
+* O3DE_AWS_DEPLOY_ACCOUNT*: The account to deploy stacks into, will default to CDK_DEFAULT_ACCOUNT
+* O3DE_AWS_PROJECT_NAME*: The name of the O3DE project stacks should be deployed for will default to AWS-PROJECT
+
+See https://docs.aws.amazon.com/cdk/latest/guide/environments.html for more information including how to pass parameters
+to use for environment variables.
+
+## Edit the sample fleet configurations
+
+Before deploy the CDK application, please update the sample fleet configurations defined in the
+[sample fleet configurations](aws_gamelift/fleet_configurations.py)
+ with project specific settings.
+
+## Synthesize the project
+
+At this point you can now synthesize the CloudFormation template for this code.
+
+```
+$ cdk synth
+```
+
+## Optional features
+To create a game session queue using this CDK application, provide the following context variable 
+when synthesize the CloudFormation template or deploy the application:
+
+```
+$ cdk deploy -c create_game_session_queue=true
+```
+
+You can also deploy a support stack which is used to upload local build files to S3 and provide GameLift access 
+to the S3 objects when create GameLift builds:
+
+```
+$ cdk deploy -c upload-with-support-stack=true --all
+```
+
+You may need todo a one time bootstrap, once per account, per region. The CDK application will prompt you on this.
+
+To add additional dependencies, for example other CDK libraries, just add
+them to your `setup.py` file and rerun the `pip install -r requirements.txt`
+command.
+
+## Useful commands
+
+ * `cdk ls`          list all stacks in the app
+ * `cdk synth`       emits the synthesized CloudFormation template
+ * `cdk deploy`      deploy this stack to your default AWS account/region
+ * `cdk diff`        compare deployed stack with current state
+ * `cdk docs`        open CDK documentation
+ 
+## GameLift reference and best practise
+https://docs.aws.amazon.com/gamelift/index.html
+

+ 53 - 0
Gems/AWSGameLift/cdk/app.py

@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+"""
+All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+its licensors.
+
+For complete copyright and license terms please see the LICENSE at the root of this
+distribution (the "License"). All use of this software is governed by the License,
+or, if provided, by the license below or the license accompanying this file. Do not
+remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+"""
+
+import os
+
+from aws_cdk import core
+
+from aws_gamelift.aws_gamelift_construct import AWSGameLift
+
+"""Configuration"""
+REGION = os.environ.get('O3DE_AWS_DEPLOY_REGION', os.environ.get('CDK_DEFAULT_REGION'))
+ACCOUNT = os.environ.get('O3DE_AWS_DEPLOY_ACCOUNT', os.environ.get('CDK_DEFAULT_ACCOUNT'))
+
+# Set the common prefix to group stacks in a project together.
+PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME', f'O3DE-AWS-PROJECT').upper()
+
+# The name of this feature
+FEATURE_NAME = 'AWSGameLift'
+
+# The name of this CDK application
+PROJECT_FEATURE_NAME = f'{PROJECT_NAME}-{FEATURE_NAME}'
+
+# Standard Tag Key for project based tags
+O3DE_PROJECT_TAG_NAME = 'O3DEProject'
+# Standard Tag Key for feature based tags
+O3DE_FEATURE_TAG_NAME = 'O3DEFeature'
+
+"""End of Configuration"""
+
+# Set-up regions to deploy stack to, or use default if not set
+env = core.Environment(
+    account=ACCOUNT,
+    region=REGION)
+
+app = core.App()
+feature_struct = AWSGameLift(
+    app,
+    id_=PROJECT_FEATURE_NAME,
+    project_name=PROJECT_NAME,
+    feature_name=FEATURE_NAME,
+    tags={O3DE_PROJECT_TAG_NAME: PROJECT_NAME, O3DE_FEATURE_TAG_NAME: FEATURE_NAME},
+    env=env
+)
+app.synth()

+ 10 - 0
Gems/AWSGameLift/cdk/aws_gamelift/__init__.py

@@ -0,0 +1,10 @@
+"""
+All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+its licensors.
+
+For complete copyright and license terms please see the LICENSE at the root of this
+distribution (the "License"). All use of this software is governed by the License,
+or, if provided, by the license below or the license accompanying this file. Do not
+remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+"""

+ 59 - 0
Gems/AWSGameLift/cdk/aws_gamelift/aws_gamelift_construct.py

@@ -0,0 +1,59 @@
+"""
+All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+its licensors.
+
+For complete copyright and license terms please see the LICENSE at the root of this
+distribution (the "License"). All use of this software is governed by the License,
+or, if provided, by the license below or the license accompanying this file. Do not
+remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+"""
+
+import copy
+
+from aws_cdk import core
+
+from aws_gamelift.fleet_configurations import FLEET_CONFIGURATIONS
+from aws_gamelift.gamelift_stack import GameLiftStack
+from aws_gamelift.support_stack import SupportStack
+
+
+class AWSGameLift(core.Construct):
+    """
+    Orchestrates setting up the AWS GameLift Stack(s)
+    """
+    def __init__(self,
+                 scope: core.Construct,
+                 id_: str,
+                 project_name: str,
+                 feature_name: str,
+                 tags: dict,
+                 env: core.Environment) -> None:
+        super().__init__(scope, id_)
+
+        stack_name = f'{project_name}-{feature_name}-{env.region}'
+
+        fleet_configurations = copy.deepcopy(FLEET_CONFIGURATIONS)
+        if self.node.try_get_context('upload-with-support-stack') == 'true':
+            # Create an optional support stack for generating GameLift builds with local build files
+            self._support_stack = SupportStack(
+                scope,
+                f'{stack_name}-Support',
+                stack_name=stack_name,
+                fleet_configurations=fleet_configurations,
+                description='(Optional) Contains resources for creating GameLift builds with local files',
+                tags=tags,
+                env=env
+            )
+
+        # Create the GameLift Stack
+        self._feature_stack = GameLiftStack(
+            scope,
+            f'{stack_name}',
+            stack_name=stack_name,
+            fleet_configurations=fleet_configurations,
+            create_game_session_queue=self.node.try_get_context('create_game_session_queue') == 'true',
+            description=f'Contains resources for the AWS GameLift Gem stack as part of the {project_name} project',
+            tags=tags,
+            env=env
+        )

+ 147 - 0
Gems/AWSGameLift/cdk/aws_gamelift/fleet_configurations.py

@@ -0,0 +1,147 @@
+"""
+All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+its licensors.
+
+For complete copyright and license terms please see the LICENSE at the root of this
+distribution (the "License"). All use of this software is governed by the License,
+or, if provided, by the license below or the license accompanying this file. Do not
+remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+"""
+
+# Configurations for the fleets to deploy.
+# Modify the fleet configuration fields below before deploying the CDK application.
+# To select the right combination of hosting resources and learn how to configure them to best suit to your application,
+# please check: https://docs.aws.amazon.com/gamelift/latest/developerguide/fleets-design.html
+FLEET_CONFIGURATIONS = [
+    {
+        # (Optional) An alias for an Amazon GameLift fleet destination.
+        # By using aliases instead of specific fleet IDs, customers can more easily and seamlessly switch
+        # player traffic from one fleet to another by changing the alias's target location.
+        'alias_configuration': {
+            # (Required) A descriptive label that is associated with an alias. Alias names do not need to be unique.
+            'name': '<alias name>',
+            # (Conditional) A type of routing strategy for the GameLift fleet alias if exists.
+            # Required if alias_configuration is provided.
+            'routing_strategy': {
+                # The message text to be used with a terminal routing strategy.
+                # If you specify TERMINAL for the Type property, you must specify this property.
+                # Required if specify TERMINAL for the Type property,
+                'message': '<routing strategy message>',
+                # (Required) A type of routing strategy.
+                'type': 'SIMPLE | TERMINAL'
+            }
+        },
+        # (Required) Information about a game server build that is installed and
+        # run on instances in an Amazon GameLift fleet.
+        'build_configuration': {
+            # (Conditional) A unique identifier for a build to be deployed on the new fleet.
+            # This parameter is required unless the parameters build_path and operating_system are defined and
+            # the conditional variable upload-with-support-stack is set to true
+            'build_id': '<build id>',
+            # (Conditional) The disk location of the local build file(zip).
+            # This parameter is required unless the parameter build_id is defined.
+            'build_path': '<build path>',
+            # (Conditional) The operating system that the game server binaries are built to run on.
+            # This parameter is required if the parameter build_path is defined.
+            'operating_system': 'AMAZON_LINUX | AMAZON_LINUX_2 | WINDOWS_2012'
+        },
+        # (Optional) Information about the use of a TLS/SSL certificate for a fleet.
+        'certificate_configuration': {
+            # (Required) Indicates whether a TLS/SSL certificate is generated for the fleet.
+            'certificate_type': 'DISABLED | GENERATED',
+        },
+        # A human-readable description of the fleet.
+        'description': 'Amazon GameLift fleet to host game servers.',
+        # (Optional) A range of IP addresses and port settings that allow inbound traffic to connect to
+        # server processes on an Amazon GameLift server.
+        # This should be the same port range as the server is configured for.
+        'ec2_inbound_permissions': [
+            {
+                # (Required) A starting value for a range of allowed port numbers.
+                # 30090 is the default server port defined by the Multiplayer Gem.
+                'from_port': 30090,
+                # (Required) A range of allowed IP addresses.
+                'ip_range': '<ip range>',
+                # (Required) The network communication protocol used by the fleet.
+                'protocol': 'UDP',
+                # (Required) An ending value for a range of allowed port numbers.
+                'to_port': 30090
+            },
+            {
+                # Open the debug port for remote into a Windows fleet.
+                'from_port': 3389,
+                'ip_range': '<external ip range>',
+                'protocol': 'TCP',
+                'to_port': 3389
+            },
+            {
+                # Open the debug port for remote into a Linux fleet.
+                'from_port': 22,
+                'ip_range': '<external ip range>',
+                'protocol': 'TCP',
+                'to_port': 22
+            }
+        ],
+        # (Optional) The GameLift-supported EC2 instance type to use for all fleet instances.
+        'ec2_instance_type': 'c3.2xlarge | c3.4xlarge | c3.8xlarge | c3.large | c3.xlarge | c4.2xlarge | c4.4xlarge |'
+                             ' c4.8xlarge | c4.large | c4.xlarge | c5.12xlarge | c5.18xlarge | c5.24xlarge |'
+                             ' c5.2xlarge | c5.4xlarge | c5.9xlarge | c5.large | c5.xlarge | c5a.12xlarge |'
+                             ' c5a.16xlarge | c5a.24xlarge | c5a.2xlarge | c5a.4xlarge | c5a.8xlarge | c5a.large |'
+                             ' c5a.xlarge | m3.2xlarge | m3.large | m3.medium | m3.xlarge | m4.10xlarge | m4.2xlarge |'
+                             ' m4.4xlarge | m4.large | m4.xlarge | m5.12xlarge | m5.16xlarge | m5.24xlarge |'
+                             ' m5.2xlarge | m5.4xlarge | m5.8xlarge | m5.large | m5.xlarge | m5a.12xlarge |'
+                             ' m5a.16xlarge | m5a.24xlarge | m5a.2xlarge | m5a.4xlarge | m5a.8xlarge | m5a.large |'
+                             ' m5a.xlarge | r3.2xlarge | r3.4xlarge | r3.8xlarge | r3.large | r3.xlarge | r4.16xlarge |'
+                             ' r4.2xlarge | r4.4xlarge | r4.8xlarge | r4.large | r4.xlarge | r5.12xlarge |'
+                             ' r5.16xlarge | r5.24xlarge | r5.2xlarge | r5.4xlarge | r5.8xlarge | r5.large |'
+                             ' r5.xlarge | r5a.12xlarge | r5a.16xlarge | r5a.24xlarge | r5a.2xlarge | r5a.4xlarge |'
+                             ' r5a.8xlarge | r5a.large | r5a.xlarge | t2.large | t2.medium | t2.micro | t2.small',
+        # (Optional) Indicates whether to use On-Demand or Spot instances for this fleet.
+        'fleet_type': 'ON_DEMAND | SPOT',
+        # (Optional) A game session protection policy to apply to all game sessions hosted on instances in this fleet.
+        'new_game_session_protection_policy': 'FullProtection | NoProtection',
+        # (Optional) A policy that limits the number of game sessions that an individual player
+        # can create on instances in this fleet within a specified span of time.
+        'resource_creation_limit_policy': {
+            # (Optional) The maximum number of game sessions that an individual can create during the policy period.
+            # Provide any integer not less than 0.
+            'new_game_sessions_per_creator': 3,
+            # (Optional) The time span used in evaluating the resource creation limit policy.
+            # Provide any integer not less than 0.
+            'policy_period_in_minutes': 15
+        },
+        # (Conditional) Instructions for launching server processes on each instance in the fleet.
+        # This parameter is required unless the parameters ServerLaunchPath and ServerLaunchParameters are defined.
+        'runtime_configuration': {
+            # (Optional) The maximum amount of time (in seconds) allowed to launch a new game session and
+            # have it report ready to host players.
+            # Provide an integer from 1 to 600.
+            'game_session_activation_timeout_seconds': 300,
+            # (Optional) The number of game sessions in status ACTIVATING to allow on an instance.
+            # Provide an integer from 1 to 2147483647.
+            'max_concurrent_game_session_activations': 2,
+            # (Optional) A collection of server process configurations that identify what server processes
+            # to run on each instance in a fleet. To set up a fleet's runtime configuration to
+            # run multiple game server processes per instance, please check the following document:
+            # https://docs.aws.amazon.com/gamelift/latest/developerguide/fleets-multiprocess.html
+            'server_processes': [
+                {
+                    # (Required) The number of server processes using this configuration that
+                    # run concurrently on each instance.
+                    # Provide any integer not less than 1.
+                    'concurrent_executions': 1,
+                    # (Required) The location of a game build executable or the Realtime script file that
+                    # contains the Init() function.
+                    'launch_path': '(Windows) <C:\\game\\<executable or script> | '
+                                   '(Linux) /local/game/MyGame/<executable or script>',
+                    # (Optional) An optional list of parameters to pass to the server executable
+                    # or Realtime script on launch.
+                    'parameters': '<launch parameters>'
+                }
+            ]
+        }
+        # For additional fleet configurations, please check:
+        # # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GameLift.html
+    }
+]

+ 184 - 0
Gems/AWSGameLift/cdk/aws_gamelift/gamelift_stack.py

@@ -0,0 +1,184 @@
+"""
+All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+its licensors.
+
+For complete copyright and license terms please see the LICENSE at the root of this
+distribution (the "License"). All use of this software is governed by the License,
+or, if provided, by the license below or the license accompanying this file. Do not
+remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+"""
+
+import typing
+
+from aws_cdk import core
+from aws_cdk import aws_gamelift as gamelift
+
+
+class GameLiftStack(core.Stack):
+    """
+    The AWS GameLift stack
+
+    Defines GameLift resources to use in project
+    """
+    def __init__(self, scope: core.Construct, id_: str,
+                 stack_name: str, fleet_configurations: dict,
+                 create_game_session_queue: bool, **kwargs) -> None:
+        super().__init__(scope, id_, **kwargs)
+
+        self._stack_name = stack_name
+
+        fleet_ids = []
+        queue_destinations = []
+        for index in range(len(fleet_configurations)):
+            fleet_configuration = fleet_configurations[index]
+            # Create a new GameLift fleet using the configuration
+            fleet_ids.append(self._create_fleet(fleet_configuration, index).attr_fleet_id)
+            destination_arn = core.Fn.sub(
+                body='arn:${AWS::Partition}:gamelift:${AWS::Region}::fleet/${FleetId}',
+                variables={
+                    'FleetId': fleet_ids[index],
+                }
+            )
+
+            if fleet_configuration.get('alias_configuration'):
+                # Create an alias for the fleet if the alias configuration is provided
+                alias = self._create_alias(fleet_configuration['alias_configuration'], fleet_ids[index])
+                destination_arn = core.Fn.sub(
+                    body='arn:${AWS::Partition}:gamelift:${AWS::Region}::alias/${AliasId}',
+                    variables={
+                        'AliasId': alias.attr_alias_id,
+                    }
+                )
+
+            queue_destinations.append(destination_arn)
+
+        # Export the GameLift fleet ids as a stack output
+        fleets_output = core.CfnOutput(
+            self,
+            id='GameLiftFleets',
+            description='List of GameLift fleet ids',
+            export_name=f'{self._stack_name}:GameLiftFleets',
+            value=','.join(fleet_ids)
+        )
+
+        if create_game_session_queue:
+            # Create a game session queue which fulfills game session placement requests using the fleets
+            game_session_queue = self._create_game_session_queue(queue_destinations)
+
+            # Export the game session queue name as a stack output
+            game_session_queue_output = core.CfnOutput(
+                self,
+                id='GameSessionQueue',
+                description='Name of the game session queue',
+                export_name=f'{self._stack_name}:GameSessionQueue',
+                value=game_session_queue.name)
+
+    def _create_fleet(self, fleet_configuration: dict, identifier: int) -> gamelift.CfnFleet:
+        """
+        Create an Amazon GameLift fleet to host game servers.
+        :param fleet_configuration: Configuration of the fleet.
+        :param identifier: Unique identifier of the fleet which will be included in the resource id.
+        :return: Generated GameLift fleet.
+        """
+        fleet = gamelift.CfnFleet(
+            self,
+            id=f'{self._stack_name}-GameLiftFleet{identifier}',
+            build_id=self._get_gamelift_build_id(fleet_configuration.get('build_configuration', {}), identifier),
+            certificate_configuration=gamelift.CfnFleet.CertificateConfigurationProperty(
+                certificate_type=fleet_configuration['certificate_configuration'].get('certificate_type')
+            ) if fleet_configuration.get('certificate_configuration') else None,
+            description=fleet_configuration.get('description'),
+            ec2_inbound_permissions=[
+                gamelift.CfnFleet.IpPermissionProperty(
+                    **inbound_permission
+                ) for inbound_permission in fleet_configuration.get('ec2_inbound_permissions', [])
+            ],
+            ec2_instance_type=fleet_configuration.get('ec2_instance_type'),
+            fleet_type=fleet_configuration.get('fleet_type'),
+            name=f'{self._stack_name}-GameLiftFleet{identifier}',
+            new_game_session_protection_policy=fleet_configuration.get('new_game_session_protection_policy'),
+            resource_creation_limit_policy=gamelift.CfnFleet.ResourceCreationLimitPolicyProperty(
+                **fleet_configuration['resource_creation_limit_policy']
+            ) if fleet_configuration.get('resource_creation_limit_policy') else None,
+            runtime_configuration=gamelift.CfnFleet.RuntimeConfigurationProperty(
+                game_session_activation_timeout_seconds=fleet_configuration['runtime_configuration'].get(
+                    'game_session_activation_timeout_seconds'),
+                max_concurrent_game_session_activations=fleet_configuration['runtime_configuration'].get(
+                    'max_concurrent_game_session_activations'),
+                server_processes=[
+                    gamelift.CfnFleet.ServerProcessProperty(
+                        **server_process
+                    ) for server_process in fleet_configuration['runtime_configuration'].get('server_processes', [])
+                ]
+            ) if fleet_configuration.get('runtime_configuration') else None,
+        )
+
+        return fleet
+
+    def _get_gamelift_build_id(self, build_configuration: dict, identifier: int) -> str:
+        """
+        Get the GameLift build id.
+        Create the GameLift build from the storage location information if the build doesn't exist.
+        :param build_configuration: Configuration of the GameLift build.
+        :param identifier: Unique identifier of the build which will be included in the resource id.
+        :return: Build id.
+        """
+        if build_configuration.get('build_id'):
+            # GameLift build already exists
+            return build_configuration['build_id']
+        elif build_configuration.get('storage_location'):
+            # Create the GameLift build using the storage location information.
+            build = gamelift.CfnBuild(
+                self,
+                id=f'{self._stack_name}-GameLiftBuild{identifier}',
+                name=f'{self._stack_name}-GameLiftBuild{identifier}',
+                operating_system=build_configuration.get('operating_system'),
+                storage_location=gamelift.CfnBuild.S3LocationProperty(
+                    **build_configuration['storage_location']
+                )
+            )
+            return build.ref
+
+        return ''
+
+    def _create_alias(self, alias_configuration: dict, fleet_id: str) -> gamelift.CfnAlias:
+        """
+        Create an alias for an Amazon GameLift fleet destination.
+        :param alias_configuration: Configuration of the alias
+        :param fleet_id: Fleet id that the alias points to.
+        :return: Generated GameLift fleet alias.
+        """
+        alias = gamelift.CfnAlias(
+            self,
+            id=f'{self._stack_name}-GameLiftAlias',
+            name=alias_configuration.get('name'),
+            routing_strategy=gamelift.CfnAlias.RoutingStrategyProperty(
+                **alias_configuration.get('routing_strategy', {}),
+                fleet_id=fleet_id
+            )
+        )
+
+        return alias
+
+    def _create_game_session_queue(self, destinations: typing.List) -> gamelift.CfnGameSessionQueue:
+        """
+        Create a placement queue that processes requests for new game sessions.
+        :param destinations: Destinations of the queue.
+        :return: Generated GameLift game session queue.
+        """
+        game_session_queue = gamelift.CfnGameSessionQueue(
+            self,
+            id=f'{self._stack_name}-GameLiftQueue',
+            name=f'{self._stack_name}-game-session-queue',
+            destinations=[
+                gamelift.CfnGameSessionQueue.DestinationProperty(
+                    destination_arn=resource_arn
+                ) for resource_arn in destinations
+            ]
+        )
+
+        return game_session_queue
+
+
+

+ 71 - 0
Gems/AWSGameLift/cdk/aws_gamelift/support_stack.py

@@ -0,0 +1,71 @@
+"""
+All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+its licensors.
+
+For complete copyright and license terms please see the LICENSE at the root of this
+distribution (the "License"). All use of this software is governed by the License,
+or, if provided, by the license below or the license accompanying this file. Do not
+remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+"""
+
+from aws_cdk import aws_iam as iam
+from aws_cdk import aws_s3_assets as assets
+from aws_cdk import core
+
+
+class SupportStack(core.Stack):
+    """
+    The support stack
+
+    Defines AWS resources that help to create GameLift builds from local files
+    """
+    def __init__(self, scope: core.Construct, id_: str,
+                 stack_name: str, fleet_configurations: dict, **kwargs) -> None:
+        super().__init__(scope, id_, **kwargs)
+        self._stack_name = stack_name
+        self._support_iam_role = self._create_support_iam_role()
+
+        for index in range(len(fleet_configurations)):
+            # Update the fleet configuration to include the corresponding build id
+            fleet_configurations[index]['build_configuration']['storage_location'] = self._upload_build_asset(
+                fleet_configurations[index].get('build_configuration', {}), index)
+
+    def _create_support_iam_role(self) -> iam.Role:
+        """
+        Create an IAM role for GameLift to read build files stored in S3.
+        :return: Generated IAM role.
+        """
+        support_role = iam.Role(
+            self,
+            id=f'{self._stack_name}-SupportRole',
+            assumed_by=iam.ServicePrincipal(
+                service='gamelift.amazonaws.com'
+            )
+        )
+
+        return support_role
+
+    def _upload_build_asset(self, build_configuration: dict, identifier: int) -> dict:
+        """
+        Upload the local build files to S3 for a creating GameLift build.
+        :param build_configuration: Configuration of the GameLift build.
+        :param identifier: Unique identifier of the asset which will be included in the resource id.
+        :return: Storage location of the S3 object.
+        """
+        build_asset = assets.Asset(
+            self,
+            id=f'{self._stack_name}-Asset{identifier}',
+            path=build_configuration.get('build_path')
+        )
+        # Grant the support IAM role permission to read the asset
+        build_asset.grant_read(self._support_iam_role)
+
+        storage_location = {
+            'bucket': build_asset.s3_bucket_name,
+            'key': build_asset.s3_object_key,
+            'role_arn': self._support_iam_role.role_arn
+        }
+
+        return storage_location
+

+ 17 - 0
Gems/AWSGameLift/cdk/cdk.json

@@ -0,0 +1,17 @@
+{
+  "app": "python app.py",
+  "context": {
+    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
+    "@aws-cdk/core:enableStackNameDuplicates": "true",
+    "aws-cdk:enableDiffNoFail": "true",
+    "@aws-cdk/core:stackRelativeExports": "true",
+    "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true,
+    "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true,
+    "@aws-cdk/aws-kms:defaultKeyPolicies": true,
+    "@aws-cdk/aws-s3:grantWriteWithoutAcl": true,
+    "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true,
+    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
+    "@aws-cdk/aws-efs:defaultEncryptionAtRest": true,
+    "@aws-cdk/aws-lambda:recognizeVersionProps": true
+  }
+}

+ 4 - 0
Gems/AWSGameLift/cdk/requirements.txt

@@ -0,0 +1,4 @@
+aws-cdk.core>=1.91.0
+aws-cdk.aws_gamelift>=1.91.0
+aws-cdk.aws_iam>=1.91.0
+aws-cdk.aws_s3_assets>=1.91.0

+ 14 - 0
Gems/AWSGameLift/gem.json

@@ -0,0 +1,14 @@
+{
+    "gem_name": "AWSGameLift",
+    "origin": "The primary repo for AWSGameLift goes here: i.e. http://www.mydomain.com",
+    "license": "What license AWSGameLift uses goes here: i.e. https://opensource.org/licenses/MIT",
+    "display_name": "AWSGameLift",
+    "summary": "The AWSGameLift Gem provides a framework to extend O3DE networking layer to work with GameLift resources via GameLift server and client SDK.",
+    "canonical_tags": [
+        "Gem"
+    ],
+    "user_tags": [
+        "AWSGameLift"
+    ],
+    "icon_path": "preview.png"
+}

+ 3 - 0
Gems/AWSGameLift/preview.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7aca75b5e82f55478f4f8c575d384ff3ef67260dde2107bd45d377516e6104f7
+size 22196

+ 1 - 0
engine.json

@@ -18,6 +18,7 @@
         "Gems/AutomatedLauncherTesting",
         "Gems/AWSClientAuth",
         "Gems/AWSCore",
+        "Gems/AWSGameLift",
         "Gems/AWSMetrics",
         "Gems/Blast",
         "Gems/Camera",