more development freshening
Signed-off-by: Scott Murray <scottmur@amazon.com>
This commit is contained in:
@@ -253,73 +253,3 @@ class TestAtomEditorComponentsMain(object):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
|
||||
@pytest.mark.system
|
||||
class TestMaterialEditorBasicTests(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_teardown(self, request, workspace, project):
|
||||
def delete_files():
|
||||
file_system.delete(
|
||||
[
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_1.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_2.material"),
|
||||
],
|
||||
True,
|
||||
True,
|
||||
)
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
def teardown():
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
@pytest.mark.parametrize("exe_file_name", ["MaterialEditor"])
|
||||
@pytest.mark.test_case_id("C34448113") # Creating a New Asset.
|
||||
@pytest.mark.test_case_id("C34448114") # Opening an Existing Asset.
|
||||
@pytest.mark.test_case_id("C34448115") # Closing Selected Material.
|
||||
@pytest.mark.test_case_id("C34448116") # Closing All Materials.
|
||||
@pytest.mark.test_case_id("C34448117") # Closing all but Selected Material.
|
||||
@pytest.mark.test_case_id("C34448118") # Saving Material.
|
||||
@pytest.mark.test_case_id("C34448119") # Saving as a New Material.
|
||||
@pytest.mark.test_case_id("C34448120") # Saving as a Child Material.
|
||||
@pytest.mark.test_case_id("C34448121") # Saving all Open Materials.
|
||||
def test_MaterialEditorBasicTests(
|
||||
self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name):
|
||||
|
||||
expected_lines = [
|
||||
"Material opened: True",
|
||||
"Test asset doesn't exist initially: True",
|
||||
"New asset created: True",
|
||||
"New Material opened: True",
|
||||
"Material closed: True",
|
||||
"All documents closed: True",
|
||||
"Close All Except Selected worked as expected: True",
|
||||
"Actual Document saved with changes: True",
|
||||
"Document saved as copy is saved with changes: True",
|
||||
"Document saved as child is saved with changes: True",
|
||||
"Save All worked as expected: True",
|
||||
]
|
||||
unexpected_lines = [
|
||||
# "Trace::Assert",
|
||||
# "Trace::Error",
|
||||
"Traceback (most recent call last):"
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
generic_launcher,
|
||||
"hydra_AtomMaterialEditor_BasicTests.py",
|
||||
run_python="--runpython",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
log_file_name="MaterialEditor.log",
|
||||
)
|
||||
|
||||
@@ -70,3 +70,75 @@ class TestAtomEditorComponentsSandbox(object):
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
|
||||
@pytest.mark.system
|
||||
class TestMaterialEditorBasicTests(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_teardown(self, request, workspace, project):
|
||||
def delete_files():
|
||||
file_system.delete(
|
||||
[
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_1.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_2.material"),
|
||||
],
|
||||
True,
|
||||
True,
|
||||
)
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
def teardown():
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
@pytest.mark.parametrize("exe_file_name", ["MaterialEditor"])
|
||||
@pytest.mark.test_case_id("C34448113") # Creating a New Asset.
|
||||
@pytest.mark.test_case_id("C34448114") # Opening an Existing Asset.
|
||||
@pytest.mark.test_case_id("C34448115") # Closing Selected Material.
|
||||
@pytest.mark.test_case_id("C34448116") # Closing All Materials.
|
||||
@pytest.mark.test_case_id("C34448117") # Closing all but Selected Material.
|
||||
@pytest.mark.test_case_id("C34448118") # Saving Material.
|
||||
@pytest.mark.test_case_id("C34448119") # Saving as a New Material.
|
||||
@pytest.mark.test_case_id("C34448120") # Saving as a Child Material.
|
||||
@pytest.mark.test_case_id("C34448121") # Saving all Open Materials.
|
||||
def test_MaterialEditorBasicTests(
|
||||
self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name):
|
||||
|
||||
expected_lines = [
|
||||
"Material opened: True",
|
||||
"Test asset doesn't exist initially: True",
|
||||
"New asset created: True",
|
||||
"New Material opened: True",
|
||||
"Material closed: True",
|
||||
"All documents closed: True",
|
||||
"Close All Except Selected worked as expected: True",
|
||||
"Actual Document saved with changes: True",
|
||||
"Document saved as copy is saved with changes: True",
|
||||
"Document saved as child is saved with changes: True",
|
||||
"Save All worked as expected: True",
|
||||
]
|
||||
unexpected_lines = [
|
||||
# "Trace::Assert",
|
||||
# "Trace::Error",
|
||||
"Traceback (most recent call last):"
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
generic_launcher,
|
||||
"hydra_AtomMaterialEditor_BasicTests.py",
|
||||
run_python="--runpython",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
log_file_name="MaterialEditor.log",
|
||||
)
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace AzFramework
|
||||
class IMatchmakingAsyncRequests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ISessionAsyncRequests, "{53513480-2D02-493C-B44E-96AA27F42429}");
|
||||
AZ_RTTI(IMatchmakingAsyncRequests, "{53513480-2D02-493C-B44E-96AA27F42429}");
|
||||
|
||||
IMatchmakingAsyncRequests() = default;
|
||||
virtual ~IMatchmakingAsyncRequests() = default;
|
||||
@@ -60,4 +60,31 @@ namespace AzFramework
|
||||
// @param stopMatchmakingRequest The request of StopMatchmaking operation
|
||||
virtual void StopMatchmakingAsync(const StopMatchmakingRequest& stopMatchmakingRequest) = 0;
|
||||
};
|
||||
|
||||
//! MatchmakingAsyncRequestNotifications
|
||||
//! The notifications correspond to matchmaking async requests
|
||||
class MatchmakingAsyncRequestNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
// Safeguard handler for multi-threaded use case
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes
|
||||
virtual void OnAcceptMatchAsyncComplete() = 0;
|
||||
|
||||
// OnStartMatchmakingAsyncComplete is fired once StartMatchmakingAsync completes
|
||||
// @param matchmakingTicketId The unique identifier for the matchmaking ticket
|
||||
virtual void OnStartMatchmakingAsyncComplete(const AZStd::string& matchmakingTicketId) = 0;
|
||||
|
||||
// OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes
|
||||
virtual void OnStopMatchmakingAsyncComplete() = 0;
|
||||
};
|
||||
using MatchmakingAsyncRequestNotificationBus = AZ::EBus<MatchmakingAsyncRequestNotifications>;
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -13,36 +13,10 @@
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
//! MatchmakingAsyncRequestNotifications
|
||||
//! The notifications correspond to matchmaking async requests
|
||||
class MatchmakingAsyncRequestNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
// Safeguard handler for multi-threaded use case
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes
|
||||
virtual void OnAcceptMatchAsyncComplete() = 0;
|
||||
|
||||
// OnStartMatchmakingAsyncComplete is fired once StartMatchmakingAsync completes
|
||||
// @param matchmakingTicketId The unique identifier for the matchmaking ticket
|
||||
virtual void OnStartMatchmakingAsyncComplete(const AZStd::string& matchmakingTicketId) = 0;
|
||||
|
||||
// OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes
|
||||
virtual void OnStopMatchmakingAsyncComplete() = 0;
|
||||
};
|
||||
using MatchmakingAsyncRequestNotificationBus = AZ::EBus<MatchmakingAsyncRequestNotifications>;
|
||||
|
||||
//! MatchmakingNotifications
|
||||
//! The matchmaking notifications to listen for performing required operations
|
||||
class MatchAcceptanceNotifications
|
||||
//! based on matchmaking ticket event
|
||||
class MatchmakingNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
@@ -55,8 +29,18 @@ namespace AzFramework
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// OnMatchAcceptance is fired when DescribeMatchmaking ticket status is REQUIRES_ACCEPTANCE
|
||||
// OnMatchAcceptance is fired when match is found and pending on acceptance
|
||||
// Use this notification to accept found match
|
||||
virtual void OnMatchAcceptance() = 0;
|
||||
|
||||
// OnMatchComplete is fired when match is complete
|
||||
virtual void OnMatchComplete() = 0;
|
||||
|
||||
// OnMatchError is fired when match is processed with error
|
||||
virtual void OnMatchError() = 0;
|
||||
|
||||
// OnMatchFailure is fired when match is failed to complete
|
||||
virtual void OnMatchFailure() = 0;
|
||||
};
|
||||
using MatchAcceptanceNotificationBus = AZ::EBus<MatchAcceptanceNotifications>;
|
||||
using MatchmakingNotificationBus = AZ::EBus<MatchmakingNotifications>;
|
||||
} // namespace AzFramework
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ namespace AzToolsFramework
|
||||
AZ_Assert(m_loaderInterface != nullptr,
|
||||
"Couldn't get prefab loader interface, it's a requirement for PrefabEntityOwnership system to work");
|
||||
|
||||
m_rootInstance = AZStd::unique_ptr<Prefab::Instance>(m_prefabSystemComponent->CreatePrefab({}, {}, "NewLevel.prefab"));
|
||||
m_rootInstance = AZStd::unique_ptr<Prefab::Instance>(m_prefabSystemComponent->CreatePrefab({}, {}, "newLevel.prefab"));
|
||||
m_sliceOwnershipService.BusConnect(m_entityContextId);
|
||||
m_sliceOwnershipService.m_shouldAssertForLegacySlicesUsage = m_shouldAssertForLegacySlicesUsage;
|
||||
m_editorSliceOwnershipService.BusConnect();
|
||||
|
||||
@@ -28,7 +28,9 @@ namespace AzToolsFramework::Prefab
|
||||
"Instance Entity Mapper Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
|
||||
EditorEntityInfoNotificationBus::Handler::BusConnect();
|
||||
EditorEntityContextNotificationBus::Handler::BusConnect();
|
||||
PrefabPublicNotificationBus::Handler::BusConnect();
|
||||
AZ::Interface<PrefabFocusInterface>::Register(this);
|
||||
AZ::Interface<PrefabFocusPublicInterface>::Register(this);
|
||||
}
|
||||
@@ -37,10 +39,12 @@ namespace AzToolsFramework::Prefab
|
||||
{
|
||||
AZ::Interface<PrefabFocusPublicInterface>::Unregister(this);
|
||||
AZ::Interface<PrefabFocusInterface>::Unregister(this);
|
||||
PrefabPublicNotificationBus::Handler::BusDisconnect();
|
||||
EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
EditorEntityInfoNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::Initialize()
|
||||
void PrefabFocusHandler::InitializeEditorInterfaces()
|
||||
{
|
||||
m_containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
AZ_Assert(
|
||||
@@ -55,13 +59,6 @@ namespace AzToolsFramework::Prefab
|
||||
"Prefab - PrefabFocusHandler - "
|
||||
"Focus Mode Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
|
||||
m_instanceEntityMapperInterface = AZ::Interface<InstanceEntityMapperInterface>::Get();
|
||||
AZ_Assert(
|
||||
m_instanceEntityMapperInterface,
|
||||
"Prefab - PrefabFocusHandler - "
|
||||
"Instance Entity Mapper Interface could not be found. "
|
||||
"Check that it is being correctly initialized.");
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId)
|
||||
@@ -90,12 +87,12 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index)
|
||||
{
|
||||
if (index < 0 || index >= m_instanceFocusVector.size())
|
||||
if (index < 0 || index >= m_instanceFocusHierarchy.size())
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex."));
|
||||
}
|
||||
|
||||
InstanceOptionalReference focusedInstance = m_instanceFocusVector[index];
|
||||
InstanceOptionalReference focusedInstance = m_instanceFocusHierarchy[index];
|
||||
|
||||
FocusOnOwningPrefab(focusedInstance->get().GetContainerEntityId());
|
||||
|
||||
@@ -134,42 +131,38 @@ namespace AzToolsFramework::Prefab
|
||||
return AZ::Failure(AZStd::string("Prefab Focus Handler: invalid instance to focus on."));
|
||||
}
|
||||
|
||||
if (!m_isInitialized)
|
||||
// Close all container entities in the old path.
|
||||
CloseInstanceContainers(m_instanceFocusHierarchy);
|
||||
|
||||
m_focusedInstance = focusedInstance;
|
||||
m_focusedTemplateId = focusedInstance->get().GetTemplateId();
|
||||
|
||||
AZ::EntityId containerEntityId;
|
||||
|
||||
if (focusedInstance->get().GetParentInstance() != AZStd::nullopt)
|
||||
{
|
||||
Initialize();
|
||||
containerEntityId = focusedInstance->get().GetContainerEntityId();
|
||||
}
|
||||
|
||||
if (!m_focusedInstance.has_value() || &m_focusedInstance->get() != &focusedInstance->get())
|
||||
else
|
||||
{
|
||||
// Close all container entities in the old path
|
||||
CloseInstanceContainers(m_instanceFocusVector);
|
||||
|
||||
m_focusedInstance = focusedInstance;
|
||||
m_focusedTemplateId = focusedInstance->get().GetTemplateId();
|
||||
|
||||
AZ::EntityId containerEntityId;
|
||||
|
||||
if (focusedInstance->get().GetParentInstance() != AZStd::nullopt)
|
||||
{
|
||||
containerEntityId = focusedInstance->get().GetContainerEntityId();
|
||||
}
|
||||
else
|
||||
{
|
||||
containerEntityId = AZ::EntityId();
|
||||
}
|
||||
containerEntityId = AZ::EntityId();
|
||||
}
|
||||
|
||||
// Focus on the descendants of the container entity
|
||||
// Focus on the descendants of the container entity in the Editor, if the interface is initialized.
|
||||
if (m_focusModeInterface)
|
||||
{
|
||||
m_focusModeInterface->SetFocusRoot(containerEntityId);
|
||||
|
||||
// Refresh path variables
|
||||
RefreshInstanceFocusList();
|
||||
|
||||
// Open all container entities in the new path
|
||||
OpenInstanceContainers(m_instanceFocusVector);
|
||||
|
||||
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
|
||||
}
|
||||
|
||||
// Refresh path variables.
|
||||
RefreshInstanceFocusList();
|
||||
RefreshInstanceFocusPath();
|
||||
|
||||
// Open all container entities in the new path.
|
||||
OpenInstanceContainers(m_instanceFocusHierarchy);
|
||||
|
||||
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
@@ -220,49 +213,80 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
const int PrefabFocusHandler::GetPrefabFocusPathLength([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
|
||||
{
|
||||
return aznumeric_cast<int>(m_instanceFocusVector.size());
|
||||
return aznumeric_cast<int>(m_instanceFocusHierarchy.size());
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::OnEntityStreamLoadSuccess()
|
||||
void PrefabFocusHandler::OnContextReset()
|
||||
{
|
||||
if (!m_isInitialized)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
// Clear the old focus vector
|
||||
m_instanceFocusVector.clear();
|
||||
m_instanceFocusHierarchy.clear();
|
||||
|
||||
// Focus on the root prefab (AZ::EntityId() will default to it)
|
||||
FocusOnPrefabInstanceOwningEntityId(AZ::EntityId());
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::OnEntityInfoUpdatedName(AZ::EntityId entityId, [[maybe_unused]]const AZStd::string& name)
|
||||
{
|
||||
// Determine if the entityId is the container for any of the instances in the vector
|
||||
auto result = AZStd::find_if(
|
||||
m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end(),
|
||||
[entityId](const InstanceOptionalReference& instance)
|
||||
{
|
||||
return (instance->get().GetContainerEntityId() == entityId);
|
||||
}
|
||||
);
|
||||
|
||||
if (result != m_instanceFocusHierarchy.end())
|
||||
{
|
||||
// Refresh the path and notify changes.
|
||||
RefreshInstanceFocusPath();
|
||||
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::OnPrefabInstancePropagationEnd()
|
||||
{
|
||||
// Refresh the path and notify changes in case propagation updated any container names.
|
||||
RefreshInstanceFocusPath();
|
||||
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::RefreshInstanceFocusList()
|
||||
{
|
||||
m_instanceFocusVector.clear();
|
||||
m_instanceFocusPath.clear();
|
||||
m_instanceFocusHierarchy.clear();
|
||||
|
||||
AZStd::list<InstanceOptionalReference> instanceFocusList;
|
||||
|
||||
// Use a support list to easily push front while traversing the prefab hierarchy
|
||||
InstanceOptionalReference currentInstance = m_focusedInstance;
|
||||
while (currentInstance.has_value())
|
||||
{
|
||||
instanceFocusList.push_front(currentInstance);
|
||||
m_instanceFocusHierarchy.emplace_back(currentInstance);
|
||||
|
||||
currentInstance = currentInstance->get().GetParentInstance();
|
||||
}
|
||||
|
||||
// Populate internals using the support list
|
||||
for (auto& instance : instanceFocusList)
|
||||
// Invert the vector, since we need the top instance to be at index 0
|
||||
AZStd::reverse(m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end());
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::RefreshInstanceFocusPath()
|
||||
{
|
||||
m_instanceFocusPath.clear();
|
||||
|
||||
for (const InstanceOptionalReference& instance : m_instanceFocusHierarchy)
|
||||
{
|
||||
m_instanceFocusPath.Append(instance->get().GetContainerEntity()->get().GetName());
|
||||
m_instanceFocusVector.emplace_back(instance);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabFocusHandler::OpenInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const
|
||||
{
|
||||
// If this is called outside the Editor, this interface won't be initialized.
|
||||
if (!m_containerEntityInterface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const InstanceOptionalReference& instance : instances)
|
||||
{
|
||||
if (instance.has_value())
|
||||
@@ -274,6 +298,12 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
void PrefabFocusHandler::CloseInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const
|
||||
{
|
||||
// If this is called outside the Editor, this interface won't be initialized.
|
||||
if (!m_containerEntityInterface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const InstanceOptionalReference& instance : instances)
|
||||
{
|
||||
if (instance.has_value())
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicNotificationBus.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -30,7 +32,9 @@ namespace AzToolsFramework::Prefab
|
||||
class PrefabFocusHandler final
|
||||
: private PrefabFocusInterface
|
||||
, private PrefabFocusPublicInterface
|
||||
, private PrefabPublicNotificationBus::Handler
|
||||
, private EditorEntityContextNotificationBus::Handler
|
||||
, private EditorEntityInfoNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabFocusHandler, AZ::SystemAllocator, 0);
|
||||
@@ -38,9 +42,8 @@ namespace AzToolsFramework::Prefab
|
||||
PrefabFocusHandler();
|
||||
~PrefabFocusHandler();
|
||||
|
||||
void Initialize();
|
||||
|
||||
// PrefabFocusInterface overrides ...
|
||||
void InitializeEditorInterfaces() override;
|
||||
PrefabFocusOperationResult FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId) override;
|
||||
TemplateId GetFocusedPrefabTemplateId(AzFramework::EntityContextId entityContextId) const override;
|
||||
InstanceOptionalReference GetFocusedPrefabInstance(AzFramework::EntityContextId entityContextId) const override;
|
||||
@@ -54,25 +57,34 @@ namespace AzToolsFramework::Prefab
|
||||
const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const override;
|
||||
|
||||
// EditorEntityContextNotificationBus overrides ...
|
||||
void OnEntityStreamLoadSuccess() override;
|
||||
void OnContextReset() override;
|
||||
|
||||
// EditorEntityInfoNotificationBus overrides ...
|
||||
void OnEntityInfoUpdatedName(AZ::EntityId entityId, const AZStd::string& name) override;
|
||||
|
||||
// PrefabPublicNotifications overrides ...
|
||||
void OnPrefabInstancePropagationEnd();
|
||||
|
||||
private:
|
||||
PrefabFocusOperationResult FocusOnPrefabInstance(InstanceOptionalReference focusedInstance);
|
||||
void RefreshInstanceFocusList();
|
||||
void RefreshInstanceFocusPath();
|
||||
|
||||
void OpenInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const;
|
||||
void CloseInstanceContainers(const AZStd::vector<InstanceOptionalReference>& instances) const;
|
||||
|
||||
//! The instance the editor is currently focusing on.
|
||||
InstanceOptionalReference m_focusedInstance;
|
||||
//! The templateId of the focused instance.
|
||||
TemplateId m_focusedTemplateId;
|
||||
AZStd::vector<InstanceOptionalReference> m_instanceFocusVector;
|
||||
//! The list of instances going from the root (index 0) to the focused instance.
|
||||
AZStd::vector<InstanceOptionalReference> m_instanceFocusHierarchy;
|
||||
//! A path containing the names of the containers in the instance focus hierarchy, separated with a /.
|
||||
AZ::IO::Path m_instanceFocusPath;
|
||||
|
||||
ContainerEntityInterface* m_containerEntityInterface = nullptr;
|
||||
FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr;
|
||||
|
||||
bool m_isInitialized = false;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
|
||||
@@ -26,6 +26,11 @@ namespace AzToolsFramework::Prefab
|
||||
public:
|
||||
AZ_RTTI(PrefabFocusInterface, "{F3CFA37B-5FD8-436A-9C30-60EB54E350E1}");
|
||||
|
||||
//! Initializes the editor interfaces for Prefab Focus mode.
|
||||
//! If this is not called on initialization, the Prefab Focus Mode functions will still work
|
||||
//! but won't trigger the Editor APIs to visualize focus mode on the UI.
|
||||
virtual void InitializeEditorInterfaces() = 0;
|
||||
|
||||
//! Set the focused prefab instance to the owning instance of the entityId provided.
|
||||
//! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on.
|
||||
virtual PrefabFocusOperationResult FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId) = 0;
|
||||
|
||||
+5
@@ -27,6 +27,7 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h>
|
||||
@@ -135,6 +136,10 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize Editor functionality for the Prefab Focus Handler
|
||||
auto prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
prefabFocusInterface->InitializeEditorInterfaces();
|
||||
|
||||
EditorContextMenuBus::Handler::BusConnect();
|
||||
EditorEventsBus::Handler::BusConnect();
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
#include <utilities/BatchApplicationManager.h>
|
||||
#include <utilities/ApplicationServer.h>
|
||||
#include <AzFramework/Asset/AssetSystemComponent.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <connection/connectionManager.h>
|
||||
#include <QCoreApplication>
|
||||
#include <QTemporaryDir>
|
||||
@@ -98,10 +100,26 @@ namespace AssetProcessorMessagesTests
|
||||
|
||||
int argC = 0;
|
||||
m_batchApplicationManager = AZStd::make_unique<UnitTestBatchApplicationManager>(&argC, nullptr, nullptr);
|
||||
m_batchApplicationManager->BeforeRun();
|
||||
|
||||
// Override Game Name to be "AutomatedTesting"
|
||||
AssetUtilities::ComputeProjectName("AutomatedTesting", true);
|
||||
auto registry = AZ::SettingsRegistry::Get();
|
||||
EXPECT_NE(registry, nullptr);
|
||||
constexpr AZ::SettingsRegistryInterface::FixedValueString bootstrapKey{
|
||||
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey
|
||||
};
|
||||
constexpr AZ::SettingsRegistryInterface::FixedValueString projectPathKey{ bootstrapKey + "/project_path" };
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
// Force the branch token into settings registry before starting the application manager.
|
||||
// This avoids writing the asset_processor.setreg file which can cause fileIO errors.
|
||||
const AZ::IO::FixedMaxPathString enginePath = AZ::Utils::GetEnginePath();
|
||||
constexpr AZ::SettingsRegistryInterface::FixedValueString branchTokenKey{ bootstrapKey + "/assetProcessor_branch_token" };
|
||||
AZStd::string token;
|
||||
AZ::StringFunc::AssetPath::CalculateBranchToken(enginePath.c_str(), token);
|
||||
registry->Set(branchTokenKey, token.c_str());
|
||||
|
||||
auto status = m_batchApplicationManager->BeforeRun();
|
||||
ASSERT_EQ(status, ApplicationManager::BeforeRunStatus::Status_Success);
|
||||
|
||||
m_batchApplicationManager->m_platformConfiguration = new PlatformConfiguration();
|
||||
m_batchApplicationManager->InitAssetProcessorManager();
|
||||
@@ -159,21 +177,25 @@ namespace AssetProcessorMessagesTests
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
QEventLoop eventLoop;
|
||||
if (m_batchApplicationManager->m_connectionManager)
|
||||
{
|
||||
QEventLoop eventLoop;
|
||||
|
||||
QObject::connect(m_batchApplicationManager->m_connectionManager, &ConnectionManager::ReadyToQuit, &eventLoop, &QEventLoop::quit);
|
||||
QObject::connect(m_batchApplicationManager->m_connectionManager, &ConnectionManager::ReadyToQuit, &eventLoop, &QEventLoop::quit);
|
||||
|
||||
m_batchApplicationManager->m_connectionManager->QuitRequested();
|
||||
m_batchApplicationManager->m_connectionManager->QuitRequested();
|
||||
|
||||
eventLoop.exec();
|
||||
eventLoop.exec();
|
||||
}
|
||||
|
||||
m_assetSystemComponent->Deactivate();
|
||||
if (m_assetSystemComponent)
|
||||
{
|
||||
m_assetSystemComponent->Deactivate();
|
||||
}
|
||||
m_batchApplicationManager->Destroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -505,6 +505,14 @@ bool ApplicationManager::StartAZFramework()
|
||||
AzFramework::Application::Descriptor appDescriptor;
|
||||
AZ::ComponentApplication::StartupParameters params;
|
||||
|
||||
QDir projectPath{ AssetUtilities::ComputeProjectPath() };
|
||||
if (!projectPath.exists("project.json"))
|
||||
{
|
||||
AZStd::string errorMsg = AZStd::string::format("Path '%s' is not a valid project path.", projectPath.path().toUtf8().constData());
|
||||
AssetProcessor::MessageInfoBus::Broadcast(&AssetProcessor::MessageInfoBus::Events::OnErrorMessage, errorMsg.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
QString projectName = AssetUtilities::ComputeProjectName();
|
||||
|
||||
// Prevent loading of gems in the Create method of the ComponentApplication
|
||||
@@ -520,7 +528,6 @@ bool ApplicationManager::StartAZFramework()
|
||||
//Registering all the Components
|
||||
m_frameworkApp.RegisterComponentDescriptor(AzFramework::LogComponent::CreateDescriptor());
|
||||
|
||||
|
||||
Reflect();
|
||||
|
||||
const AzFramework::CommandLine* commandLine = nullptr;
|
||||
|
||||
@@ -95,6 +95,8 @@ GUIApplicationManager::~GUIApplicationManager()
|
||||
|
||||
ApplicationManager::BeforeRunStatus GUIApplicationManager::BeforeRun()
|
||||
{
|
||||
AssetProcessor::MessageInfoBus::Handler::BusConnect();
|
||||
|
||||
ApplicationManager::BeforeRunStatus status = ApplicationManagerBase::BeforeRun();
|
||||
if (status != ApplicationManager::BeforeRunStatus::Status_Success)
|
||||
{
|
||||
@@ -109,7 +111,6 @@ ApplicationManager::BeforeRunStatus GUIApplicationManager::BeforeRun()
|
||||
#if defined(EXTERNAL_CRASH_REPORTING)
|
||||
CrashHandler::ToolsCrashHandler::InitCrashHandler("AssetProcessor", projectAssetRoot.absolutePath().toStdString());
|
||||
#endif
|
||||
AssetProcessor::MessageInfoBus::Handler::BusConnect();
|
||||
|
||||
// we have to monitor both the cache folder and the database file and restart AP if either of them gets deleted
|
||||
// It is important to note that we are monitoring the parent folder and not the actual cache folder itself since
|
||||
@@ -436,98 +437,7 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
||||
connection = Qt::QueuedConnection;
|
||||
}
|
||||
|
||||
if (m_isCurrentlyLoadingGems)
|
||||
{
|
||||
// if something goes wrong during gem initialization, this is a special case and we need to be extra helpful.
|
||||
const char* userSettingsFile = "_WAF_/user_settings.options";
|
||||
const char* defaultSettingsFile = "_WAF_/default_settings.json";
|
||||
|
||||
QDir engineRoot;
|
||||
AssetUtilities::ComputeEngineRoot(engineRoot);
|
||||
|
||||
QString settingsPath = engineRoot.absoluteFilePath(userSettingsFile);
|
||||
QString friendlyErrorMessage;
|
||||
bool usingDefaults = false;
|
||||
|
||||
if (QFile::exists(settingsPath))
|
||||
{
|
||||
QSettings loader(settingsPath, QSettings::IniFormat);
|
||||
QVariant settingValue = loader.value("Game Projects/enabled_game_projects");
|
||||
QStringList compiledProjects = settingValue.toStringList();
|
||||
|
||||
if (compiledProjects.isEmpty())
|
||||
{
|
||||
QByteArray byteArray;
|
||||
QFile jsonFile;
|
||||
jsonFile.setFileName(engineRoot.absoluteFilePath(defaultSettingsFile));
|
||||
jsonFile.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
byteArray = jsonFile.readAll();
|
||||
jsonFile.close();
|
||||
|
||||
QJsonObject settingsObject = QJsonDocument::fromJson(byteArray).object();
|
||||
QJsonArray projectsArray = settingsObject["Game Projects"].toArray();
|
||||
|
||||
if (!projectsArray.isEmpty())
|
||||
{
|
||||
auto projectObject = projectsArray[0].toObject();
|
||||
QString projects = projectObject["default_value"].toString();
|
||||
|
||||
if (!projects.isEmpty())
|
||||
{
|
||||
compiledProjects = projects.split(',');
|
||||
usingDefaults = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < compiledProjects.size(); ++i)
|
||||
{
|
||||
compiledProjects[i] = compiledProjects[i].trimmed();
|
||||
}
|
||||
|
||||
QString enabledProject = AssetUtilities::ComputeProjectName();
|
||||
|
||||
if (!compiledProjects.contains(enabledProject))
|
||||
{
|
||||
QString projectSourceLine;
|
||||
|
||||
if (usingDefaults)
|
||||
{
|
||||
projectSourceLine = QString("The currently compiled projects according to the defaults in %1 are '%2'").arg(defaultSettingsFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
projectSourceLine = QString("The currently compiled projects according to %1 are '%2'").arg(userSettingsFile);
|
||||
}
|
||||
|
||||
projectSourceLine = projectSourceLine.arg(compiledProjects.join(", "));
|
||||
friendlyErrorMessage = QString("An error occurred while loading gems.\n"
|
||||
"The enabled game project is not in the list of compiled projects.\n"
|
||||
"Please configure the enabled project to be compiled and rebuild or change the enabled project.\n"
|
||||
"The currently enabled game project (from bootstrap.cfg or /%4 command-line parameter) is '%1'.\n"
|
||||
"%2\n"
|
||||
"Full error text:\n"
|
||||
"%3"
|
||||
).arg(enabledProject).arg(projectSourceLine).arg(message).arg(AssetUtilities::ProjectPathOverrideParameter);
|
||||
}
|
||||
}
|
||||
|
||||
if (friendlyErrorMessage.isEmpty())
|
||||
{
|
||||
friendlyErrorMessage = QString("An error occurred while loading gems.\n"
|
||||
"This can happen when new gems are added to a project, but those gems need to be built in order to function.\n"
|
||||
"This can also happen when switching to a different project, one which uses gems which are not yet built.\n"
|
||||
"To continue, please build the current project before attempting to run Asset Processor again.\n\n"
|
||||
"Full error text:\n"
|
||||
"%1").arg(message);
|
||||
}
|
||||
QMetaObject::invokeMethod(this, "ShowMessageBox", connection, Q_ARG(QString, QString("Error")), Q_ARG(QString, friendlyErrorMessage), Q_ARG(bool, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "ShowMessageBox", connection, Q_ARG(QString, QString("Error")), Q_ARG(QString, QString(message)), Q_ARG(bool, true));
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(this, "ShowMessageBox", connection, Q_ARG(QString, QString("Error")), Q_ARG(QString, QString(message)), Q_ARG(bool, true));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+4
-63
@@ -5,75 +5,16 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzFramework/Matchmaking/IMatchmakingRequests.h>
|
||||
#include <AzFramework/Session/ISessionRequests.h>
|
||||
|
||||
namespace AWSGameLift
|
||||
{
|
||||
//! IAWSGameLiftRequests
|
||||
//! GameLift Gem interfaces to configure client manager
|
||||
class IAWSGameLiftRequests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(IAWSGameLiftRequests, "{494167AD-1185-4AF3-8BF9-C8C37FC9C199}");
|
||||
|
||||
IAWSGameLiftRequests() = default;
|
||||
virtual ~IAWSGameLiftRequests() = default;
|
||||
|
||||
//! ConfigureGameLiftClient
|
||||
//! Configure GameLift client to interact with Amazon GameLift service
|
||||
//! @param region Specifies the AWS region to use
|
||||
//! @return True if client configuration succeeds, false otherwise
|
||||
virtual bool ConfigureGameLiftClient(const AZStd::string& region) = 0;
|
||||
|
||||
//! CreatePlayerId
|
||||
//! Create a new, random ID number for every player in every new game session.
|
||||
//! @param includeBrackets Whether includes brackets in player id
|
||||
//! @param includeDashes Whether includes dashes in player id
|
||||
//! @return The player id to use in game session
|
||||
virtual AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) = 0;
|
||||
};
|
||||
|
||||
// IAWSGameLiftRequests EBus wrapper for scripting
|
||||
class AWSGameLiftRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
};
|
||||
using AWSGameLiftRequestBus = AZ::EBus<IAWSGameLiftRequests, AWSGameLiftRequests>;
|
||||
|
||||
// ISessionAsyncRequests EBus wrapper for scripting
|
||||
class AWSGameLiftSessionAsyncRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
};
|
||||
using AWSGameLiftSessionAsyncRequestBus = AZ::EBus<AzFramework::ISessionAsyncRequests, AWSGameLiftSessionAsyncRequests>;
|
||||
|
||||
// ISessionRequests EBus wrapper for scripting
|
||||
class AWSGameLiftSessionRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
};
|
||||
using AWSGameLiftSessionRequestBus = AZ::EBus<AzFramework::ISessionRequests, AWSGameLiftSessionRequests>;
|
||||
|
||||
// IMatchmakingAsyncRequests EBus wrapper for scripting
|
||||
// IMatchmakingAsyncRequests EBus wrapper
|
||||
class AWSGameLiftMatchmakingAsyncRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
@@ -84,7 +25,7 @@ namespace AWSGameLift
|
||||
};
|
||||
using AWSGameLiftMatchmakingAsyncRequestBus = AZ::EBus<AzFramework::IMatchmakingAsyncRequests, AWSGameLiftMatchmakingAsyncRequests>;
|
||||
|
||||
// IMatchmakingRequests EBus wrapper for scripting
|
||||
// IMatchmakingRequests EBus wrapper
|
||||
class AWSGameLiftMatchmakingRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
@@ -121,7 +62,7 @@ namespace AWSGameLift
|
||||
virtual void StopPolling() = 0;
|
||||
};
|
||||
|
||||
// IAWSGameLiftMatchmakingEventRequests EBus wrapper for scripting
|
||||
// IAWSGameLiftMatchmakingEventRequests EBus wrapper
|
||||
class AWSGameLiftMatchmakingEventRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AWSGameLift
|
||||
{
|
||||
//! IAWSGameLiftRequests
|
||||
//! GameLift Gem interfaces to configure GameLift client and other help functions,
|
||||
//! like creating random GameLift player id
|
||||
class IAWSGameLiftRequests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(IAWSGameLiftRequests, "{494167AD-1185-4AF3-8BF9-C8C37FC9C199}");
|
||||
|
||||
IAWSGameLiftRequests() = default;
|
||||
virtual ~IAWSGameLiftRequests() = default;
|
||||
|
||||
//! ConfigureGameLiftClient
|
||||
//! Configure GameLift client to interact with Amazon GameLift service
|
||||
//! @param region Specifies the AWS region to use
|
||||
//! @return True if client configuration succeeds, false otherwise
|
||||
virtual bool ConfigureGameLiftClient(const AZStd::string& region) = 0;
|
||||
|
||||
//! CreatePlayerId
|
||||
//! Create a new, random ID number for every player in every new game session.
|
||||
//! @param includeBrackets Whether includes brackets in player id
|
||||
//! @param includeDashes Whether includes dashes in player id
|
||||
//! @return The player id to use in game session
|
||||
virtual AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) = 0;
|
||||
};
|
||||
|
||||
// IAWSGameLiftRequests EBus wrapper
|
||||
class AWSGameLiftRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
};
|
||||
using AWSGameLiftRequestBus = AZ::EBus<IAWSGameLiftRequests, AWSGameLiftRequests>;
|
||||
} // namespace AWSGameLift
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzFramework/Session/ISessionRequests.h>
|
||||
|
||||
namespace AWSGameLift
|
||||
{
|
||||
// ISessionAsyncRequests EBus wrapper
|
||||
class AWSGameLiftSessionAsyncRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
};
|
||||
using AWSGameLiftSessionAsyncRequestBus = AZ::EBus<AzFramework::ISessionAsyncRequests, AWSGameLiftSessionAsyncRequests>;
|
||||
|
||||
// ISessionRequests EBus wrapper
|
||||
class AWSGameLiftSessionRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
};
|
||||
using AWSGameLiftSessionRequestBus = AZ::EBus<AzFramework::ISessionRequests, AWSGameLiftSessionRequests>;
|
||||
} // namespace AWSGameLift
|
||||
+11
-5
@@ -97,6 +97,7 @@ namespace AWSGameLift
|
||||
AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName,
|
||||
"Matchmaking ticket %s is complete.", ticket.GetTicketId().c_str());
|
||||
RequestPlayerJoinMatch(ticket, playerId);
|
||||
AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchComplete);
|
||||
m_status = TicketTrackerStatus::Idle;
|
||||
return;
|
||||
}
|
||||
@@ -104,25 +105,28 @@ namespace AWSGameLift
|
||||
ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::FAILED ||
|
||||
ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::CANCELLED)
|
||||
{
|
||||
AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Matchmaking ticket %s is not complete, %s",
|
||||
ticket.GetTicketId().c_str(), ticket.GetStatusReason().c_str());
|
||||
AZ_Warning(AWSGameLiftClientLocalTicketTrackerName, false, "Matchmaking ticket %s is not complete, %s",
|
||||
ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str());
|
||||
AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchFailure);
|
||||
m_status = TicketTrackerStatus::Idle;
|
||||
return;
|
||||
}
|
||||
else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::REQUIRES_ACCEPTANCE)
|
||||
{
|
||||
// broadcast acceptance requires to player
|
||||
AzFramework::MatchAcceptanceNotificationBus::Broadcast(&AzFramework::MatchAcceptanceNotifications::OnMatchAcceptance);
|
||||
AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is pending on acceptance, %s.",
|
||||
ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str());
|
||||
AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchAcceptance);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is processing, %s.",
|
||||
ticket.GetTicketId().c_str(), ticket.GetStatusReason().c_str());
|
||||
ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Unable to find expected ticket with id %s", ticketId.c_str());
|
||||
AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchError);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -130,11 +134,13 @@ namespace AWSGameLift
|
||||
AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftErrorMessageTemplate,
|
||||
describeMatchmakingOutcome.GetError().GetExceptionName().c_str(),
|
||||
describeMatchmakingOutcome.GetError().GetMessage().c_str());
|
||||
AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchError);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftClientMissingErrorMessage);
|
||||
AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchError);
|
||||
}
|
||||
m_waitEvent.try_acquire_for(AZStd::chrono::milliseconds(m_pollingPeriodInMS));
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
|
||||
#include <Request/IAWSGameLiftRequests.h>
|
||||
#include <Request/AWSGameLiftMatchmakingRequestBus.h>
|
||||
|
||||
#include <aws/gamelift/model/MatchmakingTicket.h>
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <AWSCoreBus.h>
|
||||
#include <Credential/AWSCredentialBus.h>
|
||||
#include <Framework/AWSApiJobConfig.h>
|
||||
#include <ResourceMapping/AWSResourceMappingBus.h>
|
||||
|
||||
#include <AWSGameLiftClientManager.h>
|
||||
@@ -75,7 +76,15 @@ namespace AWSGameLift
|
||||
bool AWSGameLiftClientManager::ConfigureGameLiftClient(const AZStd::string& region)
|
||||
{
|
||||
AZ::Interface<IAWSGameLiftInternalRequests>::Get()->SetGameLiftClient(nullptr);
|
||||
|
||||
Aws::Client::ClientConfiguration clientConfig;
|
||||
AWSCore::AwsApiJobConfig* defaultConfig = nullptr;
|
||||
AWSCore::AWSCoreRequestBus::BroadcastResult(defaultConfig, &AWSCore::AWSCoreRequests::GetDefaultConfig);
|
||||
if (defaultConfig)
|
||||
{
|
||||
clientConfig = defaultConfig->GetClientConfiguration();
|
||||
}
|
||||
|
||||
// Set up client endpoint or region
|
||||
AZStd::string localEndpoint = "";
|
||||
#if defined(AWSGAMELIFT_DEV)
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzFramework/Matchmaking/MatchmakingNotifications.h>
|
||||
|
||||
#include <Request/IAWSGameLiftRequests.h>
|
||||
#include <Request/AWSGameLiftRequestBus.h>
|
||||
#include <Request/AWSGameLiftSessionRequestBus.h>
|
||||
#include <Request/AWSGameLiftMatchmakingRequestBus.h>
|
||||
|
||||
namespace AWSGameLift
|
||||
{
|
||||
@@ -23,22 +26,37 @@ namespace AWSGameLift
|
||||
struct AWSGameLiftStartMatchmakingRequest;
|
||||
struct AWSGameLiftStopMatchmakingRequest;
|
||||
|
||||
// MatchAcceptanceNotificationBus EBus handler for scripting
|
||||
class AWSGameLiftMatchAcceptanceNotificationBusHandler
|
||||
: public AzFramework::MatchAcceptanceNotificationBus::Handler
|
||||
// MatchmakingNotificationBus EBus handler for scripting
|
||||
class AWSGameLiftMatchmakingNotificationBusHandler
|
||||
: public AzFramework::MatchmakingNotificationBus::Handler
|
||||
, public AZ::BehaviorEBusHandler
|
||||
{
|
||||
public:
|
||||
AZ_EBUS_BEHAVIOR_BINDER(
|
||||
AWSGameLiftMatchAcceptanceNotificationBusHandler,
|
||||
AWSGameLiftMatchmakingNotificationBusHandler,
|
||||
"{CBE057D3-F5CE-46D3-B02D-8A6A1446B169}",
|
||||
AZ::SystemAllocator,
|
||||
OnMatchAcceptance);
|
||||
OnMatchAcceptance, OnMatchComplete, OnMatchError, OnMatchFailure);
|
||||
|
||||
void OnMatchAcceptance() override
|
||||
{
|
||||
Call(FN_OnMatchAcceptance);
|
||||
}
|
||||
|
||||
void OnMatchComplete() override
|
||||
{
|
||||
Call(FN_OnMatchComplete);
|
||||
}
|
||||
|
||||
void OnMatchError() override
|
||||
{
|
||||
Call(FN_OnMatchError);
|
||||
}
|
||||
|
||||
void OnMatchFailure() override
|
||||
{
|
||||
Call(FN_OnMatchFailure);
|
||||
}
|
||||
};
|
||||
|
||||
// MatchmakingAsyncRequestNotificationBus EBus handler for scripting
|
||||
|
||||
+18
-17
@@ -65,13 +65,6 @@ namespace AWSGameLift
|
||||
->Event("CreatePlayerId", &AWSGameLiftRequestBus::Events::CreatePlayerId,
|
||||
{ { { "IncludeBrackets", "" },
|
||||
{ "IncludeDashes", "" } } });
|
||||
|
||||
behaviorContext->EBus<AWSGameLiftMatchmakingEventRequestBus>("AWSGameLiftMatchmakingEventRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Event("StartPolling", &AWSGameLiftMatchmakingEventRequestBus::Events::StartPolling,
|
||||
{ { { "TicketId", "" },
|
||||
{ "PlayerId", "" } } })
|
||||
->Event("StopPolling", &AWSGameLiftMatchmakingEventRequestBus::Events::StopPolling);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +121,7 @@ namespace AWSGameLift
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<AWSGameLiftMatchmakingAsyncRequestBus>("AWSGameLiftMatchmakingAsyncRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Matchmaking")
|
||||
->Event("AcceptMatchAsync", &AWSGameLiftMatchmakingAsyncRequestBus::Events::AcceptMatchAsync,
|
||||
{ { { "AcceptMatchRequest", "" } } })
|
||||
->Event("StartMatchmakingAsync", &AWSGameLiftMatchmakingAsyncRequestBus::Events::StartMatchmakingAsync,
|
||||
@@ -137,20 +130,28 @@ namespace AWSGameLift
|
||||
{ { { "StopMatchmakingRequest", "" } } });
|
||||
|
||||
behaviorContext->EBus<AzFramework::MatchmakingAsyncRequestNotificationBus>("AWSGameLiftMatchmakingAsyncRequestNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Matchmaking")
|
||||
->Handler<AWSGameLiftMatchmakingAsyncRequestNotificationBusHandler>();
|
||||
|
||||
behaviorContext->EBus<AWSGameLiftMatchmakingRequestBus>("AWSGameLiftMatchmakingRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Event("AcceptMatch", &AWSGameLiftMatchmakingRequestBus::Events::AcceptMatch, { { { "AcceptMatchRequest", "" } } })
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Matchmaking")
|
||||
->Event("AcceptMatch", &AWSGameLiftMatchmakingRequestBus::Events::AcceptMatch,
|
||||
{ { { "AcceptMatchRequest", "" } } })
|
||||
->Event("StartMatchmaking", &AWSGameLiftMatchmakingRequestBus::Events::StartMatchmaking,
|
||||
{ { { "StartMatchmakingRequest", "" } } })
|
||||
->Event("StopMatchmaking", &AWSGameLiftMatchmakingRequestBus::Events::StopMatchmaking,
|
||||
{ { { "StopMatchmakingRequest", "" } } });
|
||||
|
||||
behaviorContext->EBus<AzFramework::MatchAcceptanceNotificationBus>("AWSGameLiftMatchAcceptanceNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Handler<AWSGameLiftMatchAcceptanceNotificationBusHandler>();
|
||||
behaviorContext->EBus<AWSGameLiftMatchmakingEventRequestBus>("AWSGameLiftMatchmakingEventRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Matchmaking")
|
||||
->Event("StartPolling", &AWSGameLiftMatchmakingEventRequestBus::Events::StartPolling,
|
||||
{ { { "TicketId", "" },
|
||||
{ "PlayerId", "" } } })
|
||||
->Event("StopPolling", &AWSGameLiftMatchmakingEventRequestBus::Events::StopPolling);
|
||||
|
||||
behaviorContext->EBus<AzFramework::MatchmakingNotificationBus>("AWSGameLiftMatchmakingNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Matchmaking")
|
||||
->Handler<AWSGameLiftMatchmakingNotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ namespace AWSGameLift
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<AWSGameLiftSessionAsyncRequestBus>("AWSGameLiftSessionAsyncRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Session")
|
||||
->Event("CreateSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::CreateSessionAsync,
|
||||
{ { { "CreateSessionRequest", "" } } })
|
||||
->Event("JoinSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::JoinSessionAsync, { { { "JoinSessionRequest", "" } } })
|
||||
@@ -175,11 +176,11 @@ namespace AWSGameLift
|
||||
->Event("LeaveSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::LeaveSessionAsync);
|
||||
|
||||
behaviorContext->EBus<AzFramework::SessionAsyncRequestNotificationBus>("AWSGameLiftSessionAsyncRequestNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Session")
|
||||
->Handler<AWSGameLiftSessionAsyncRequestNotificationBusHandler>();
|
||||
|
||||
behaviorContext->EBus<AWSGameLiftSessionRequestBus>("AWSGameLiftSessionRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Session")
|
||||
->Event("CreateSession", &AWSGameLiftSessionRequestBus::Events::CreateSession, { { { "CreateSessionRequest", "" } } })
|
||||
->Event("JoinSession", &AWSGameLiftSessionRequestBus::Events::JoinSession, { { { "JoinSessionRequest", "" } } })
|
||||
->Event("SearchSessions", &AWSGameLiftSessionRequestBus::Events::SearchSessions, { { { "SearchSessionsRequest", "" } } })
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ namespace Aws
|
||||
|
||||
namespace AWSGameLift
|
||||
{
|
||||
//! IAWSGameLiftRequests
|
||||
//! IAWSGameLiftInternalRequests
|
||||
//! GameLift Gem internal interface which is used to fetch gem global GameLift client
|
||||
class IAWSGameLiftInternalRequests
|
||||
{
|
||||
|
||||
+60
-44
@@ -82,27 +82,12 @@ protected:
|
||||
m_gameliftClientMockPtr.reset();
|
||||
}
|
||||
|
||||
void WaitForProcessFinish(uint64_t expectedNum)
|
||||
void WaitForProcessFinish(AZStd::function<bool()> processFinishCondition)
|
||||
{
|
||||
int processingTime = 0;
|
||||
while (processingTime < TEST_WAIT_MAXIMUM_TIME_MS)
|
||||
{
|
||||
if (::UnitTest::TestRunner::Instance().m_numAssertsFailed == expectedNum)
|
||||
{
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(expectedNum);
|
||||
return;
|
||||
}
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(TEST_WAIT_BUFFER_TIME_MS));
|
||||
processingTime += TEST_WAIT_BUFFER_TIME_MS;
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForProcessFinish()
|
||||
{
|
||||
int processingTime = 0;
|
||||
while (processingTime < TEST_WAIT_MAXIMUM_TIME_MS)
|
||||
{
|
||||
if (m_gameliftClientTicketTracker->IsTrackerIdle())
|
||||
if (processFinishCondition())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -119,19 +104,27 @@ public:
|
||||
TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithoutClientSetup_GetExpectedErrors)
|
||||
{
|
||||
AZ::Interface<IAWSGameLiftInternalRequests>::Get()->SetGameLiftClient(nullptr);
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; });
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1);
|
||||
ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_MultipleCallsWithoutClientSetup_GetExpectedErrors)
|
||||
{
|
||||
AZ::Interface<IAWSGameLiftInternalRequests>::Get()->SetGameLiftClient(nullptr);
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; });
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1);
|
||||
ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -144,9 +137,12 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButWithFailedOu
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; });
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1);
|
||||
ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -161,9 +157,12 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithMoreThanOne
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([](){ return ::UnitTest::TestRunner::Instance().m_numAssertsFailed == 1; });
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchError == 1);
|
||||
ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -189,13 +188,15 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithCompleteSta
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
SessionHandlingClientRequestsMock handlerMock;
|
||||
EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_))
|
||||
SessionHandlingClientRequestsMock sessionHandlerMock;
|
||||
EXPECT_CALL(sessionHandlerMock, RequestPlayerJoinSession(::testing::_))
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish();
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchComplete == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -217,9 +218,12 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButNoPlayerSess
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchComplete == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -245,14 +249,17 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButFailedToJoin
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
SessionHandlingClientRequestsMock handlerMock;
|
||||
EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_))
|
||||
SessionHandlingClientRequestsMock sessionHandlerMock;
|
||||
EXPECT_CALL(sessionHandlerMock, RequestPlayerJoinSession(::testing::_))
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(false));
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchComplete == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -269,9 +276,10 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButTicketTimeOu
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchFailure == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -288,9 +296,10 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButTicketFailed
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchFailure == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -307,9 +316,10 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButTicketCancel
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(outcome));
|
||||
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish(1);
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchFailure == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -342,13 +352,15 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallAndTicketComple
|
||||
.WillOnce(::testing::Return(outcome1))
|
||||
.WillOnce(::testing::Return(outcome2));
|
||||
|
||||
SessionHandlingClientRequestsMock handlerMock;
|
||||
EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_))
|
||||
SessionHandlingClientRequestsMock sessionHandlerMock;
|
||||
EXPECT_CALL(sessionHandlerMock, RequestPlayerJoinSession(::testing::_))
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish();
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchComplete == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -365,7 +377,9 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_RequiresAcceptanceA
|
||||
connectionInfo.SetIpAddress("DummyIpAddress");
|
||||
connectionInfo.SetPort(123);
|
||||
connectionInfo.AddMatchedPlayerSessions(
|
||||
Aws::GameLift::Model::MatchedPlayerSession().WithPlayerId("player1").WithPlayerSessionId("playersession1"));
|
||||
Aws::GameLift::Model::MatchedPlayerSession()
|
||||
.WithPlayerId("player1")
|
||||
.WithPlayerSessionId("playersession1"));
|
||||
|
||||
Aws::GameLift::Model::MatchmakingTicket ticket2;
|
||||
ticket2.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED);
|
||||
@@ -379,13 +393,15 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_RequiresAcceptanceA
|
||||
.WillOnce(::testing::Return(outcome1))
|
||||
.WillOnce(::testing::Return(outcome2));
|
||||
|
||||
MatchAcceptanceNotificationsHandlerMock handlerMock1;
|
||||
EXPECT_CALL(handlerMock1, OnMatchAcceptance()).Times(1);
|
||||
|
||||
SessionHandlingClientRequestsMock handlerMock2;
|
||||
EXPECT_CALL(handlerMock2, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(true));
|
||||
SessionHandlingClientRequestsMock sessionHandlerMock;
|
||||
EXPECT_CALL(sessionHandlerMock, RequestPlayerJoinSession(::testing::_))
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
MatchmakingNotificationsHandlerMock matchmakingHandlerMock;
|
||||
m_gameliftClientTicketTracker->StartPolling("ticket1", "player1");
|
||||
WaitForProcessFinish();
|
||||
WaitForProcessFinish([this](){ return m_gameliftClientTicketTracker->IsTrackerIdle(); });
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchAcceptance == 1);
|
||||
ASSERT_TRUE(matchmakingHandlerMock.m_numMatchComplete == 1);
|
||||
ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle());
|
||||
}
|
||||
|
||||
@@ -266,6 +266,8 @@ const char* const AWSGameLiftClientManagerTest::DummyPlayerId = "dummyPlayerId";
|
||||
|
||||
TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutRegion_GetFalseAsResult)
|
||||
{
|
||||
AWSCoreRequestsHandlerMock coreHandlerMock;
|
||||
EXPECT_CALL(coreHandlerMock, GetDefaultConfig()).Times(1).WillOnce(nullptr);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
auto result = m_gameliftClientManager->ConfigureGameLiftClient("");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message
|
||||
@@ -274,6 +276,8 @@ TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutRegion_G
|
||||
|
||||
TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutCredential_GetFalseAsResult)
|
||||
{
|
||||
AWSCoreRequestsHandlerMock coreHandlerMock;
|
||||
EXPECT_CALL(coreHandlerMock, GetDefaultConfig()).Times(1).WillOnce(nullptr);
|
||||
AWSResourceMappingRequestsHandlerMock handlerMock;
|
||||
EXPECT_CALL(handlerMock, GetDefaultRegion()).Times(1).WillOnce(::testing::Return("us-west-2"));
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
@@ -284,6 +288,8 @@ TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutCredenti
|
||||
|
||||
TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithRegionAndCredential_GetTrueAsResult)
|
||||
{
|
||||
AWSCoreRequestsHandlerMock coreHandlerMock;
|
||||
EXPECT_CALL(coreHandlerMock, GetDefaultConfig()).Times(1).WillOnce(nullptr);
|
||||
AWSCredentialRequestsHandlerMock handlerMock;
|
||||
EXPECT_CALL(handlerMock, GetCredentialsProvider())
|
||||
.Times(1)
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzFramework/Matchmaking/MatchmakingNotifications.h>
|
||||
#include <AzFramework/Session/ISessionRequests.h>
|
||||
#include <AzFramework/Session/ISessionHandlingRequests.h>
|
||||
#include <AzFramework/Matchmaking/IMatchmakingRequests.h>
|
||||
#include <AzFramework/Matchmaking/MatchmakingNotifications.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
@@ -76,21 +76,44 @@ public:
|
||||
MOCK_METHOD0(OnStopMatchmakingAsyncComplete, void());
|
||||
};
|
||||
|
||||
class MatchAcceptanceNotificationsHandlerMock
|
||||
: public AzFramework::MatchAcceptanceNotificationBus::Handler
|
||||
class MatchmakingNotificationsHandlerMock
|
||||
: public AzFramework::MatchmakingNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
MatchAcceptanceNotificationsHandlerMock()
|
||||
MatchmakingNotificationsHandlerMock()
|
||||
{
|
||||
AzFramework::MatchAcceptanceNotificationBus::Handler::BusConnect();
|
||||
AzFramework::MatchmakingNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
~MatchAcceptanceNotificationsHandlerMock()
|
||||
~MatchmakingNotificationsHandlerMock()
|
||||
{
|
||||
AzFramework::MatchAcceptanceNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::MatchmakingNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD0(OnMatchAcceptance, void());
|
||||
void OnMatchAcceptance() override
|
||||
{
|
||||
++m_numMatchAcceptance;
|
||||
}
|
||||
|
||||
void OnMatchComplete() override
|
||||
{
|
||||
++m_numMatchComplete;
|
||||
}
|
||||
|
||||
void OnMatchError() override
|
||||
{
|
||||
++m_numMatchError;
|
||||
}
|
||||
|
||||
void OnMatchFailure() override
|
||||
{
|
||||
++m_numMatchFailure;
|
||||
}
|
||||
|
||||
int m_numMatchAcceptance = 0;
|
||||
int m_numMatchComplete = 0;
|
||||
int m_numMatchError = 0;
|
||||
int m_numMatchFailure = 0;
|
||||
};
|
||||
|
||||
class SessionAsyncRequestNotificationsHandlerMock
|
||||
|
||||
@@ -17,7 +17,9 @@ set(FILES
|
||||
Include/Request/AWSGameLiftSearchSessionsRequest.h
|
||||
Include/Request/AWSGameLiftStartMatchmakingRequest.h
|
||||
Include/Request/AWSGameLiftStopMatchmakingRequest.h
|
||||
Include/Request/IAWSGameLiftRequests.h
|
||||
Include/Request/AWSGameLiftRequestBus.h
|
||||
Include/Request/AWSGameLiftSessionRequestBus.h
|
||||
Include/Request/AWSGameLiftMatchmakingRequestBus.h
|
||||
Source/Activity/AWSGameLiftActivityUtils.cpp
|
||||
Source/Activity/AWSGameLiftActivityUtils.h
|
||||
Source/Activity/AWSGameLiftAcceptMatchActivity.cpp
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
@@ -45,7 +45,7 @@ namespace AWSGameLift
|
||||
virtual bool StopMatchBackfill(const AZStd::string& ticketId) = 0;
|
||||
};
|
||||
|
||||
// IAWSGameLiftServerRequests EBus wrapper for scripting
|
||||
// IAWSGameLiftServerRequests EBus wrapper
|
||||
class AWSGameLiftServerRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <AzFramework/Session/SessionConfig.h>
|
||||
|
||||
#include <AWSGameLiftPlayer.h>
|
||||
#include <Request/IAWSGameLiftServerRequests.h>
|
||||
#include <Request/AWSGameLiftServerRequestBus.h>
|
||||
|
||||
namespace AWSGameLift
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ set(FILES
|
||||
../AWSGameLiftCommon/Include/AWSGameLiftPlayer.h
|
||||
../AWSGameLiftCommon/Source/AWSGameLiftPlayer.cpp
|
||||
../AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h
|
||||
Include/Request/IAWSGameLiftServerRequests.h
|
||||
Include/Request/AWSGameLiftServerRequestBus.h
|
||||
Source/AWSGameLiftServerManager.cpp
|
||||
Source/AWSGameLiftServerManager.h
|
||||
Source/AWSGameLiftServerSystemComponent.cpp
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace AWSMetrics
|
||||
static const unsigned int DesiredMaxWorkers = 2;
|
||||
|
||||
MetricsManager();
|
||||
~MetricsManager();
|
||||
virtual ~MetricsManager();
|
||||
|
||||
//! Initializing the metrics manager
|
||||
//! @return Whether the operation is successful.
|
||||
@@ -93,6 +93,12 @@ namespace AWSMetrics
|
||||
//! @return Total number of requests for sending metrics events.
|
||||
int GetNumTotalRequests() const;
|
||||
|
||||
protected:
|
||||
//! Send metrics to a local file.
|
||||
//! @param metricsQueue metricsQueue Metrics queue that stores the metrics.
|
||||
//! @return Outcome of the operation.
|
||||
virtual AZ::Outcome<void, AZStd::string> SendMetricsToFile(AZStd::shared_ptr<MetricsQueue> metricsQueue);
|
||||
|
||||
private:
|
||||
//! Job management
|
||||
void SetupJobContext();
|
||||
@@ -112,11 +118,6 @@ namespace AWSMetrics
|
||||
//! @param metricsQueue Metrics events to send.
|
||||
void SendMetricsToServiceApiAsync(const MetricsQueue& metricsQueue);
|
||||
|
||||
//! Send metrics to a local file.
|
||||
//! @param metricsQueue metricsQueue Metrics queue that stores the metrics.
|
||||
//! @return Outcome of the operation.
|
||||
AZ::Outcome<void, AZStd::string> SendMetricsToFile(AZStd::shared_ptr<MetricsQueue> metricsQueue);
|
||||
|
||||
//! Push metrics events to the front of the queue for retry.
|
||||
//! @param metricsEventsForRetry Metrics events for retry.
|
||||
void PushMetricsForRetry(MetricsQueue& metricsEventsForRetry);
|
||||
|
||||
@@ -139,11 +139,6 @@ namespace AWSMetrics
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveDirectory(const AZStd::string& directory)
|
||||
{
|
||||
return AZ::IO::SystemFile::DeleteDir(directory.c_str());
|
||||
}
|
||||
|
||||
AZ::IO::FileIOBase* m_priorFileIO = nullptr;
|
||||
AZ::IO::FileIOBase* m_localFileIO = nullptr;
|
||||
|
||||
|
||||
@@ -75,6 +75,23 @@ namespace AZ
|
||||
|
||||
namespace AWSMetrics
|
||||
{
|
||||
class MetricsManagerMock
|
||||
: public MetricsManager
|
||||
{
|
||||
private:
|
||||
AZ::Outcome<void, AZStd::string> SendMetricsToFile(AZStd::shared_ptr<MetricsQueue> metricsQueue) override
|
||||
{
|
||||
if (AZ::IO::FileIOBase::GetInstance())
|
||||
{
|
||||
return AZ::Success();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Failure(AZStd::string{ "Invalid File IO" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AWSMetricsNotificationBusMock
|
||||
: protected AWSMetricsNotificationBus::Handler
|
||||
{
|
||||
@@ -134,13 +151,11 @@ namespace AWSMetrics
|
||||
AWSMetricsGemAllocatorFixture::SetUp();
|
||||
AWSMetricsRequestBus::Handler::BusConnect();
|
||||
|
||||
m_metricsManager = AZStd::make_unique<MetricsManager>();
|
||||
m_metricsManager = AZStd::make_unique<MetricsManagerMock>();
|
||||
AZStd::string configFilePath = CreateClientConfigFile(true, (double) TestMetricsEventSizeInBytes / MbToBytes * 2, DefaultFlushPeriodInSeconds, 0);
|
||||
m_settingsRegistry->MergeSettingsFile(configFilePath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {});
|
||||
m_metricsManager->Init();
|
||||
|
||||
RemoveFile(m_metricsManager->GetMetricsFilePath());
|
||||
|
||||
ReplaceLocalFileIOWithMockIO();
|
||||
}
|
||||
|
||||
@@ -149,8 +164,6 @@ namespace AWSMetrics
|
||||
RevertMockIOToLocalFileIO();
|
||||
|
||||
RemoveFile(GetDefaultTestFilePath());
|
||||
RemoveFile(m_metricsManager->GetMetricsFilePath());
|
||||
RemoveDirectory(m_metricsManager->GetMetricsFileDirectory());
|
||||
|
||||
m_metricsManager.reset();
|
||||
|
||||
@@ -233,7 +246,7 @@ namespace AWSMetrics
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<MetricsManager> m_metricsManager;
|
||||
AZStd::unique_ptr<MetricsManagerMock> m_metricsManager;
|
||||
AWSMetricsNotificationBusMock m_notifications;
|
||||
|
||||
AZ::IO::FileIOBase* m_fileIOMock;
|
||||
|
||||
+9
-7
@@ -111,16 +111,18 @@ void DirectionalLightShadow::GetShadowCoords(
|
||||
float3 worldPosition,
|
||||
out float3 shadowCoords[ViewSrg::MaxCascadeCount])
|
||||
{
|
||||
const float4x4 depthBiasMatrices[ViewSrg::MaxCascadeCount] =
|
||||
ViewSrg::m_directionalLightShadows[lightIndex].m_depthBiasMatrices;
|
||||
const uint cascadeCount = ViewSrg::m_directionalLightShadows[lightIndex].m_cascadeCount;
|
||||
|
||||
const float shadowBias = ViewSrg::m_directionalLightShadows[lightIndex].m_shadowBias;
|
||||
const float4x4 lightViewToShadowmapMatrices[ViewSrg::MaxCascadeCount] = ViewSrg::m_directionalLightShadows[lightIndex].m_lightViewToShadowmapMatrices;
|
||||
const float4x4 worldToLightViewMatrices[ViewSrg::MaxCascadeCount] = ViewSrg::m_directionalLightShadows[lightIndex].m_worldToLightViewMatrices;
|
||||
|
||||
for (uint index = 0; index < cascadeCount; ++index)
|
||||
{
|
||||
const float4x4 depthBiasMatrix = depthBiasMatrices[index];
|
||||
const float4 shadowCoordHomogeneous = mul(depthBiasMatrix,
|
||||
float4(worldPosition, 1.));
|
||||
shadowCoords[index] = shadowCoordHomogeneous.xyz / shadowCoordHomogeneous.w;
|
||||
float4 lightSpacePos = mul(worldToLightViewMatrices[index], float4(worldPosition, 1.));
|
||||
lightSpacePos.z += shadowBias;
|
||||
|
||||
const float4 clipSpacePos = mul(lightViewToShadowmapMatrices[index], lightSpacePos);
|
||||
shadowCoords[index] = clipSpacePos.xyz / clipSpacePos.w;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,18 +102,19 @@ partial ShaderResourceGroup ViewSrg
|
||||
|
||||
struct DirectionalLightShadow
|
||||
{
|
||||
float4x4 m_depthBiasMatrices[MaxCascadeCount];
|
||||
float4x4 m_lightViewToShadowmapMatrices[MaxCascadeCount];
|
||||
float4x4 m_worldToLightViewMatrices[MaxCascadeCount];
|
||||
float m_slopeBiasBase[MaxCascadeCount];
|
||||
float m_boundaryScale;
|
||||
uint m_shadowmapSize; // width and height of shadowmap
|
||||
uint m_cascadeCount;
|
||||
float m_shadowBias;
|
||||
uint m_predictionSampleCount;
|
||||
uint m_filteringSampleCount;
|
||||
uint m_debugFlags;
|
||||
uint m_shadowFilterMethod;
|
||||
float m_far_minus_near;
|
||||
float3 m_padding;
|
||||
};
|
||||
|
||||
enum ShadowFilterMethod
|
||||
|
||||
+3
@@ -157,6 +157,9 @@ namespace AZ
|
||||
//! Sets whether the directional shadowmap should use receiver plane bias.
|
||||
//! This attempts to reduce shadow acne when using large pcf filters.
|
||||
virtual void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) = 0;
|
||||
|
||||
//! Reduces acne by applying a small amount of bias along shadow-space z.
|
||||
virtual void SetShadowBias(LightHandle handle, float bias) = 0;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+9
-4
@@ -589,6 +589,15 @@ namespace AZ
|
||||
m_shadowProperties.GetData(handle.GetIndex()).m_isReceiverPlaneBiasEnabled = enable;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::SetShadowBias(LightHandle handle, float bias)
|
||||
{
|
||||
for (auto& it : m_shadowData)
|
||||
{
|
||||
it.second.GetData(handle.GetIndex()).m_shadowBias = bias;
|
||||
}
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
|
||||
{
|
||||
PrepareForChangingRenderPipelineAndCameraView();
|
||||
@@ -1522,10 +1531,6 @@ namespace AZ
|
||||
|
||||
for (uint16_t cascadeIndex = 0; cascadeIndex < GetCascadeCount(handle); ++cascadeIndex)
|
||||
{
|
||||
const Matrix4x4& worldToLightClipMatrix = property.m_segments.at(cameraView)[cascadeIndex].m_view->GetWorldToClipMatrix();
|
||||
const Matrix4x4 depthBiasMatrix = Shadow::GetClipToShadowmapTextureMatrix() * worldToLightClipMatrix;
|
||||
shadowData.m_depthBiasMatrices[cascadeIndex] = depthBiasMatrix;
|
||||
|
||||
const Matrix4x4& lightViewToLightClipMatrix = property.m_segments.at(cameraView)[cascadeIndex].m_view->GetViewToClipMatrix();
|
||||
const Matrix4x4 lightViewToShadowmapMatrix = Shadow::GetClipToShadowmapTextureMatrix() * lightViewToLightClipMatrix;
|
||||
shadowData.m_lightViewToShadowmapMatrices[cascadeIndex] = lightViewToShadowmapMatrix;
|
||||
|
||||
@@ -72,12 +72,6 @@ namespace AZ
|
||||
// [GFX TODO][ATOM-15172] Look into compacting struct DirectionalLightShadowData
|
||||
struct DirectionalLightShadowData
|
||||
{
|
||||
AZStd::array<Matrix4x4, Shadow::MaxNumberOfCascades> m_depthBiasMatrices =
|
||||
{ {
|
||||
Matrix4x4::CreateIdentity(),
|
||||
Matrix4x4::CreateIdentity(),
|
||||
Matrix4x4::CreateIdentity(),
|
||||
Matrix4x4::CreateIdentity() } };
|
||||
AZStd::array<Matrix4x4, Shadow::MaxNumberOfCascades> m_lightViewToShadowmapMatrices =
|
||||
{ {
|
||||
Matrix4x4::CreateIdentity(),
|
||||
@@ -97,11 +91,14 @@ namespace AZ
|
||||
float m_boundaryScale = 0.f;
|
||||
uint32_t m_shadowmapSize = 1; // width and height of shadowmap
|
||||
uint32_t m_cascadeCount = 1;
|
||||
// Reduce acne by applying a small amount of bias to apply along shadow-space z.
|
||||
float m_shadowBias = 0.0f;
|
||||
uint32_t m_predictionSampleCount = 0;
|
||||
uint32_t m_filteringSampleCount = 0;
|
||||
uint32_t m_debugFlags = 0;
|
||||
uint32_t m_shadowFilterMethod = 0;
|
||||
float m_far_minus_near = 0;
|
||||
float m_padding[3];
|
||||
};
|
||||
|
||||
class DirectionalLightFeatureProcessor final
|
||||
@@ -218,6 +215,7 @@ namespace AZ
|
||||
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
|
||||
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) override;
|
||||
void SetShadowBias(LightHandle handle, float bias) override;
|
||||
|
||||
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
|
||||
uint32_t GetLightCount() const;
|
||||
|
||||
+8
@@ -168,6 +168,14 @@ namespace AZ
|
||||
//! Sets whether the directional shadowmap should use receiver plane bias.
|
||||
//! @param enable flag specifying whether to enable the receiver plane bias feature
|
||||
virtual void SetShadowReceiverPlaneBiasEnabled(bool enable) = 0;
|
||||
|
||||
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
|
||||
//! @return Returns the amount of bias to apply.
|
||||
virtual float GetShadowBias() const = 0;
|
||||
|
||||
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
|
||||
//! @param Sets the amount of bias to apply.
|
||||
virtual void SetShadowBias(float bias) = 0;
|
||||
};
|
||||
using DirectionalLightRequestBus = EBus<DirectionalLightRequests>;
|
||||
|
||||
|
||||
+3
@@ -109,6 +109,9 @@ namespace AZ
|
||||
//! This uses partial derivatives to reduce shadow acne when using large pcf kernels.
|
||||
bool m_receiverPlaneBiasEnabled = true;
|
||||
|
||||
//! Reduces shadow acne by applying a small amount of offset along shadow-space z.
|
||||
float m_shadowBias = 0.0f;
|
||||
|
||||
bool IsSplitManual() const;
|
||||
bool IsSplitAutomatic() const;
|
||||
bool IsCascadeCorrectionDisabled() const;
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ namespace AZ
|
||||
->Field("IsDebugColoringEnabled", &DirectionalLightComponentConfig::m_isDebugColoringEnabled)
|
||||
->Field("ShadowFilterMethod", &DirectionalLightComponentConfig::m_shadowFilterMethod)
|
||||
->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount)
|
||||
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled);
|
||||
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled)
|
||||
->Field("Shadow Bias", &DirectionalLightComponentConfig::m_shadowBias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-1
@@ -84,6 +84,8 @@ namespace AZ
|
||||
->Event("SetFilteringSampleCount", &DirectionalLightRequestBus::Events::SetFilteringSampleCount)
|
||||
->Event("GetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::GetShadowReceiverPlaneBiasEnabled)
|
||||
->Event("SetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::SetShadowReceiverPlaneBiasEnabled)
|
||||
->Event("GetShadowBias", &DirectionalLightRequestBus::Events::GetShadowBias)
|
||||
->Event("SetShadowBias", &DirectionalLightRequestBus::Events::SetShadowBias)
|
||||
->VirtualProperty("Color", "GetColor", "SetColor")
|
||||
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
|
||||
->VirtualProperty("AngularDiameter", "GetAngularDiameter", "SetAngularDiameter")
|
||||
@@ -98,7 +100,8 @@ namespace AZ
|
||||
->VirtualProperty("DebugColoringEnabled", "GetDebugColoringEnabled", "SetDebugColoringEnabled")
|
||||
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
|
||||
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
|
||||
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled");
|
||||
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled")
|
||||
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias");
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -406,6 +409,20 @@ namespace AZ
|
||||
return aznumeric_cast<uint32_t>(m_configuration.m_filteringSampleCount);
|
||||
}
|
||||
|
||||
void DirectionalLightComponentController::SetShadowBias(float bias)
|
||||
{
|
||||
m_configuration.m_shadowBias = bias;
|
||||
if (m_featureProcessor)
|
||||
{
|
||||
m_featureProcessor->SetShadowBias(m_lightHandle, bias);
|
||||
}
|
||||
}
|
||||
|
||||
float DirectionalLightComponentController::GetShadowBias() const
|
||||
{
|
||||
return m_configuration.m_shadowBias;
|
||||
}
|
||||
|
||||
void DirectionalLightComponentController::SetFilteringSampleCount(uint32_t count)
|
||||
{
|
||||
const uint16_t count16 = GetMin(Shadow::MaxPcfSamplingCount, aznumeric_cast<uint16_t>(count));
|
||||
@@ -499,6 +516,7 @@ namespace AZ
|
||||
SetViewFrustumCorrectionEnabled(m_configuration.m_isCascadeCorrectionEnabled);
|
||||
SetDebugColoringEnabled(m_configuration.m_isDebugColoringEnabled);
|
||||
SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
|
||||
SetShadowBias(m_configuration.m_shadowBias);
|
||||
SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
|
||||
SetShadowReceiverPlaneBiasEnabled(m_configuration.m_receiverPlaneBiasEnabled);
|
||||
|
||||
|
||||
+2
@@ -80,6 +80,8 @@ namespace AZ
|
||||
void SetFilteringSampleCount(uint32_t count) override;
|
||||
bool GetShadowReceiverPlaneBiasEnabled() const override;
|
||||
void SetShadowReceiverPlaneBiasEnabled(bool enable) override;
|
||||
float GetShadowBias() const override;
|
||||
void SetShadowBias(float width) override;
|
||||
|
||||
private:
|
||||
friend class EditorDirectionalLightComponent;
|
||||
|
||||
+13
-4
@@ -133,8 +133,8 @@ namespace AZ
|
||||
->EnumAttribute(ShadowFilterMethod::Esm, "ESM")
|
||||
->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF")
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count",
|
||||
"This is used only when the pixel is predicted as on the boundary. "
|
||||
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count\n",
|
||||
"This is used only when the pixel is predicted as on the boundary.\n"
|
||||
"Specific to PCF and ESM+PCF.")
|
||||
->Attribute(Edit::Attributes::Min, 4)
|
||||
->Attribute(Edit::Attributes::Max, 64)
|
||||
@@ -142,10 +142,19 @@ namespace AZ
|
||||
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
|
||||
->DataElement(
|
||||
Edit::UIHandlers::CheckBox, &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled,
|
||||
"Shadow Receiver Plane Bias Enable",
|
||||
"Shadow Receiver Plane Bias Enable\n",
|
||||
"This reduces shadow acne when using large pcf kernels.")
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled);
|
||||
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
|
||||
->DataElement(
|
||||
Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_shadowBias,
|
||||
"Shadow Bias\n",
|
||||
"Reduces acne by applying a fixed bias along z in shadow-space.\n"
|
||||
"If this is 0, no biasing is applied.")
|
||||
->Attribute(Edit::Attributes::Min, 0.f)
|
||||
->Attribute(Edit::Attributes::Max, 0.2)
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,44 @@ def process_add_o3de_repo(file_name: str or pathlib.Path,
|
||||
return 0
|
||||
|
||||
|
||||
def get_gem_json_paths_from_cached_repo(repo_uri: str) -> list:
|
||||
url = f'{repo_uri}/repo.json'
|
||||
repo_sha256 = hashlib.sha256(url.encode())
|
||||
cache_folder = manifest.get_o3de_cache_folder()
|
||||
cache_filename = cache_folder / str(repo_sha256.hexdigest() + '.json')
|
||||
|
||||
gem_list = []
|
||||
|
||||
file_name = pathlib.Path(cache_filename).resolve()
|
||||
if not file_name.is_file():
|
||||
logger.error(f'Could not find cached repo json file for {repo_uri}')
|
||||
return gem_list
|
||||
|
||||
with file_name.open('r') as f:
|
||||
try:
|
||||
repo_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f'{file_name} failed to load: {str(e)}')
|
||||
return gem_list
|
||||
|
||||
# Get list of gems, then add all json paths to the list if they exist in the cache
|
||||
repo_gems = []
|
||||
try:
|
||||
repo_gems.append((repo_data['gems'], 'gem.json'))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for o3de_object_uris, manifest_json in repo_gems:
|
||||
for o3de_object_uri in o3de_object_uris:
|
||||
manifest_json_uri = f'{o3de_object_uri}/{manifest_json}'
|
||||
manifest_json_sha256 = hashlib.sha256(manifest_json_uri.encode())
|
||||
cache_gem_json_filepath = cache_folder / str(manifest_json_sha256.hexdigest() + '.json')
|
||||
if cache_gem_json_filepath.is_file():
|
||||
logger.warn(f'Could not find cached gem json file for {o3de_object_uri} in repo {repo_uri}')
|
||||
gem_list.append(cache_gem_json_filepath)
|
||||
|
||||
return gem_list
|
||||
|
||||
def refresh_repos() -> int:
|
||||
json_data = manifest.load_o3de_manifest()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user