Merge branch 'main' of https://github.com/aws-lumberyard/o3de into cgalvan/DuplicateEntities
This commit is contained in:
@@ -307,6 +307,8 @@ namespace AZ
|
||||
Asset(AssetLoadBehavior loadBehavior = AssetLoadBehavior::Default);
|
||||
/// Create an asset from a valid asset data (created asset), might not be loaded or currently loading.
|
||||
Asset(AssetData* assetData, AssetLoadBehavior loadBehavior);
|
||||
/// Create an asset from a valid asset data (created asset) and set the asset id for both, might not be loaded or currently loading.
|
||||
Asset(const AZ::Data::AssetId& id, AssetData* assetData, AssetLoadBehavior loadBehavior);
|
||||
/// Initialize asset pointer with id, type, and hint. No data construction will occur until QueueLoad is called.
|
||||
Asset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type, const AZStd::string& hint = AZStd::string());
|
||||
|
||||
@@ -787,6 +789,18 @@ namespace AZ
|
||||
SetData(assetData);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
template<class T>
|
||||
Asset<T>::Asset(const AssetId& id, AssetData* assetData, AssetLoadBehavior loadBehavior)
|
||||
: m_assetId(id)
|
||||
, m_assetType(azrtti_typeid<T>())
|
||||
, m_loadBehavior(loadBehavior)
|
||||
{
|
||||
AZ_Assert(!assetData->m_assetId.IsValid(), "Asset data already has an ID set.");
|
||||
assetData->m_assetId = id;
|
||||
SetData(assetData);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
template<class T>
|
||||
Asset<T>::Asset(const AssetId& id, const AZ::Data::AssetType& type, const AZStd::string& hint)
|
||||
|
||||
@@ -41,10 +41,6 @@ namespace AZ
|
||||
if (const char* homePath = std::getenv("HOME"); homePath != nullptr)
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{homePath};
|
||||
if (!path.empty())
|
||||
{
|
||||
path /= ".o3de";
|
||||
}
|
||||
return path.Native();
|
||||
}
|
||||
return {};
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ namespace AzPhysics
|
||||
namespace
|
||||
{
|
||||
const float TimestepMin = 0.001f; //1000fps
|
||||
const float TimestepMax = 0.05f; //20fps
|
||||
const float TimestepMax = 0.1f; //10fps
|
||||
}
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(SystemConfiguration, AZ::SystemAllocator, 0);
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace AzPhysics
|
||||
|
||||
static constexpr float DefaultFixedTimestep = 0.0166667f; //! Value represents 1/60th or 60 FPS.
|
||||
|
||||
float m_maxTimestep = 1.f / 20.f; //!< Maximum fixed timestep in seconds to run the physics update.
|
||||
float m_maxTimestep = 0.1f; //!< Maximum fixed timestep in seconds to run the physics update (10FPS).
|
||||
float m_fixedTimestep = DefaultFixedTimestep; //!< Timestep in seconds to run the physics update. See DefaultFixedTimestep.
|
||||
|
||||
AZ::u64 m_raycastBufferSize = 32; //!< Maximum number of hits that will be returned from a raycast.
|
||||
|
||||
@@ -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/std/string/string.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
//! SessionConnectionConfig
|
||||
//! The properties for handling join session request.
|
||||
struct SessionConnectionConfig
|
||||
{
|
||||
// A unique identifier for registered player in session.
|
||||
AZStd::string m_playerSessionId;
|
||||
|
||||
// The DNS identifier assigned to the instance that is running the session.
|
||||
AZStd::string m_dnsName;
|
||||
|
||||
// The IP address of the session.
|
||||
AZStd::string m_ipAddress;
|
||||
|
||||
// The port number for the session.
|
||||
uint16_t m_port;
|
||||
};
|
||||
|
||||
//! SessionConnectionConfig
|
||||
//! The properties for handling player connect/disconnect
|
||||
struct PlayerConnectionConfig
|
||||
{
|
||||
// A unique identifier for player connection.
|
||||
uint32_t m_playerConnectionId;
|
||||
|
||||
// A unique identifier for registered player in session.
|
||||
AZStd::string m_playerSessionId;
|
||||
};
|
||||
|
||||
//! ISessionHandlingClientRequests
|
||||
//! The session handling events to invoke multiplayer component handle the work on client side
|
||||
class ISessionHandlingClientRequests
|
||||
{
|
||||
public:
|
||||
// Handle the player join session process
|
||||
// @param sessionConnectionConfig The required properties to handle the player join session process
|
||||
// @return The result of player join session process
|
||||
virtual bool HandlePlayerJoinSession(const SessionConnectionConfig& sessionConnectionConfig) = 0;
|
||||
|
||||
// Handle the player leave session process
|
||||
virtual void HandlePlayerLeaveSession() = 0;
|
||||
};
|
||||
|
||||
//! ISessionHandlingServerRequests
|
||||
//! The session handling events to invoke server provider handle the work on server side
|
||||
class ISessionHandlingServerRequests
|
||||
{
|
||||
public:
|
||||
// Handle the destroy session process
|
||||
virtual void HandleDestroySession() = 0;
|
||||
|
||||
// Validate the player join session process
|
||||
// @param playerConnectionConfig The required properties to validate the player join session process
|
||||
// @return The result of player join session validation
|
||||
virtual bool ValidatePlayerJoinSession(const PlayerConnectionConfig& playerConnectionConfig) = 0;
|
||||
|
||||
// Handle the player leave session process
|
||||
// @param playerConnectionConfig The required properties to handle the player leave session process
|
||||
virtual void HandlePlayerLeaveSession(const PlayerConnectionConfig& playerConnectionConfig) = 0;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
@@ -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 <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Session/ISessionRequests.h>
|
||||
#include <AzFramework/Session/SessionConfig.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void CreateSessionRequest::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<CreateSessionRequest>()
|
||||
->Version(0)
|
||||
->Field("creatorId", &CreateSessionRequest::m_creatorId)
|
||||
->Field("sessionProperties", &CreateSessionRequest::m_sessionProperties)
|
||||
->Field("sessionName", &CreateSessionRequest::m_sessionName)
|
||||
->Field("maxPlayer", &CreateSessionRequest::m_maxPlayer)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<CreateSessionRequest>("CreateSessionRequest", "The container for CreateSession request parameters")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CreateSessionRequest::m_creatorId,
|
||||
"CreatorId", "A unique identifier for a player or entity creating the session")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CreateSessionRequest::m_sessionProperties,
|
||||
"SessionProperties", "A collection of custom properties for a session")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CreateSessionRequest::m_sessionName,
|
||||
"SessionName", "A descriptive label that is associated with a session")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CreateSessionRequest::m_maxPlayer,
|
||||
"MaxPlayer", "The maximum number of players that can be connected simultaneously to the session")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchSessionsRequest::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<SearchSessionsRequest>()
|
||||
->Version(0)
|
||||
->Field("filterExpression", &SearchSessionsRequest::m_filterExpression)
|
||||
->Field("sortExpression", &SearchSessionsRequest::m_sortExpression)
|
||||
->Field("maxResult", &SearchSessionsRequest::m_maxResult)
|
||||
->Field("nextToken", &SearchSessionsRequest::m_nextToken)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<SearchSessionsRequest>("SearchSessionsRequest", "The container for SearchSessions request parameters")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &SearchSessionsRequest::m_filterExpression,
|
||||
"FilterExpression", "String containing the search criteria for the session search")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &SearchSessionsRequest::m_sortExpression,
|
||||
"SortExpression", "Instructions on how to sort the search results")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &SearchSessionsRequest::m_maxResult,
|
||||
"MaxResult", "The maximum number of results to return")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &SearchSessionsRequest::m_nextToken,
|
||||
"NextToken", "A token that indicates the start of the next sequential page of results")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchSessionsResponse::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<SearchSessionsResponse>()
|
||||
->Version(0)
|
||||
->Field("sessionConfigs", &SearchSessionsResponse::m_sessionConfigs)
|
||||
->Field("nextToken", &SearchSessionsResponse::m_nextToken)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<SearchSessionsResponse>("SearchSessionsResponse", "The container for SearchSession request results")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &SearchSessionsResponse::m_sessionConfigs,
|
||||
"SessionConfigs", "A collection of sessions that match the search criteria and sorted in specific order")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &SearchSessionsResponse::m_nextToken,
|
||||
"NextToken", "A token that indicates the start of the next sequential page of results")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JoinSessionRequest::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<JoinSessionRequest>()
|
||||
->Version(0)
|
||||
->Field("sessionId", &JoinSessionRequest::m_sessionId)
|
||||
->Field("playerId", &JoinSessionRequest::m_playerId)
|
||||
->Field("playerData", &JoinSessionRequest::m_playerData)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<JoinSessionRequest>("JoinSessionRequest", "The container for JoinSession request parameters")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &JoinSessionRequest::m_sessionId,
|
||||
"SessionId", "A unique identifier for the session")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &JoinSessionRequest::m_playerId,
|
||||
"PlayerId", "A unique identifier for a player. Player IDs are developer-defined")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &JoinSessionRequest::m_playerData,
|
||||
"PlayerData", "Developer-defined information related to a player")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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/ReflectContext.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct SessionConfig;
|
||||
|
||||
//! CreateSessionRequest
|
||||
//! The container for CreateSession request parameters.
|
||||
struct CreateSessionRequest
|
||||
{
|
||||
AZ_RTTI(CreateSessionRequest, "{E39C2A45-89C9-4CFB-B337-9734DC798930}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
CreateSessionRequest() = default;
|
||||
virtual ~CreateSessionRequest() = default;
|
||||
|
||||
// A unique identifier for a player or entity creating the session.
|
||||
AZStd::string m_creatorId;
|
||||
|
||||
// A collection of custom properties for a session.
|
||||
AZStd::unordered_map<AZStd::string, AZStd::string> m_sessionProperties;
|
||||
|
||||
// A descriptive label that is associated with a session.
|
||||
AZStd::string m_sessionName;
|
||||
|
||||
// The maximum number of players that can be connected simultaneously to the session.
|
||||
uint64_t m_maxPlayer;
|
||||
};
|
||||
|
||||
//! SearchSessionsRequest
|
||||
//! The container for SearchSessions request parameters.
|
||||
struct SearchSessionsRequest
|
||||
{
|
||||
AZ_RTTI(SearchSessionsRequest, "{B49207A8-8549-4ADB-B7D9-D7A4932F9B4B}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
SearchSessionsRequest() = default;
|
||||
virtual ~SearchSessionsRequest() = default;
|
||||
|
||||
// String containing the search criteria for the session search. If no filter expression is included, the request returns results
|
||||
// for all active sessions.
|
||||
AZStd::string m_filterExpression;
|
||||
|
||||
// Instructions on how to sort the search results. If no sort expression is included, the request returns results in random order.
|
||||
AZStd::string m_sortExpression;
|
||||
|
||||
// The maximum number of results to return.
|
||||
uint8_t m_maxResult;
|
||||
|
||||
// A token that indicates the start of the next sequential page of results.
|
||||
AZStd::string m_nextToken;
|
||||
};
|
||||
|
||||
//! SearchSessionsResponse
|
||||
//! The container for SearchSession request results.
|
||||
struct SearchSessionsResponse
|
||||
{
|
||||
AZ_RTTI(SearchSessionsResponse, "{F93DE7DC-D381-4E08-8A3B-0B08F7C38714}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
SearchSessionsResponse() = default;
|
||||
virtual ~SearchSessionsResponse() = default;
|
||||
|
||||
// A collection of sessions that match the search criteria and sorted in specific order.
|
||||
AZStd::vector<SessionConfig> m_sessionConfigs;
|
||||
|
||||
// A token that indicates the start of the next sequential page of results.
|
||||
AZStd::string m_nextToken;
|
||||
};
|
||||
|
||||
//! JoinSessionRequest
|
||||
//! The container for JoinSession request parameters.
|
||||
struct JoinSessionRequest
|
||||
{
|
||||
AZ_RTTI(JoinSessionRequest, "{519769E8-3CDE-4385-A0D7-24DBB3685657}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
JoinSessionRequest() = default;
|
||||
virtual ~JoinSessionRequest() = default;
|
||||
|
||||
// A unique identifier for the session.
|
||||
AZStd::string m_sessionId;
|
||||
|
||||
// A unique identifier for a player. Player IDs are developer-defined.
|
||||
AZStd::string m_playerId;
|
||||
|
||||
// Developer-defined information related to a player.
|
||||
AZStd::string m_playerData;
|
||||
};
|
||||
|
||||
//! ISessionRequests
|
||||
//! Pure virtual session interface class to abstract the details of session handling from application code.
|
||||
class ISessionRequests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ISessionRequests, "{D6C41A71-DD8D-47FE-8515-FAF90670AE2F}");
|
||||
|
||||
ISessionRequests() = default;
|
||||
virtual ~ISessionRequests() = default;
|
||||
|
||||
// Create a session for players to find and join.
|
||||
// @param createSessionRequest The request of CreateSession operation
|
||||
// @return The request id if session creation request succeeds; empty if it fails
|
||||
virtual AZStd::string CreateSession(const CreateSessionRequest& createSessionRequest) = 0;
|
||||
|
||||
// Retrieve all active sessions that match the given search criteria and sorted in specific order.
|
||||
// @param searchSessionsRequest The request of SearchSessions operation
|
||||
// @return The response of SearchSessions operation
|
||||
virtual SearchSessionsResponse SearchSessions(const SearchSessionsRequest& searchSessionsRequest) const = 0;
|
||||
|
||||
// Reserve an open player slot in a session, and perform connection from client to server.
|
||||
// @param joinSessionRequest The request of JoinSession operation
|
||||
// @return True if joining session succeeds; False otherwise
|
||||
virtual bool JoinSession(const JoinSessionRequest& joinSessionRequest) = 0;
|
||||
|
||||
// Disconnect player from session.
|
||||
virtual void LeaveSession() = 0;
|
||||
};
|
||||
|
||||
//! ISessionAsyncRequests
|
||||
//! Async version of ISessionRequests
|
||||
class ISessionAsyncRequests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ISessionAsyncRequests, "{471542AF-96B9-4930-82FE-242A4E68432D}");
|
||||
|
||||
ISessionAsyncRequests() = default;
|
||||
virtual ~ISessionAsyncRequests() = default;
|
||||
|
||||
// CreateSession Async
|
||||
// @param createSessionRequest The request of CreateSession operation
|
||||
virtual void CreateSessionAsync(const CreateSessionRequest& createSessionRequest) = 0;
|
||||
|
||||
// SearchSessions Async
|
||||
// @param searchSessionsRequest The request of SearchSessions operation
|
||||
virtual void SearchSessionsAsync(const SearchSessionsRequest& searchSessionsRequest) const = 0;
|
||||
|
||||
// JoinSession Async
|
||||
// @param joinSessionRequest The request of JoinSession operation
|
||||
virtual void JoinSessionAsync(const JoinSessionRequest& joinSessionRequest) = 0;
|
||||
|
||||
// LeaveSession Async
|
||||
virtual void LeaveSessionAsync() = 0;
|
||||
};
|
||||
|
||||
//! SessionAsyncRequestNotifications
|
||||
//! The notifications correspond to session async requests
|
||||
class SessionAsyncRequestNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// OnCreateSessionAsyncComplete is fired once CreateSessionAsync completes
|
||||
// @param createSessionResponse The request id if session creation request succeeds; empty if it fails
|
||||
virtual void OnCreateSessionAsyncComplete(const AZStd::string& createSessionReponse) = 0;
|
||||
|
||||
// OnSearchSessionsAsyncComplete is fired once SearchSessionsAsync completes
|
||||
// @param searchSessionsResponse The response of SearchSessions call
|
||||
virtual void OnSearchSessionsAsyncComplete(const SearchSessionsResponse& searchSessionsResponse) = 0;
|
||||
|
||||
// OnJoinSessionAsyncComplete is fired once JoinSessionAsync completes
|
||||
// @param joinSessionsResponse True if joining session succeeds; False otherwise
|
||||
virtual void OnJoinSessionAsyncComplete(bool joinSessionsResponse) = 0;
|
||||
|
||||
// OnLeaveSessionAsyncComplete is fired once LeaveSessionAsync completes
|
||||
virtual void OnLeaveSessionAsyncComplete() = 0;
|
||||
};
|
||||
using SessionAsyncRequestNotificationBus = AZ::EBus<SessionAsyncRequestNotifications>;
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void SessionConfig::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<SessionConfig>()
|
||||
->Version(0)
|
||||
->Field("creationTime", &SessionConfig::m_creationTime)
|
||||
->Field("terminationTime", &SessionConfig::m_terminationTime)
|
||||
->Field("creatorId", &SessionConfig::m_creatorId)
|
||||
->Field("sessionProperties", &SessionConfig::m_sessionProperties)
|
||||
->Field("sessionId", &SessionConfig::m_sessionId)
|
||||
->Field("sessionName", &SessionConfig::m_sessionName)
|
||||
->Field("dnsName", &SessionConfig::m_dnsName)
|
||||
->Field("ipAddress", &SessionConfig::m_ipAddress)
|
||||
->Field("port", &SessionConfig::m_port)
|
||||
->Field("maxPlayer", &SessionConfig::m_maxPlayer)
|
||||
->Field("currentPlayer", &SessionConfig::m_currentPlayer)
|
||||
->Field("status", &SessionConfig::m_status)
|
||||
->Field("statusReason", &SessionConfig::m_statusReason)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<SessionConfig>("SessionConfig", "Properties describing a session")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_creationTime,
|
||||
"CreationTime", "A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_terminationTime,
|
||||
"TerminationTime", "A time stamp indicating when this data object was terminated. Same format as creation time.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_creatorId,
|
||||
"CreatorId", "A unique identifier for a player or entity creating the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionProperties,
|
||||
"SessionProperties", "A collection of custom properties for a session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionId,
|
||||
"SessionId", "A unique identifier for the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionName,
|
||||
"SessionName", "A descriptive label that is associated with a session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_dnsName,
|
||||
"DnsName", "The DNS identifier assigned to the instance that is running the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_ipAddress,
|
||||
"IpAddress", "The IP address of the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_port,
|
||||
"Port", "The port number for the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_maxPlayer,
|
||||
"MaxPlayer", "The maximum number of players that can be connected simultaneously to the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_currentPlayer,
|
||||
"CurrentPlayer", "Number of players currently in the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_status,
|
||||
"Status", "Current status of the session.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_statusReason,
|
||||
"StatusReason", "Provides additional information about session status.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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/RTTI/ReflectContext.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
//! SessionConfig
|
||||
//! Properties describing a session.
|
||||
struct SessionConfig
|
||||
{
|
||||
AZ_RTTI(SessionConfig, "{992DD4BE-8BA5-4071-8818-B99FD2952086}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
SessionConfig() = default;
|
||||
virtual ~SessionConfig() = default;
|
||||
|
||||
// A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds.
|
||||
uint64_t m_creationTime;
|
||||
|
||||
// A time stamp indicating when this data object was terminated. Same format as creation time.
|
||||
uint64_t m_terminationTime;
|
||||
|
||||
// A unique identifier for a player or entity creating the session.
|
||||
AZStd::string m_creatorId;
|
||||
|
||||
// A collection of custom properties for a session.
|
||||
AZStd::unordered_map<AZStd::string, AZStd::string> m_sessionProperties;
|
||||
|
||||
// A unique identifier for the session.
|
||||
AZStd::string m_sessionId;
|
||||
|
||||
// A descriptive label that is associated with a session.
|
||||
AZStd::string m_sessionName;
|
||||
|
||||
// The DNS identifier assigned to the instance that is running the session.
|
||||
AZStd::string m_dnsName;
|
||||
|
||||
// The IP address of the session.
|
||||
AZStd::string m_ipAddress;
|
||||
|
||||
// The port number for the session.
|
||||
uint16_t m_port;
|
||||
|
||||
// The maximum number of players that can be connected simultaneously to the session.
|
||||
uint64_t m_maxPlayer;
|
||||
|
||||
// Number of players currently in the session.
|
||||
uint64_t m_currentPlayer;
|
||||
|
||||
// Current status of the session.
|
||||
AZStd::string m_status;
|
||||
|
||||
// Provides additional information about session status.
|
||||
AZStd::string m_statusReason;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct SessionConfig;
|
||||
|
||||
//! SessionNotifications
|
||||
//! The session notifications to listen for performing required operations
|
||||
class SessionNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// OnSessionHealthCheck is fired in health check process
|
||||
// @return The result of all OnSessionHealthCheck
|
||||
virtual bool OnSessionHealthCheck() = 0;
|
||||
|
||||
// OnCreateSessionBegin is fired at the beginning of session creation
|
||||
// @param sessionConfig The properties to describe a session
|
||||
// @return The result of all OnCreateSessionBegin notifications
|
||||
virtual bool OnCreateSessionBegin(const SessionConfig& sessionConfig) = 0;
|
||||
|
||||
// OnDestroySessionBegin is fired at the beginning of session termination
|
||||
// @return The result of all OnDestroySessionBegin notifications
|
||||
virtual bool OnDestroySessionBegin() = 0;
|
||||
};
|
||||
using SessionNotificationBus = AZ::EBus<SessionNotifications>;
|
||||
} // namespace AzFramework
|
||||
@@ -84,6 +84,7 @@ namespace AzFramework
|
||||
};
|
||||
|
||||
using EntitySpawnCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableConstEntityContainerView)>;
|
||||
using EntityPreInsertionCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableEntityContainerView)>;
|
||||
using EntityDespawnCallback = AZStd::function<void(EntitySpawnTicket&)>;
|
||||
using ReloadSpawnableCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableConstEntityContainerView)>;
|
||||
using ListEntitiesCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableConstEntityContainerView)>;
|
||||
@@ -110,7 +111,8 @@ namespace AzFramework
|
||||
//! @param completionCallback Optional callback that's called when spawning entities has completed. This can be called from
|
||||
//! a different thread than the one that made the function call. The returned list of entities contains all the newly
|
||||
//! created entities.
|
||||
virtual void SpawnAllEntities(EntitySpawnTicket& ticket, EntitySpawnCallback completionCallback = {}) = 0;
|
||||
virtual void SpawnAllEntities(EntitySpawnTicket& ticket, EntityPreInsertionCallback preInsertionCallback = {},
|
||||
EntitySpawnCallback completionCallback = {}) = 0;
|
||||
//! Spawn instances of some entities in the spawnable.
|
||||
//! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them.
|
||||
//! @param entityIndices The indices into the template entities stored in the spawnable that will be used to spawn entities from.
|
||||
@@ -118,7 +120,7 @@ namespace AzFramework
|
||||
//! a different thread than the one that made this function call. The returned list of entities contains all the newly
|
||||
//! created entities.
|
||||
virtual void SpawnEntities(EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices,
|
||||
EntitySpawnCallback completionCallback = {}) = 0;
|
||||
EntityPreInsertionCallback preInsertionCallback = {}, EntitySpawnCallback completionCallback = {}) = 0;
|
||||
//! Removes all entities in the provided list from the environment.
|
||||
//! @param ticket The ticket previously used to spawn entities with.
|
||||
//! @param completionCallback Optional callback that's called when despawning entities has completed. This can be called from
|
||||
|
||||
@@ -11,20 +11,24 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Serialization/IdUtils.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesManager.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void SpawnableEntitiesManager::SpawnAllEntities(EntitySpawnTicket& ticket, EntitySpawnCallback completionCallback)
|
||||
void SpawnableEntitiesManager::SpawnAllEntities(EntitySpawnTicket& ticket, EntityPreInsertionCallback preInsertionCallback,
|
||||
EntitySpawnCallback completionCallback)
|
||||
{
|
||||
SpawnAllEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
queueEntry.m_completionCallback = AZStd::move(completionCallback);
|
||||
queueEntry.m_preInsertionCallback = AZStd::move(preInsertionCallback);
|
||||
{
|
||||
AZStd::scoped_lock queueLock(m_pendingRequestQueueMutex);
|
||||
queueEntry.m_ticketId = GetTicketPayload<Ticket>(ticket).m_nextTicketId++;
|
||||
@@ -32,13 +36,15 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::SpawnEntities(EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices,
|
||||
EntitySpawnCallback completionCallback)
|
||||
void SpawnableEntitiesManager::SpawnEntities(
|
||||
EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices,
|
||||
EntityPreInsertionCallback preInsertionCallback, EntitySpawnCallback completionCallback)
|
||||
{
|
||||
SpawnEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
queueEntry.m_entityIndices = AZStd::move(entityIndices);
|
||||
queueEntry.m_completionCallback = AZStd::move(completionCallback);
|
||||
queueEntry.m_preInsertionCallback = AZStd::move(preInsertionCallback);
|
||||
{
|
||||
AZStd::scoped_lock queueLock(m_pendingRequestQueueMutex);
|
||||
queueEntry.m_ticketId = GetTicketPayload<Ticket>(ticket).m_nextTicketId++;
|
||||
@@ -205,32 +211,85 @@ namespace AzFramework
|
||||
AZ::Entity* clone = serializeContext.CloneObject(&entityTemplate);
|
||||
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
|
||||
clone->SetId(AZ::Entity::MakeId());
|
||||
|
||||
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
AZ::Entity* SpawnableEntitiesManager::CloneSingleEntity(const AZ::Entity& entityTemplate,
|
||||
EntityIdMap& templateToCloneEntityIdMap, AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
return AZ::IdUtils::Remapper<AZ::EntityId>::CloneObjectAndGenerateNewIdsAndFixRefs(
|
||||
&entityTemplate, templateToCloneEntityIdMap, &serializeContext);
|
||||
}
|
||||
|
||||
bool SpawnableEntitiesManager::ProcessRequest(SpawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
Ticket& ticket = GetTicketPayload<Ticket>(*request.m_ticket);
|
||||
if (ticket.m_spawnable.IsReady() && request.m_ticketId == ticket.m_currentTicketId)
|
||||
{
|
||||
size_t spawnedEntitiesCount = ticket.m_spawnedEntities.size();
|
||||
AZStd::vector<AZ::Entity*>& spawnedEntities = ticket.m_spawnedEntities;
|
||||
AZStd::vector<size_t>& spawnedEntityIndices = ticket.m_spawnedEntityIndices;
|
||||
|
||||
const Spawnable::EntityList& entities = ticket.m_spawnable->GetEntities();
|
||||
size_t entitiesSize = entities.size();
|
||||
ticket.m_spawnedEntities.reserve(ticket.m_spawnedEntities.size() + entitiesSize);
|
||||
ticket.m_spawnedEntityIndices.reserve(ticket.m_spawnedEntityIndices.size() + entitiesSize);
|
||||
// Keep track how many entities there were in the array initially
|
||||
size_t spawnedEntitiesInitialCount = spawnedEntities.size();
|
||||
|
||||
for(size_t i=0; i<entitiesSize; ++i)
|
||||
// These are 'template' entities we'll be cloning from
|
||||
const Spawnable::EntityList& entitiesToSpawn = ticket.m_spawnable->GetEntities();
|
||||
size_t entitiesToSpawnSize = entitiesToSpawn.size();
|
||||
|
||||
// Map keeps track of ids from template (spawnable) to clone (instance)
|
||||
// Allowing patch ups of fields referring to entityIds outside of a given entity
|
||||
EntityIdMap templateToCloneEntityIdMap;
|
||||
|
||||
// Reserve buffers
|
||||
spawnedEntities.reserve(spawnedEntities.size() + entitiesToSpawnSize);
|
||||
spawnedEntityIndices.reserve(spawnedEntityIndices.size() + entitiesToSpawnSize);
|
||||
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
|
||||
|
||||
// Mark all indices as spawned
|
||||
for (size_t i = 0; i < entitiesToSpawnSize; ++i)
|
||||
{
|
||||
ticket.m_spawnedEntities.push_back(SpawnSingleEntity(*entities[i], serializeContext));
|
||||
ticket.m_spawnedEntityIndices.push_back(i);
|
||||
const AZ::Entity& entityTemplate = *entitiesToSpawn[i];
|
||||
|
||||
AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, serializeContext);
|
||||
|
||||
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
|
||||
|
||||
spawnedEntities.emplace_back(clone);
|
||||
spawnedEntityIndices.push_back(i);
|
||||
}
|
||||
|
||||
// loadAll is true if every entity has been spawned only once
|
||||
if (spawnedEntities.size() == entitiesToSpawnSize)
|
||||
{
|
||||
ticket.m_loadAll = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case where there were already spawns from a previous request
|
||||
ticket.m_loadAll = false;
|
||||
}
|
||||
|
||||
// Let other systems know about newly spawned entities for any pre-processing before adding to the scene/game context.
|
||||
if (request.m_preInsertionCallback)
|
||||
{
|
||||
request.m_preInsertionCallback(*request.m_ticket, SpawnableEntityContainerView(
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end()));
|
||||
}
|
||||
|
||||
// Add to the game context, now the entities are active
|
||||
AZStd::for_each(ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end(),
|
||||
[](AZ::Entity* entity)
|
||||
{
|
||||
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, entity);
|
||||
});
|
||||
|
||||
// Let other systems know about newly spawned entities for any post-processing after adding to the scene/game context.
|
||||
if (request.m_completionCallback)
|
||||
{
|
||||
request.m_completionCallback(*request.m_ticket, SpawnableConstEntityContainerView(
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesCount, ticket.m_spawnedEntities.end()));
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end()));
|
||||
}
|
||||
|
||||
m_onSpawnedEvent.Signal(ticket.m_spawnable);
|
||||
@@ -249,24 +308,56 @@ namespace AzFramework
|
||||
Ticket& ticket = GetTicketPayload<Ticket>(*request.m_ticket);
|
||||
if (ticket.m_spawnable.IsReady() && request.m_ticketId == ticket.m_currentTicketId)
|
||||
{
|
||||
size_t spawnedEntitiesCount = ticket.m_spawnedEntities.size();
|
||||
AZStd::vector<AZ::Entity*>& spawnedEntities = ticket.m_spawnedEntities;
|
||||
AZStd::vector<size_t>& spawnedEntityIndices = ticket.m_spawnedEntityIndices;
|
||||
|
||||
const Spawnable::EntityList& entities = ticket.m_spawnable->GetEntities();
|
||||
size_t entitiesSize = entities.size();
|
||||
ticket.m_spawnedEntities.reserve(ticket.m_spawnedEntities.size() + entitiesSize);
|
||||
ticket.m_spawnedEntityIndices.reserve(ticket.m_spawnedEntityIndices.size() + entitiesSize);
|
||||
// Keep track how many entities there were in the array initially
|
||||
size_t spawnedEntitiesInitialCount = spawnedEntities.size();
|
||||
|
||||
// These are 'template' entities we'll be cloning from
|
||||
const Spawnable::EntityList& entitiesToSpawn = ticket.m_spawnable->GetEntities();
|
||||
size_t entitiesToSpawnSize = request.m_entityIndices.size();
|
||||
|
||||
spawnedEntities.reserve(spawnedEntities.size() + entitiesToSpawnSize);
|
||||
spawnedEntityIndices.reserve(spawnedEntityIndices.size() + entitiesToSpawnSize);
|
||||
|
||||
for (size_t index : request.m_entityIndices)
|
||||
{
|
||||
ticket.m_spawnedEntities.push_back(SpawnSingleEntity(*entities[index], serializeContext));
|
||||
ticket.m_spawnedEntityIndices.push_back(index);
|
||||
if (index < entitiesToSpawn.size())
|
||||
{
|
||||
const AZ::Entity& entityTemplate = *entitiesToSpawn[index];
|
||||
|
||||
AZ::Entity* clone = serializeContext.CloneObject(&entityTemplate);
|
||||
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
|
||||
clone->SetId(AZ::Entity::MakeId());
|
||||
|
||||
spawnedEntities.push_back(clone);
|
||||
spawnedEntityIndices.push_back(index);
|
||||
|
||||
}
|
||||
}
|
||||
ticket.m_loadAll = false;
|
||||
|
||||
// Let other systems know about newly spawned entities for any pre-processing before adding to the scene/game context.
|
||||
if (request.m_preInsertionCallback)
|
||||
{
|
||||
request.m_preInsertionCallback(
|
||||
*request.m_ticket,
|
||||
SpawnableEntityContainerView(
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end()));
|
||||
}
|
||||
|
||||
// Add to the game context, now the entities are active
|
||||
AZStd::for_each(ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end(),
|
||||
[](AZ::Entity* entity)
|
||||
{
|
||||
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, entity);
|
||||
});
|
||||
|
||||
if (request.m_completionCallback)
|
||||
{
|
||||
request.m_completionCallback(*request.m_ticket, SpawnableConstEntityContainerView(
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesCount, ticket.m_spawnedEntities.end()));
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end()));
|
||||
}
|
||||
|
||||
m_onSpawnedEvent.Signal(ticket.m_spawnable);
|
||||
@@ -343,10 +434,23 @@ namespace AzFramework
|
||||
// to load every, simply start over.
|
||||
ticket.m_spawnedEntityIndices.clear();
|
||||
|
||||
size_t entitiesSize = entities.size();
|
||||
for (size_t i = 0; i < entitiesSize; ++i)
|
||||
size_t entitiesToSpawnSize = entities.size();
|
||||
|
||||
// Map keeps track of ids from template (spawnable) to clone (instance)
|
||||
// Allowing patch ups of fields referring to entityIds outside of a given entity
|
||||
EntityIdMap templateToCloneEntityIdMap;
|
||||
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
|
||||
|
||||
// Mark all indices as spawned
|
||||
for (size_t i = 0; i < entitiesToSpawnSize; ++i)
|
||||
{
|
||||
ticket.m_spawnedEntities.push_back(SpawnSingleEntity(*entities[i], serializeContext));
|
||||
const AZ::Entity& entityTemplate = *entities[i];
|
||||
|
||||
AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, serializeContext);
|
||||
|
||||
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
|
||||
|
||||
ticket.m_spawnedEntities.emplace_back(clone);
|
||||
ticket.m_spawnedEntityIndices.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace AZ
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
using EntityIdMap = AZStd::unordered_map<AZ::EntityId, AZ::EntityId>;
|
||||
|
||||
class SpawnableEntitiesManager
|
||||
: public SpawnableEntitiesInterface::Registrar
|
||||
{
|
||||
@@ -47,8 +49,8 @@ namespace AzFramework
|
||||
// The following functions are thread safe
|
||||
//
|
||||
|
||||
void SpawnAllEntities(EntitySpawnTicket& ticket, EntitySpawnCallback completionCallback = {}) override;
|
||||
void SpawnEntities(EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices,
|
||||
void SpawnAllEntities(EntitySpawnTicket& ticket, EntityPreInsertionCallback preInsertionCallback = {}, EntitySpawnCallback completionCallback = {}) override;
|
||||
void SpawnEntities(EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices, EntityPreInsertionCallback preInsertionCallback = {},
|
||||
EntitySpawnCallback completionCallback = {}) override;
|
||||
void DespawnAllEntities(EntitySpawnTicket& ticket, EntityDespawnCallback completionCallback = {}) override;
|
||||
|
||||
@@ -90,6 +92,7 @@ namespace AzFramework
|
||||
struct SpawnAllEntitiesCommand
|
||||
{
|
||||
EntitySpawnCallback m_completionCallback;
|
||||
EntityPreInsertionCallback m_preInsertionCallback;
|
||||
EntitySpawnTicket* m_ticket;
|
||||
uint32_t m_ticketId;
|
||||
};
|
||||
@@ -97,6 +100,7 @@ namespace AzFramework
|
||||
{
|
||||
AZStd::vector<size_t> m_entityIndices;
|
||||
EntitySpawnCallback m_completionCallback;
|
||||
EntityPreInsertionCallback m_preInsertionCallback;
|
||||
EntitySpawnTicket* m_ticket;
|
||||
uint32_t m_ticketId;
|
||||
};
|
||||
@@ -140,7 +144,11 @@ namespace AzFramework
|
||||
using Requests = AZStd::variant<SpawnAllEntitiesCommand, SpawnEntitiesCommand, DespawnAllEntitiesCommand, ReloadSpawnableCommand,
|
||||
ListEntitiesCommand, ClaimEntitiesCommand, BarrierCommand, DestroyTicketCommand>;
|
||||
|
||||
AZ::Entity* SpawnSingleEntity(const AZ::Entity& entityTemplate, AZ::SerializeContext& serializeContext);
|
||||
AZ::Entity* SpawnSingleEntity(const AZ::Entity& entityTemplate,
|
||||
AZ::SerializeContext& serializeContext);
|
||||
|
||||
AZ::Entity* CloneSingleEntity(const AZ::Entity& entityTemplate,
|
||||
EntityIdMap& templateToCloneEntityIdMap, AZ::SerializeContext& serializeContext);
|
||||
|
||||
bool ProcessRequest(SpawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext);
|
||||
bool ProcessRequest(SpawnEntitiesCommand& request, AZ::SerializeContext& serializeContext);
|
||||
|
||||
@@ -193,13 +193,12 @@ namespace AzFramework
|
||||
bool handling = false;
|
||||
for (auto& cameraInput : m_activeCameraInputs)
|
||||
{
|
||||
cameraInput->HandleEvents(event, cursorDelta, scrollDelta);
|
||||
handling = !cameraInput->Idle() || handling;
|
||||
handling = cameraInput->HandleEvents(event, cursorDelta, scrollDelta) || handling;
|
||||
}
|
||||
|
||||
for (auto& cameraInput : m_idleCameraInputs)
|
||||
{
|
||||
cameraInput->HandleEvents(event, cursorDelta, scrollDelta);
|
||||
handling = cameraInput->HandleEvents(event, cursorDelta, scrollDelta) || handling;
|
||||
}
|
||||
|
||||
return handling;
|
||||
@@ -262,17 +261,26 @@ namespace AzFramework
|
||||
{
|
||||
m_activeCameraInputs[i]->Reset();
|
||||
m_idleCameraInputs.push_back(m_activeCameraInputs[i]);
|
||||
m_activeCameraInputs[i] = m_activeCameraInputs[m_activeCameraInputs.size() - 1];
|
||||
using AZStd::swap;
|
||||
swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
|
||||
m_activeCameraInputs.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void Cameras::Clear()
|
||||
{
|
||||
Reset();
|
||||
AZ_Assert(m_activeCameraInputs.empty(), "Active Camera Inputs is not empty");
|
||||
|
||||
m_idleCameraInputs.clear();
|
||||
}
|
||||
|
||||
RotateCameraInput::RotateCameraInput(const InputChannelId rotateChannelId)
|
||||
: m_rotateChannelId(rotateChannelId)
|
||||
{
|
||||
}
|
||||
|
||||
void RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
bool RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
const ClickDetector::ClickEvent clickEvent = [&event, this] {
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
@@ -304,6 +312,11 @@ namespace AzFramework
|
||||
// noop
|
||||
break;
|
||||
}
|
||||
|
||||
// note - must also check !ending to ensure the mouse up (release) event
|
||||
// is not consumed and can be propagated to other systems.
|
||||
// (don't swallow mouse up events)
|
||||
return !Idle() && !Ending();
|
||||
}
|
||||
|
||||
Camera RotateCameraInput::StepCamera(
|
||||
@@ -330,7 +343,7 @@ namespace AzFramework
|
||||
{
|
||||
}
|
||||
|
||||
void PanCameraInput::HandleEvents(
|
||||
bool PanCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
@@ -347,6 +360,8 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !Idle();
|
||||
}
|
||||
|
||||
Camera PanCameraInput::StepCamera(
|
||||
@@ -411,7 +426,7 @@ namespace AzFramework
|
||||
{
|
||||
}
|
||||
|
||||
void TranslateCameraInput::HandleEvents(
|
||||
bool TranslateCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
@@ -429,7 +444,8 @@ namespace AzFramework
|
||||
m_boost = true;
|
||||
}
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
// ensure we don't process end events in the idle state
|
||||
else if (input->m_state == InputChannel::State::Ended && !Idle())
|
||||
{
|
||||
m_translation &= ~(translationFromKey(input->m_channelId));
|
||||
if (m_translation == TranslationType::Nil)
|
||||
@@ -442,6 +458,8 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !Idle();
|
||||
}
|
||||
|
||||
Camera TranslateCameraInput::StepCamera(
|
||||
@@ -503,7 +521,7 @@ namespace AzFramework
|
||||
m_boost = false;
|
||||
}
|
||||
|
||||
void OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta)
|
||||
bool OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta)
|
||||
{
|
||||
if (const auto* input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
@@ -522,8 +540,10 @@ namespace AzFramework
|
||||
|
||||
if (Active())
|
||||
{
|
||||
m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta);
|
||||
return m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta);
|
||||
}
|
||||
|
||||
return !Idle();
|
||||
}
|
||||
|
||||
Camera OrbitCameraInput::StepCamera(
|
||||
@@ -533,7 +553,7 @@ namespace AzFramework
|
||||
|
||||
if (Beginning())
|
||||
{
|
||||
const auto hasLookAt = [&nextCamera, &targetCamera, lookAtFn = m_lookAtFn] {
|
||||
const auto hasLookAt = [&nextCamera, &targetCamera, &lookAtFn = m_lookAtFn] {
|
||||
if (lookAtFn)
|
||||
{
|
||||
if (const auto lookAt = lookAtFn())
|
||||
@@ -585,13 +605,15 @@ namespace AzFramework
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void OrbitDollyScrollCameraInput::HandleEvents(
|
||||
bool OrbitDollyScrollCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
|
||||
return !Idle();
|
||||
}
|
||||
|
||||
Camera OrbitDollyScrollCameraInput::StepCamera(
|
||||
@@ -609,7 +631,7 @@ namespace AzFramework
|
||||
{
|
||||
}
|
||||
|
||||
void OrbitDollyCursorMoveCameraInput::HandleEvents(
|
||||
bool OrbitDollyCursorMoveCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
@@ -626,6 +648,8 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !Idle();
|
||||
}
|
||||
|
||||
Camera OrbitDollyCursorMoveCameraInput::StepCamera(
|
||||
@@ -637,13 +661,15 @@ namespace AzFramework
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void ScrollTranslationCameraInput::HandleEvents(
|
||||
bool ScrollTranslationCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
|
||||
return !Idle();
|
||||
}
|
||||
|
||||
Camera ScrollTranslationCameraInput::StepCamera(
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace AzFramework
|
||||
ResetImpl();
|
||||
}
|
||||
|
||||
virtual void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) = 0;
|
||||
virtual bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) = 0;
|
||||
virtual Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) = 0;
|
||||
|
||||
virtual bool Exclusive() const
|
||||
@@ -171,16 +171,29 @@ namespace AzFramework
|
||||
class Cameras
|
||||
{
|
||||
public:
|
||||
void AddCamera(AZStd::shared_ptr<CameraInput> cameraInput);
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta);
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime);
|
||||
|
||||
void AddCamera(AZStd::shared_ptr<CameraInput> cameraInput);
|
||||
//! Reset the state of all cameras.
|
||||
void Reset();
|
||||
//! Remove all cameras that were added.
|
||||
void Clear();
|
||||
//! Is one of the cameras in the active camera inputs marked as 'exclusive'.
|
||||
//! @note This implies no other sibling cameras can begin while the exclusive camera is running.
|
||||
bool Exclusive() const;
|
||||
|
||||
private:
|
||||
AZStd::vector<AZStd::shared_ptr<CameraInput>> m_activeCameraInputs;
|
||||
AZStd::vector<AZStd::shared_ptr<CameraInput>> m_idleCameraInputs;
|
||||
};
|
||||
|
||||
inline bool Cameras::Exclusive() const
|
||||
{
|
||||
return AZStd::any_of(
|
||||
m_activeCameraInputs.begin(), m_activeCameraInputs.end(), [](const auto& cameraInput) { return cameraInput->Exclusive(); });
|
||||
}
|
||||
|
||||
class CameraSystem
|
||||
{
|
||||
public:
|
||||
@@ -200,7 +213,7 @@ namespace AzFramework
|
||||
explicit RotateCameraInput(InputChannelId rotateChannelId);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
private:
|
||||
@@ -241,7 +254,7 @@ namespace AzFramework
|
||||
PanCameraInput(InputChannelId panChannelId, PanAxesFn panAxesFn);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
private:
|
||||
@@ -282,7 +295,7 @@ namespace AzFramework
|
||||
explicit TranslateCameraInput(TranslationAxesFn translationAxesFn);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
void ResetImpl() override;
|
||||
|
||||
@@ -352,7 +365,7 @@ namespace AzFramework
|
||||
{
|
||||
public:
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
};
|
||||
|
||||
@@ -362,7 +375,7 @@ namespace AzFramework
|
||||
explicit OrbitDollyCursorMoveCameraInput(InputChannelId dollyChannelId);
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
private:
|
||||
@@ -373,7 +386,7 @@ namespace AzFramework
|
||||
{
|
||||
public:
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
};
|
||||
|
||||
@@ -383,7 +396,7 @@ namespace AzFramework
|
||||
using LookAtFn = AZStd::function<AZStd::optional<AZ::Vector3>()>;
|
||||
|
||||
// CameraInput overrides ...
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
bool Exclusive() const override;
|
||||
|
||||
|
||||
@@ -17,6 +17,17 @@ namespace AzFramework
|
||||
{
|
||||
ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta)
|
||||
{
|
||||
const auto previousDetectionState = m_detectionState;
|
||||
if (previousDetectionState == DetectionState::WaitingForMove)
|
||||
{
|
||||
// only allow the action to begin if the mouse has been moved a small amount
|
||||
m_moveAccumulator += ScreenVectorLength(cursorDelta);
|
||||
if (m_moveAccumulator > m_deadZone)
|
||||
{
|
||||
m_detectionState = DetectionState::Moved;
|
||||
}
|
||||
}
|
||||
|
||||
if (clickEvent == ClickEvent::Down)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
@@ -52,15 +63,9 @@ namespace AzFramework
|
||||
return clickOutcome;
|
||||
}
|
||||
|
||||
if (m_detectionState == DetectionState::WaitingForMove)
|
||||
if (previousDetectionState == DetectionState::WaitingForMove && m_detectionState == DetectionState::Moved)
|
||||
{
|
||||
// only allow the action to begin if the mouse has been moved a small amount
|
||||
m_moveAccumulator += ScreenVectorLength(cursorDelta);
|
||||
if (m_moveAccumulator > m_deadZone)
|
||||
{
|
||||
m_detectionState = DetectionState::Moved;
|
||||
return ClickOutcome::Move;
|
||||
}
|
||||
return ClickOutcome::Move;
|
||||
}
|
||||
|
||||
return ClickOutcome::Nil;
|
||||
|
||||
@@ -50,7 +50,11 @@ namespace AzFramework
|
||||
//! Called from any type of 'handle event' function.
|
||||
ClickOutcome DetectClick(ClickEvent clickEvent, const ScreenVector& cursorDelta);
|
||||
|
||||
//! Override the default double click interval.
|
||||
//! @note Default is 400ms - system default.
|
||||
void SetDoubleClickInterval(float doubleClickInterval);
|
||||
//! Override the dead zone before a 'move' outcome will be triggered.
|
||||
void SetDeadZone(float deadZone);
|
||||
|
||||
private:
|
||||
//! Internal state of ClickDetector based on incoming events.
|
||||
@@ -72,4 +76,9 @@ namespace AzFramework
|
||||
{
|
||||
m_doubleClickInterval = doubleClickInterval;
|
||||
}
|
||||
|
||||
inline void ClickDetector::SetDeadZone(const float deadZone)
|
||||
{
|
||||
m_deadZone = deadZone;
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -188,6 +188,12 @@ set(FILES
|
||||
Script/ScriptDebugMsgReflection.h
|
||||
Script/ScriptRemoteDebugging.cpp
|
||||
Script/ScriptRemoteDebugging.h
|
||||
Session/ISessionHandlingRequests.h
|
||||
Session/ISessionRequests.cpp
|
||||
Session/ISessionRequests.h
|
||||
Session/SessionConfig.cpp
|
||||
Session/SessionConfig.h
|
||||
Session/SessionNotifications.h
|
||||
StreamingInstall/StreamingInstall.h
|
||||
StreamingInstall/StreamingInstall.cpp
|
||||
StreamingInstall/StreamingInstallRequests.h
|
||||
|
||||
@@ -116,8 +116,8 @@ namespace AzNetworking
|
||||
|
||||
int32_t TcpSocket::Receive(uint8_t* outData, uint32_t size) const
|
||||
{
|
||||
AZ_Assert(size > 0, "Invalid data size for send");
|
||||
AZ_Assert(outData != nullptr, "NULL data pointer passed to send");
|
||||
AZ_Assert(size > 0, "Invalid data size for receive");
|
||||
AZ_Assert(outData != nullptr, "NULL data pointer passed to receive");
|
||||
if (!IsOpen())
|
||||
{
|
||||
return SocketOpResultErrorNotOpen;
|
||||
@@ -176,7 +176,7 @@ namespace AzNetworking
|
||||
if (::bind(aznumeric_cast<int32_t>(m_socketFd), (const sockaddr*)&hints, sizeof(hints)) != 0)
|
||||
{
|
||||
const int32_t error = GetLastNetworkError();
|
||||
AZLOG_ERROR("Failed to bind socket (%d:%s)", error, GetNetworkErrorDesc(error));
|
||||
AZLOG_ERROR("Failed to bind TCP socket to port %u (%d:%s)", uint32_t(port), error, GetNetworkErrorDesc(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace AzNetworking
|
||||
const UdpReaderThread::ReceivedPackets* packets = m_readerThread.GetReceivedPackets(m_socket.get());
|
||||
if (packets == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "nullptr was retrieved for the received packet buffer, check that the socket has been registered with the reader thread");
|
||||
// Socket is not yet registered with the reader thread and is likely still pending, try again later
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace AzNetworking
|
||||
if (::bind(static_cast<int32_t>(m_socketFd), (const sockaddr *)&hints, sizeof(hints)) != 0)
|
||||
{
|
||||
const int32_t error = GetLastNetworkError();
|
||||
AZLOG_ERROR("Failed to bind socket to port %u (%d:%s)", uint32_t(port), error, GetNetworkErrorDesc(error));
|
||||
AZLOG_ERROR("Failed to bind UDP socket to port %u (%d:%s)", uint32_t(port), error, GetNetworkErrorDesc(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -12,6 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
@@ -46,6 +47,10 @@ namespace AzToolsFramework
|
||||
|
||||
virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;
|
||||
|
||||
//! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
|
||||
//! /return The vector of Assets generated by Prefab processing
|
||||
virtual const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() = 0;
|
||||
|
||||
virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
|
||||
virtual bool SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
|
||||
|
||||
|
||||
+5
@@ -314,6 +314,11 @@ namespace AzToolsFramework
|
||||
return *m_rootInstance;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& PrefabEditorEntityOwnershipService::GetPlayInEditorAssetData()
|
||||
{
|
||||
return m_playInEditorData.m_assets;
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::OnEntityRemoved(AZ::EntityId entityId)
|
||||
{
|
||||
AzFramework::SliceEntityRequestBus::MultiHandler::BusDisconnect(entityId);
|
||||
|
||||
+2
@@ -195,6 +195,8 @@ namespace AzToolsFramework
|
||||
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) override;
|
||||
|
||||
Prefab::InstanceOptionalReference GetRootPrefabInstance() override;
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OnEntityRemoved(AZ::EntityId entityId);
|
||||
|
||||
+6
-2
@@ -134,9 +134,13 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
auto findInstancesResult = m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId)->get();
|
||||
auto findInstancesResult = m_templateInstanceMapperInterface->FindInstancesOwnedByTemplate(instanceTemplateId);
|
||||
AZ_Assert(
|
||||
findInstancesResult.has_value(), "Prefab Instances corresponding to template with id %llu couldn't be found.",
|
||||
instanceTemplateId);
|
||||
|
||||
if (findInstancesResult.find(instanceToUpdate) == findInstancesResult.end())
|
||||
if (findInstancesResult == AZStd::nullopt ||
|
||||
findInstancesResult->get().find(instanceToUpdate) == findInstancesResult->get().end())
|
||||
{
|
||||
// Since nested instances get reconstructed during propagation, remove any nested instance that no longer
|
||||
// maps to a template.
|
||||
|
||||
@@ -182,16 +182,16 @@ namespace AzToolsFramework
|
||||
else
|
||||
{
|
||||
AZ::JsonSerializationResult::ResultCode applyPatchResult = AZ::JsonSerialization::ApplyPatch(
|
||||
linkedInstanceDom,
|
||||
sourceTemplateDomCopy,
|
||||
targetTemplatePrefabDom.GetAllocator(),
|
||||
sourceTemplatePrefabDom,
|
||||
patchesReference->get(),
|
||||
AZ::JsonMergeApproach::JsonPatch);
|
||||
linkedInstanceDom.CopyFrom(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator());
|
||||
if (applyPatchResult.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
|
||||
{
|
||||
AZ_Error("Prefab", false,
|
||||
"Link::UpdateTarget - "
|
||||
"ApplyPatches failed for Prefab DOM from source Template '%u' and target Template '%u'.",
|
||||
AZ_Error(
|
||||
"Prefab", false,
|
||||
"Link::UpdateTarget - ApplyPatches failed for Prefab DOM from source Template '%u' and target Template '%u'.",
|
||||
m_sourceTemplateId, m_targetTemplateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -135,11 +135,14 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
|
||||
|
||||
// Parent the entities to the container entity. Parenting the container entities of the instances passed to createPrefab
|
||||
// will be done during the creation of links below.
|
||||
for (AZ::Entity* topLevelEntity : entities)
|
||||
// Parent the non-container top level entities to the container entity.
|
||||
// Parenting the top level container entities will be done during the creation of links.
|
||||
for (AZ::Entity* topLevelEntity : topLevelEntities)
|
||||
{
|
||||
AZ::TransformBus::Event(topLevelEntity->GetId(), &AZ::TransformBus::Events::SetParent, containerEntityId);
|
||||
if (!IsInstanceContainerEntity(topLevelEntity->GetId()))
|
||||
{
|
||||
AZ::TransformBus::Event(topLevelEntity->GetId(), &AZ::TransformBus::Events::SetParent, containerEntityId);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the template of the instance since the entities are modified since the template creation.
|
||||
@@ -155,11 +158,25 @@ namespace AzToolsFramework
|
||||
AZ_Assert(
|
||||
nestedInstanceContainerEntity, "Invalid container entity found for the nested instance used in prefab creation.");
|
||||
|
||||
AZ::EntityId parentId;
|
||||
AZ::TransformBus::EventResult(
|
||||
parentId, nestedInstanceContainerEntity->get().GetId(), &AZ::TransformBus::Events::GetParentId);
|
||||
|
||||
auto entityIterator = AZStd::find_if(
|
||||
entities.begin(), entities.end(), [parentId](AZ::Entity* entity) { return entity->GetId() == parentId; });
|
||||
|
||||
// If the previous parent entity of the nested instance is not part of the entities of the newly created prefab,
|
||||
// then set the parent of the nested prefab as the container entity of the newly created prefab.
|
||||
if (entityIterator == entities.end())
|
||||
{
|
||||
parentId = containerEntityId;
|
||||
}
|
||||
|
||||
// These link creations shouldn't be undone because that would put the template in a non-usable state if a user
|
||||
// chooses to instantiate the template after undoing the creation.
|
||||
CreateLink(
|
||||
{&nestedInstanceContainerEntity->get()}, *nestedInstance, instanceToCreate->get().GetTemplateId(),
|
||||
undoBatch.GetUndoBatch(), containerEntityId, false);
|
||||
undoBatch.GetUndoBatch(), parentId, false);
|
||||
});
|
||||
|
||||
// Create a link between the templates of the newly created instance and the instance it's being parented under.
|
||||
|
||||
+28
@@ -27,6 +27,7 @@ AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") // 4244: con
|
||||
#include <QtGui/QTextLayout>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QMessageBox>
|
||||
#include <QStylePainter>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
static const int LabelColumnStretch = 2;
|
||||
@@ -121,6 +122,19 @@ namespace AzToolsFramework
|
||||
setLayout(m_mainLayout);
|
||||
}
|
||||
|
||||
void PropertyRowWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
|
||||
if (CanBeReordered())
|
||||
{
|
||||
const QPen linePen(QColor(0x3B3E3F));
|
||||
p.setPen(linePen);
|
||||
int indent = m_treeDepth * m_treeIndentation;
|
||||
p.drawLine(event->rect().topLeft() + QPoint(indent, 0), event->rect().topRight());
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::HasChildWidgetAlready() const
|
||||
{
|
||||
return m_childWidget != nullptr;
|
||||
@@ -1661,6 +1675,20 @@ namespace AzToolsFramework
|
||||
m_nameLabel->setFilter(m_currentFilterString);
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::CanChildrenBeReordered() const
|
||||
{
|
||||
return m_containerEditable;
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::CanBeReordered() const
|
||||
{
|
||||
if (!m_parentRow)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_parentRow->CanChildrenBeReordered();
|
||||
}
|
||||
}
|
||||
|
||||
#include "UI/PropertyEditor/moc_PropertyRowWidget.cpp"
|
||||
|
||||
+5
@@ -44,6 +44,7 @@ namespace AzToolsFramework
|
||||
Q_PROPERTY(bool hasChildRows READ HasChildRows);
|
||||
Q_PROPERTY(bool isTopLevel READ IsTopLevel);
|
||||
Q_PROPERTY(int getLevel READ GetLevel);
|
||||
Q_PROPERTY(bool canBeReordered READ CanBeReordered);
|
||||
Q_PROPERTY(bool appendDefaultLabelToName READ GetAppendDefaultLabelToName WRITE AppendDefaultLabelToName)
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PropertyRowWidget, AZ::SystemAllocator, 0)
|
||||
@@ -126,6 +127,7 @@ namespace AzToolsFramework
|
||||
void SetSelectionEnabled(bool selectionEnabled);
|
||||
void SetSelected(bool selected);
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
|
||||
/// Apply tooltip to widget and some of its children.
|
||||
void SetDescription(const QString& text);
|
||||
@@ -146,6 +148,9 @@ namespace AzToolsFramework
|
||||
QLabel* GetNameLabel() { return m_nameLabel; }
|
||||
void SetIndentSize(int w);
|
||||
void SetAsCustom(bool custom) { m_custom = custom; }
|
||||
|
||||
bool CanChildrenBeReordered() const;
|
||||
bool CanBeReordered() const;
|
||||
protected:
|
||||
int CalculateLabelWidth() const;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
|
||||
@@ -304,4 +305,24 @@ namespace AzToolsFramework
|
||||
|
||||
return entityContextId;
|
||||
}
|
||||
|
||||
//! Maps a mouse interaction event to a ClickDetector event.
|
||||
//! @note Function only cares about up or down events, all other events are mapped to Nil (ignored).
|
||||
inline AzFramework::ClickDetector::ClickEvent ClickDetectorEventFromViewportInteraction(
|
||||
const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
|
||||
{
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left())
|
||||
{
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Down;
|
||||
}
|
||||
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Up;
|
||||
}
|
||||
}
|
||||
return AzFramework::ClickDetector::ClickEvent::Nil;
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+9
-4
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -27,8 +28,11 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
|
||||
m_cursorState.SetCurrentPosition(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates);
|
||||
|
||||
const auto selectClickEvent = ClickDetectorEventFromViewportInteraction(mouseInteraction);
|
||||
const auto clickOutcome = m_clickDetector.DetectClick(selectClickEvent, m_cursorState.CursorDelta());
|
||||
if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Move)
|
||||
{
|
||||
if (m_leftMouseDown)
|
||||
{
|
||||
@@ -58,8 +62,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
||||
mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
|
||||
if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Release)
|
||||
{
|
||||
if (m_leftMouseUp)
|
||||
{
|
||||
@@ -77,6 +80,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
m_cursorState.Update();
|
||||
|
||||
if (m_boxSelectRegion)
|
||||
{
|
||||
debugDisplay.DepthTestOff();
|
||||
|
||||
+21
-17
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzFramework/Viewport/CursorState.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
|
||||
#include <QRect>
|
||||
@@ -26,49 +28,49 @@ namespace AzFramework
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
/// Utility to provide box select (click and drag) support for viewport types.
|
||||
/// Users can override the mouse event callbacks and display scene function to customize behavior.
|
||||
//! Utility to provide box select (click and drag) support for viewport types.
|
||||
//! Users can override the mouse event callbacks and display scene function to customize behavior.
|
||||
class EditorBoxSelect
|
||||
{
|
||||
public:
|
||||
EditorBoxSelect() = default;
|
||||
|
||||
/// Return if a box select action is currently taking place.
|
||||
//! Return if a box select action is currently taking place.
|
||||
bool Active() const { return m_boxSelectRegion.has_value(); }
|
||||
|
||||
/// Update the box select for various mouse events.
|
||||
/// Call HandleMouseInteraction from type/system implementing MouseViewportRequests interface.
|
||||
//! Update the box select for various mouse events.
|
||||
//! Call HandleMouseInteraction from type/system implementing MouseViewportRequests interface.
|
||||
void HandleMouseInteraction(
|
||||
const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
|
||||
|
||||
/// Responsible for drawing the 2d box representing the selection in screen space.
|
||||
//! Responsible for drawing the 2d box representing the selection in screen space.
|
||||
void Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay);
|
||||
|
||||
/// Custom drawing behavior to happen during a box select.
|
||||
//! Custom drawing behavior to happen during a box select.
|
||||
void DisplayScene(
|
||||
const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay);
|
||||
|
||||
/// Set the left mouse down callback.
|
||||
//! Set the left mouse down callback.
|
||||
void InstallLeftMouseDown(
|
||||
const AZStd::function<void(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)>& leftMouseDown);
|
||||
/// Set the mouse move callback.
|
||||
//! Set the mouse move callback.
|
||||
void InstallMouseMove(
|
||||
const AZStd::function<void(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)>& mouseMove);
|
||||
/// Set the left mouse up callback.
|
||||
//! Set the left mouse up callback.
|
||||
void InstallLeftMouseUp(
|
||||
const AZStd::function<void()>& leftMouseUp);
|
||||
/// Set the display scene callback.
|
||||
//! Set the display scene callback.
|
||||
void InstallDisplayScene(
|
||||
const AZStd::function<void(
|
||||
const AzFramework::ViewportInfo& viewportInfo,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay)>& displayScene);
|
||||
|
||||
/// Return the box select region.
|
||||
/// If a box selection is being made, return the current rectangle representing the area.
|
||||
/// If there is currently no active box select, then the Maybe type will be empty (there will be no region/area).
|
||||
//! Return the box select region.
|
||||
//! If a box selection is being made, return the current rectangle representing the area.
|
||||
//! If there is currently no active box select, then the Maybe type will be empty (there will be no region/area).
|
||||
const AZStd::optional<QRect>& BoxRegion() const { return m_boxSelectRegion; }
|
||||
|
||||
/// Return the active modifiers from the previous frame.
|
||||
//! Return the active modifiers from the previous frame.
|
||||
ViewportInteraction::KeyboardModifiers PreviousModifiers() const { return m_previousModifiers; }
|
||||
|
||||
private:
|
||||
@@ -79,7 +81,9 @@ namespace AzToolsFramework
|
||||
AZStd::function<void(
|
||||
const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)> m_displayScene;
|
||||
|
||||
AZStd::optional<QRect> m_boxSelectRegion; ///< Maybe/optional value to store box select region while active.
|
||||
ViewportInteraction::KeyboardModifiers m_previousModifiers; ///< Modifier keys active on the previous frame.
|
||||
AZStd::optional<QRect> m_boxSelectRegion; //!< Maybe/optional value to store box select region while active.
|
||||
ViewportInteraction::KeyboardModifiers m_previousModifiers; //!< Modifier keys active on the previous frame.
|
||||
AzFramework::ClickDetector m_clickDetector; //!< Utility type to detect if a mouse click or move has occurred.
|
||||
AzFramework::CursorState m_cursorState; //!< Utility type to track the current cursor position (and movement/delta).
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-16
@@ -1782,22 +1782,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_cachedEntityIdUnderCursor = m_editorHelpers->HandleMouseInteraction(cameraState, mouseInteraction);
|
||||
|
||||
const AzFramework::ClickDetector::ClickEvent selectClickEvent = [&mouseInteraction] {
|
||||
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left())
|
||||
{
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Down;
|
||||
}
|
||||
|
||||
if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
|
||||
{
|
||||
return AzFramework::ClickDetector::ClickEvent::Up;
|
||||
}
|
||||
}
|
||||
return AzFramework::ClickDetector::ClickEvent::Nil;
|
||||
}();
|
||||
|
||||
const auto selectClickEvent = ClickDetectorEventFromViewportInteraction(mouseInteraction);
|
||||
m_cursorState.SetCurrentPosition(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates);
|
||||
const auto clickOutcome = m_clickDetector.DetectClick(selectClickEvent, m_cursorState.CursorDelta());
|
||||
|
||||
|
||||
@@ -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 <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Viewport/CameraInput.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class CameraInputFixture : public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
AzFramework::Camera m_camera;
|
||||
AzFramework::Camera m_targetCamera;
|
||||
AZStd::shared_ptr<AzFramework::CameraSystem> m_cameraSystem;
|
||||
|
||||
bool HandleEventAndUpdate(const AzFramework::InputEvent& event)
|
||||
{
|
||||
constexpr float deltaTime = 0.01666f; // 60fps
|
||||
const bool consumed = m_cameraSystem->HandleEvents(event);
|
||||
m_camera = m_cameraSystem->StepCamera(m_targetCamera, deltaTime);
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
|
||||
AzFramework::ReloadCameraKeyBindings();
|
||||
|
||||
m_cameraSystem = AZStd::make_shared<AzFramework::CameraSystem>();
|
||||
|
||||
auto firstPersonRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::InputDeviceMouse::Button::Right);
|
||||
auto firstPersonTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(AzFramework::LookTranslation);
|
||||
|
||||
auto orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>();
|
||||
auto orbitRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::InputDeviceMouse::Button::Left);
|
||||
auto orbitTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(AzFramework::OrbitTranslation);
|
||||
|
||||
orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera);
|
||||
orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera);
|
||||
|
||||
m_cameraSystem->m_cameras.AddCamera(firstPersonRotateCamera);
|
||||
m_cameraSystem->m_cameras.AddCamera(firstPersonTranslateCamera);
|
||||
m_cameraSystem->m_cameras.AddCamera(orbitCamera);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_cameraSystem->m_cameras.Clear();
|
||||
m_cameraSystem.reset();
|
||||
|
||||
AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CameraInputFixture, BeginEndOrbitCameraConsumesCorrectEvents)
|
||||
{
|
||||
// set initial mouse position
|
||||
const bool consumed1 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(5, 5)});
|
||||
// begin orbit camera
|
||||
const bool consumed2 = HandleEventAndUpdate(
|
||||
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceKeyboard::Key::ModifierAltL, AzFramework::InputChannel::State::Began});
|
||||
// begin listening for orbit rotate (click detector) - event is not consumed
|
||||
const bool consumed3 = HandleEventAndUpdate(
|
||||
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began});
|
||||
// begin orbit rotate (mouse has moved sufficient distance to initiate)
|
||||
const bool consumed4 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(10, 10)});
|
||||
// end orbit (mouse up) - event is not consumed
|
||||
const bool consumed5 = HandleEventAndUpdate(
|
||||
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Ended});
|
||||
|
||||
const auto allConsumed = AZStd::vector<bool>{consumed1, consumed2, consumed3, consumed4, consumed5};
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
EXPECT_THAT(allConsumed, ElementsAre(false, true, false, true, false));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -139,4 +139,21 @@ namespace UnitTest
|
||||
EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // ignored double click
|
||||
EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered
|
||||
}
|
||||
|
||||
// if the click detector registers a mouse down event, but then all intermediate calls are ignored
|
||||
// (another system may start intercepting events and swallowing them) then when we do receive a mouse
|
||||
// up event we should ensure we take into account the current delta - if the delta is large, then the
|
||||
// outcome will be release
|
||||
TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterIgnoringMouseMovesBeforeMouseUpWithLargeDelta)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const ClickDetector::ClickOutcome downOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
|
||||
const ClickDetector::ClickOutcome upOutcome =
|
||||
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(50, 50));
|
||||
|
||||
EXPECT_THAT(downOutcome, Eq(ClickDetector::ClickOutcome::Nil));
|
||||
EXPECT_THAT(upOutcome, Eq(ClickDetector::ClickOutcome::Release));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -17,6 +17,7 @@ set(FILES
|
||||
BinToTextEncode.cpp
|
||||
ComponentAddRemove.cpp
|
||||
ComponentAdapterTests.cpp
|
||||
CameraInputTests.cpp
|
||||
ClickDetectorTests.cpp
|
||||
CursorStateTests.cpp
|
||||
EntityContext.cpp
|
||||
|
||||
Reference in New Issue
Block a user