diff --git a/AutomatedTesting/Levels/Physics/C14902098_ScriptCanvas_PostPhysicsUpdate/onpostphysicsupdate.scriptcanvas b/AutomatedTesting/Levels/Physics/C14902098_ScriptCanvas_PostPhysicsUpdate/onpostphysicsupdate.scriptcanvas
index f4ca23b882..10c40fbb9f 100644
--- a/AutomatedTesting/Levels/Physics/C14902098_ScriptCanvas_PostPhysicsUpdate/onpostphysicsupdate.scriptcanvas
+++ b/AutomatedTesting/Levels/Physics/C14902098_ScriptCanvas_PostPhysicsUpdate/onpostphysicsupdate.scriptcanvas
@@ -742,14 +742,14 @@
-
+
-
+
diff --git a/AutomatedTesting/ScriptCanvas/C14195074_ScriptCanvas_PostUpdateEvent.scriptcanvas b/AutomatedTesting/ScriptCanvas/C14195074_ScriptCanvas_PostUpdateEvent.scriptcanvas
index b9f438a4f3..ffdac5dd8c 100644
--- a/AutomatedTesting/ScriptCanvas/C14195074_ScriptCanvas_PostUpdateEvent.scriptcanvas
+++ b/AutomatedTesting/ScriptCanvas/C14195074_ScriptCanvas_PostUpdateEvent.scriptcanvas
@@ -1045,14 +1045,14 @@
-
+
-
+
diff --git a/AutomatedTesting/ScriptCanvas/C14902097_ScriptCanvas_PreUpdateEvent.scriptcanvas b/AutomatedTesting/ScriptCanvas/C14902097_ScriptCanvas_PreUpdateEvent.scriptcanvas
index 7db4f3a35c..4954eb4684 100644
--- a/AutomatedTesting/ScriptCanvas/C14902097_ScriptCanvas_PreUpdateEvent.scriptcanvas
+++ b/AutomatedTesting/ScriptCanvas/C14902097_ScriptCanvas_PreUpdateEvent.scriptcanvas
@@ -1085,14 +1085,14 @@
-
+
-
+
diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp
index 3f86260f8d..c2f16a84b1 100644
--- a/Code/Editor/EditorViewportWidget.cpp
+++ b/Code/Editor/EditorViewportWidget.cpp
@@ -1896,7 +1896,7 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
if (m_pressedKeyState != KeyPressedState::PressedInPreviousFrame)
{
- CUndo undo("Move Camera");
+ AzToolsFramework::ScopedUndoBatch undo("Move Camera");
if (bMoveOnly)
{
// specify eObjectUpdateFlags_UserInput so that an undo command gets logged
@@ -1932,7 +1932,7 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
if (m_pressedKeyState != KeyPressedState::PressedInPreviousFrame)
{
- CUndo undo("Move Camera");
+ AzToolsFramework::ScopedUndoBatch undo("Move Camera");
if (bMoveOnly)
{
AZ::TransformBus::Event(
@@ -1945,6 +1945,8 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
m_viewEntityId, &AZ::TransformInterface::SetWorldTM,
LYTransformToAZTransform(camMatrix));
}
+
+ AzToolsFramework::ToolsApplicationRequestBus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::AddDirtyEntity, m_viewEntityId);
}
else
{
diff --git a/Code/Editor/Platform/Mac/gui_info.plist b/Code/Editor/Platform/Mac/gui_info.plist
index 0ec7b59e98..5b5f94e977 100644
--- a/Code/Editor/Platform/Mac/gui_info.plist
+++ b/Code/Editor/Platform/Mac/gui_info.plist
@@ -5,7 +5,7 @@
CFBundleExecutable
Editor
CFBundleIdentifier
- com.Amazon.Lumberyard.Editor
+ org.O3DE.Editor
CFBundlePackageType
APPL
CFBundleSignature
diff --git a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
index 96d9cce5b7..048f77cd0c 100644
--- a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
+++ b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
@@ -46,4 +46,8 @@ ly_add_target(
AZ::AzCore
AZ::AzToolsFramework
AZ::AzQtComponents
+ RUNTIME_DEPENDENCIES
+ AZ::AzCore
+ AZ::AzToolsFramework
+ AZ::AzQtComponents
)
diff --git a/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp b/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp
index 46717440d5..82e230d54a 100644
--- a/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp
+++ b/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp
@@ -116,7 +116,7 @@ namespace AZ
{
const char* uuidString = nullptr;
unsigned int uuidStringLength = 0;
- if (dc.ReadArg(0, uuidString) && dc.ReadValue(1, uuidStringLength))
+ if (dc.ReadArg(0, uuidString) && dc.ReadArg(1, uuidStringLength))
{
dc.PushResult(Uuid(uuidString, uuidStringLength));
}
diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptContextDebug.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptContextDebug.cpp
index b68b19ddda..0444c4ce2a 100644
--- a/Code/Framework/AzCore/AzCore/Script/ScriptContextDebug.cpp
+++ b/Code/Framework/AzCore/AzCore/Script/ScriptContextDebug.cpp
@@ -157,8 +157,11 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
lua_pop(l, 2); // pop the Class name and behaviorClass
lua_pushnil(l);
+
+ // iterate over the key/value pairs
while (lua_next(l, -2) != 0)
{
+ // if key: string value: function
if (lua_isstring(l, -2) && lua_isfunction(l, -1))
{
const char* name = lua_tostring(l, -2);
@@ -167,6 +170,7 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
bool isRead = true;
bool isWrite = true;
+ // check if there is a getter provided
lua_getupvalue(l, -1, 1);
if (lua_isnil(l, -1))
{
@@ -174,6 +178,7 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
}
lua_pop(l, 1);
+ // check if there is a setter provided
lua_getupvalue(l, -1, 2);
if (lua_isnil(l, -1))
{
@@ -181,6 +186,7 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
}
lua_pop(l, 1);
+ // enumerate the remaining property
if (!enumProperty(&behaviorClass->m_typeId, name, isRead, isWrite, userData))
{
lua_pop(l, 5);
@@ -189,21 +195,30 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
}
else
{
+ // for any non-built in methods
if (strncmp(name, "__", 2) != 0)
{
const char* dbgParamInfo = NULL;
- lua_getupvalue(l, -1, 2);
+
+ // attempt to get the name
+ bool popDebugName = lua_getupvalue(l, -1, 2) != nullptr;
if (lua_isstring(l, -1))
{
dbgParamInfo = lua_tostring(l, -1);
}
+ // enumerate the method's parameters
if (!enumMethod(&behaviorClass->m_typeId, name, dbgParamInfo, userData))
{
lua_pop(l, 6);
return;
}
- lua_pop(l, 1); // pop the DBG name
+
+ // if we were able to get the name, pop it from the stack
+ if (popDebugName)
+ {
+ lua_pop(l, 1);
+ }
}
}
}
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h b/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h
index a1ec4a05f0..a122fe3133 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h
@@ -205,6 +205,25 @@ namespace AzFramework
class InputDeviceImplementationRequest : public AZ::EBusTraits
{
public:
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! EBus Trait: requests can be addressed to a specific InputDeviceId so that they are only
+ //! handled by one input device that has connected to the bus using that unique id, or they
+ //! can be broadcast to all input devices that have connected to the bus, regardless of id.
+ //! Connected input devices are ordered by their local player index from lowest to highest.
+ static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ByIdAndOrdered;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! EBus Trait: requests should be handled by only one input device connected to each id
+ static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! EBus Trait: requests can be addressed to a specific InputDeviceId
+ using BusIdType = InputDeviceId;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! EBus Trait: requests are handled by connected devices in the order of local player index
+ using BusIdOrderCompare = AZStd::less;
+
////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the EBus implementation of this interface
using Bus = AZ::EBus>;
@@ -214,11 +233,12 @@ namespace AzFramework
using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
////////////////////////////////////////////////////////////////////////////////////////////
- //! Create a custom implementation for all the existing instances of this input device type.
+ //! 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 CreateCustomImplementation(CreateFunctionType createFunction) = 0;
+ virtual void SetCustomImplementation(CreateFunctionType createFunction) = 0;
};
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -238,7 +258,7 @@ namespace AzFramework
AZ_INLINE InputDeviceImplementationRequestHandler(InputDeviceType& inputDevice)
: m_inputDevice(inputDevice)
{
- InputDeviceImplementationRequest::Bus::Handler::BusConnect();
+ InputDeviceImplementationRequest::Bus::Handler::BusConnect(m_inputDevice.GetInputDeviceId());
}
////////////////////////////////////////////////////////////////////////////////////////////
@@ -251,8 +271,8 @@ namespace AzFramework
using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
////////////////////////////////////////////////////////////////////////////////////////////
- //! \ref InputDeviceImplementationRequest::CreateCustomImplementation
- AZ_INLINE void CreateCustomImplementation(CreateFunctionType createFunction) override
+ //! \ref InputDeviceImplementationRequest::SetCustomImplementation
+ AZ_INLINE void SetCustomImplementation(CreateFunctionType createFunction) override
{
AZStd::unique_ptr newImplementation;
if (createFunction)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorPythonConsoleBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorPythonConsoleBus.h
index 51aecbd8e7..6dd6b0b448 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorPythonConsoleBus.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorPythonConsoleBus.h
@@ -63,6 +63,9 @@ namespace AzToolsFramework
//! Signal the Python handler to stop
virtual bool StopPython(bool silenceWarnings = false) = 0;
+ //! Query to determine if the Python VM has been initialized indicating an active state
+ virtual bool IsPythonActive() = 0;
+
//! Determines if the caller needs to wait for the Python VM to initialize (non-main thread only)
virtual void WaitForInitialization() {}
diff --git a/Code/Tools/SceneAPI/SceneCore/Components/ExportingComponent.cpp b/Code/Tools/SceneAPI/SceneCore/Components/ExportingComponent.cpp
index 62daba1197..911f469b2f 100644
--- a/Code/Tools/SceneAPI/SceneCore/Components/ExportingComponent.cpp
+++ b/Code/Tools/SceneAPI/SceneCore/Components/ExportingComponent.cpp
@@ -7,6 +7,8 @@
#include
#include
+#include
+#include
namespace AZ
{
@@ -31,6 +33,12 @@ namespace AZ
{
serializeContext->Class()->Version(2);
}
+
+ AZ::BehaviorContext* behaviorContext = azrtti_cast(context);
+ if (behaviorContext)
+ {
+ Events::ExportProductList::Reflect(behaviorContext);
+ }
}
} // namespace SceneCore
} // namespace SceneAPI
diff --git a/Code/Tools/SceneAPI/SceneCore/DllMain.cpp b/Code/Tools/SceneAPI/SceneCore/DllMain.cpp
index 7874ada7be..ac3c307b6c 100644
--- a/Code/Tools/SceneAPI/SceneCore/DllMain.cpp
+++ b/Code/Tools/SceneAPI/SceneCore/DllMain.cpp
@@ -211,6 +211,7 @@ namespace AZ
AZ::SceneAPI::Containers::SceneGraph::Reflect(context);
AZ::SceneAPI::Containers::SceneManifest::Reflect(context);
AZ::SceneAPI::Containers::RuleContainer::Reflect(context);
+ AZ::SceneAPI::SceneCore::ExportingComponent::Reflect(context);
}
void Activate()
diff --git a/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.cpp b/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.cpp
index c3a9abcbd2..798978024e 100644
--- a/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.cpp
+++ b/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.cpp
@@ -6,6 +6,8 @@
*/
#include
+#include
+#include
namespace AZ
{
@@ -49,6 +51,45 @@ namespace AZ
return *this;
}
+ void ExportProductList::Reflect(ReflectContext* context)
+ {
+ if (auto* serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()->Version(1);
+ serializeContext->Class()->Version(1);
+ }
+
+ if (auto* behaviorContext = azrtti_cast(context))
+ {
+ behaviorContext->Class("ExportProduct")
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ ->Attribute(AZ::Script::Attributes::Module, "scene")
+ ->Property("filename", BehaviorValueProperty(&ExportProduct::m_filename))
+ ->Property("sourceId", BehaviorValueProperty(&ExportProduct::m_id))
+ ->Property("assetType", BehaviorValueProperty(&ExportProduct::m_assetType))
+ ->Property("productDependencies", BehaviorValueProperty(&ExportProduct::m_productDependencies))
+ ->Property("subId",
+ [](ExportProduct* self) { return self->m_subId.has_value() ? self->m_subId.value() : 0; },
+ [](ExportProduct* self, u32 subId) { self->m_subId = AZStd::optional(subId); });
+
+ behaviorContext->Class("ExportProductList")
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ ->Attribute(AZ::Script::Attributes::Module, "scene")
+ ->Method("AddProduct", [](ExportProductList& self, ExportProduct& product)
+ {
+ self.AddProduct(
+ product.m_filename,
+ product.m_id,
+ product.m_assetType,
+ product.m_lod,
+ product.m_subId,
+ product.m_dependencyFlags);
+ })
+ ->Method("GetProducts", &ExportProductList::GetProducts)
+ ->Method("AddDependencyToProduct", &ExportProductList::AddDependencyToProduct);
+ }
+ }
+
ExportProduct& ExportProductList::AddProduct(const AZStd::string& filename, Uuid id, Data::AssetType assetType, AZStd::optional lod, AZStd::optional subId,
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags)
{
diff --git a/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.h b/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.h
index 38deea3f9f..a99303e08b 100644
--- a/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.h
+++ b/Code/Tools/SceneAPI/SceneCore/Events/ExportProductList.h
@@ -14,6 +14,8 @@
namespace AZ
{
+ class ReflectContext;
+
namespace SceneAPI
{
namespace Events
@@ -24,6 +26,7 @@ namespace AZ
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags = Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad));
SCENE_CORE_API ExportProduct(AZStd::string&& filename, Uuid id, Data::AssetType assetType, AZStd::optional lod, AZStd::optional subId,
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags = Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad));
+ ExportProduct() = default;
ExportProduct(const ExportProduct& rhs) = default;
SCENE_CORE_API ExportProduct(ExportProduct&& rhs);
@@ -54,6 +57,8 @@ namespace AZ
class ExportProductList
{
public:
+ static void Reflect(ReflectContext* context);
+
SCENE_CORE_API ExportProduct& AddProduct(const AZStd::string& filename, Uuid id, Data::AssetType assetType, AZStd::optional lod, AZStd::optional subId,
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags = Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad));
SCENE_CORE_API ExportProduct& AddProduct(AZStd::string&& filename, Uuid id, Data::AssetType assetType, AZStd::optional lod, AZStd::optional subId,
@@ -69,3 +74,9 @@ namespace AZ
} // namespace Events
} // namespace SceneAPI
} // namespace AZ
+
+namespace AZ
+{
+ AZ_TYPE_INFO_SPECIALIZE(SceneAPI::Events::ExportProduct, "{6054EDCB-4C04-4D96-BF26-704999FFB725}");
+ AZ_TYPE_INFO_SPECIALIZE(SceneAPI::Events::ExportProductList, "{1C76A51F-431B-4987-B653-CFCC940D0D0F}");
+}
diff --git a/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp b/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp
index a4b002db7d..073f357ee6 100644
--- a/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp
+++ b/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -75,15 +76,16 @@ namespace AZ
filename += s_extension;
filename += s_generated;
- AZStd::string altManifestPath = path;
+ AZStd::string altManifestFolder = path;
AzFramework::ApplicationRequests::Bus::Broadcast(
- &AzFramework::ApplicationRequests::Bus::Events::MakePathRootRelative,
- altManifestPath);
+ &AzFramework::ApplicationRequests::Bus::Events::MakePathRelative,
+ altManifestFolder,
+ AZ::Utils::GetProjectPath().c_str());
- AZ::StringFunc::Path::GetFolderPath(altManifestPath.c_str(), altManifestPath);
+ AZ::StringFunc::Path::GetFolderPath(altManifestFolder.c_str(), altManifestFolder);
AZStd::string generatedAssetInfoPath;
- AZ::StringFunc::Path::Join(assetCacheRoot.c_str(), altManifestPath.c_str(), generatedAssetInfoPath);
+ AZ::StringFunc::Path::Join(assetCacheRoot.c_str(), altManifestFolder.c_str(), generatedAssetInfoPath);
AZ::StringFunc::Path::ConstructFull(generatedAssetInfoPath.c_str(), filename.c_str(), generatedAssetInfoPath);
if (!AZ::IO::FileIOBase::GetInstance()->Exists(generatedAssetInfoPath.c_str()))
diff --git a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp
index e1c72bc8b4..4e08181b83 100644
--- a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp
+++ b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp
@@ -28,710 +28,731 @@ extern "C" AZ_DLL_EXPORT void ReflectBehavior(AZ::BehaviorContext* context);
// the DLL entry point for SceneCore to reflect its serialize context
extern "C" AZ_DLL_EXPORT void ReflectTypes(AZ::SerializeContext* context);
-namespace AZ
+namespace AZ::SceneAPI::Containers
{
- namespace SceneAPI
+ class MockManifestRule : public DataTypes::IManifestObject
{
- namespace Containers
+ public:
+ AZ_RTTI(MockManifestRule, "{D6F96B48-4E6F-4EE8-A5A3-959B76F90DA8}", IManifestObject);
+ AZ_CLASS_ALLOCATOR(MockManifestRule, AZ::SystemAllocator, 0);
+
+ MockManifestRule() = default;
+
+ MockManifestRule(double value)
+ : m_value(value)
{
- class MockManifestRule : public DataTypes::IManifestObject
+ }
+
+ double GetValue() const
+ {
+ return m_value;
+ }
+
+ void SetValue(double value)
+ {
+ m_value = value;
+ }
+
+ static void Reflect(AZ::ReflectContext* context)
+ {
+ AZ::SerializeContext* serializeContext = azrtti_cast(context);
+ if (serializeContext)
{
- public:
- AZ_RTTI(MockManifestRule, "{D6F96B48-4E6F-4EE8-A5A3-959B76F90DA8}", IManifestObject);
- AZ_CLASS_ALLOCATOR(MockManifestRule, AZ::SystemAllocator, 0);
-
- MockManifestRule() = default;
-
- MockManifestRule(double value)
- : m_value(value)
- {
- }
-
- double GetValue() const
- {
- return m_value;
- }
-
- void SetValue(double value)
- {
- m_value = value;
- }
-
- static void Reflect(AZ::ReflectContext* context)
- {
- AZ::SerializeContext* serializeContext = azrtti_cast(context);
- if (serializeContext)
- {
- serializeContext->Class()
- ->Version(1)
- ->Field("value", &MockManifestRule::m_value);
- }
- }
-
- private:
- double m_value = 0.0;
- };
-
- struct MockBuilder final
- {
- AZ_TYPE_INFO(MockBuilder, "{ECF0FB2C-E5C0-4B89-993C-8511A7EF6894}");
-
- AZStd::unique_ptr m_scene;
-
- MockBuilder()
- {
- m_scene = AZStd::make_unique("unit_scene");
- }
-
- ~MockBuilder()
- {
- m_scene.reset();
- }
-
- void BuildSceneGraph()
- {
- m_scene->SetManifestFilename("manifest_filename");
- m_scene->SetSource("unit_source_filename", azrtti_typeid());
-
- auto& graph = m_scene->GetGraph();
-
- /*----------------------------\
- | Root |
- | / \ |
- | | | |
- | A B |
- | | /|\ |
- | C I J K |
- | / | \ \ |
- | D E F L |
- | / \ |
- | G H |
- \----------------------------*/
-
- //Build up the graph
- const auto indexA = graph.AddChild(graph.GetRoot(), "A", AZStd::make_shared(1));
- const auto indexC = graph.AddChild(indexA, "C", AZStd::make_shared(3));
- const auto indexE = graph.AddChild(indexC, "E", AZStd::make_shared(4));
- graph.AddChild(indexC, "D", AZStd::make_shared(5));
- graph.AddChild(indexC, "F", AZStd::make_shared(6));
- graph.AddChild(indexE, "G", AZStd::make_shared(7));
- graph.AddChild(indexE, "H", AZStd::make_shared(8));
- const auto indexB = graph.AddChild(graph.GetRoot(), "B", AZStd::make_shared(2));
- const auto indexK = graph.AddChild(indexB, "K", AZStd::make_shared(2));
- graph.AddChild(indexB, "I", AZStd::make_shared(9));
- graph.AddChild(indexB, "J", AZStd::make_shared(10));
- graph.AddChild(indexK, "L", AZStd::make_shared(12));
-
- m_scene->GetManifest().AddEntry(AZStd::make_shared(0.1));
- m_scene->GetManifest().AddEntry(AZStd::make_shared(2.3));
- m_scene->GetManifest().AddEntry(AZStd::make_shared(4.5));
- }
-
- static void Reflect(ReflectContext* context)
- {
- BehaviorContext* behaviorContext = azrtti_cast(context);
- if (behaviorContext)
- {
- behaviorContext->Class()
- ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
- ->Attribute(AZ::Script::Attributes::Module, "scene")
- ->Method("BuildSceneGraph", [](MockBuilder& self)
- {
- return self.BuildSceneGraph();
- })
- ->Method("GetScene", [](MockBuilder& self)
- {
- return self.m_scene.get();
- });
- }
- }
- };
-
- class SceneGraphBehaviorTest
- : public ::testing::Test
- {
- public:
- void SetUp() override
- {
- m_behaviorContext = AZStd::make_unique();
- ReflectBehavior(m_behaviorContext.get());
- }
-
- void TearDown() override
- {
- m_behaviorContext.reset();
- }
-
- AZ::BehaviorClass* GetBehaviorClass(const AZ::TypeId& behaviorClassType)
- {
- auto entry = m_behaviorContext->m_typeToClassMap.find(behaviorClassType);
- return (entry != m_behaviorContext->m_typeToClassMap.end()) ? entry->second : nullptr;
- }
-
- AZ::BehaviorProperty* GetBehaviorProperty(AZ::BehaviorClass& behaviorClass, AZStd::string_view propertyName)
- {
- auto entry = behaviorClass.m_properties.find(propertyName);
- return (entry != behaviorClass.m_properties.end()) ? entry->second : nullptr;
- }
-
- bool HasBehaviorClass(const AZ::TypeId& behaviorClassType)
- {
- return GetBehaviorClass(behaviorClassType) != nullptr;
- }
-
- bool HasProperty(AZ::BehaviorClass& behaviorClass, AZStd::string_view propertyName, const AZ::TypeId& propertyClassType)
- {
- AZ::BehaviorProperty* behaviorProperty = GetBehaviorProperty(behaviorClass, propertyName);
- if (behaviorProperty)
- {
- return behaviorProperty->m_getter->GetResult()->m_typeId == propertyClassType;
- }
- return false;
- }
-
- using ArgList = AZStd::vector;
-
- bool HasMethodWithInput(AZ::BehaviorClass& behaviorClass, AZStd::string_view methodName, const ArgList& input)
- {
- auto entry = behaviorClass.m_methods.find(methodName);
- if (entry == behaviorClass.m_methods.end())
- {
- return false;
- }
- AZ::BehaviorMethod* method = entry->second;
-
- const size_t methodArgsCount = method->IsMember() ? method->GetNumArguments() - 1 : method->GetNumArguments();
- if (input.size() != methodArgsCount)
- {
- return false;
- }
-
- for (size_t argIndex = 0; argIndex < input.size(); ++argIndex)
- {
- const size_t thisPointerOffset = method->IsMember() ? 1 : 0;
- const auto argType = method->GetArgument(argIndex + thisPointerOffset)->m_typeId;
- const auto inputType = input[argIndex];
- if (inputType != argType)
- {
- return false;
- }
- }
- return true;
- }
-
- bool HasMethodWithOutput(AZ::BehaviorClass& behaviorClass, AZStd::string_view methodName, const AZ::TypeId& output, const ArgList& input)
- {
- auto entry = behaviorClass.m_methods.find(methodName);
- if (entry == behaviorClass.m_methods.end())
- {
- return false;
- }
- AZ::BehaviorMethod* method = entry->second;
- if (method->HasResult())
- {
- if (method->GetResult()->m_typeId != output)
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- return HasMethodWithInput(behaviorClass, methodName, input);
- }
-
- AZStd::unique_ptr m_behaviorContext;
- };
-
- TEST_F(SceneGraphBehaviorTest, SceneClass_BehaviorContext_Exists)
- {
- EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
- }
-
- TEST_F(SceneGraphBehaviorTest, SceneClass_BehaviorContext_HasExpectedProperties)
- {
- AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
- ASSERT_NE(nullptr, behaviorClass);
- EXPECT_TRUE(HasProperty(*behaviorClass, "name", azrtti_typeid()));
- EXPECT_TRUE(HasProperty(*behaviorClass, "manifestFilename", azrtti_typeid()));
- EXPECT_TRUE(HasProperty(*behaviorClass, "sourceFilename", azrtti_typeid()));
- EXPECT_TRUE(HasProperty(*behaviorClass, "sourceGuid", azrtti_typeid()));
- EXPECT_TRUE(HasProperty(*behaviorClass, "graph", azrtti_typeid()));
- EXPECT_TRUE(HasProperty(*behaviorClass, "manifest", azrtti_typeid()));
- }
-
- TEST_F(SceneGraphBehaviorTest, SceneGraphClass_BehaviorContext_Exists)
- {
- EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
- EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
- EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
- }
-
- TEST_F(SceneGraphBehaviorTest, SceneGraphClass_BehaviorContext_HasExpectedProperties)
- {
- using namespace AZ::SceneAPI::Containers;
-
- AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
- ASSERT_NE(nullptr, behaviorClass);
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetNodeName", azrtti_typeid(), { azrtti_typeid() }));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetRoot", azrtti_typeid(), {}));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeContent", azrtti_typeid(), { azrtti_typeid() }));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeSibling", azrtti_typeid(), { azrtti_typeid() }));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeChild", azrtti_typeid(), { azrtti_typeid() }));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeParent", azrtti_typeid(), { azrtti_typeid() }));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "IsNodeEndPoint", azrtti_typeid(), { azrtti_typeid() }));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetNodeCount", azrtti_typeid(), {}));
- EXPECT_TRUE(HasMethodWithOutput(
- *behaviorClass,
- "GetNodeParent",
- azrtti_typeid(),
- { azrtti_typeid(), azrtti_typeid() }
- ));
- EXPECT_TRUE(HasMethodWithOutput(
- *behaviorClass,
- "GetNodeSibling",
- azrtti_typeid(),
- { azrtti_typeid(), azrtti_typeid() }
- ));
- EXPECT_TRUE(HasMethodWithOutput(
- *behaviorClass,
- "GetNodeChild",
- azrtti_typeid(),
- { azrtti_typeid(), azrtti_typeid() }
- ));
- EXPECT_TRUE(HasMethodWithOutput(
- *behaviorClass,
- "FindWithPath",
- azrtti_typeid(),
- { azrtti_typeid(), azrtti_typeid() }
- ));
- EXPECT_TRUE(HasMethodWithOutput(
- *behaviorClass,
- "FindWithRootAndPath",
- azrtti_typeid(),
- { azrtti_typeid(), azrtti_typeid(), azrtti_typeid() }
- ));
- }
-
- TEST_F(SceneGraphBehaviorTest, SceneGraphNodeIndexClass_BehaviorContext_HasExpectedProperties)
- {
- using namespace AZ::SceneAPI::Containers;
-
- AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
- ASSERT_NE(nullptr, behaviorClass);
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "AsNumber", azrtti_typeid(), {}));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "Distance", azrtti_typeid(), { azrtti_typeid() }));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "IsValid", azrtti_typeid(), {}));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "Equal", azrtti_typeid(), { azrtti_typeid() }));
- }
-
- TEST_F(SceneGraphBehaviorTest, SceneGraphNameClass_BehaviorContext_HasExpectedProperties)
- {
- using namespace AZ::SceneAPI::Containers;
-
- AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
- ASSERT_NE(nullptr, behaviorClass);
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetPath", azrtti_typeid(), {}));
- EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetName", azrtti_typeid(), {}));
- }
-
- class MockSceneComponentApplication
- : public AZ::ComponentApplicationBus::Handler
- {
- public:
- MockSceneComponentApplication()
- {
- AZ::ComponentApplicationBus::Handler::BusConnect();
- AZ::Interface::Register(this);
- }
-
- ~MockSceneComponentApplication()
- {
- AZ::Interface::Unregister(this);
- AZ::ComponentApplicationBus::Handler::BusDisconnect();
- }
-
- MOCK_METHOD1(FindEntity, AZ::Entity* (const AZ::EntityId&));
- MOCK_METHOD1(AddEntity, bool(AZ::Entity*));
- MOCK_METHOD0(Destroy, void());
- MOCK_METHOD1(RegisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
- MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
- MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&));
- MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&));
- MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&));
- MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&));
- MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*));
- MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*));
- MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*));
- MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&));
- MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&));
- MOCK_METHOD1(EnumerateEntities, void(const ComponentApplicationRequests::EntityCallback&));
- MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ());
- MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ());
- MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
- MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
- MOCK_CONST_METHOD0(GetAppRoot, const char*());
- MOCK_CONST_METHOD0(GetEngineRoot, const char*());
- MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
- MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
- MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
- };
-
- class MockEditorPythonConsoleInterface final
- : public AzToolsFramework::EditorPythonConsoleInterface
- {
- public:
- MockEditorPythonConsoleInterface()
- {
- AZ::Interface::Register(this);
- }
-
- ~MockEditorPythonConsoleInterface()
- {
- AZ::Interface::Unregister(this);
- }
-
- MOCK_CONST_METHOD1(GetModuleList, void(AZStd::vector&));
- MOCK_CONST_METHOD1(GetGlobalFunctionList, void(GlobalFunctionCollection&));
- MOCK_METHOD1(FetchPythonTypeName, AZStd::string(const AZ::BehaviorParameter&));
- };
-
- //
- // SceneGraphBehaviorScriptTest
- //
- class SceneGraphBehaviorScriptTest
- : public UnitTest::AllocatorsFixture
- {
- public:
- AZStd::unique_ptr m_componentApplication;
- AZStd::unique_ptr m_editorPythonConsoleInterface;
- AZStd::unique_ptr m_scriptContext;
- AZStd::unique_ptr m_behaviorContext;
- AZStd::unique_ptr m_serializeContext;
-
- static void TestExpectTrue(bool value)
- {
- EXPECT_TRUE(value);
- }
-
- static void TestExpectEquals(AZ::s64 lhs, AZ::s64 rhs)
- {
- EXPECT_EQ(lhs, rhs);
- }
-
- static void ReflectTestTypes(AZ::ReflectContext* context)
- {
- AZ::BehaviorContext* behaviorContext = azrtti_cast(context);
- if (behaviorContext)
- {
- behaviorContext->Class()
- ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
- ->Attribute(AZ::Script::Attributes::Module, "scene.graph.test")
- ->Method("GetId", [](const DataTypes::MockIGraphObject& self)
- {
- return self.m_id;
- })
- ->Method("SetId", [](DataTypes::MockIGraphObject& self, int value)
- {
- self.m_id = value;
- })
- ->Method("AddAndSet", [](DataTypes::MockIGraphObject& self, int lhs, int rhs)
- {
- self.m_id = lhs + rhs;
- });
- }
- }
-
- void SetUp() override
- {
- UnitTest::AllocatorsFixture::SetUp();
-
- m_serializeContext = AZStd::make_unique();
-
- m_behaviorContext = AZStd::make_unique();
- m_behaviorContext->Method("TestExpectTrue", &TestExpectTrue);
- m_behaviorContext->Method("TestExpectEquals", &TestExpectEquals);
-
- AZ::MathReflect(m_behaviorContext.get());
- ReflectBehavior(m_behaviorContext.get());
- ReflectTestTypes(m_behaviorContext.get());
- MockBuilder::Reflect(m_behaviorContext.get());
-
- m_scriptContext = AZStd::make_unique();
- m_scriptContext->BindTo(m_behaviorContext.get());
-
- m_componentApplication = AZStd::make_unique<::testing::NiceMock>();
-
- ON_CALL(*m_componentApplication, GetBehaviorContext())
- .WillByDefault(::testing::Invoke([this]()
- {
- return this->m_behaviorContext.get();
- }));
-
- ON_CALL(*m_componentApplication, GetSerializeContext())
- .WillByDefault(::testing::Invoke([this]()
- {
- return this->m_serializeContext.get();
- }));
-
- m_editorPythonConsoleInterface = AZStd::make_unique();
- }
-
- void SetupEditorPythonConsoleInterface()
- {
- EXPECT_CALL(*m_editorPythonConsoleInterface, FetchPythonTypeName(::testing::_))
- .Times(4)
- .WillRepeatedly(::testing::Invoke([](const AZ::BehaviorParameter&) {return "int"; }));
- }
-
- void TearDown() override
- {
- m_scriptContext.reset();
- m_serializeContext.reset();
- m_behaviorContext.reset();
-
- UnitTest::AllocatorsFixture::TearDown();
- }
-
- void ExpectExecute(AZStd::string_view script)
- {
- EXPECT_TRUE(m_scriptContext->Execute(script.data()));
- }
- };
-
- TEST_F(SceneGraphBehaviorScriptTest, Scene_ScriptContext_Access)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("TestExpectTrue(scene ~= nil)");
- ExpectExecute("TestExpectTrue(scene.name == 'unit_scene')");
- ExpectExecute("TestExpectTrue(scene.manifestFilename == 'manifest_filename')");
- ExpectExecute("TestExpectTrue(scene.sourceFilename == 'unit_source_filename')");
- ExpectExecute("TestExpectTrue(tostring(scene.sourceGuid) == '{1F2E6142-B0D8-42C6-A6E5-CD726DAA9EF0}')");
- ExpectExecute("TestExpectTrue(scene:GetOriginalSceneOrientation() == Scene.SceneOrientation_YUp)");
- }
-
- TEST_F(SceneGraphBehaviorScriptTest, SceneGraph_ScriptContext_AccessMockNodes)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("scene = builder:GetScene()");
-
- // instance methods
- ExpectExecute("TestExpectTrue(scene.graph ~= nil)");
- ExpectExecute("TestExpectTrue(scene.graph:GetRoot():IsValid())");
- ExpectExecute("TestExpectEquals(scene.graph:GetNodeCount(), 13)");
- ExpectExecute("nodeRoot = scene.graph:GetRoot()");
- ExpectExecute("nodeA = scene.graph:GetNodeChild(nodeRoot); TestExpectTrue(nodeA:IsValid())");
- ExpectExecute("TestExpectTrue(scene.graph:HasNodeContent(nodeA))");
- ExpectExecute("nodeC = scene.graph:GetNodeChild(nodeA); TestExpectTrue(nodeC:IsValid())");
- ExpectExecute("nodeNameC = scene.graph:GetNodeName(nodeC); TestExpectTrue(nodeNameC ~= nil)");
- ExpectExecute("nodeE = scene.graph:GetNodeChild(nodeC); TestExpectTrue(nodeE:IsValid())");
- ExpectExecute("TestExpectTrue(scene.graph:HasNodeSibling(nodeE))");
- ExpectExecute("TestExpectTrue(scene.graph:HasNodeChild(nodeE))");
- ExpectExecute("TestExpectTrue(scene.graph:HasNodeParent(nodeE))");
- ExpectExecute("nodeG = scene.graph:GetNodeChild(nodeE); TestExpectTrue(nodeG:IsValid())");
- ExpectExecute("TestExpectTrue(scene.graph:GetNodeParent(nodeG) == nodeE)");
- ExpectExecute("nodeH = scene.graph:GetNodeSibling(nodeG); TestExpectTrue(nodeH:IsValid())");
- ExpectExecute("TestExpectTrue(scene.graph:GetNodeName(nodeH):GetPath() == 'A.C.E.H')");
- ExpectExecute("nodeB = scene.graph:GetNodeSibling(nodeA); TestExpectTrue(nodeB:IsValid())");
- ExpectExecute("nodeK = scene.graph:GetNodeChild(nodeB); TestExpectTrue(nodeK:IsValid())");
- ExpectExecute("TestExpectTrue(scene.graph:FindWithPath('B.K') == nodeK)");
- ExpectExecute("nodeL = scene.graph:GetNodeChild(nodeK); TestExpectTrue(nodeL:IsValid())");
- ExpectExecute("TestExpectTrue(scene.graph:FindWithRootAndPath(nodeK, 'L') == nodeL)");
-
- // static methods
- ExpectExecute("TestExpectTrue(scene.graph.IsValidName('A'))");
- ExpectExecute("TestExpectTrue(scene.graph.GetNodeSeperationCharacter() == string.byte('.'))");
- }
-
- TEST_F(SceneGraphBehaviorScriptTest, SceneGraphNodeIndex_ScriptContext_AccessMockNodes)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("nodeA = scene.graph:GetNodeChild(scene.graph:GetRoot())");
- ExpectExecute("TestExpectTrue(nodeA:IsValid())");
- ExpectExecute("TestExpectEquals(nodeA:AsNumber(), 1)");
- ExpectExecute("TestExpectEquals(scene.graph:GetRoot():Distance(nodeA), 1)");
- ExpectExecute("TestExpectEquals(nodeA:Distance(scene.graph:GetRoot()), -1)");
- ExpectExecute("TestExpectTrue(nodeA == scene.graph:FindWithPath('A'))");
- }
-
- TEST_F(SceneGraphBehaviorScriptTest, SceneGraphName_ScriptContext_AccessMockNodes)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
- ExpectExecute("nodeNameG = scene.graph:GetNodeName(nodeG)");
- ExpectExecute("TestExpectTrue(nodeNameG:GetPath() == 'A.C.E.G')");
- ExpectExecute("TestExpectTrue(nodeNameG:GetName() == 'G')");
- }
-
- TEST_F(SceneGraphBehaviorScriptTest, SceneGraphIGraphNode_ScriptContext_AccessMockNodes)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
- ExpectExecute("proxy = scene.graph:GetNodeContent(nodeG)");
- ExpectExecute("TestExpectTrue(proxy:CastWithTypeName('MockIGraphObject'))");
- ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
- ExpectExecute("TestExpectEquals(value, 7)");
- ExpectExecute("setIdArgs = vector_any(); setIdArgs:push_back(8);");
- ExpectExecute("proxy:Invoke('SetId', setIdArgs)");
- ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
- ExpectExecute("TestExpectEquals(value, 8)");
- ExpectExecute("addArgs = vector_any(); addArgs:push_back(8); addArgs:push_back(9)");
- ExpectExecute("proxy:Invoke('AddAndSet', addArgs)");
- ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
- ExpectExecute("TestExpectEquals(value, 17)");
- }
-
- TEST_F(SceneGraphBehaviorScriptTest, GraphObjectProxy_GetClassInfo_Loads)
- {
- SetupEditorPythonConsoleInterface();
-
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
- ExpectExecute("proxy = scene.graph:GetNodeContent(nodeG)");
- ExpectExecute("TestExpectTrue(proxy:CastWithTypeName('MockIGraphObject'))");
- ExpectExecute("info = proxy:GetClassInfo()");
- ExpectExecute("TestExpectTrue(info ~= nil)");
- }
-
- TEST_F(SceneGraphBehaviorScriptTest, GraphObjectProxy_GetClassInfo_CorrectFormats)
- {
- SetupEditorPythonConsoleInterface();
-
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
- ExpectExecute("proxy = scene.graph:GetNodeContent(nodeG)");
- ExpectExecute("TestExpectTrue(proxy:CastWithTypeName('MockIGraphObject'))");
- ExpectExecute("info = proxy:GetClassInfo()");
- ExpectExecute("TestExpectTrue(info.className == 'MockIGraphObject')");
- ExpectExecute("TestExpectTrue(info.classUuid == '{66A082CC-851D-4E1F-ABBD-45B58A216CFA}')");
- ExpectExecute("TestExpectTrue(info.methodList[1] == 'def GetId(self) -> int')");
- ExpectExecute("TestExpectTrue(info.methodList[2] == 'def SetId(self, arg1: int) -> None')");
- ExpectExecute("TestExpectTrue(info.methodList[3] == 'def AddAndSet(self, arg1: int, arg2: int) -> None')");
- }
-
- //
- // SceneManifestBehaviorScriptTest is meant to test the script abilities of the SceneManifest
- //
- class SceneManifestBehaviorScriptTest
- : public UnitTest::AllocatorsFixture
- {
- public:
- AZStd::unique_ptr m_componentApplication;
- AZStd::unique_ptr m_scriptContext;
- AZStd::unique_ptr m_behaviorContext;
- AZStd::unique_ptr m_serializeContext;
- AZStd::unique_ptr m_jsonRegistrationContext;
- AZStd::string_view m_jsonMockData = R"JSON('{"values":[{"$type":"MockManifestRule","value":0.1},{"$type":"MockManifestRule","value":2.3},{"$type":"MockManifestRule","value":4.5}]}')JSON";
-
- static void TestAssertTrue(bool value)
- {
- EXPECT_TRUE(value);
- }
-
- void SetUp() override
- {
- UnitTest::AllocatorsFixture::SetUp();
-
- m_serializeContext = AZStd::make_unique();
- MockBuilder::Reflect(m_serializeContext.get());
- MockManifestRule::Reflect(m_serializeContext.get());
- ReflectTypes(m_serializeContext.get());
-
- m_behaviorContext = AZStd::make_unique();
- m_behaviorContext->Method("TestAssertTrue", &TestAssertTrue);
- AZ::MathReflect(m_behaviorContext.get());
- MockBuilder::Reflect(m_behaviorContext.get());
- MockManifestRule::Reflect(m_behaviorContext.get());
- ReflectBehavior(m_behaviorContext.get());
-
- m_jsonRegistrationContext = AZStd::make_unique();
- AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
-
- m_scriptContext = AZStd::make_unique();
- m_scriptContext->BindTo(m_behaviorContext.get());
-
- m_componentApplication = AZStd::make_unique<::testing::NiceMock>();
-
- ON_CALL(*m_componentApplication, GetBehaviorContext()).WillByDefault(::testing::Invoke([this]()
- {
- return this->m_behaviorContext.get();
- }));
-
- ON_CALL(*m_componentApplication, GetSerializeContext()).WillByDefault(::testing::Invoke([this]()
- {
- return this->m_serializeContext.get();
- }));
-
- ON_CALL(*m_componentApplication, GetJsonRegistrationContext()).WillByDefault(::testing::Invoke([this]()
- {
- return this->m_jsonRegistrationContext.get();
- }));
- }
-
- void TearDown() override
- {
- m_jsonRegistrationContext->EnableRemoveReflection();
- AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
- m_jsonRegistrationContext->DisableRemoveReflection();
-
- m_jsonRegistrationContext.reset();
- m_serializeContext.reset();
- m_scriptContext.reset();
- m_behaviorContext.reset();
- m_componentApplication.reset();
- UnitTest::AllocatorsFixture::TearDown();
- }
-
- void ExpectExecute(AZStd::string_view script)
- {
- EXPECT_TRUE(m_scriptContext->Execute(script.data()));
- }
- };
-
- TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_GetDefaultJSON)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("manifest = scene.manifest:ExportToJson()");
- ExpectExecute(R"JSON(TestAssertTrue(manifest == '{}'))JSON");
- }
-
- TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_GetComplexJSON)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("builder:BuildSceneGraph()");
- ExpectExecute("manifest = scene.manifest:ExportToJson()");
- auto read = AZStd::fixed_string<1024>::format("TestAssertTrue(manifest == %s)", m_jsonMockData.data());
- ExpectExecute(read);
- }
-
- TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_SetComplexJSON)
- {
- ExpectExecute("builder = MockBuilder()");
- ExpectExecute("scene = builder:GetScene()");
- ExpectExecute("manifest = scene.manifest:ExportToJson()");
- ExpectExecute(R"JSON(TestAssertTrue(manifest == '{}'))JSON");
- auto load = AZStd::fixed_string<1024>::format("TestAssertTrue(scene.manifest:ImportFromJson(%s))", m_jsonMockData.data());
- ExpectExecute(load);
- ExpectExecute("manifest = scene.manifest:ExportToJson()");
- auto read = AZStd::fixed_string<1024>::format("TestAssertTrue(manifest == %s)", m_jsonMockData.data());
- ExpectExecute(read);
+ serializeContext->Class()
+ ->Version(1)
+ ->Field("value", &MockManifestRule::m_value);
}
}
+
+ private:
+ double m_value = 0.0;
+ };
+
+ struct MockBuilder final
+ {
+ AZ_TYPE_INFO(MockBuilder, "{ECF0FB2C-E5C0-4B89-993C-8511A7EF6894}");
+
+ AZStd::unique_ptr m_scene;
+
+ MockBuilder()
+ {
+ m_scene = AZStd::make_unique("unit_scene");
+ }
+
+ ~MockBuilder()
+ {
+ m_scene.reset();
+ }
+
+ void BuildSceneGraph()
+ {
+ m_scene->SetManifestFilename("manifest_filename");
+ m_scene->SetSource("unit_source_filename", azrtti_typeid());
+
+ auto& graph = m_scene->GetGraph();
+
+ /*----------------------------\
+ | Root |
+ | / \ |
+ | | | |
+ | A B |
+ | | /|\ |
+ | C I J K |
+ | / | \ \ |
+ | D E F L |
+ | / \ |
+ | G H |
+ \----------------------------*/
+
+ //Build up the graph
+ const auto indexA = graph.AddChild(graph.GetRoot(), "A", AZStd::make_shared(1));
+ const auto indexC = graph.AddChild(indexA, "C", AZStd::make_shared(3));
+ const auto indexE = graph.AddChild(indexC, "E", AZStd::make_shared(4));
+ graph.AddChild(indexC, "D", AZStd::make_shared(5));
+ graph.AddChild(indexC, "F", AZStd::make_shared(6));
+ graph.AddChild(indexE, "G", AZStd::make_shared(7));
+ graph.AddChild(indexE, "H", AZStd::make_shared(8));
+ const auto indexB = graph.AddChild(graph.GetRoot(), "B", AZStd::make_shared(2));
+ const auto indexK = graph.AddChild(indexB, "K", AZStd::make_shared(2));
+ graph.AddChild(indexB, "I", AZStd::make_shared(9));
+ graph.AddChild(indexB, "J", AZStd::make_shared(10));
+ graph.AddChild(indexK, "L", AZStd::make_shared(12));
+
+ m_scene->GetManifest().AddEntry(AZStd::make_shared(0.1));
+ m_scene->GetManifest().AddEntry(AZStd::make_shared(2.3));
+ m_scene->GetManifest().AddEntry(AZStd::make_shared(4.5));
+ }
+
+ static void Reflect(ReflectContext* context)
+ {
+ BehaviorContext* behaviorContext = azrtti_cast(context);
+ if (behaviorContext)
+ {
+ behaviorContext->Class()
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ ->Attribute(AZ::Script::Attributes::Module, "scene")
+ ->Method("BuildSceneGraph", [](MockBuilder& self)
+ {
+ return self.BuildSceneGraph();
+ })
+ ->Method("GetScene", [](MockBuilder& self)
+ {
+ return self.m_scene.get();
+ });
+ }
+ }
+ };
+
+ class SceneGraphBehaviorTest
+ : public ::testing::Test
+ {
+ public:
+ void SetUp() override
+ {
+ m_behaviorContext = AZStd::make_unique();
+ ReflectBehavior(m_behaviorContext.get());
+ }
+
+ void TearDown() override
+ {
+ m_behaviorContext.reset();
+ }
+
+ AZ::BehaviorClass* GetBehaviorClass(const AZ::TypeId& behaviorClassType)
+ {
+ auto entry = m_behaviorContext->m_typeToClassMap.find(behaviorClassType);
+ return (entry != m_behaviorContext->m_typeToClassMap.end()) ? entry->second : nullptr;
+ }
+
+ AZ::BehaviorProperty* GetBehaviorProperty(AZ::BehaviorClass& behaviorClass, AZStd::string_view propertyName)
+ {
+ auto entry = behaviorClass.m_properties.find(propertyName);
+ return (entry != behaviorClass.m_properties.end()) ? entry->second : nullptr;
+ }
+
+ bool HasBehaviorClass(const AZ::TypeId& behaviorClassType)
+ {
+ return GetBehaviorClass(behaviorClassType) != nullptr;
+ }
+
+ bool HasProperty(AZ::BehaviorClass& behaviorClass, AZStd::string_view propertyName, const AZ::TypeId& propertyClassType)
+ {
+ AZ::BehaviorProperty* behaviorProperty = GetBehaviorProperty(behaviorClass, propertyName);
+ if (behaviorProperty)
+ {
+ return behaviorProperty->m_getter->GetResult()->m_typeId == propertyClassType;
+ }
+ return false;
+ }
+
+ using ArgList = AZStd::vector;
+
+ bool HasMethodWithInput(AZ::BehaviorClass& behaviorClass, AZStd::string_view methodName, const ArgList& input)
+ {
+ auto entry = behaviorClass.m_methods.find(methodName);
+ if (entry == behaviorClass.m_methods.end())
+ {
+ return false;
+ }
+ AZ::BehaviorMethod* method = entry->second;
+
+ const size_t methodArgsCount = method->IsMember() ? method->GetNumArguments() - 1 : method->GetNumArguments();
+ if (input.size() != methodArgsCount)
+ {
+ return false;
+ }
+
+ for (size_t argIndex = 0; argIndex < input.size(); ++argIndex)
+ {
+ const size_t thisPointerOffset = method->IsMember() ? 1 : 0;
+ const auto argType = method->GetArgument(argIndex + thisPointerOffset)->m_typeId;
+ const auto inputType = input[argIndex];
+ if (inputType != argType)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool HasMethodWithOutput(AZ::BehaviorClass& behaviorClass, AZStd::string_view methodName, const AZ::TypeId& output, const ArgList& input)
+ {
+ auto entry = behaviorClass.m_methods.find(methodName);
+ if (entry == behaviorClass.m_methods.end())
+ {
+ return false;
+ }
+ AZ::BehaviorMethod* method = entry->second;
+ if (method->HasResult())
+ {
+ if (method->GetResult()->m_typeId != output)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ return HasMethodWithInput(behaviorClass, methodName, input);
+ }
+
+ AZStd::unique_ptr m_behaviorContext;
+ };
+
+ TEST_F(SceneGraphBehaviorTest, SceneClass_BehaviorContext_Exists)
+ {
+ EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
}
-}
+
+ TEST_F(SceneGraphBehaviorTest, SceneClass_BehaviorContext_HasExpectedProperties)
+ {
+ AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
+ ASSERT_NE(nullptr, behaviorClass);
+ EXPECT_TRUE(HasProperty(*behaviorClass, "name", azrtti_typeid()));
+ EXPECT_TRUE(HasProperty(*behaviorClass, "manifestFilename", azrtti_typeid()));
+ EXPECT_TRUE(HasProperty(*behaviorClass, "sourceFilename", azrtti_typeid()));
+ EXPECT_TRUE(HasProperty(*behaviorClass, "sourceGuid", azrtti_typeid()));
+ EXPECT_TRUE(HasProperty(*behaviorClass, "graph", azrtti_typeid()));
+ EXPECT_TRUE(HasProperty(*behaviorClass, "manifest", azrtti_typeid()));
+ }
+
+ TEST_F(SceneGraphBehaviorTest, SceneGraphClass_BehaviorContext_Exists)
+ {
+ EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
+ EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
+ EXPECT_TRUE(HasBehaviorClass(azrtti_typeid()));
+ }
+
+ TEST_F(SceneGraphBehaviorTest, SceneGraphClass_BehaviorContext_HasExpectedProperties)
+ {
+ using namespace AZ::SceneAPI::Containers;
+
+ AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
+ ASSERT_NE(nullptr, behaviorClass);
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetNodeName", azrtti_typeid(), { azrtti_typeid() }));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetRoot", azrtti_typeid(), {}));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeContent", azrtti_typeid(), { azrtti_typeid() }));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeSibling", azrtti_typeid(), { azrtti_typeid() }));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeChild", azrtti_typeid(), { azrtti_typeid() }));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeParent", azrtti_typeid(), { azrtti_typeid() }));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "IsNodeEndPoint", azrtti_typeid(), { azrtti_typeid() }));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetNodeCount", azrtti_typeid(), {}));
+ EXPECT_TRUE(HasMethodWithOutput(
+ *behaviorClass,
+ "GetNodeParent",
+ azrtti_typeid(),
+ { azrtti_typeid(), azrtti_typeid() }
+ ));
+ EXPECT_TRUE(HasMethodWithOutput(
+ *behaviorClass,
+ "GetNodeSibling",
+ azrtti_typeid(),
+ { azrtti_typeid(), azrtti_typeid() }
+ ));
+ EXPECT_TRUE(HasMethodWithOutput(
+ *behaviorClass,
+ "GetNodeChild",
+ azrtti_typeid(),
+ { azrtti_typeid(), azrtti_typeid() }
+ ));
+ EXPECT_TRUE(HasMethodWithOutput(
+ *behaviorClass,
+ "FindWithPath",
+ azrtti_typeid(),
+ { azrtti_typeid(), azrtti_typeid() }
+ ));
+ EXPECT_TRUE(HasMethodWithOutput(
+ *behaviorClass,
+ "FindWithRootAndPath",
+ azrtti_typeid(),
+ { azrtti_typeid(), azrtti_typeid(), azrtti_typeid() }
+ ));
+ }
+
+ TEST_F(SceneGraphBehaviorTest, SceneGraphNodeIndexClass_BehaviorContext_HasExpectedProperties)
+ {
+ using namespace AZ::SceneAPI::Containers;
+
+ AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
+ ASSERT_NE(nullptr, behaviorClass);
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "AsNumber", azrtti_typeid(), {}));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "Distance", azrtti_typeid(), { azrtti_typeid() }));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "IsValid", azrtti_typeid(), {}));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "Equal", azrtti_typeid(), { azrtti_typeid() }));
+ }
+
+ TEST_F(SceneGraphBehaviorTest, SceneGraphNameClass_BehaviorContext_HasExpectedProperties)
+ {
+ using namespace AZ::SceneAPI::Containers;
+
+ AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid());
+ ASSERT_NE(nullptr, behaviorClass);
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetPath", azrtti_typeid(), {}));
+ EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetName", azrtti_typeid(), {}));
+ }
+
+ class MockSceneComponentApplication
+ : public AZ::ComponentApplicationBus::Handler
+ {
+ public:
+ MockSceneComponentApplication()
+ {
+ AZ::ComponentApplicationBus::Handler::BusConnect();
+ AZ::Interface::Register(this);
+ }
+
+ ~MockSceneComponentApplication()
+ {
+ AZ::Interface::Unregister(this);
+ AZ::ComponentApplicationBus::Handler::BusDisconnect();
+ }
+
+ MOCK_METHOD1(FindEntity, AZ::Entity* (const AZ::EntityId&));
+ MOCK_METHOD1(AddEntity, bool(AZ::Entity*));
+ MOCK_METHOD0(Destroy, void());
+ MOCK_METHOD1(RegisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
+ MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
+ MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&));
+ MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&));
+ MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&));
+ MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&));
+ MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*));
+ MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*));
+ MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*));
+ MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&));
+ MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&));
+ MOCK_METHOD1(EnumerateEntities, void(const ComponentApplicationRequests::EntityCallback&));
+ MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ());
+ MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ());
+ MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
+ MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
+ MOCK_CONST_METHOD0(GetAppRoot, const char*());
+ MOCK_CONST_METHOD0(GetEngineRoot, const char*());
+ MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
+ MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
+ MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
+ };
+
+ class MockEditorPythonConsoleInterface final
+ : public AzToolsFramework::EditorPythonConsoleInterface
+ {
+ public:
+ MockEditorPythonConsoleInterface()
+ {
+ AZ::Interface::Register(this);
+ }
+
+ ~MockEditorPythonConsoleInterface()
+ {
+ AZ::Interface::Unregister(this);
+ }
+
+ MOCK_CONST_METHOD1(GetModuleList, void(AZStd::vector&));
+ MOCK_CONST_METHOD1(GetGlobalFunctionList, void(GlobalFunctionCollection&));
+ MOCK_METHOD1(FetchPythonTypeName, AZStd::string(const AZ::BehaviorParameter&));
+ };
+
+ //
+ // SceneGraphBehaviorScriptTest
+ //
+ class SceneGraphBehaviorScriptTest
+ : public UnitTest::AllocatorsFixture
+ {
+ public:
+ AZStd::unique_ptr m_componentApplication;
+ AZStd::unique_ptr m_editorPythonConsoleInterface;
+ AZStd::unique_ptr m_scriptContext;
+ AZStd::unique_ptr m_behaviorContext;
+ AZStd::unique_ptr m_serializeContext;
+
+ static void TestExpectTrue(bool value)
+ {
+ EXPECT_TRUE(value);
+ }
+
+ static void TestExpectEquals(AZ::s64 lhs, AZ::s64 rhs)
+ {
+ EXPECT_EQ(lhs, rhs);
+ }
+
+ static void ReflectTestTypes(AZ::ReflectContext* context)
+ {
+ AZ::BehaviorContext* behaviorContext = azrtti_cast(context);
+ if (behaviorContext)
+ {
+ behaviorContext->Class()
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ ->Attribute(AZ::Script::Attributes::Module, "scene.graph.test")
+ ->Method("GetId", [](const DataTypes::MockIGraphObject& self)
+ {
+ return self.m_id;
+ })
+ ->Method("SetId", [](DataTypes::MockIGraphObject& self, int value)
+ {
+ self.m_id = value;
+ })
+ ->Method("AddAndSet", [](DataTypes::MockIGraphObject& self, int lhs, int rhs)
+ {
+ self.m_id = lhs + rhs;
+ });
+ }
+ }
+
+ void SetUp() override
+ {
+ UnitTest::AllocatorsFixture::SetUp();
+
+ m_serializeContext = AZStd::make_unique();
+
+ m_behaviorContext = AZStd::make_unique();
+ m_behaviorContext->Method("TestExpectTrue", &TestExpectTrue);
+ m_behaviorContext->Method("TestExpectEquals", &TestExpectEquals);
+
+ AZ::MathReflect(m_behaviorContext.get());
+ ReflectBehavior(m_behaviorContext.get());
+ ReflectTestTypes(m_behaviorContext.get());
+ MockBuilder::Reflect(m_behaviorContext.get());
+
+ m_scriptContext = AZStd::make_unique();
+ m_scriptContext->BindTo(m_behaviorContext.get());
+
+ m_componentApplication = AZStd::make_unique<::testing::NiceMock>();
+
+ ON_CALL(*m_componentApplication, GetBehaviorContext())
+ .WillByDefault(::testing::Invoke([this]()
+ {
+ return this->m_behaviorContext.get();
+ }));
+
+ ON_CALL(*m_componentApplication, GetSerializeContext())
+ .WillByDefault(::testing::Invoke([this]()
+ {
+ return this->m_serializeContext.get();
+ }));
+
+ m_editorPythonConsoleInterface = AZStd::make_unique();
+ }
+
+ void SetupEditorPythonConsoleInterface()
+ {
+ EXPECT_CALL(*m_editorPythonConsoleInterface, FetchPythonTypeName(::testing::_))
+ .Times(4)
+ .WillRepeatedly(::testing::Invoke([](const AZ::BehaviorParameter&) {return "int"; }));
+ }
+
+ void TearDown() override
+ {
+ m_scriptContext.reset();
+ m_serializeContext.reset();
+ m_behaviorContext.reset();
+
+ UnitTest::AllocatorsFixture::TearDown();
+ }
+
+ void ExpectExecute(AZStd::string_view script)
+ {
+ EXPECT_TRUE(m_scriptContext->Execute(script.data()));
+ }
+ };
+
+ TEST_F(SceneGraphBehaviorScriptTest, Scene_ScriptContext_Access)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("TestExpectTrue(scene ~= nil)");
+ ExpectExecute("TestExpectTrue(scene.name == 'unit_scene')");
+ ExpectExecute("TestExpectTrue(scene.manifestFilename == 'manifest_filename')");
+ ExpectExecute("TestExpectTrue(scene.sourceFilename == 'unit_source_filename')");
+ ExpectExecute("TestExpectTrue(tostring(scene.sourceGuid) == '{1F2E6142-B0D8-42C6-A6E5-CD726DAA9EF0}')");
+ ExpectExecute("TestExpectTrue(scene:GetOriginalSceneOrientation() == Scene.SceneOrientation_YUp)");
+ }
+
+ TEST_F(SceneGraphBehaviorScriptTest, SceneGraph_ScriptContext_AccessMockNodes)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("scene = builder:GetScene()");
+
+ // instance methods
+ ExpectExecute("TestExpectTrue(scene.graph ~= nil)");
+ ExpectExecute("TestExpectTrue(scene.graph:GetRoot():IsValid())");
+ ExpectExecute("TestExpectEquals(scene.graph:GetNodeCount(), 13)");
+ ExpectExecute("nodeRoot = scene.graph:GetRoot()");
+ ExpectExecute("nodeA = scene.graph:GetNodeChild(nodeRoot); TestExpectTrue(nodeA:IsValid())");
+ ExpectExecute("TestExpectTrue(scene.graph:HasNodeContent(nodeA))");
+ ExpectExecute("nodeC = scene.graph:GetNodeChild(nodeA); TestExpectTrue(nodeC:IsValid())");
+ ExpectExecute("nodeNameC = scene.graph:GetNodeName(nodeC); TestExpectTrue(nodeNameC ~= nil)");
+ ExpectExecute("nodeE = scene.graph:GetNodeChild(nodeC); TestExpectTrue(nodeE:IsValid())");
+ ExpectExecute("TestExpectTrue(scene.graph:HasNodeSibling(nodeE))");
+ ExpectExecute("TestExpectTrue(scene.graph:HasNodeChild(nodeE))");
+ ExpectExecute("TestExpectTrue(scene.graph:HasNodeParent(nodeE))");
+ ExpectExecute("nodeG = scene.graph:GetNodeChild(nodeE); TestExpectTrue(nodeG:IsValid())");
+ ExpectExecute("TestExpectTrue(scene.graph:GetNodeParent(nodeG) == nodeE)");
+ ExpectExecute("nodeH = scene.graph:GetNodeSibling(nodeG); TestExpectTrue(nodeH:IsValid())");
+ ExpectExecute("TestExpectTrue(scene.graph:GetNodeName(nodeH):GetPath() == 'A.C.E.H')");
+ ExpectExecute("nodeB = scene.graph:GetNodeSibling(nodeA); TestExpectTrue(nodeB:IsValid())");
+ ExpectExecute("nodeK = scene.graph:GetNodeChild(nodeB); TestExpectTrue(nodeK:IsValid())");
+ ExpectExecute("TestExpectTrue(scene.graph:FindWithPath('B.K') == nodeK)");
+ ExpectExecute("nodeL = scene.graph:GetNodeChild(nodeK); TestExpectTrue(nodeL:IsValid())");
+ ExpectExecute("TestExpectTrue(scene.graph:FindWithRootAndPath(nodeK, 'L') == nodeL)");
+
+ // static methods
+ ExpectExecute("TestExpectTrue(scene.graph.IsValidName('A'))");
+ ExpectExecute("TestExpectTrue(scene.graph.GetNodeSeperationCharacter() == string.byte('.'))");
+ }
+
+ TEST_F(SceneGraphBehaviorScriptTest, SceneGraphNodeIndex_ScriptContext_AccessMockNodes)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("nodeA = scene.graph:GetNodeChild(scene.graph:GetRoot())");
+ ExpectExecute("TestExpectTrue(nodeA:IsValid())");
+ ExpectExecute("TestExpectEquals(nodeA:AsNumber(), 1)");
+ ExpectExecute("TestExpectEquals(scene.graph:GetRoot():Distance(nodeA), 1)");
+ ExpectExecute("TestExpectEquals(nodeA:Distance(scene.graph:GetRoot()), -1)");
+ ExpectExecute("TestExpectTrue(nodeA == scene.graph:FindWithPath('A'))");
+ }
+
+ TEST_F(SceneGraphBehaviorScriptTest, SceneGraphName_ScriptContext_AccessMockNodes)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
+ ExpectExecute("nodeNameG = scene.graph:GetNodeName(nodeG)");
+ ExpectExecute("TestExpectTrue(nodeNameG:GetPath() == 'A.C.E.G')");
+ ExpectExecute("TestExpectTrue(nodeNameG:GetName() == 'G')");
+ }
+
+ TEST_F(SceneGraphBehaviorScriptTest, SceneGraphIGraphNode_ScriptContext_AccessMockNodes)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
+ ExpectExecute("proxy = scene.graph:GetNodeContent(nodeG)");
+ ExpectExecute("TestExpectTrue(proxy:CastWithTypeName('MockIGraphObject'))");
+ ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
+ ExpectExecute("TestExpectEquals(value, 7)");
+ ExpectExecute("setIdArgs = vector_any(); setIdArgs:push_back(8);");
+ ExpectExecute("proxy:Invoke('SetId', setIdArgs)");
+ ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
+ ExpectExecute("TestExpectEquals(value, 8)");
+ ExpectExecute("addArgs = vector_any(); addArgs:push_back(8); addArgs:push_back(9)");
+ ExpectExecute("proxy:Invoke('AddAndSet', addArgs)");
+ ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
+ ExpectExecute("TestExpectEquals(value, 17)");
+ }
+
+ TEST_F(SceneGraphBehaviorScriptTest, GraphObjectProxy_GetClassInfo_Loads)
+ {
+ SetupEditorPythonConsoleInterface();
+
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
+ ExpectExecute("proxy = scene.graph:GetNodeContent(nodeG)");
+ ExpectExecute("TestExpectTrue(proxy:CastWithTypeName('MockIGraphObject'))");
+ ExpectExecute("info = proxy:GetClassInfo()");
+ ExpectExecute("TestExpectTrue(info ~= nil)");
+ }
+
+ TEST_F(SceneGraphBehaviorScriptTest, GraphObjectProxy_GetClassInfo_CorrectFormats)
+ {
+ SetupEditorPythonConsoleInterface();
+
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
+ ExpectExecute("proxy = scene.graph:GetNodeContent(nodeG)");
+ ExpectExecute("TestExpectTrue(proxy:CastWithTypeName('MockIGraphObject'))");
+ ExpectExecute("info = proxy:GetClassInfo()");
+ ExpectExecute("TestExpectTrue(info.className == 'MockIGraphObject')");
+ ExpectExecute("TestExpectTrue(info.classUuid == '{66A082CC-851D-4E1F-ABBD-45B58A216CFA}')");
+ ExpectExecute("TestExpectTrue(info.methodList[1] == 'def GetId(self) -> int')");
+ ExpectExecute("TestExpectTrue(info.methodList[2] == 'def SetId(self, arg1: int) -> None')");
+ ExpectExecute("TestExpectTrue(info.methodList[3] == 'def AddAndSet(self, arg1: int, arg2: int) -> None')");
+ }
+
+ TEST_F(SceneGraphBehaviorScriptTest, ExportProduct_ExpectedClassesAndFields_Work)
+ {
+ ExpectExecute("mockAssetType = Uuid.CreateString('{B7AD6A54-963F-4F0F-A70E-1CFC0364BE6B}')");
+ ExpectExecute("exportProduct = ExportProduct()");
+ ExpectExecute("exportProduct.filename = 'some/file.name'");
+ ExpectExecute("exportProduct.sourceId = Uuid.CreateString('{A19F5FDB-C5FB-478F-A0B0-B697D2C10DB5}', 0)");
+ ExpectExecute("exportProduct.assetType = mockAssetType");
+ ExpectExecute("exportProduct.subId = 10101");
+ ExpectExecute("TestExpectEquals(exportProduct.subId, 10101)");
+ ExpectExecute("TestExpectEquals(exportProduct.productDependencies:GetSize(), 0)");
+
+ ExpectExecute("exportProductDep = ExportProduct()");
+ ExpectExecute("exportProductDep.filename = 'some/file.dep'");
+ ExpectExecute("exportProductDep.sourceId = Uuid.CreateString('{A19F5FDB-C5FB-478F-A0B0-B697D2C10DB5}', 0)");
+ ExpectExecute("exportProductDep.assetType = mockAssetType");
+ ExpectExecute("exportProductDep.subId = 2");
+
+ ExpectExecute("exportProductList = ExportProductList()");
+ ExpectExecute("exportProductList:AddProduct(exportProduct)");
+ ExpectExecute("exportProductList:AddProduct(exportProductDep)");
+ ExpectExecute("productList = exportProductList:GetProducts()");
+ ExpectExecute("TestExpectEquals(productList:GetSize(), 2)");
+ ExpectExecute("exportProductList:AddDependencyToProduct(exportProduct.filename, exportProductDep)");
+ ExpectExecute("TestExpectEquals(productList:Front().productDependencies:GetSize(), 1)");
+ }
+
+ //
+ // SceneManifestBehaviorScriptTest is meant to test the script abilities of the SceneManifest
+ //
+ class SceneManifestBehaviorScriptTest
+ : public UnitTest::AllocatorsFixture
+ {
+ public:
+ AZStd::unique_ptr m_componentApplication;
+ AZStd::unique_ptr m_scriptContext;
+ AZStd::unique_ptr m_behaviorContext;
+ AZStd::unique_ptr m_serializeContext;
+ AZStd::unique_ptr m_jsonRegistrationContext;
+ AZStd::string_view m_jsonMockData = R"JSON('{"values":[{"$type":"MockManifestRule","value":0.1},{"$type":"MockManifestRule","value":2.3},{"$type":"MockManifestRule","value":4.5}]}')JSON";
+
+ static void TestAssertTrue(bool value)
+ {
+ EXPECT_TRUE(value);
+ }
+
+ void SetUp() override
+ {
+ UnitTest::AllocatorsFixture::SetUp();
+
+ m_serializeContext = AZStd::make_unique();
+ MockBuilder::Reflect(m_serializeContext.get());
+ MockManifestRule::Reflect(m_serializeContext.get());
+ ReflectTypes(m_serializeContext.get());
+
+ m_behaviorContext = AZStd::make_unique();
+ m_behaviorContext->Method("TestAssertTrue", &TestAssertTrue);
+ AZ::MathReflect(m_behaviorContext.get());
+ MockBuilder::Reflect(m_behaviorContext.get());
+ MockManifestRule::Reflect(m_behaviorContext.get());
+ ReflectBehavior(m_behaviorContext.get());
+
+ m_jsonRegistrationContext = AZStd::make_unique();
+ AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
+
+ m_scriptContext = AZStd::make_unique();
+ m_scriptContext->BindTo(m_behaviorContext.get());
+
+ m_componentApplication = AZStd::make_unique<::testing::NiceMock>();
+
+ ON_CALL(*m_componentApplication, GetBehaviorContext()).WillByDefault(::testing::Invoke([this]()
+ {
+ return this->m_behaviorContext.get();
+ }));
+
+ ON_CALL(*m_componentApplication, GetSerializeContext()).WillByDefault(::testing::Invoke([this]()
+ {
+ return this->m_serializeContext.get();
+ }));
+
+ ON_CALL(*m_componentApplication, GetJsonRegistrationContext()).WillByDefault(::testing::Invoke([this]()
+ {
+ return this->m_jsonRegistrationContext.get();
+ }));
+ }
+
+ void TearDown() override
+ {
+ m_jsonRegistrationContext->EnableRemoveReflection();
+ AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
+ m_jsonRegistrationContext->DisableRemoveReflection();
+
+ m_jsonRegistrationContext.reset();
+ m_serializeContext.reset();
+ m_scriptContext.reset();
+ m_behaviorContext.reset();
+ m_componentApplication.reset();
+ UnitTest::AllocatorsFixture::TearDown();
+ }
+
+ void ExpectExecute(AZStd::string_view script)
+ {
+ EXPECT_TRUE(m_scriptContext->Execute(script.data()));
+ }
+ };
+
+ TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_GetDefaultJSON)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("manifest = scene.manifest:ExportToJson()");
+ ExpectExecute(R"JSON(TestAssertTrue(manifest == '{}'))JSON");
+ }
+
+ TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_GetComplexJSON)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("builder:BuildSceneGraph()");
+ ExpectExecute("manifest = scene.manifest:ExportToJson()");
+ auto read = AZStd::fixed_string<1024>::format("TestAssertTrue(manifest == %s)", m_jsonMockData.data());
+ ExpectExecute(read);
+ }
+
+ TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_SetComplexJSON)
+ {
+ ExpectExecute("builder = MockBuilder()");
+ ExpectExecute("scene = builder:GetScene()");
+ ExpectExecute("manifest = scene.manifest:ExportToJson()");
+ ExpectExecute(R"JSON(TestAssertTrue(manifest == '{}'))JSON");
+ auto load = AZStd::fixed_string<1024>::format("TestAssertTrue(scene.manifest:ImportFromJson(%s))", m_jsonMockData.data());
+ ExpectExecute(load);
+ ExpectExecute("manifest = scene.manifest:ExportToJson()");
+ auto read = AZStd::fixed_string<1024>::format("TestAssertTrue(manifest == %s)", m_jsonMockData.data());
+ ExpectExecute(read);
+ }
+
+} // namespace AZ::SceneAPI::Containers
diff --git a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp
index 5ae547b577..b7fda1e0dc 100644
--- a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp
+++ b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp
@@ -25,213 +25,319 @@
#include
#include
#include
+#include
-namespace AZ
+namespace AZ::SceneAPI::Behaviors
{
- namespace SceneAPI
+ class EditorPythonConsoleNotificationHandler final
+ : protected AzToolsFramework::EditorPythonConsoleNotificationBus::Handler
{
- namespace Behaviors
+ public:
+ EditorPythonConsoleNotificationHandler()
{
- class EditorPythonConsoleNotificationHandler final
- : protected AzToolsFramework::EditorPythonConsoleNotificationBus::Handler
+ BusConnect();
+ }
+
+ ~EditorPythonConsoleNotificationHandler()
+ {
+ BusDisconnect();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // AzToolsFramework::EditorPythonConsoleNotifications
+ void OnTraceMessage([[maybe_unused]] AZStd::string_view message) override
+ {
+ using namespace AZ::SceneAPI::Utilities;
+ AZ_TracePrintf(LogWindow, "%.*s \n", AZ_STRING_ARG(message));
+ }
+
+ void OnErrorMessage([[maybe_unused]] AZStd::string_view message) override
+ {
+ using namespace AZ::SceneAPI::Utilities;
+ AZ_TracePrintf(ErrorWindow, "[ERROR] %.*s \n", AZ_STRING_ARG(message));
+ }
+
+ void OnExceptionMessage([[maybe_unused]] AZStd::string_view message) override
+ {
+ using namespace AZ::SceneAPI::Utilities;
+ AZ_TracePrintf(ErrorWindow, "[EXCEPTION] %.*s \n", AZ_STRING_ARG(message));
+ }
+ };
+
+ using ExportProductList = AZ::SceneAPI::Events::ExportProductList;
+
+ // a event bus to signal during scene building
+ struct ScriptBuildingNotifications
+ : public AZ::EBusTraits
+ {
+ virtual AZStd::string OnUpdateManifest(Containers::Scene& scene) = 0;
+ virtual ExportProductList OnPrepareForExport(
+ const Containers::Scene& scene,
+ AZStd::string_view outputDirectory,
+ AZStd::string_view platformIdentifier,
+ const ExportProductList& productList) = 0;
+ };
+ using ScriptBuildingNotificationBus = AZ::EBus;
+
+ // a back end to handle scene builder events for a script
+ struct ScriptBuildingNotificationBusHandler final
+ : public ScriptBuildingNotificationBus::Handler
+ , public AZ::BehaviorEBusHandler
+ {
+ AZ_EBUS_BEHAVIOR_BINDER(
+ ScriptBuildingNotificationBusHandler,
+ "{DF2B51DE-A4D0-4139-B5D0-DF185832380D}",
+ AZ::SystemAllocator,
+ OnUpdateManifest,
+ OnPrepareForExport);
+
+ virtual ~ScriptBuildingNotificationBusHandler() = default;
+
+ AZStd::string OnUpdateManifest(Containers::Scene& scene) override
+ {
+ AZStd::string result;
+ CallResult(result, FN_OnUpdateManifest, scene);
+ return result;
+ }
+
+ ExportProductList OnPrepareForExport(
+ const Containers::Scene& scene,
+ AZStd::string_view outputDirectory,
+ AZStd::string_view platformIdentifier,
+ const ExportProductList& productList) override
+ {
+ ExportProductList result;
+ CallResult(result, FN_OnPrepareForExport, scene, outputDirectory, platformIdentifier, productList);
+ return result;
+ }
+
+ static void Reflect(AZ::ReflectContext* context)
+ {
+ if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context))
{
- public:
- EditorPythonConsoleNotificationHandler()
- {
- BusConnect();
- }
+ behaviorContext->EBus("ScriptBuildingNotificationBus")
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
+ ->Attribute(AZ::Script::Attributes::Module, "scene")
+ ->Handler()
+ ->Event("OnUpdateManifest", &ScriptBuildingNotificationBus::Events::OnUpdateManifest)
+ ->Event("OnPrepareForExport", &ScriptBuildingNotificationBus::Events::OnPrepareForExport);
+ }
+ }
+ };
- ~EditorPythonConsoleNotificationHandler()
- {
- BusDisconnect();
- }
+ struct ScriptProcessorRuleBehavior::ExportEventHandler final
+ : public AZ::SceneAPI::SceneCore::ExportingComponent
+ {
+ using PreExportEventContextFunction = AZStd::function