Quellcode durchsuchen

Properly storing RequestMatchmaking response; json is crashing when hitting arrays or dictionaries if they are ignored, for that reason, player data is being stored even though we only need the ticket id.

Signed-off-by: AMZN-Gene <[email protected]>
AMZN-Gene vor 2 Jahren
Ursprung
Commit
00e3080f95

+ 6 - 0
MPSGameLift/Code/CMakeLists.txt

@@ -56,6 +56,7 @@ ly_add_target(
         PUBLIC
         PUBLIC
             AZ::AzCore
             AZ::AzCore
             AZ::AzFramework
             AZ::AzFramework
+            Gem::AWSCore
             Gem::HttpRequestor
             Gem::HttpRequestor
             Gem::Multiplayer.Client
             Gem::Multiplayer.Client
             Gem::LyShine
             Gem::LyShine
@@ -64,6 +65,7 @@ ly_add_target(
             Gem::AWSCore.Static
             Gem::AWSCore.Static
             Gem::HttpRequestor.Static
             Gem::HttpRequestor.Static
             Gem::AWSGameLift.Client.Static
             Gem::AWSGameLift.Client.Static
+            Gem::AWSClientAuth.Static
             Gem::LyShine.Static
             Gem::LyShine.Static
 )
 )
 
 
@@ -117,6 +119,7 @@ ly_add_target(
             Gem::Multiplayer.Unified.Static
             Gem::Multiplayer.Unified.Static
             Gem::AWSCore.Static
             Gem::AWSCore.Static
             Gem::AWSGameLift.Client.Static
             Gem::AWSGameLift.Client.Static
+            Gem::AWSClientAuth.Static
             Gem::LyShine.Static
             Gem::LyShine.Static
 	    Gem::HttpRequestor.Static
 	    Gem::HttpRequestor.Static
     RUNTIME_DEPENDENCIES
     RUNTIME_DEPENDENCIES
@@ -142,6 +145,7 @@ ly_add_target(
             Gem::Multiplayer.Client.Static
             Gem::Multiplayer.Client.Static
             Gem::AWSCore.Static
             Gem::AWSCore.Static
             Gem::AWSGameLift.Client.Static
             Gem::AWSGameLift.Client.Static
+            Gem::AWSClientAuth.Static
             Gem::${gem_name}.Client.Private.Object
             Gem::${gem_name}.Client.Private.Object
     RUNTIME_DEPENDENCIES
     RUNTIME_DEPENDENCIES
         Gem::AWSGameLift.Clients
         Gem::AWSGameLift.Clients
@@ -240,6 +244,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
                 Gem::Multiplayer.Unified.Static
                 Gem::Multiplayer.Unified.Static
                 Gem::AWSCore.Static
                 Gem::AWSCore.Static
                 Gem::AWSGameLift.Client.Static
                 Gem::AWSGameLift.Client.Static
+                Gem::AWSClientAuth.Static
+                AZ::AWSNativeSDKInit
                 Gem::HttpRequestor.Static
                 Gem::HttpRequestor.Static
                 $<TARGET_OBJECTS:Gem::${gem_name}.Unified.Private.Object>
                 $<TARGET_OBJECTS:Gem::${gem_name}.Unified.Private.Object>
     )
     )

+ 39 - 0
MPSGameLift/Code/Include/MPSGameLift/IMatchmaking.h

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+#include <MPSGameLift/IRegionalLatencyFinder.h>
+
+
+namespace MPSGameLift
+{
+    // Result data structure for a check on a matchmaking request
+    struct MatchmakingResults
+    {
+        AZStd::string address;
+        uint32_t port = 0;
+        AZStd::string playerId;
+        bool found = false;
+    };
+
+    // Supports matchmaking request calls to a serverless backend
+    class IMatchmaking
+    {
+    public:
+        AZ_RTTI(IMatchmaking, "{371687E5-9626-4201-91E3-0FD1F79CB8B6}");
+        virtual ~IMatchmaking() = default;
+
+        // Request a match for the player, providing player latencies for defined regions
+        virtual bool RequestMatch(const RegionalLatencies& regionalLatencies) = 0;
+
+        // Gets the current ticket id if any
+        virtual AZStd::string GetTicketId() const = 0;
+
+        // Checks if a match has been made
+        // TODO: Needs to return the matchmaking results
+        virtual bool HasMatch(const AZStd::string& ticketId) = 0;
+    };
+} // namespace MPSGameLift

