Merge branch 'development' of https://github.com/o3de/o3de into sc-editor-asset-redux

This commit is contained in:
chcurran
2021-11-04 15:58:44 -07:00
337 changed files with 8195 additions and 4099 deletions
@@ -56,15 +56,21 @@ namespace AZ::ComponentApplicationLifecycle
}
bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName)
AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent)
{
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
using Type = AZ::SettingsRegistryInterface::Type;
using NotifyEventHandler = AZ::SettingsRegistryInterface::NotifyEventHandler;
if (!ValidateEvent(settingsRegistry, eventName))
// Some systems may attempt to register a handler before the settings registry has been loaded
// If so, this flag lets them automatically register an event if it hasn't yet been registered.
// RegisterEvent calls validate event.
if ((!autoRegisterEvent && !ValidateEvent(settingsRegistry, eventName)) ||
(autoRegisterEvent && !RegisterEvent(settingsRegistry, eventName)))
{
AZ_Warning("ComponentApplicationLifecycle", false, R"(Cannot register event %.*s. Name does is not a field of object "%.*s".)"
AZ_Warning(
"ComponentApplicationLifecycle", false,
R"(Cannot register event %.*s. Name is not a field of object "%.*s".)"
R"( Please make sure the entry exists in the '<engine-root>/Registry/application_lifecycle_events.setreg")"
" or in *.setreg within the project", AZ_STRING_ARG(eventName), AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey));
return false;
@@ -14,7 +14,7 @@
namespace AZ::ComponentApplicationLifecycle
{
//! Root Key where lifecycle events should be registered under
inline constexpr AZStd::string_view ApplicationLifecycleEventRegistrationKey = "/O3DE/Runtime/Application/LifecycleEvents";
inline constexpr AZStd::string_view ApplicationLifecycleEventRegistrationKey = "/O3DE/Application/LifecycleEvents";
//! Validates that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey
@@ -48,7 +48,9 @@ namespace AZ::ComponentApplicationLifecycle
//! if the specified @eventName passes validation
//! @param callback will be moved into the handler if the specified @eventName is valid
//! @param eventName name of key underneath the ApplicationLifecycleEventRegistrationKey to register
//! @param autoRegisterEvent automatically register this event if it hasn't been registered yet. This is useful
//! when registering a handler before the settings registry has been loaded.
//! @return true if the handler was registered with the SettingsRegistry NotifyEvent
bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName);
AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent = false);
}
@@ -7,4 +7,63 @@
*/
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Debug/ProfilerBus.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h>
#include <AzCore/Settings/SettingsRegistry.h>
namespace AZ::Debug
{
AZStd::string GenerateOutputFile(const char* nameHint)
{
AZ::IO::FixedMaxPathString captureOutput = GetProfilerCaptureLocation();
return AZStd::string::format("%s/capture_%s_%lld.json", captureOutput.c_str(), nameHint, AZStd::GetTimeNowSecond());
}
void ProfilerCaptureFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem)
{
AZStd::string captureFile = GenerateOutputFile("single");
AZLOG_INFO("Setting capture file to %s", captureFile.c_str());
profilerSystem->CaptureFrame(captureFile);
}
}
AZ_CONSOLEFREEFUNC(ProfilerCaptureFrame, AZ::ConsoleFunctorFlags::DontReplicate, "Capture a single frame of profiling data");
void ProfilerStartCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem)
{
AZStd::string captureFile = GenerateOutputFile("multi");
AZLOG_INFO("Setting capture file to %s", captureFile.c_str());
profilerSystem->StartCapture(AZStd::move(captureFile));
}
}
AZ_CONSOLEFREEFUNC(ProfilerStartCapture, AZ::ConsoleFunctorFlags::DontReplicate, "Start a multi-frame capture of profiling data");
void ProfilerEndCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem)
{
profilerSystem->EndCapture();
}
}
AZ_CONSOLEFREEFUNC(ProfilerEndCapture, AZ::ConsoleFunctorFlags::DontReplicate, "End and dump an in-progress continuous capture");
AZ::IO::FixedMaxPathString GetProfilerCaptureLocation()
{
AZ::IO::FixedMaxPathString captureOutput;
if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry)
{
settingsRegistry->Get(captureOutput, RegistryKey_ProfilerCaptureLocation);
}
if (captureOutput.empty())
{
captureOutput = ProfilerCaptureLocationFallback;
}
return captureOutput;
}
} // namespace AZ::Debug
@@ -9,11 +9,20 @@
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/IO/Path/Path_fwd.h>
#include <AzCore/std/string/string.h>
namespace AZ
{
namespace Debug
{
//! settings registry entry for specifying where to output profiler captures
static constexpr const char* RegistryKey_ProfilerCaptureLocation = "/O3DE/AzCore/Debug/Profiler/CaptureLocation";
//! fallback value in the event the settings registry isn't ready or doesn't contain the key
static constexpr const char* ProfilerCaptureLocationFallback = "@user@/Profiler";
/**
* ProfilerNotifications provides a profiler event interface that can be used to update listeners on profiler status
*/
@@ -23,32 +32,38 @@ namespace AZ
public:
virtual ~ProfilerNotifications() = default;
virtual void OnProfileSystemInitialized() = 0;
//! Notify when the current profiler capture is finished
//! @param result Set to true if it's finished successfully
//! @param info The output file path or error information which depends on the return.
virtual void OnCaptureFinished(bool result, const AZStd::string& info) = 0;
};
using ProfilerNotificationBus = AZ::EBus<ProfilerNotifications>;
enum class ProfileFrameAdvanceType
{
Game,
Render,
Default = Game
};
/**
* ProfilerRequests provides an interface for making profiling system requests
*/
class ProfilerRequests
: public AZ::EBusTraits
{
public:
// Allow multiple threads to concurrently make requests
using MutexType = AZStd::mutex;
AZ_RTTI(ProfilerRequests, "{90AEC117-14C1-4BAE-9704-F916E49EF13F}");
virtual ~ProfilerRequests() = default;
virtual bool IsActive() = 0;
virtual void FrameAdvance(ProfileFrameAdvanceType type) = 0;
//! Getter/setter for the profiler active state
virtual bool IsActive() const = 0;
virtual void SetActive(bool active) = 0;
//! Capture a single frame of profiling data
virtual bool CaptureFrame(const AZStd::string& outputFilePath) = 0;
//! Starting/ending a multi-frame capture of profiling data
virtual bool StartCapture(AZStd::string outputFilePath) = 0;
virtual bool EndCapture() = 0;
};
using ProfilerRequestBus = AZ::EBus<ProfilerRequests>;
}
}
using ProfilerSystemInterface = AZ::Interface<ProfilerRequests>;
//! helper function for getting the profiler capture location from the settings registry that
//! includes fallback handing in the event the registry value can't be determined
AZ::IO::FixedMaxPathString GetProfilerCaptureLocation();
} // namespace Debug
} // namespace AZ
@@ -0,0 +1,92 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Debug/ProfilerBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/BehaviorInterfaceProxy.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
namespace AZ::Debug
{
static constexpr const char* ProfilerScriptCategory = "Profiler";
static constexpr const char* ProfilerScriptModule = "debug";
static constexpr AZ::Script::Attributes::ScopeFlags ProfilerScriptScope = AZ::Script::Attributes::ScopeFlags::Automation;
class ProfilerNotificationBusHandler final
: public ProfilerNotificationBus::Handler
, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(ProfilerNotificationBusHandler, "{44161459-B816-4876-95A4-BA16DEC767D6}", AZ::SystemAllocator,
OnCaptureFinished
);
void OnCaptureFinished(bool result, const AZStd::string& info) override
{
Call(FN_OnCaptureFinished, result, info);
}
static void Reflect(AZ::ReflectContext* context)
{
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<ProfilerNotificationBus>("ProfilerNotificationBus")
->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory)
->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule)
->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope)
->Handler<ProfilerNotificationBusHandler>();
}
}
};
class ProfilerSystemScriptProxy
: public BehaviorInterfaceProxy<ProfilerRequests>
{
public:
AZ_RTTI(ProfilerSystemScriptProxy, "{D671FB70-8B09-4C3A-96CD-06A339F3138E}", BehaviorInterfaceProxy<ProfilerRequests>);
AZ_BEHAVIOR_INTERFACE(ProfilerSystemScriptProxy, ProfilerRequests);
};
void ProfilerReflect(AZ::ReflectContext* context)
{
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->ConstantProperty("g_ProfilerSystem", ProfilerSystemScriptProxy::GetProxy)
->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory)
->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule)
->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope);
behaviorContext->Class<ProfilerSystemScriptProxy>("ProfilerSystemInterface")
->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory)
->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule)
->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope)
->Method("IsValid", &ProfilerSystemScriptProxy::IsValid)
->Method("GetCaptureLocation",
[](ProfilerSystemScriptProxy*) -> AZStd::string
{
AZ::IO::FixedMaxPathString captureOutput = GetProfilerCaptureLocation();
return AZStd::string(captureOutput.c_str(), captureOutput.length());
})
->Method("IsActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::IsActive>())
->Method("SetActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::SetActive>())
->Method("CaptureFrame", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::CaptureFrame>())
->Method("StartCapture", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::StartCapture>())
->Method("EndCapture", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::EndCapture>());
}
ProfilerNotificationBusHandler::Reflect(context);
}
} // namespace AZ::Debug
@@ -0,0 +1,19 @@
/*
* 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
namespace AZ
{
class ReflectContext;
namespace Debug
{
//! Reflects the profiler bus script bindings
void ProfilerReflect(AZ::ReflectContext* context);
} // namespace Debug
} // namespace AZ
+11 -16
View File
@@ -27,26 +27,21 @@
#include <AzCore/Console/IConsole.h>
#include <AzCore/std/chrono/chrono.h>
namespace AZ
namespace AZ::Debug
{
namespace Debug
struct StackFrame;
namespace Platform
{
struct StackFrame;
namespace Platform
{
#if defined(AZ_ENABLE_DEBUG_TOOLS)
bool AttachDebugger();
bool IsDebuggerPresent();
void HandleExceptions(bool isEnabled);
void DebugBreak();
bool AttachDebugger();
bool IsDebuggerPresent();
void HandleExceptions(bool isEnabled);
void DebugBreak();
#endif
void Terminate(int exitCode);
}
void Terminate(int exitCode);
}
using namespace AZ::Debug;
namespace DebugInternal
{
// other threads can trigger fatals and errors, but the same thread should not, to avoid stack overflow.
@@ -60,7 +55,7 @@ namespace AZ
// Globals
const int g_maxMessageLength = 4096;
static const char* g_dbgSystemWnd = "System";
Trace Debug::g_tracer;
Trace g_tracer;
void* g_exceptionInfo = nullptr;
// Environment var needed to track ignored asserts across systems and disable native UI under certain conditions
@@ -616,4 +611,4 @@ namespace AZ
val.Set(level);
}
}
} // namspace AZ
} // namspace AZ::Debug
@@ -156,7 +156,10 @@ namespace AZ
void StreamerComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
bool isEnabled = false;
AZ::Debug::ProfilerRequestBus::BroadcastResult(isEnabled, &AZ::Debug::ProfilerRequests::IsActive);
if (auto profilerSystem = AZ::Debug::ProfilerSystemInterface::Get(); profilerSystem)
{
isEnabled = profilerSystem->IsActive();
}
if (isEnabled)
{
@@ -383,36 +383,36 @@ namespace AZ
AZ_MATH_INLINE bool CmpAllEq(__m128 arg1, __m128 arg2, int32_t mask)
{
const __m128i compare = CastToInt(CmpNeq(arg1, arg2));
return (_mm_movemask_epi8(compare) & mask) == 0;
const __m128 compare = CmpEq(arg1, arg2);
return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllLt(__m128 arg1, __m128 arg2, int32_t mask)
{
const __m128i compare = CastToInt(CmpGtEq(arg1, arg2));
return (_mm_movemask_epi8(compare) & mask) == 0;
const __m128 compare = CmpLt(arg1, arg2);
return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllLtEq(__m128 arg1, __m128 arg2, int32_t mask)
{
const __m128i compare = CastToInt(CmpGt(arg1, arg2));
return (_mm_movemask_epi8(compare) & mask) == 0;
const __m128 compare = CmpLtEq(arg1, arg2);
return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllGt(__m128 arg1, __m128 arg2, int32_t mask)
{
const __m128i compare = CastToInt(CmpLtEq(arg1, arg2));
return (_mm_movemask_epi8(compare) & mask) == 0;
const __m128 compare = CmpGt(arg1, arg2);
return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllGtEq(__m128 arg1, __m128 arg2, int32_t mask)
{
const __m128i compare = CastToInt(CmpLt(arg1, arg2));
return (_mm_movemask_epi8(compare) & mask) == 0;
const __m128 compare = CmpGtEq(arg1, arg2);
return (_mm_movemask_ps(compare) & mask) == mask;
}
@@ -331,31 +331,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec1::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllEq(arg1, arg2, 0x000F);
// Only check the first bit for Vector1
return Sse::CmpAllEq(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLt(arg1, arg2, 0x000F);
return Sse::CmpAllLt(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLtEq(arg1, arg2, 0x000F);
return Sse::CmpAllLtEq(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGt(arg1, arg2, 0x000F);
return Sse::CmpAllGt(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGtEq(arg1, arg2, 0x000F);
return Sse::CmpAllGtEq(arg1, arg2, 0b0001);
}
@@ -397,7 +398,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec1::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
return Sse::CmpAllEq(arg1, arg2, 0x000F);
return Sse::CmpAllEq(arg1, arg2, 0b0001);
}
@@ -383,31 +383,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec2::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllEq(arg1, arg2, 0x00FF);
// Only check the first two bits for Vector2
return Sse::CmpAllEq(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLt(arg1, arg2, 0x00FF);
return Sse::CmpAllLt(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLtEq(arg1, arg2, 0x00FF);
return Sse::CmpAllLtEq(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGt(arg1, arg2, 0x00FF);
return Sse::CmpAllGt(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGtEq(arg1, arg2, 0x00FF);
return Sse::CmpAllGtEq(arg1, arg2, 0b0011);
}
@@ -419,31 +419,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec3::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllEq(arg1, arg2, 0x0FFF);
// Only check the first three bits for Vector3
return Sse::CmpAllEq(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLt(arg1, arg2, 0x0FFF);
return Sse::CmpAllLt(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLtEq(arg1, arg2, 0x0FFF);
return Sse::CmpAllLtEq(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGt(arg1, arg2, 0x0FFF);
return Sse::CmpAllGt(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGtEq(arg1, arg2, 0x0FFF);
return Sse::CmpAllGtEq(arg1, arg2, 0b0111);
}
@@ -485,7 +486,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec3::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
return Sse::CmpAllEq(arg1, arg2, 0x0FFF);
return Sse::CmpAllEq(arg1, arg2, 0b0111);
}
@@ -455,31 +455,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec4::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllEq(arg1, arg2, 0xFFFF);
// Check the first four bits for Vector4
return Sse::CmpAllEq(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLt(arg1, arg2, 0xFFFF);
return Sse::CmpAllLt(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllLtEq(arg1, arg2, 0xFFFF);
return Sse::CmpAllLtEq(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGt(arg1, arg2, 0xFFFF);
return Sse::CmpAllGt(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
return Sse::CmpAllGtEq(arg1, arg2, 0xFFFF);
return Sse::CmpAllGtEq(arg1, arg2, 0b1111);
}
@@ -521,7 +522,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec4::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
return Sse::CmpAllEq(arg1, arg2, 0xFFFF);
return Sse::CmpAllEq(arg1, arg2, 0b1111);
}
@@ -0,0 +1,126 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/functional.h>
#include <AzCore/std/typetraits/function_traits.h>
namespace AZ
{
/**
* Utility class for reflecting an AZ::Interface through the BehaviorContext
*
* Example:
*
* class MyInterface
* {
* public:
* AZ_RTTI(MyInterface, "{BADDF000D-CDCD-CDCD-CDCD-BAAAADF0000D}");
* virtual ~MyInterface() = default;
*
* virtual AZStd::string Foo() = 0;
* virtual void Bar(float x, float y) = 0;
* };
*
* class MySystemProxy
* : public BehaviorInterfaceProxy<MyInterface>
* {
* public:
* AZ_RTTI(MySystemProxy, "{CDCDCDCD-BAAD-BADD-F00D-CDCDCDCDCDCD}", BehaviorInterfaceProxy<MyInterface>);
* AZ_BEHAVIOR_INTERFACE(MySystemProxy, MyInterface);
* };
*
* void Reflect(AZ::ReflectContext* context)
* {
* if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
* {
* behaviorContext->ConstantProperty("g_MySystem", MySystemProxy::GetProxy)
* ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
* ->Attribute(AZ::Script::Attributes::Module, "MyModule");
*
* behaviorContext->Class<MySystemProxy>("MySystemInterface")
* ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
* ->Attribute(AZ::Script::Attributes::Module, "MyModule")
*
* ->Method("Foo", MySystemProxy::WrapMethod<&MyInterface::Foo>())
* ->Method("Bar", MySystemProxy::WrapMethod<&MyInterface::Bar>());
* }
* }
*/
template<typename T>
class BehaviorInterfaceProxy
{
public:
AZ_CLASS_ALLOCATOR(BehaviorInterfaceProxy, AZ::SystemAllocator, 0);
AZ_RTTI(BehaviorInterfaceProxy<T>, "{E7CC8D27-4499-454E-A7DF-3F72FBECD30D}");
BehaviorInterfaceProxy() = default;
virtual ~BehaviorInterfaceProxy() = default;
//! Stores the instance which will use the provided shared_ptr deleter when the reference count hits zero
BehaviorInterfaceProxy(AZStd::shared_ptr<T> sharedInstance)
: m_instance(AZStd::move(sharedInstance))
{
}
//! Stores the instance which will perform a no-op deleter when the reference count hits zero
BehaviorInterfaceProxy(T* rawIntance)
: m_instance(rawIntance, [](T*) {})
{
}
//! Returns if the m_instance shared pointer is non-nullptr
bool IsValid() const { return m_instance; }
protected:
//! Internal access for use in the derived GetProxy function
static T* GetInstance()
{
T* interfacePtr = AZ::Interface<T>::Get();
AZ_Warning("BehaviorInterfaceProxy", interfacePtr,
"There is currently no global %s registered with an AZ Interface<T>",
AzTypeInfo<T>::Name()
);
// Don't delete the global instance, it is not owned by the behavior context
return interfacePtr;
}
template<typename... Args>
struct MethodWrapper
{
template<typename Proxy, auto Method>
static auto WrapMethod()
{
using ReturnType = AZStd::function_traits_get_result_t<AZStd::remove_cvref_t<decltype(Method)>>;
return [](Proxy* proxy, Args... params) -> ReturnType
{
if (proxy && proxy->IsValid())
{
return AZStd::invoke(Method, proxy->m_instance, AZStd::forward<Args>(params)...);
}
return ReturnType();
};
}
};
AZStd::shared_ptr<T> m_instance;
};
#define AZ_BEHAVIOR_INTERFACE(ProxyType, InterfaceType) \
static ProxyType GetProxy() { return GetInstance(); } \
template<auto Method> \
static auto WrapMethod() { \
using FuncTraits = AZStd::function_traits<AZStd::remove_cvref_t<decltype(Method)>>; \
return FuncTraits::template expand_args<MethodWrapper>::template WrapMethod<ProxyType, Method>(); \
} \
ProxyType() = default; \
ProxyType(AZStd::shared_ptr<InterfaceType> sharedInstance) : BehaviorInterfaceProxy(sharedInstance) {} \
ProxyType(InterfaceType* rawIntance) : BehaviorInterfaceProxy(rawIntance) {}
} // namespace AZ
@@ -14,6 +14,7 @@
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Debug/ProfilerReflection.h>
#include <AzCore/Debug/TraceReflection.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Math/MathReflection.h>
@@ -87,6 +88,8 @@ void ScriptSystemComponent::Activate()
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, "lua");
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, "luac");
AZ::Data::AssetCatalogRequestBus::Broadcast(
&AZ::Data::AssetCatalogRequests::EnableCatalogForAsset, AZ::AzTypeInfo<AZ::ScriptAsset>::Uuid());
if (Data::AssetManager::Instance().IsReady())
{
@@ -925,6 +928,7 @@ void ScriptSystemComponent::Reflect(ReflectContext* reflection)
// reflect default entity
MathReflect(behaviorContext);
ScriptDebug::Reflect(behaviorContext);
Debug::ProfilerReflect(behaviorContext);
Debug::TraceReflect(behaviorContext);
behaviorContext->Class<PlatformID>("Platform")
@@ -363,7 +363,11 @@ namespace AZ
{
++m_graphsRemaining;
event->m_executor = this; // Used to validate event is not waited for inside a job
if (event)
{
event->IncWaitCount();
event->m_executor = this; // Used to validate event is not waited for inside a job
}
// Submit all tasks that have no inbound edges
for (Internal::Task& task : graph.Tasks())
@@ -20,6 +20,46 @@ namespace AZ
m_semaphore.acquire();
}
void TaskGraphEvent::IncWaitCount()
{
// guess zero to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
int expectedValue = 0;
while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue + 1))
{
// value will be negative once event is ready to signal or has been signaled. Shouldn't happen.
AZ_Assert(expectedValue >= 0, "Called TaskGraphEvent::IncWaitCount on a signalled event");
if (expectedValue < 0) // event already signaled, skip
{
return;
}
};
}
void TaskGraphEvent::Signal()
{
// guess one to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
int expectedValue = 1;
while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue - 1))
{
// It's an error for Signal to be called if no one is waiting, or the event has already been signaled
AZ_Assert(expectedValue > 0, "Called TaskGraphEvent::Signal when event is either signaled or unused");
if (expectedValue < 0) // return if already signaled
{
return;
}
};
if (expectedValue == 1) // This call to Signal decremented the value to 0.
{
expectedValue = 0;
// validate no one incremented the wait count and mark signalling state
if (m_waitCount.compare_exchange_strong(expectedValue, -1))
{
m_semaphore.release();
}
}
}
void TaskToken::PrecedesInternal(TaskToken& comesAfter)
{
AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted.");
@@ -61,14 +61,14 @@ namespace AZ
uint32_t m_index;
};
// A TaskGraphEvent may be used to block until a task graph has finished executing. Usage
// A TaskGraphEvent may be used to block until one or more task graphs has finished executing. Usage
// is NOT recommended for the majority of tasks (prefer to simply containing expanding/contracting
// the graph without synchronization over the course of the frame). However, the event
// is useful for the edges of the computation graph.
//
// You are responsible for ensuring the event object lifetime exceeds the task graph lifetime.
//
// After the TaskGraphEvent is signaled, you are allowed to reuse the same TaskGraphEvent
// After the TaskGraphEvent is signaled, you are NOT allowed to reuse the same TaskGraphEvent
// for a future submission.
class TaskGraphEvent
{
@@ -81,10 +81,12 @@ namespace AZ
friend class TaskGraph;
friend class TaskExecutor;
void IncWaitCount();
void Signal();
AZStd::binary_semaphore m_semaphore;
TaskExecutor* m_executor = nullptr;
AZStd::atomic_int m_waitCount = 0;
TaskExecutor* m_executor = nullptr;
};
// The TaskGraph encapsulates a set of tasks and their interdependencies. After adding
@@ -33,11 +33,6 @@ namespace AZ
return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 });
}
inline void TaskGraphEvent::Signal()
{
m_semaphore.release();
}
template<typename Lambda>
TaskToken TaskGraph::AddTask(TaskDescriptor const& desc, Lambda&& lambda)
{
@@ -108,6 +108,8 @@ set(FILES
Debug/Profiler.inl
Debug/Profiler.h
Debug/ProfilerBus.h
Debug/ProfilerReflection.cpp
Debug/ProfilerReflection.h
Debug/StackTracer.h
Debug/EventTrace.h
Debug/EventTrace.cpp
@@ -456,6 +458,7 @@ set(FILES
RTTI/BehaviorContext.h
RTTI/BehaviorContextUtilities.h
RTTI/BehaviorContextUtilities.cpp
RTTI/BehaviorInterfaceProxy.h
RTTI/BehaviorObjectSignals.h
RTTI/TypeSafeIntegral.h
Script/ScriptAsset.cpp
@@ -17,7 +17,7 @@
#include <stdio.h>
namespace AZ
namespace AZ::Debug
{
#if defined(AZ_ENABLE_DEBUG_TOOLS)
LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo);
@@ -26,94 +26,91 @@ namespace AZ
constexpr int g_maxMessageLength = 4096;
namespace Debug
namespace Platform
{
namespace Platform
{
#if defined(AZ_ENABLE_DEBUG_TOOLS)
bool IsDebuggerPresent()
bool IsDebuggerPresent()
{
return ::IsDebuggerPresent() ? true : false;
}
void HandleExceptions(bool isEnabled)
{
if (isEnabled)
{
return ::IsDebuggerPresent() ? true : false;
g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler);
}
void HandleExceptions(bool isEnabled)
else
{
if (isEnabled)
{
g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler);
}
else
{
::SetUnhandledExceptionFilter(g_previousExceptionHandler);
g_previousExceptionHandler = NULL;
}
}
bool AttachDebugger()
{
if (IsDebuggerPresent())
{
return true;
}
// Launch vsjitdebugger.exe, this app is always present in System32 folder
// with an installation of any version of visual studio.
// It will open a debugging dialog asking the user what debugger to use
STARTUPINFOW startupInfo = {0};
startupInfo.cb = sizeof(startupInfo);
PROCESS_INFORMATION processInfo = {0};
wchar_t cmdline[MAX_PATH];
swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId());
bool success = ::CreateProcessW(
NULL, // No module name (use command line)
cmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // No handle inheritance
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
&processInfo); // Pointer to PROCESS_INFORMATION structure
if (success)
{
::WaitForSingleObject(processInfo.hProcess, INFINITE);
::CloseHandle(processInfo.hProcess);
::CloseHandle(processInfo.hThread);
return true;
}
return false;
}
void DebugBreak()
{
__debugbreak();
}
#endif // AZ_ENABLE_DEBUG_TOOLS
void Terminate(int exitCode)
{
TerminateProcess(GetCurrentProcess(), exitCode);
}
void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
{
AZStd::fixed_wstring<g_maxMessageLength> tmpW;
if(window)
{
AZStd::to_wstring(tmpW, window);
tmpW += L": ";
OutputDebugStringW(tmpW.c_str());
tmpW.clear();
}
AZStd::to_wstring(tmpW, message);
OutputDebugStringW(tmpW.c_str());
::SetUnhandledExceptionFilter(g_previousExceptionHandler);
g_previousExceptionHandler = NULL;
}
}
}
bool AttachDebugger()
{
if (IsDebuggerPresent())
{
return true;
}
// Launch vsjitdebugger.exe, this app is always present in System32 folder
// with an installation of any version of visual studio.
// It will open a debugging dialog asking the user what debugger to use
STARTUPINFOW startupInfo = {0};
startupInfo.cb = sizeof(startupInfo);
PROCESS_INFORMATION processInfo = {0};
wchar_t cmdline[MAX_PATH];
swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId());
bool success = ::CreateProcessW(
NULL, // No module name (use command line)
cmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // No handle inheritance
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
&processInfo); // Pointer to PROCESS_INFORMATION structure
if (success)
{
::WaitForSingleObject(processInfo.hProcess, INFINITE);
::CloseHandle(processInfo.hProcess);
::CloseHandle(processInfo.hThread);
return true;
}
return false;
}
void DebugBreak()
{
__debugbreak();
}
#endif // AZ_ENABLE_DEBUG_TOOLS
void Terminate(int exitCode)
{
TerminateProcess(GetCurrentProcess(), exitCode);
}
void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
{
AZStd::fixed_wstring<g_maxMessageLength> tmpW;
if(window)
{
AZStd::to_wstring(tmpW, window);
tmpW += L": ";
OutputDebugStringW(tmpW.c_str());
tmpW.clear();
}
AZStd::to_wstring(tmpW, message);
OutputDebugStringW(tmpW.c_str());
}
} // namespace Platform
#if defined(AZ_ENABLE_DEBUG_TOOLS)
@@ -187,6 +184,8 @@ namespace AZ
azsnprintf(message, g_maxMessageLength, "Exception : 0x%lX - '%s' [%p]\n", ExceptionInfo->ExceptionRecord->ExceptionCode, GetExeptionName(ExceptionInfo->ExceptionRecord->ExceptionCode), ExceptionInfo->ExceptionRecord->ExceptionAddress);
Debug::Trace::Instance().Output(nullptr, message);
Debug::Trace::Instance().PrintCallstack(nullptr, 0, ExceptionInfo->ContextRecord);
EBUS_EVENT(Debug::TraceMessageDrillerBus, OnException, message);
bool result = false;
@@ -198,7 +197,7 @@ namespace AZ
// if someone ever returns TRUE we assume that they somehow handled this exception and continue.
return EXCEPTION_CONTINUE_EXECUTION;
}
Debug::Trace::Instance().PrintCallstack(nullptr, 0, ExceptionInfo->ContextRecord);
Debug::Trace::Instance().Output(nullptr, "==================================================================\n");
// allowing continue of execution is not valid here. This handler gets called for serious exceptions.
@@ -211,4 +210,4 @@ namespace AZ
}
#endif
}
} // namspace AZ::Debug
+6 -5
View File
@@ -610,15 +610,16 @@ namespace UnitTest
g.Follows(e, f);
g.Precedes(d);
TaskGraphEvent ev;
graph.SubmitOnExecutor(*m_executor, &ev);
ev.Wait();
TaskGraphEvent ev1;
graph.SubmitOnExecutor(*m_executor, &ev1);
ev1.Wait();
EXPECT_EQ(3 | 0b100000, x);
x = 0;
graph.SubmitOnExecutor(*m_executor, &ev);
ev.Wait();
TaskGraphEvent ev2;
graph.SubmitOnExecutor(*m_executor, &ev2);
ev2.Wait();
EXPECT_EQ(3 | 0b100000, x);
}
@@ -204,7 +204,6 @@ namespace AzFramework
systemEntity->Activate();
AZ_Assert(systemEntity->GetState() == AZ::Entity::State::Active, "System Entity failed to activate.");
if (m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active); m_isStarted)
{
if (m_startupParameters.m_loadAssetCatalog)
@@ -12,6 +12,7 @@
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/ComponentApplicationLifecycle.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Interface/Interface.h>
@@ -363,6 +364,23 @@ namespace AZ::IO
, m_mainThreadId{ AZStd::this_thread::get_id() }
{
CompressionBus::Handler::BusConnect();
// If the settings registry is not available at this point,
// then something catastrophic has happened in the application startup.
// That should have been caught and messaged out earlier in startup.
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
// Automatically register the event if it's not registered, because
// this system is initialized before the settings registry has loaded the event list.
AZ::ComponentApplicationLifecycle::RegisterHandler(
*settingsRegistry, m_componentApplicationLifecycleHandler,
[this](AZStd::string_view /*path*/, AZ::SettingsRegistryInterface::Type /*type*/)
{
OnSystemEntityActivated();
},
"SystemComponentsActivated",
/*autoRegisterEvent*/ true);
}
}
//////////////////////////////////////////////////////////////////////////
@@ -1175,13 +1193,20 @@ namespace AZ::IO
}
}
auto bundleManifest = GetBundleManifest(desc.pZip);
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog;
auto bundleManifest = GetBundleManifest(desc.pZip);
if (bundleManifest)
{
bundleCatalog = GetBundleCatalog(desc.pZip, bundleManifest->GetCatalogName());
}
// If this archive is loaded before the serialize context is available, then the manifest and catalog will need to be loaded later.
if (!bundleManifest || !bundleCatalog)
{
m_archivesWithCatalogsToLoad.push_back(
ArchivesWithCatalogsToLoad(szFullPath, szBindRoot, flags, nextBundle, desc.m_strFileName));
}
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
@@ -1219,12 +1244,17 @@ namespace AZ::IO
m_levelOpenEvent.Signal(levelDirs);
}
AZ::IO::ArchiveNotificationBus::Broadcast([](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
AZStd::shared_ptr<AzFramework::AssetBundleManifest> bundleManifest, const AZ::IO::FixedMaxPath& nextBundle, AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog)
if (bundleManifest && bundleCatalog)
{
archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
}, desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
AZ::IO::ArchiveNotificationBus::Broadcast(
[](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
AZStd::shared_ptr<AzFramework::AssetBundleManifest> bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog)
{
archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
},
desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
}
return true;
}
@@ -2138,7 +2168,7 @@ namespace AZ::IO
}
currentDirPattern = currentDir + AZ_FILESYSTEM_SEPARATOR_WILDCARD;
currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "levels.pak";
currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "level.pak";
ZipDir::FileEntry* fileEntry = findFile.FindExact(currentFilePattern.c_str());
if (fileEntry)
@@ -2175,4 +2205,36 @@ namespace AZ::IO
return catalogInfo;
}
void Archive::OnSystemEntityActivated()
{
for (const auto& archiveInfo : m_archivesWithCatalogsToLoad)
{
AZStd::intrusive_ptr<INestedArchive> archive =
OpenArchive(archiveInfo.m_fullPath, archiveInfo.m_bindRoot, archiveInfo.m_flags, nullptr);
if (!archive)
{
continue;
}
ZipDir::CachePtr pZip = static_cast<NestedArchive*>(archive.get())->GetCache();
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog;
auto bundleManifest = GetBundleManifest(pZip);
if (bundleManifest)
{
bundleCatalog = GetBundleCatalog(pZip, bundleManifest->GetCatalogName());
}
AZ::IO::ArchiveNotificationBus::Broadcast(
[](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
AZStd::shared_ptr<AzFramework::AssetBundleManifest> bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog)
{
archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
},
archiveInfo.m_strFileName.c_str(), bundleManifest, archiveInfo.m_nextBundle, bundleCatalog);
}
m_archivesWithCatalogsToLoad.clear();
}
}
@@ -19,6 +19,7 @@
#include <AzCore/IO/CompressionBus.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/std/containers/set.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/parallel/lock.h>
@@ -271,6 +272,11 @@ namespace AZ::IO
ZipDir::CachePtr* pZip = {}) const;
private:
// Archives can't be fully mounted until the system entity has been activated,
// because mounting them requires the BundlingSystemComponent and the serialization system
// to both be available.
void OnSystemEntityActivated();
bool OpenPackCommon(AZStd::string_view szBindRoot, AZStd::string_view pName, AZStd::intrusive_ptr<AZ::IO::MemoryBlock> pData = nullptr, bool addLevels = true);
bool OpenPacksCommon(AZStd::string_view szDir, AZStd::string_view pWildcardIn, AZStd::vector<AZ::IO::FixedMaxPathString>* pFullPaths = nullptr, bool addLevels = true);
@@ -313,6 +319,8 @@ namespace AZ::IO
mutable AZStd::shared_mutex m_csZips;
ZipArray m_arrZips;
AZ::SettingsRegistryInterface::NotifyEventHandler m_componentApplicationLifecycleHandler;
//////////////////////////////////////////////////////////////////////////
// Opened files collector.
//////////////////////////////////////////////////////////////////////////
@@ -339,5 +347,34 @@ namespace AZ::IO
// [LYN-2376] Remove once legacy slice support is removed
LevelPackOpenEvent m_levelOpenEvent;
LevelPackCloseEvent m_levelCloseEvent;
// If pak files are loaded before the serialization and bundling system
// are ready to go, their asset catalogs can't be loaded.
// In this case, cache information about those archives,
// and attempt to load the catalogs later, when the required systems are enabled.
struct ArchivesWithCatalogsToLoad
{
ArchivesWithCatalogsToLoad(
AZStd::string_view fullPath,
AZStd::string_view bindRoot,
int flags,
AZ::IO::PathView nextBundle,
AZ::IO::Path strFileName)
: m_fullPath(fullPath)
, m_bindRoot(bindRoot)
, m_flags(flags)
, m_nextBundle(nextBundle)
, m_strFileName(strFileName)
{
}
AZ::IO::Path m_strFileName;
AZStd::string m_fullPath;
AZStd::string m_bindRoot;
AZ::IO::PathView m_nextBundle;
int m_flags;
};
AZStd::vector<ArchivesWithCatalogsToLoad> m_archivesWithCatalogsToLoad;
};
}
@@ -229,17 +229,13 @@ namespace AzFramework
//! Alias for the EBus implementation of this interface
using Bus = AZ::EBus<InputDeviceImplementationRequest<InputDeviceType>>;
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create the custom implementations
using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
////////////////////////////////////////////////////////////////////////////////////////////
//! Set a custom implementation for this input device type, either for a specific instance
//! by addressing the call to an InputDeviceId, or for all existing instances by broadcast.
//! Passing InputDeviceType::Implementation::Create as the argument will create the default
//! device implementation, while passing nullptr will delete any existing implementation.
//! \param[in] createFunction Pointer to the function that will create the implementation.
virtual void SetCustomImplementation(CreateFunctionType createFunction) = 0;
//! \param[in] implementationFactory Pointer to the function that creates the implementation.
virtual void SetCustomImplementation(typename InputDeviceType::ImplementationFactory implementationFactory) = 0;
};
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -267,18 +263,14 @@ namespace AzFramework
AZ_DISABLE_COPY_MOVE(InputDeviceImplementationRequestHandler);
protected:
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create the custom implementations
using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
////////////////////////////////////////////////////////////////////////////////////////////
//! \ref InputDeviceImplementationRequest<InputDeviceType>::SetCustomImplementation
AZ_INLINE void SetCustomImplementation(CreateFunctionType createFunction) override
AZ_INLINE void SetCustomImplementation(typename InputDeviceType::ImplementationFactory implementationFactory) override
{
AZStd::unique_ptr<typename InputDeviceType::Implementation> newImplementation;
if (createFunction)
if (implementationFactory)
{
newImplementation.reset(createFunction(m_inputDevice));
newImplementation.reset(implementationFactory(m_inputDevice));
}
m_inputDevice.SetImplementation(AZStd::move(newImplementation));
}
@@ -94,7 +94,14 @@ namespace AzFramework
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceGamepad::InputDeviceGamepad(AZ::u32 index)
: InputDevice(InputDeviceId(Name, index))
: InputDeviceGamepad(InputDeviceId(Name, index)) // Delegated constructor
{
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceGamepad::InputDeviceGamepad(const InputDeviceId& inputDeviceId,
ImplementationFactory implementationFactory)
: InputDevice(inputDeviceId)
, m_allChannelsById()
, m_buttonChannelsById()
, m_triggerChannelsById()
@@ -144,8 +151,8 @@ namespace AzFramework
m_thumbStickDirectionChannelsById[channelId] = channel;
}
// Create the platform specific implementation
m_pimpl.reset(Implementation::Create(*this));
// Create the platform specific or custom implementation
m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the haptic feedback request bus
InputHapticFeedbackRequestBus::Handler::BusConnect(GetInputDeviceId());
@@ -182,6 +182,14 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////////////////////////
// Foward declare the internal Implementation class so it can be passed into the constructor
class Implementation;
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create a custom implementation for this input device
using ImplementationFactory = Implementation*(InputDeviceGamepad&);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
explicit InputDeviceGamepad();
@@ -191,6 +199,13 @@ namespace AzFramework
//! \param[in] index Index of the game-pad device
explicit InputDeviceGamepad(AZ::u32 index);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
//! \param[in] inputDeviceId Id of the input device
//! \param[in] implementationFactory Optional override of the default Implementation::Create
explicit InputDeviceGamepad(const InputDeviceId& inputDeviceId,
ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
AZ_DISABLE_COPY_MOVE(InputDeviceGamepad);
@@ -182,8 +182,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceKeyboard::InputDeviceKeyboard(AzFramework::InputDeviceId id)
: InputDevice(id)
InputDeviceKeyboard::InputDeviceKeyboard(const InputDeviceId& inputDeviceId,
ImplementationFactory implementationFactory)
: InputDevice(inputDeviceId)
, m_modifierKeyStates(AZStd::make_shared<ModifierKeyStates>())
, m_allChannelsById()
, m_keyChannelsById()
@@ -203,8 +204,8 @@ namespace AzFramework
m_keyChannelsById[channelId] = channel;
}
// Create the platform specific implementation
m_pimpl.reset(Implementation::Create(*this));
// Create the platform specific or custom implementation
m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the text entry request bus
InputTextEntryRequestBus::Handler::BusConnect(GetInputDeviceId());
@@ -370,9 +370,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////////////////////////
// Foward declare the internal Implementation class so it can be passed into the constructor
class Implementation;
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create a custom implementation for this input device
using ImplementationFactory = Implementation*(InputDeviceKeyboard&);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
InputDeviceKeyboard(AzFramework::InputDeviceId id = Id);
//! \param[in] inputDeviceId Optional override of the default input device id
//! \param[in] implementationFactory Optional override of the default Implementation::Create
explicit InputDeviceKeyboard(const InputDeviceId& inputDeviceId = Id,
ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
@@ -60,8 +60,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceMotion::InputDeviceMotion()
: InputDevice(Id)
InputDeviceMotion::InputDeviceMotion(const InputDeviceId& inputDeviceId,
ImplementationFactory implementationFactory)
: InputDevice(inputDeviceId)
, m_allChannelsById()
, m_accelerationChannelsById()
, m_rotationRateChannelsById()
@@ -107,8 +108,8 @@ namespace AzFramework
m_orientationChannelsById[channelId] = channel;
}
// Create the platform specific implementation
m_pimpl.reset(Implementation::Create(*this));
// Create the platform specific or custom implementation
m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the motion sensor request bus
InputMotionSensorRequestBus::Handler::BusConnect(GetInputDeviceId());
@@ -126,9 +126,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////////////////////////
// Foward declare the internal Implementation class so it can be passed into the constructor
class Implementation;
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create a custom implementation for this input device
using ImplementationFactory = Implementation*(InputDeviceMotion&);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
InputDeviceMotion();
//! \param[in] inputDeviceId Optional override of the default input device id
//! \param[in] implementationFactory Optional override of the default Implementation::Create
explicit InputDeviceMotion(const InputDeviceId& inputDeviceId = Id,
ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
@@ -67,8 +67,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceMouse::InputDeviceMouse(AzFramework::InputDeviceId id)
: InputDevice(id)
InputDeviceMouse::InputDeviceMouse(const InputDeviceId& inputDeviceId,
ImplementationFactory implementationFactory)
: InputDevice(inputDeviceId)
, m_allChannelsById()
, m_buttonChannelsById()
, m_movementChannelsById()
@@ -97,8 +98,8 @@ namespace AzFramework
m_cursorPositionChannel = aznew InputChannelDeltaWithSharedPosition2D(SystemCursorPosition, *this, m_cursorPositionData2D);
m_allChannelsById[SystemCursorPosition] = m_cursorPositionChannel;
// Create the platform specific implementation
m_pimpl.reset(Implementation::Create(*this));
// Create the platform specific or custom implementation
m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the system cursor request bus
InputSystemCursorRequestBus::Handler::BusConnect(GetInputDeviceId());
@@ -122,9 +122,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////////////////////////
// Foward declare the internal Implementation class so it can be passed into the constructor
class Implementation;
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create a custom implementation for this input device
using ImplementationFactory = Implementation*(InputDeviceMouse&);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
explicit InputDeviceMouse(AzFramework::InputDeviceId id = Id);
//! \param[in] inputDeviceId Optional override of the default input device id
//! \param[in] implementationFactory Optional override of the default Implementation::Create
explicit InputDeviceMouse(const InputDeviceId& inputDeviceId = Id,
ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
@@ -59,8 +59,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceTouch::InputDeviceTouch()
: InputDevice(Id)
InputDeviceTouch::InputDeviceTouch(const InputDeviceId& inputDeviceId,
ImplementationFactory implementationFactory)
: InputDevice(inputDeviceId)
, m_allChannelsById()
, m_touchChannelsById()
, m_pimpl(nullptr)
@@ -75,8 +76,8 @@ namespace AzFramework
m_touchChannelsById[channelId] = channel;
}
// Create the platform specific implementation
m_pimpl.reset(Implementation::Create(*this));
// Create the platform specific or custom implementation
m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
}
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -77,9 +77,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////////////////////////
// Foward declare the internal Implementation class so it can be passed into the constructor
class Implementation;
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create a custom implementation for this input device
using ImplementationFactory = Implementation*(InputDeviceTouch&);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
InputDeviceTouch();
//! \param[in] inputDeviceId Optional override of the default input device id
//! \param[in] implementationFactory Optional override of the default Implementation::Create
explicit InputDeviceTouch(const InputDeviceId& inputDeviceId = Id,
ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
@@ -51,8 +51,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceVirtualKeyboard::InputDeviceVirtualKeyboard()
: InputDevice(Id)
InputDeviceVirtualKeyboard::InputDeviceVirtualKeyboard(const InputDeviceId& inputDeviceId,
ImplementationFactory implementationFactory)
: InputDevice(inputDeviceId)
, m_allChannelsById()
, m_pimpl()
, m_implementationRequestHandler(*this)
@@ -65,8 +66,8 @@ namespace AzFramework
m_commandChannelsById[channelId] = channel;
}
// Create the platform specific implementation
m_pimpl.reset(Implementation::Create(*this));
// Create the platform specific or custom implementation
m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the text entry request bus
InputTextEntryRequestBus::Handler::BusConnect(GetInputDeviceId());
@@ -69,9 +69,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////////////////////////
// Foward declare the internal Implementation class so it can be passed into the constructor
class Implementation;
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the function type used to create a custom implementation for this input device
using ImplementationFactory = Implementation*(InputDeviceVirtualKeyboard&);
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
InputDeviceVirtualKeyboard();
//! \param[in] inputDeviceId Optional override of the default input device id
//! \param[in] implementationFactory Optional override of the default Implementation::Create
explicit InputDeviceVirtualKeyboard(const InputDeviceId& inputDeviceId = Id,
ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
@@ -24,17 +24,17 @@ namespace AzFramework
IMatchmakingRequests() = default;
virtual ~IMatchmakingRequests() = default;
// Registers a player's acceptance or rejection of a proposed matchmaking.
// @param acceptMatchRequest The request of AcceptMatch operation
//! Registers a player's acceptance or rejection of a proposed matchmaking.
//! @param acceptMatchRequest The request of AcceptMatch operation
virtual void AcceptMatch(const AcceptMatchRequest& acceptMatchRequest) = 0;
// Create a game match for a group of players.
// @param startMatchmakingRequest The request of StartMatchmaking operation
// @return A unique identifier for a matchmaking ticket
//! Create a game match for a group of players.
//! @param startMatchmakingRequest The request of StartMatchmaking operation
//! @return A unique identifier for a matchmaking ticket
virtual AZStd::string StartMatchmaking(const StartMatchmakingRequest& startMatchmakingRequest) = 0;
// Cancels a matchmaking ticket that is currently being processed.
// @param stopMatchmakingRequest The request of StopMatchmaking operation
//! Cancels a matchmaking ticket that is currently being processed.
//! @param stopMatchmakingRequest The request of StopMatchmaking operation
virtual void StopMatchmaking(const StopMatchmakingRequest& stopMatchmakingRequest) = 0;
};
@@ -48,16 +48,16 @@ namespace AzFramework
IMatchmakingAsyncRequests() = default;
virtual ~IMatchmakingAsyncRequests() = default;
// AcceptMatch Async
// @param acceptMatchRequest The request of AcceptMatch operation
//! AcceptMatch Async
//! @param acceptMatchRequest The request of AcceptMatch operation
virtual void AcceptMatchAsync(const AcceptMatchRequest& acceptMatchRequest) = 0;
// StartMatchmaking Async
// @param startMatchmakingRequest The request of StartMatchmaking operation
//! StartMatchmaking Async
//! @param startMatchmakingRequest The request of StartMatchmaking operation
virtual void StartMatchmakingAsync(const StartMatchmakingRequest& startMatchmakingRequest) = 0;
// StopMatchmaking Async
// @param stopMatchmakingRequest The request of StopMatchmaking operation
//! StopMatchmaking Async
//! @param stopMatchmakingRequest The request of StopMatchmaking operation
virtual void StopMatchmakingAsync(const StopMatchmakingRequest& stopMatchmakingRequest) = 0;
};
@@ -76,14 +76,14 @@ namespace AzFramework
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
// OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes
//! 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
//! 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
//! OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes
virtual void OnStopMatchmakingAsyncComplete() = 0;
};
using MatchmakingAsyncRequestNotificationBus = AZ::EBus<MatchmakingAsyncRequestNotifications>;
@@ -29,17 +29,17 @@ namespace AzFramework
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
// OnMatchAcceptance is fired when match is found and pending on acceptance
// Use this notification to accept found match
//! 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
//! OnMatchComplete is fired when match is complete
virtual void OnMatchComplete() = 0;
// OnMatchError is fired when match is processed with error
//! OnMatchError is fired when match is processed with error
virtual void OnMatchError() = 0;
// OnMatchFailure is fired when match is failed to complete
//! OnMatchFailure is fired when match is failed to complete
virtual void OnMatchFailure() = 0;
};
using MatchmakingNotificationBus = AZ::EBus<MatchmakingNotifications>;
@@ -29,11 +29,11 @@ namespace AzFramework
AcceptMatchRequest() = default;
virtual ~AcceptMatchRequest() = default;
// Player response to accept or reject match
//! Player response to accept or reject match
bool m_acceptMatch;
// A list of unique identifiers for players delivering the response
//! A list of unique identifiers for players delivering the response
AZStd::vector<AZStd::string> m_playerIds;
// A unique identifier for a matchmaking ticket
//! A unique identifier for a matchmaking ticket
AZStd::string m_ticketId;
};
@@ -47,7 +47,7 @@ namespace AzFramework
StartMatchmakingRequest() = default;
virtual ~StartMatchmakingRequest() = default;
// A unique identifier for a matchmaking ticket
//! A unique identifier for a matchmaking ticket
AZStd::string m_ticketId;
};
@@ -61,7 +61,7 @@ namespace AzFramework
StopMatchmakingRequest() = default;
virtual ~StopMatchmakingRequest() = default;
// A unique identifier for a matchmaking ticket
//! A unique identifier for a matchmaking ticket
AZStd::string m_ticketId;
};
} // namespace AzFramework
@@ -18,16 +18,16 @@ namespace AzFramework
//! The properties for handling join session request.
struct SessionConnectionConfig
{
// A unique identifier for registered player in session.
//! A unique identifier for registered player in session.
AZStd::string m_playerSessionId;
// The DNS identifier assigned to the instance that is running the session.
//! The DNS identifier assigned to the instance that is running the session.
AZStd::string m_dnsName;
// The IP address of the session.
//! The IP address of the session.
AZStd::string m_ipAddress;
// The port number for the session.
//! The port number for the session.
uint16_t m_port = 0;
};
@@ -35,10 +35,10 @@ namespace AzFramework
//! The properties for handling player connect/disconnect
struct PlayerConnectionConfig
{
// A unique identifier for player connection.
//! A unique identifier for player connection.
uint32_t m_playerConnectionId = 0;
// A unique identifier for registered player in session.
//! A unique identifier for registered player in session.
AZStd::string m_playerSessionId;
};
@@ -51,12 +51,12 @@ namespace AzFramework
ISessionHandlingClientRequests() = default;
virtual ~ISessionHandlingClientRequests() = default;
// Request the player join session
// @param sessionConnectionConfig The required properties to handle the player join session process
// @return The result of player join session process
//! Request the player join session
//! @param sessionConnectionConfig The required properties to handle the player join session process
//! @return The result of player join session process
virtual bool RequestPlayerJoinSession(const SessionConnectionConfig& sessionConnectionConfig) = 0;
// Request the connected player leave session
//! Request the connected player leave session
virtual void RequestPlayerLeaveSession() = 0;
};
@@ -69,26 +69,26 @@ namespace AzFramework
ISessionHandlingProviderRequests() = default;
virtual ~ISessionHandlingProviderRequests() = default;
// Handle the destroy session process
//! 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
//! 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
//! 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;
// Retrieves the file location of a pem-encoded TLS certificate for Client to Server communication
// @return If successful, returns the file location of TLS certificate file; if not successful, returns
// empty string.
//! Retrieves the file location of a pem-encoded TLS certificate for Client to Server communication
//! @return If successful, returns the file location of TLS certificate file; if not successful, returns
//! empty string.
virtual AZ::IO::Path GetExternalSessionCertificate() = 0;
// Retrieves the file location of a pem-encoded TLS certificate for Server to Server communication
// @return If successful, returns the file location of TLS certificate file; if not successful, returns
// empty string.
//! Retrieves the file location of a pem-encoded TLS certificate for Server to Server communication
//! @return If successful, returns the file location of TLS certificate file; if not successful, returns
//! empty string.
virtual AZ::IO::Path GetInternalSessionCertificate() = 0;
};
} // namespace AzFramework
@@ -25,22 +25,22 @@ namespace AzFramework
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
//! 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
//! 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
//! 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.
//! Disconnect player from session.
virtual void LeaveSession() = 0;
};
@@ -54,19 +54,19 @@ namespace AzFramework
ISessionAsyncRequests() = default;
virtual ~ISessionAsyncRequests() = default;
// CreateSession Async
// @param createSessionRequest The request of CreateSession operation
//! 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
//! 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
//! JoinSession Async
//! @param joinSessionRequest The request of JoinSession operation
virtual void JoinSessionAsync(const JoinSessionRequest& joinSessionRequest) = 0;
// LeaveSession Async
//! LeaveSession Async
virtual void LeaveSessionAsync() = 0;
};
@@ -85,19 +85,19 @@ namespace AzFramework
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
//! 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
//! 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
//! 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
//! OnLeaveSessionAsyncComplete is fired once LeaveSessionAsync completes
virtual void OnLeaveSessionAsyncComplete() = 0;
};
using SessionAsyncRequestNotificationBus = AZ::EBus<SessionAsyncRequestNotifications>;
@@ -24,46 +24,46 @@ namespace AzFramework
SessionConfig() = default;
virtual ~SessionConfig() = default;
// A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds.
//! A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds.
uint64_t m_creationTime = 0;
// A time stamp indicating when this data object was terminated. Same format as creation time.
//! A time stamp indicating when this data object was terminated. Same format as creation time.
uint64_t m_terminationTime = 0;
// A unique identifier for a player or entity creating the session.
//! A unique identifier for a player or entity creating the session.
AZStd::string m_creatorId;
// A collection of custom properties for a session.
//! A collection of custom properties for a session.
AZStd::unordered_map<AZStd::string, AZStd::string> m_sessionProperties;
// The matchmaking process information that was used to create the session.
//! The matchmaking process information that was used to create the session.
AZStd::string m_matchmakingData;
// A unique identifier for the session.
//! A unique identifier for the session.
AZStd::string m_sessionId;
// A descriptive label that is associated with a session.
//! 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.
//! The DNS identifier assigned to the instance that is running the session.
AZStd::string m_dnsName;
// The IP address of the session.
//! The IP address of the session.
AZStd::string m_ipAddress;
// The port number for the session.
//! The port number for the session.
uint16_t m_port = 0;
// The maximum number of players that can be connected simultaneously to the session.
//! The maximum number of players that can be connected simultaneously to the session.
uint64_t m_maxPlayer = 0;
// Number of players currently in the session.
//! Number of players currently in the session.
uint64_t m_currentPlayer = 0;
// Current status of the session.
//! Current status of the session.
AZStd::string m_status;
// Provides additional information about session status.
//! Provides additional information about session status.
AZStd::string m_statusReason;
};
} // namespace AzFramework
@@ -29,42 +29,42 @@ namespace AzFramework
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
// OnSessionHealthCheck is fired in health check process
// Use this notification to perform any custom health check
// @return True if OnSessionHealthCheck succeeds, false otherwise
//! OnSessionHealthCheck is fired in health check process
//! Use this notification to perform any custom health check
//! @return True if OnSessionHealthCheck succeeds, false otherwise
virtual bool OnSessionHealthCheck() = 0;
// OnCreateSessionBegin is fired at the beginning of session creation process
// Use this notification to perform any necessary configuration or initialization before
// creating session
// @param sessionConfig The properties to describe a session
// @return True if OnCreateSessionBegin succeeds, false otherwise
//! OnCreateSessionBegin is fired at the beginning of session creation process
//! Use this notification to perform any necessary configuration or initialization before
//! creating session
//! @param sessionConfig The properties to describe a session
//! @return True if OnCreateSessionBegin succeeds, false otherwise
virtual bool OnCreateSessionBegin(const SessionConfig& sessionConfig) = 0;
// OnCreateSessionEnd is fired at the end of session creation process
// Use this notification to perform any follow-up operation after session is created and active
//! OnCreateSessionEnd is fired at the end of session creation process
//! Use this notification to perform any follow-up operation after session is created and active
virtual void OnCreateSessionEnd() = 0;
// OnDestroySessionBegin is fired at the beginning of session termination process
// Use this notification to perform any cleanup operation before destroying session,
// like gracefully disconnect players, cleanup data, etc.
// @return True if OnDestroySessionBegin succeeds, false otherwise
//! OnDestroySessionBegin is fired at the beginning of session termination process
//! Use this notification to perform any cleanup operation before destroying session,
//! like gracefully disconnect players, cleanup data, etc.
//! @return True if OnDestroySessionBegin succeeds, false otherwise
virtual bool OnDestroySessionBegin() = 0;
// OnDestroySessionEnd is fired at the end of session termination process
// Use this notification to perform any follow-up operation after session is destroyed,
// like shutdown application process, etc.
//! OnDestroySessionEnd is fired at the end of session termination process
//! Use this notification to perform any follow-up operation after session is destroyed,
//! like shutdown application process, etc.
virtual void OnDestroySessionEnd() = 0;
// OnUpdateSessionBegin is fired at the beginning of session update process
// Use this notification to perform any configuration or initialization to handle
// the session settings changing
// @param sessionConfig The properties to describe a session
// @param updateReason The reason for session update
//! OnUpdateSessionBegin is fired at the beginning of session update process
//! Use this notification to perform any configuration or initialization to handle
//! the session settings changing
//! @param sessionConfig The properties to describe a session
//! @param updateReason The reason for session update
virtual void OnUpdateSessionBegin(const SessionConfig& sessionConfig, const AZStd::string& updateReason) = 0;
// OnUpdateSessionBegin is fired at the end of session update process
// Use this notification to perform any follow-up operations after session is updated
//! OnUpdateSessionBegin is fired at the end of session update process
//! Use this notification to perform any follow-up operations after session is updated
virtual void OnUpdateSessionEnd() = 0;
};
using SessionNotificationBus = AZ::EBus<SessionNotifications>;
@@ -31,16 +31,16 @@ namespace AzFramework
CreateSessionRequest() = default;
virtual ~CreateSessionRequest() = default;
// A unique identifier for a player or entity creating the session.
//! A unique identifier for a player or entity creating the session.
AZStd::string m_creatorId;
// A collection of custom properties for a session.
//! 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.
//! 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.
//! The maximum number of players that can be connected simultaneously to the session.
uint64_t m_maxPlayer = 0;
};
@@ -54,17 +54,17 @@ namespace AzFramework
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.
//! 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.
//! 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.
//! The maximum number of results to return.
uint8_t m_maxResult = 0;
// A token that indicates the start of the next sequential page of results.
//! A token that indicates the start of the next sequential page of results.
AZStd::string m_nextToken;
};
@@ -78,10 +78,10 @@ namespace AzFramework
SearchSessionsResponse() = default;
virtual ~SearchSessionsResponse() = default;
// A collection of sessions that match the search criteria and sorted in specific order.
//! 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.
//! A token that indicates the start of the next sequential page of results.
AZStd::string m_nextToken;
};
@@ -95,13 +95,13 @@ namespace AzFramework
JoinSessionRequest() = default;
virtual ~JoinSessionRequest() = default;
// A unique identifier for the session.
//! A unique identifier for the session.
AZStd::string m_sessionId;
// A unique identifier for a player. Player IDs are developer-defined.
//! A unique identifier for a player. Player IDs are developer-defined.
AZStd::string m_playerId;
// Developer-defined information related to a player.
//! Developer-defined information related to a player.
AZStd::string m_playerData;
};
} // namespace AzFramework
@@ -10,6 +10,8 @@
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzFramework/Process/ProcessWatcher.h>
#include <sys/types.h>
#include <unistd.h>
@@ -24,14 +26,20 @@ namespace AzFramework::AssetSystem::Platform
AZ::IO::FixedMaxPath assetProcessorPath{ executableDirectory };
// In Mac the Editor and game is within a bundle, so the path to the sibling app
// has to go up from the Contents/MacOS folder the binary is in
assetProcessorPath /= "../../../AssetProcessor.app";
assetProcessorPath /= "../../../AssetProcessor.app/Contents/MacOS/AssetProcessor";
assetProcessorPath = assetProcessorPath.LexicallyNormal();
if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str()))
{
// Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure.
assetProcessorPath =
AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.app";
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
if (AZ::IO::FixedMaxPath installedBinariesPath;
settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
{
// Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure.
assetProcessorPath = AZ::IO::FixedMaxPath{ engineRoot } / installedBinariesPath / "AssetProcessor.app/Contents/MacOS/AssetProcessor";
}
}
if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str()))
{
@@ -39,23 +47,21 @@ namespace AzFramework::AssetSystem::Platform
}
}
auto fullLaunchCommand = AZ::IO::FixedMaxPathString::format(R"(open -g "%s" --args --start-hidden)", assetProcessorPath.c_str());
AZStd::string commandLineParams;
// Add the engine path to the launch command if not empty
if (!engineRoot.empty())
{
fullLaunchCommand += R"( --engine-path=")";
fullLaunchCommand += engineRoot;
fullLaunchCommand += '"';
commandLineParams += AZStd::string::format("\"--engine-path=\"%s\"\"", engineRoot.data());
}
// Add the active project path to the launch command if not empty
if (!projectPath.empty())
{
fullLaunchCommand += R"( --project-path=")";
fullLaunchCommand += projectPath;
fullLaunchCommand += '"';
commandLineParams += AZStd::string::format(" \"--regset=/Amazon/AzCore/Bootstrap/project_path=\"%s\"\"", projectPath.data());
}
return system(fullLaunchCommand.c_str()) == 0;
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
processLaunchInfo.m_processExecutableString = AZStd::move(assetProcessorPath.Native());
processLaunchInfo.m_commandlineParameters = commandLineParams;
return AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
}
}
@@ -54,6 +54,7 @@ namespace AzFramework
RECT m_windowRectToRestoreOnFullScreenExit; //!< The position and size of the window to restore when exiting full screen.
UINT m_windowStyleToRestoreOnFullScreenExit; //!< The style(s) of the window to restore when exiting full screen.
bool m_isInBorderlessWindowFullScreenState = false; //!< Was a borderless window used to enter full screen state?
bool m_shouldEnterFullScreenStateOnActivate = false; //!< Should we enter full screen state when the window is activated?
using GetDpiForWindowType = UINT(HWND hwnd);
GetDpiForWindowType* m_getDpiFunction = nullptr;
@@ -249,6 +250,28 @@ namespace AzFramework
AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputCodeUnitUTF16Event, codeUnitUTF16);
break;
}
case WM_ACTIVATE:
{
// Alt-tabbing out of the app while it is in a full screen state does not
// work unless we explicitly exit the full screen state upon deactivation,
// in which case we want to enter full screen state again upon activation.
const bool windowIsNowInactive = (LOWORD(wParam) == WA_INACTIVE);
const bool windowFullScreenState = nativeWindowImpl->GetFullScreenState();
if (windowIsNowInactive &&
windowFullScreenState)
{
nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate = true;
nativeWindowImpl->SetFullScreenState(false);
}
else if (!windowIsNowInactive &&
!windowFullScreenState &&
nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate)
{
nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate = false;
nativeWindowImpl->SetFullScreenState(true);
}
break;
}
case WM_SYSKEYDOWN:
{
// Handle ALT+ENTER to toggle full screen unless exclsuive full screen
@@ -45,6 +45,13 @@ namespace AzGameFramework
enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak";
m_archive->OpenPack("@products@", enginePakPath.Native());
}
// By default, load all archives in the products folder.
// If you want to adjust this for your project, make sure that the archive containing
// the bootstrap for the settings registry is still loaded here, and any archives containing
// assets used early in startup, like default shaders, are loaded here.
constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed)
m_archive->OpenPacks(paksFolder);
}
GameApplication::~GameApplication()
@@ -27,7 +27,6 @@ namespace AzQtComponents
setProperty("HasNoWindowDecorations", true);
setAttribute(Qt::WA_ShowWithoutActivating);
setAttribute(Qt::WA_DeleteOnClose);
m_borderRadius = toastConfiguration.m_borderRadius;
if (m_borderRadius > 0)
@@ -31,7 +31,6 @@ namespace AzQtComponents
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(ToastNotification, AZ::SystemAllocator, 0);
ToastNotification(QWidget* parent, const ToastConfiguration& toastConfiguration);
virtual ~ToastNotification();
@@ -73,7 +72,7 @@ namespace AzQtComponents
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZStd::chrono::milliseconds m_fadeDuration;
AZStd::unique_ptr<Ui::ToastNotification> m_ui;
QScopedPointer<Ui::ToastNotification> m_ui;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
} // namespace AzQtComponents
@@ -27,7 +27,6 @@ namespace AzQtComponents
class AZ_QT_COMPONENTS_API ToastConfiguration
{
public:
AZ_CLASS_ALLOCATOR(ToastConfiguration, AZ::SystemAllocator, 0);
ToastConfiguration(ToastType toastType, const QString& title, const QString& description);
bool m_closeOnClick = true;
@@ -657,13 +657,18 @@ bool SpinBoxWatcher::handleMouseDragStepping(QAbstractSpinBox* spinBox, QEvent*
QPoint screenPos = mouseEvent->screenPos().toPoint();
const int xPos = screenPos.x();
int newXPos = xPos;
// cursor bounces on the left and right side of the screen
// looks like buggy behaviour so mouse cursor is wrapped
// around to the other side of the screen.
if (xPos >= screenRect.right())
{
newXPos = screenRect.right() - 1;
// wraps mouse cursor around to the left side of the screen
newXPos = screenRect.left() + 1;
}
else if (xPos <= screenRect.left())
{
newXPos = screenRect.left() + 1;
// wraps mouse cursor around to the right side of the screen
newXPos = screenRect.right() - 1;
}
if (newXPos != xPos)
@@ -40,7 +40,7 @@ namespace AzToolsFramework
bool isDisabledInSimMode = false; ///< set to true if the view pane should not be openable from level editor menu when editor is in simulation mode.
bool showOnToolsToolbar = false; ///< set to true if the view pane should create a button on the tools toolbar to open/close the pane
QString toolbarIcon; ///< path to the icon to use for the toolbar button - only used if showOnToolsToolbar is set to true
AZStd::string toolbarIcon; ///< path to the icon to use for the toolbar button - only used if showOnToolsToolbar is set to true
};
} // namespace AzToolsFramework
@@ -426,6 +426,8 @@ namespace AzToolsFramework
->Property("showInMenu", BehaviorValueProperty(&ViewPaneOptions::showInMenu))
->Property("canHaveMultipleInstances", BehaviorValueProperty(&ViewPaneOptions::canHaveMultipleInstances))
->Property("isPreview", BehaviorValueProperty(&ViewPaneOptions::isPreview))
->Property("showOnToolsToolbar", BehaviorValueProperty(&ViewPaneOptions::showOnToolsToolbar))
->Property("toolbarIcon", BehaviorValueProperty(&ViewPaneOptions::toolbarIcon))
;
behaviorContext->EBus<EditorRequestBus>("EditorRequestBus")
@@ -102,7 +102,7 @@ namespace AzToolsFramework
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AssetSystemBus::Handler::BusDisconnect();
m_assetBrowserModel.release();
m_assetBrowserModel.reset();
EntryCache::DestroyInstance();
}
@@ -26,8 +26,12 @@ namespace AzToolsFramework
AZ::Interface<ContainerEntityInterface>::Unregister(this);
}
void ContainerEntitySystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
void ContainerEntitySystemComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ContainerEntitySystemComponent, AZ::Component>()->Version(1);
}
}
void ContainerEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
@@ -47,8 +47,12 @@ namespace AzToolsFramework
AZ::Interface<FocusModeInterface>::Unregister(this);
}
void FocusModeSystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
void FocusModeSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<FocusModeSystemComponent, AZ::Component>()->Version(1);
}
}
void FocusModeSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
@@ -210,8 +210,8 @@ namespace AzToolsFramework
m_enabled = enabled;
if (!enabled)
{
// Send an internal focus change event to reset our input state to fresh if we're disabled.
HandleFocusChange(nullptr);
// Clear input channels to reset our input state if we're disabled.
ClearInputChannels(nullptr);
}
}
@@ -246,7 +246,7 @@ namespace AzToolsFramework
if (eventType == QEvent::Type::MouseMove)
{
// clear override cursor when moving outside of the viewport
// Clear override cursor when moving outside of the viewport
const auto* mouseEvent = static_cast<const QMouseEvent*>(event);
if (m_overrideCursor && !m_sourceWidget->geometry().contains(m_sourceWidget->mapFromGlobal(mouseEvent->globalPos())))
{
@@ -255,6 +255,13 @@ namespace AzToolsFramework
}
}
// If the application state changes (e.g. we have alt-tabbed or minimized the
// main editor window) then ensure all input channels are cleared
if (eventType == QEvent::ApplicationStateChange)
{
ClearInputChannels(event);
}
// Only accept mouse & key release events that originate from an object that is not our target widget,
// as we don't want to erroneously intercept user input meant for another component.
if (object != m_sourceWidget && eventType != QEvent::Type::KeyRelease && eventType != QEvent::Type::MouseButtonRelease)
@@ -264,9 +271,6 @@ namespace AzToolsFramework
if (eventType == QEvent::FocusIn || eventType == QEvent::FocusOut)
{
// If our focus changes, go ahead and reset all input devices.
HandleFocusChange(event);
// If we focus in on the source widget and the mouse is contained in its
// bounds, refresh the cached cursor position to ensure it is up to date (this
// ensures cursor positions are refreshed correctly with context menu focus changes)
@@ -451,7 +455,7 @@ namespace AzToolsFramework
NotifyUpdateChannelIfNotIdle(cursorZChannel, wheelEvent);
}
void QtEventToAzInputMapper::HandleFocusChange(QEvent* event)
void QtEventToAzInputMapper::ClearInputChannels(QEvent* event)
{
for (auto& channelData : m_channels)
{
@@ -138,8 +138,9 @@ namespace AzToolsFramework
void HandleKeyEvent(QKeyEvent* keyEvent);
// Handles mouse wheel events.
void HandleWheelEvent(QWheelEvent* wheelEvent);
// Handles focus change events.
void HandleFocusChange(QEvent* event);
// Clear all input channels (set all channel states to 'ended').
void ClearInputChannels(QEvent* event);
// Populates m_keyMappings.
void InitializeKeyMappings();
@@ -12,11 +12,12 @@
#include <AzCore/Utils/TypeHash.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.h>
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
@@ -565,6 +566,7 @@ namespace AzToolsFramework
parentId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
}
// If the parent entity isn't owned by a prefab instance, bail.
InstanceOptionalReference owningInstanceOfParentEntity = GetOwnerInstanceByEntityId(parentId);
if (!owningInstanceOfParentEntity)
{
@@ -572,6 +574,14 @@ namespace AzToolsFramework
"Cannot add entity because the owning instance of parent entity with id '%llu' could not be found.",
static_cast<AZ::u64>(parentId)));
}
// If the parent entity is a closed container, bail.
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get(); !containerEntityInterface->IsContainerOpen(parentId))
{
return AZ::Failure(AZStd::string::format(
"Cannot add entity because the parent entity (id '%llu') is a closed container entity.",
static_cast<AZ::u64>(parentId)));
}
EntityAlias entityAlias = Instance::GenerateEntityAlias();
@@ -129,7 +129,7 @@ namespace AzToolsFramework
ToastId ToastNotificationsView::CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration)
{
AzQtComponents::ToastNotification* notification = aznew AzQtComponents::ToastNotification(parentWidget(), toastConfiguration);
AzQtComponents::ToastNotification* notification = new AzQtComponents::ToastNotification(this, toastConfiguration);
ToastId toastId = AZ::Entity::MakeId();
m_notifications[toastId] = notification;
@@ -10,7 +10,6 @@ AzToolsFramework--EntityOutlinerWidget #m_display_options
{
qproperty-icon: url(:/stylesheet/img/UI20/menu-centered.svg);
qproperty-iconSize: 16px 16px;
qproperty-flat: true;
}
AzToolsFramework--EntityOutlinerWidget QTreeView
@@ -43,6 +43,7 @@
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserSourceDropBus.h>
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
@@ -764,10 +765,21 @@ namespace AzToolsFramework
return canHandleData;
}
bool EntityOutlinerListModel::CanDropMimeDataAssets(const QMimeData* data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex& /*parent*/) const
bool EntityOutlinerListModel::CanDropMimeDataAssets(
const QMimeData* data,
[[maybe_unused]] Qt::DropAction action,
[[maybe_unused]] int row,
[[maybe_unused]] int column,
const QModelIndex& parent) const
{
using namespace AzToolsFramework;
// Disable dropping assets on closed container entities.
AZ::EntityId parentId = GetEntityFromIndex(parent);
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
!containerEntityInterface->IsContainerOpen(parentId))
{
return false;
}
if (data->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType()))
{
return DecodeAssetMimeData(data);
@@ -788,8 +800,15 @@ namespace AzToolsFramework
return false;
}
// If the parent entity is a closed container, bail.
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
!containerEntityInterface->IsContainerOpen(assignParentId))
{
return false;
}
// Source Files
if (sourceFiles.size() > 0)
if (!sourceFiles.empty())
{
// Get position (center of viewport). If no viewport is available, (0,0,0) will be used.
AZ::Vector3 viewportCenterPosition = AZ::Vector3::CreateZero();
@@ -973,6 +992,12 @@ namespace AzToolsFramework
return false;
}
// If the new parent is a closed container, bail.
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get(); !containerEntityInterface->IsContainerOpen(newParentId))
{
return false;
}
// Ignore entities not owned by the editor context. It is assumed that all entities belong
// to the same context since multiple selection doesn't span across views.
for (const AZ::EntityId& entityId : selectedEntityIds)
@@ -80,8 +80,9 @@ namespace AzToolsFramework
private:
AZStd::string m_message; //!< Message to display for fading text.
float m_opacity = 1.0f; //!< The opacity of the invalid click message.
AzFramework::ScreenPoint m_invalidClickPosition; //!< The position to display the invalid click message.
float m_opacity = 0.0f; //!< The opacity of the invalid click message.
//! The position to display the invalid click message.
AzFramework::ScreenPoint m_invalidClickPosition = AzFramework::ScreenPoint(0, 0);
};
//! Interface to begin invalid click feedback (will run all added InvalidClick behaviors).
@@ -28,9 +28,12 @@ namespace UnitTest
return true;
}
void BoundsTestComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
void BoundsTestComponent::Reflect(AZ::ReflectContext* context)
{
// noop
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<BoundsTestComponent, EditorComponentBase>()->Version(1);
}
}
void BoundsTestComponent::Activate()
@@ -42,5 +42,4 @@ namespace UnitTest
AZ::Aabb GetWorldBounds() override;
AZ::Aabb GetLocalBounds() override;
};
} // namespace UnitTest
@@ -0,0 +1,130 @@
/*
* 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
*
*/
#if defined(HAVE_BENCHMARK)
#include <Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h>
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
namespace Benchmark
{
using BM_SpawnAllEntities = BM_Spawnable;
BENCHMARK_DEFINE_F(BM_SpawnAllEntities, SingleEntitySpawnable_SpawnCallVariable)(::benchmark::State& state)
{
const uint64_t spawnAllEntitiesCallCount = aznumeric_cast<uint64_t>(state.range());
const uint64_t entityCountInSourcePrefab = 1;
SetUpSpawnableAsset(entityCountInSourcePrefab);
for (auto _ : state)
{
state.PauseTiming();
m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
state.ResumeTiming();
for (uint64_t spwanableCounter = 0; spwanableCounter < spawnAllEntitiesCallCount; spwanableCounter++)
{
AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
}
m_rootSpawnableInterface->ProcessSpawnableQueue();
// Destroy the ticket so that this queues a request to delete all the entities spawned with this ticket.
state.PauseTiming();
delete m_spawnTicket;
m_spawnTicket = nullptr;
// This will process the request to delete all entities spawned with the ticket
m_rootSpawnableInterface->ProcessSpawnableQueue();
state.ResumeTiming();
}
state.SetComplexityN(spawnAllEntitiesCallCount);
}
BENCHMARK_REGISTER_F(BM_SpawnAllEntities, SingleEntitySpawnable_SpawnCallVariable)
->RangeMultiplier(10)
->Range(100, 10000)
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK_DEFINE_F(BM_SpawnAllEntities, SingleSpawnCall_EntityCountVariable)(::benchmark::State& state)
{
const uint64_t entityCountInSpawnable = aznumeric_cast<uint64_t>(state.range());
SetUpSpawnableAsset(entityCountInSpawnable);
for (auto _ : state)
{
state.PauseTiming();
m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
state.ResumeTiming();
AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
m_rootSpawnableInterface->ProcessSpawnableQueue();
// Destroy the ticket so that this queues a request to delete all the entities spawned with this ticket.
state.PauseTiming();
delete m_spawnTicket;
m_spawnTicket = nullptr;
// This will process the request to delete all entities spawned with the ticket
m_rootSpawnableInterface->ProcessSpawnableQueue();
state.ResumeTiming();
}
state.SetComplexityN(entityCountInSpawnable);
}
BENCHMARK_REGISTER_F(BM_SpawnAllEntities, SingleSpawnCall_EntityCountVariable)
->RangeMultiplier(10)
->Range(100, 10000)
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK_DEFINE_F(BM_SpawnAllEntities, EntityCountVariable_SpawnCallCountVariable)(::benchmark::State& state)
{
const uint64_t entityCountInSpawnable = aznumeric_cast<uint64_t>(state.range(0));
const uint64_t spawnCallCount = aznumeric_cast<uint64_t>(state.range(1));
SetUpSpawnableAsset(entityCountInSpawnable);
for (auto _ : state)
{
state.PauseTiming();
m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
state.ResumeTiming();
for (uint64_t spawnCallCounter = 0; spawnCallCounter < spawnCallCount; spawnCallCounter++)
{
AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
}
m_rootSpawnableInterface->ProcessSpawnableQueue();
state.PauseTiming();
delete m_spawnTicket;
m_spawnTicket = nullptr;
m_rootSpawnableInterface->ProcessSpawnableQueue();
state.ResumeTiming();
}
state.SetComplexityN(entityCountInSpawnable * spawnCallCount);
}
// Provide ranges here to compare times for spawning the same number of entities by altering entityCountInSpawnable and spawnCallCount.
BENCHMARK_REGISTER_F(BM_SpawnAllEntities, EntityCountVariable_SpawnCallCountVariable)
->Args({ 10, 100 })
->Args({ 100, 10 })
->Args({ 10, 1000 })
->Args({ 1000, 10 })
->Args({ 100, 1000 })
->Args({ 1000, 100 })
->Unit(benchmark::kMillisecond)
->Complexity();
} // namespace Benchmark
#endif
@@ -0,0 +1,69 @@
/*
* 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
*
*/
#if defined(HAVE_BENCHMARK)
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
#include <Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h>
namespace Benchmark
{
void BM_Spawnable::SetUp(const benchmark::State& state)
{
SetUpHelper(state);
}
void BM_Spawnable::SetUp(benchmark::State& state)
{
SetUpHelper(state);
}
void BM_Spawnable::SetUpHelper(const benchmark::State& state)
{
BM_Prefab::SetUp(state);
m_rootSpawnableInterface = AzFramework::RootSpawnableInterface::Get();
AZ_Assert(m_rootSpawnableInterface != nullptr, "RootSpawnableInterface isn't found.");
}
void BM_Spawnable::TearDown(const benchmark::State& state)
{
TearDownHelper(state);
}
void BM_Spawnable::TearDown(benchmark::State& state)
{
TearDownHelper(state);
}
void BM_Spawnable::TearDownHelper(const benchmark::State& state)
{
m_spawnableAsset.Release();
BM_Prefab::TearDown(state);
}
void BM_Spawnable::SetUpSpawnableAsset(uint64_t entityCount)
{
AZStd::vector<AZ::Entity*> entities;
entities.reserve(entityCount);
for (uint64_t i = 0; i < entityCount; i++)
{
entities.emplace_back(CreateEntity("Entity"));
}
AZStd::unique_ptr<Instance> instance = m_prefabSystemComponent->CreatePrefab(AZStd::move(entities), {}, m_pathString);
const PrefabDom& prefabDom = m_prefabSystemComponent->FindTemplateDom(instance->GetTemplateId());
// Lifecycle of spawnable is managed by the asset that's created using it.
AzFramework::Spawnable* spawnable = new AzFramework::Spawnable(
AZ::Data::AssetId::CreateString("{612F2AB1-30DF-44BB-AFBE-17A85199F09E}:0"), AZ::Data::AssetData::AssetStatus::Ready);
AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(*spawnable, prefabDom);
m_spawnableAsset = AZ::Data::Asset<AzFramework::Spawnable>(spawnable, AZ::Data::AssetLoadBehavior::Default);
}
} // namespace Benchmark
#endif
@@ -0,0 +1,44 @@
/*
* 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
*
*/
#if defined(HAVE_BENCHMARK)
#pragma once
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
#include <Prefab/Benchmark/PrefabBenchmarkFixture.h>
namespace AzFramework
{
class EntitySpawnTicket;
class RootSpawnableDefinition;
}
namespace Benchmark
{
class BM_Spawnable
: public Benchmark::BM_Prefab
{
protected:
void SetUp(const benchmark::State& state) override;
void SetUp(benchmark::State& state) override;
void SetUpHelper(const benchmark::State& state);
void TearDown(const benchmark::State& state) override;
void TearDown(benchmark::State& state) override;
void TearDownHelper(const benchmark::State& state);
void SetUpSpawnableAsset(uint64_t entityCount);
AZ::Data::Asset<AzFramework::Spawnable> m_spawnableAsset;
AzFramework::EntitySpawnTicket* m_spawnTicket;
AzFramework::RootSpawnableDefinition* m_rootSpawnableInterface;
};
} // namespace Benchmark
#endif
@@ -60,6 +60,9 @@ set(FILES
Prefab/Benchmark/PrefabLoadBenchmarks.cpp
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h
Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.cpp
Prefab/Benchmark/Spawnable/SpawnAllEntitiesBenchmarks.cpp
Prefab/PrefabFocus/PrefabFocusTests.cpp
Prefab/MockPrefabFileIOActionValidator.cpp
Prefab/MockPrefabFileIOActionValidator.h