+ 1 - 0
MPSGameLift/Code/Include/MPSGameLift/IRegionalLatencyFinder.h

@@ -8,6 +8,7 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AzCore/EBus/Event.h>
 #include <AzCore/RTTI/RTTIMacros.h>
 #include <AzCore/RTTI/RTTIMacros.h>
 #include <AzCore/std/chrono/chrono.h>
 #include <AzCore/std/chrono/chrono.h>
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/string/string.h>

+ 3 - 0
MPSGameLift/Code/Source/MPSGameLiftModuleInterface.h

@@ -12,6 +12,7 @@
 
 
 
 
 #if AZ_TRAIT_CLIENT
 #if AZ_TRAIT_CLIENT
+    #include <MatchmakingSystemComponent.h>
     #include <MPSGameLiftClientSystemComponent.h>
     #include <MPSGameLiftClientSystemComponent.h>
     #include <Components/UI/UiGameLiftConnectWithPlayerSessionData.h>
     #include <Components/UI/UiGameLiftConnectWithPlayerSessionData.h>
     #include <RegionalLatencySystemComponent.h>
     #include <RegionalLatencySystemComponent.h>
@@ -64,6 +65,7 @@ namespace MPSGameLift
             m_descriptors.insert(m_descriptors.end(), {
             m_descriptors.insert(m_descriptors.end(), {
                 MPSGameLiftSystemComponent::CreateDescriptor(),
                 MPSGameLiftSystemComponent::CreateDescriptor(),
                 #if AZ_TRAIT_CLIENT
                 #if AZ_TRAIT_CLIENT
+                    MatchmakingSystemComponent::CreateDescriptor(),
                     RegionalLatencySystemComponent::CreateDescriptor(),
                     RegionalLatencySystemComponent::CreateDescriptor(),
                     MPSGameLiftClientSystemComponent::CreateDescriptor(),
                     MPSGameLiftClientSystemComponent::CreateDescriptor(),
                     UiGameLiftConnectWithPlayerSessionData::CreateDescriptor(),
                     UiGameLiftConnectWithPlayerSessionData::CreateDescriptor(),
@@ -84,6 +86,7 @@ namespace MPSGameLift
             };
             };
 
 
             #if AZ_TRAIT_CLIENT
             #if AZ_TRAIT_CLIENT
+                requiredSystemComponents.push_back(azrtti_typeid<MatchmakingSystemComponent>());
                 requiredSystemComponents.push_back(azrtti_typeid<RegionalLatencySystemComponent>());
                 requiredSystemComponents.push_back(azrtti_typeid<RegionalLatencySystemComponent>());
                 requiredSystemComponents.push_back(azrtti_typeid<MPSGameLiftClientSystemComponent>());
                 requiredSystemComponents.push_back(azrtti_typeid<MPSGameLiftClientSystemComponent>());
             #endif
             #endif

+ 246 - 0
MPSGameLift/Code/Source/MatchmakingSystemComponent.cpp

@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ * 
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include "MatchmakingSystemComponent.h"
+
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/RTTI/BehaviorContext.h>
+
+#include <AWSCoreBus.h>
+#include <ResourceMapping/AWSResourceMappingBus.h>
+
+#include <Framework/ServiceRequestJob.h>
+
+
+namespace MPSGameLift
+{
+    namespace ServiceAPI
+    {
+        struct PlayerSkill
+        {
+            bool OnJsonKey(const char* key, AWSCore::JsonReader& reader)
+            {
+                if (strcmp(key, "N") == 0)
+                {
+                    return reader.Accept(skill);
+                }
+                return reader.Ignore();
+            }
+
+            int skill;
+        };
+
+        struct PlayerAttributes
+        {
+            bool OnJsonKey(const char* key, AWSCore::JsonReader& reader)
+            {
+                if (strcmp(key, "skill") == 0)
+                {
+                    return reader.Accept(skill);
+                }
+                return reader.Ignore();
+            }
+
+            PlayerSkill skill;
+        };
+
+        struct Latencies
+        {
+            bool OnJsonKey(const char* key, AWSCore::JsonReader& reader)
+            {
+                return reader.Accept(latencies[key]);
+            }
+
+            AZStd::unordered_map<AZStd::string, int> latencies;
+        };
+
+        struct Player
+        {
+            bool OnJsonKey(const char* key, AWSCore::JsonReader& reader)
+            {
+                if (strcmp(key, "LatencyInMs") == 0)
+                {
+                    return reader.Accept(latencies);
+                }
+                if (strcmp(key, "PlayerId") == 0)
+                {
+                    return reader.Accept(playerId);
+                }
+                if (strcmp(key, "Team") == 0)
+                {
+                    return reader.Accept(team);
+                }
+                if (strcmp(key, "PlayerAttributes") == 0)
+                {
+                    return reader.Accept(playerAttributes);
+                }
+                return reader.Ignore();
+            }
+
+            AZStd::string playerId;
+            AZStd::string team;
+            Latencies latencies;
+            PlayerAttributes playerAttributes;
+        };
+
+
+        //! Struct for storing the success response.
+        struct RequestMatchmakingResponse
+        {
+            bool OnJsonKey(const char* key, AWSCore::JsonReader& reader)
+            {
+                if (strcmp(key, "TicketId") == 0)
+                {
+                    return reader.Accept(ticketId);
+                }
+                if (strcmp(key, "Players") == 0)
+                {
+                    return reader.Accept(players);
+                }
+
+                return reader.Ignore();
+            }
+
+            AZStd::string ticketId;
+            AZStd::vector<Player> players;
+        };
+
+        //! Struct for storing the error.
+        struct RequestMatchmakingError
+        {
+            bool OnJsonKey(const char* key, AWSCore::JsonReader& reader)
+            {
+                if (strcmp(key, "message") == 0)
+                {
+                    return reader.Accept(message);
+                }
+
+                if (strcmp(key, "type") == 0)
+                {
+                    return reader.Accept(type);
+                }
+
+                return reader.Ignore();
+            }
+
+            //! Do not rename the following members since they are expected by the AWSCore dependency.
+            AZStd::string message; //!< Error message.
+            AZStd::string type; //!< Error type.
+        };
+
+        // Service RequestJobs
+        AWS_FEATURE_GEM_SERVICE(MPSGameLift);
+
+        //! GET request to place a matchmaking request "/requestmatchmaking".
+        class RequestMatchmaking
+            : public AWSCore::ServiceRequest
+        {
+        public:
+            SERVICE_REQUEST(MPSGameLift, HttpMethod::HTTP_GET, "");
+
+            struct Parameters
+            {
+                bool BuildRequest(AWSCore::RequestBuilder& request)
+                {
+                    return request.WriteJsonBodyParameter(*this);
+                }
+
+                bool WriteJson([[maybe_unused]]AWSCore::JsonWriter& writer) const
+                {
+                    return true;
+                }
+            };
+
+            RequestMatchmakingResponse result;
+            RequestMatchmakingError error;
+            Parameters parameters; //! Request parameter.
+        };
+
+        using MPSRequestMatchmakingRequestJob = AWSCore::ServiceRequestJob<RequestMatchmaking>;
+    }  // ServiceAPI
+
+    void MatchmakingSystemComponent::Activate()
+    {
+        AZ::Interface<IMatchmaking>::Register(this);
+    }
+
+    void MatchmakingSystemComponent::Deactivate()
+    {
+        AZ::Interface<IMatchmaking>::Unregister(this);
+    }
+
+    void MatchmakingSystemComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<MatchmakingSystemComponent, AZ::Component>()
+                ->Version(0)
+                ;
+        }
+    }
+
+    void MatchmakingSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("MPSGameLiftMatchmaking"));
+    }
+
+
+   bool MatchmakingSystemComponent::RequestMatch(const RegionalLatencies& regionalLatencies)
+    {
+        if (!m_ticketId.empty())
+        {
+            AZ_Warning("MatchmakingSystemComponent", false, "Ticket already exists %s", m_ticketId.c_str())
+            return true;
+        }
+
+        // Digest latencies for the HTTP GET parameter
+        AZ_Assert(!regionalLatencies.empty(), "IMatchmaking::RequestMatch failed! Client needs to provide regional latencies in order to determine the best server to join!")
+        AZStd::string httpLatenciesParam;
+        for (auto const& [region, latencyMs] : regionalLatencies)
+        {
+            httpLatenciesParam += AZStd::string::format("%s_%lld ", region.c_str(), latencyMs.count());
+        }
+
+        httpLatenciesParam.pop_back();  // pop the trailing white-space
+
+        // Set API endpoint and region
+        ServiceAPI::MPSRequestMatchmakingRequestJob::Config* config = ServiceAPI::MPSRequestMatchmakingRequestJob::GetDefaultConfig();
+        AZStd::string actualRegion;
+        AWSCore::AWSResourceMappingRequestBus::BroadcastResult(actualRegion, &AWSCore::AWSResourceMappingRequests::GetDefaultRegion);
+
+        AZStd::string restApi;
+        AWSCore::AWSResourceMappingRequestBus::BroadcastResult(restApi, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, "MPSMatchmaking");
+        config->region = actualRegion.c_str();
+        config->endpointOverride = AZStd::string::format("https://%s.execute-api.%s.amazonaws.com/%s?latencies=%s",
+            restApi.c_str(), actualRegion.c_str(), "Prod/requestmatchmaking", httpLatenciesParam.c_str()).c_str();
+
+        // Request Match
+        ServiceAPI::MPSRequestMatchmakingRequestJob* requestJob = ServiceAPI::MPSRequestMatchmakingRequestJob::Create(
+            [this](ServiceAPI::MPSRequestMatchmakingRequestJob* successJob)
+            {
+                m_ticketId = successJob->result.ticketId;
+            },
+            []([[maybe_unused]] ServiceAPI::MPSRequestMatchmakingRequestJob* failJob)
+            {
+                AZ_Error("MatchmakingSystemComponent", false, "Unable to request match error: %s", failJob->error.message.c_str());
+            },
+            config);
+
+        requestJob->Start();
+        return true;
+    }
+
+    bool MatchmakingSystemComponent::HasMatch(const AZStd::string& ticketId)
+    {
+        if (ticketId.empty())
+        {
+            return false;
+        }
+        return false;
+    }
+}

+ 36 - 0
MPSGameLift/Code/Source/MatchmakingSystemComponent.h

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ * 
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <MPSGameLift/IMatchmaking.h>
+
+namespace MPSGameLift
+{
+    class MatchmakingSystemComponent final
+        : public AZ::Component
+        , public IMatchmaking
+    {
+    public:
+        AZ_COMPONENT(MatchmakingSystemComponent, "{BF5F9343-63B5-4703-89ED-9CDBF4FE6004}");
+        static void Reflect(AZ::ReflectContext* context);
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+
+        // IMatchmaking overrides...
+        bool RequestMatch(const RegionalLatencies& regionalLatencies) override;
+        AZStd::string GetTicketId() const override {return m_ticketId;}
+        bool HasMatch(const AZStd::string& ticketId) override;
+
+     protected:
+        void Activate() override;
+        void Deactivate() override;
+
+    private:
+        AZStd::string m_ticketId;
+     };
+}

+ 1 - 0
MPSGameLift/Code/Source/Tools/MPSGameLiftEditorModule.cpp

@@ -36,6 +36,7 @@ namespace MPSGameLift
         AZ::ComponentTypeList GetRequiredSystemComponents() const override
         AZ::ComponentTypeList GetRequiredSystemComponents() const override
         {
         {
             return AZ::ComponentTypeList {
             return AZ::ComponentTypeList {
+                azrtti_typeid<MatchmakingSystemComponent>(),
                 azrtti_typeid<MPSGameLiftEditorSystemComponent>(),
                 azrtti_typeid<MPSGameLiftEditorSystemComponent>(),
                 azrtti_typeid<RegionalLatencySystemComponent>()
                 azrtti_typeid<RegionalLatencySystemComponent>()
             };
             };

+ 1 - 0
MPSGameLift/Code/mpsgamelift_api_files.cmake

@@ -6,5 +6,6 @@
 
 
 set(FILES
 set(FILES
     Include/MPSGameLift/MPSGameLiftBus.h
     Include/MPSGameLift/MPSGameLiftBus.h
+    Include/MPSGameLift/IMatchmaking.h
     Include/MPSGameLift/IRegionalLatencyFinder.h
     Include/MPSGameLift/IRegionalLatencyFinder.h
 )
 )

+ 2 - 0
MPSGameLift/Code/mpsgamelift_client_files.cmake

@@ -6,6 +6,8 @@
 #
 #
 
 
 set(FILES
 set(FILES
+    Source/MatchmakingSystemComponent.cpp
+    Source/MatchmakingSystemComponent.h
     Source/MPSGameLiftClientSystemComponent.cpp
     Source/MPSGameLiftClientSystemComponent.cpp
     Source/MPSGameLiftClientSystemComponent.h
     Source/MPSGameLiftClientSystemComponent.h
     Source/Components/UI/UiGameLiftConnectWithPlayerSessionData.cpp
     Source/Components/UI/UiGameLiftConnectWithPlayerSessionData.cpp