Merge pull request #1657 from aws-lumberyard-dev/carlitosan/scriptcanvas/prefabs

Initial prefab integration
main
Sandeep 5 years ago committed by GitHub
commit 4c684b1a10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -58,8 +58,11 @@ class TestFileMenuDefaultNewOpen:
sc_main = sc.findChild(QtWidgets.QMainWindow)
sc_tabs = sc_main.findChild(QtWidgets.QTabWidget, "ScriptCanvasTabs")
# 3) Trigger File->New action
# wait for the intial tab count
general.idle_wait(GENERAL_WAIT)
initial_tabs_count = sc_tabs.count()
# 3) Trigger File->New action
action = pyside_utils.find_child_by_pattern(
sc_main, {"objectName": "action_New_Script", "type": QtWidgets.QAction}
)

@ -689,6 +689,81 @@ namespace AZ
return 1;
}
int Class__IndexAllowNil(lua_State* l)
{
LSV_BEGIN(l, 1);
// calling format __index(table,key)
lua_getmetatable(l, -2); // load the userdata metatable
int metaTableIndex = lua_gettop(l);
// Check if the key is string, if so we expect it to be a function or property name
// otherwise we allow users to provide custom index handlers
// Technically we can allow strings too, but it will clash with function/property names and it be hard to figure
// out what is going on from with in the system.
if (lua_type(l, -2) == LUA_TSTRING)
{
lua_pushvalue(l, -2); // duplicate the key
lua_rawget(l, -2); // load the value at this index
}
else
{
lua_pushliteral(l, "__AZ_Index");
lua_rawget(l, -2); // check if the user provided custom Index method in the class metatable
if (lua_isnil(l, -1)) // if not report an error
{
lua_rawgeti(l, -2, AZ_LUA_CLASS_METATABLE_NAME_INDEX); // load the class name for a better error
if (!lua_isstring(l, -1)) // if we failed it means we are the base metatable
{
lua_pop(l, 1);
lua_rawgeti(l, 1, AZ_LUA_CLASS_METATABLE_NAME_INDEX);
}
ScriptContext::FromNativeContext(l)->Error(ScriptContext::ErrorType::Warning, true, "Invalid index type [], should be string! '%s:%s'!", lua_tostring(l, -1), lua_tostring(l, -4));
}
else
{
// if we have custom index handler
lua_pushvalue(l, -4); // duplicate the table (class pointer)
lua_pushvalue(l, -4); // duplicate the index value for the call
lua_call(l, 2, 1); // call the function
}
lua_remove(l, metaTableIndex); // remove the metatable
return 1;
}
if (!lua_isnil(l, -1))
{
if (lua_tocfunction(l, -1) == &Internal::LuaPropertyTagHelper) // if it's a property
{
lua_getupvalue(l, -1, 1); // push on the stack the getter function
lua_remove(l, -2); // remove property object
if (lua_isnil(l, -1))
{
lua_rawgeti(l, -2, AZ_LUA_CLASS_METATABLE_NAME_INDEX); // load the class name for a better error
if (!lua_isstring(l, -1)) // if we failed it means we are the base metatable
{
lua_pop(l, 1);
lua_rawgeti(l, 1, AZ_LUA_CLASS_METATABLE_NAME_INDEX);
}
ScriptContext::FromNativeContext(l)->Error(ScriptContext::ErrorType::Warning, true, "Property '%s:%s' is write only", lua_tostring(l, -1), lua_tostring(l, -4));
lua_pop(l, 1); // pop class name
}
else
{
lua_pushvalue(l, -4); // copy the user data to be passed as a this pointer.
lua_call(l, 1, 1); // call a function with one argument (this pointer) and 1 result
}
}
}
lua_remove(l, metaTableIndex); // remove the metatable
return 1;
}
//=========================================================================
// Class__NewIndex
// [3/22/2012]
@ -826,30 +901,6 @@ namespace AZ
return 1;
}
//=========================================================================
// ClassMetatable__Index
// [3/24/2012]
//=========================================================================
int ClassMetatable__Index(lua_State* l)
{
// since the Class__Index is generic function (ask for the class metatable)
// we can reuse the code for the base metatable (which is a metatable
// of the class metatable)
return Class__Index(l);
}
//=========================================================================
// ClassMetatable__NewIndex
// [3/30/2012]
//=========================================================================
int ClassMetatable__NewIndex(lua_State* l)
{
// since the Class__NewIndex is generic function (ask for the class metatable)
// we can reuse the code for the base metatable (which is a metatable
// of the class metatable)
return Class__NewIndex(l);
}
inline size_t BufferStringCopy(const char* source, char* destination, size_t destinationSize)
{
size_t srcLen = strlen(source);
@ -5053,9 +5104,20 @@ LUA_API const Node* lua_getDummyNode()
lua_pushcclosure(m_lua, &DefaultBehaviorCaller::Destroy, 0);
lua_rawset(m_lua, -3);
{
lua_pushliteral(m_lua, "__index");
if (FindAttribute(Script::Attributes::UseClassIndexAllowNil, behaviorClass->m_attributes))
{
lua_pushcclosure(m_lua, &Internal::Class__IndexAllowNil, 0);
}
else
{
lua_pushcclosure(m_lua, &Internal::Class__Index, 0);
}
lua_rawset(m_lua, -3);
}
lua_pushliteral(m_lua, "__newindex");
lua_pushcclosure(m_lua, &Internal::Class__NewIndex, 0);

@ -16,19 +16,20 @@ namespace AZ
{
namespace Attributes
{
const static AZ::Crc32 Ignore = AZ_CRC("ScriptIgnore", 0xeb7615e1); ///< Don't use the element in the script reflection
const static AZ::Crc32 ClassNameOverride = AZ_CRC("ScriptClassNameOverride", 0x891238a3); ///< Provide a custom name for script reflection, that doesn't match the behavior Context name
const static AZ::Crc32 MethodOverride = AZ_CRC("ScriptFunctionOverride", 0xf89a7882); ///< Use a custom function in the attribute instead of the function
const static AZ::Crc32 ConstructorOverride = AZ_CRC("ConstructorOverride", 0xef5ce4aa); ///< You can provide a custom constructor to be called when created from Lua script
const static AZ::Crc32 EventHandlerCreationFunction = AZ_CRC_CE("EventHandlerCreationFunction"); ///< helps create a handler for any script target so that script functions can be used for AZ::Event signals
const static AZ::Crc32 GenericConstructorOverride = AZ_CRC("GenericConstructorOverride", 0xe6a1698e); ///< You can provide a custom constructor to be called when creating a script
const static AZ::Crc32 ReaderWriterOverride = AZ_CRC("ReaderWriterOverride", 0x1ad9ce2a); ///< paired with \ref ScriptContext::CustomReaderWriter allows you to customize read/write to Lua VM
const static AZ::Crc32 ConstructibleFromNil = AZ_CRC("ConstructibleFromNil", 0x23908169); ///< Applied to classes. Value (bool) specifies if the class be default constructed when nil is provided.
const static AZ::Crc32 ToolTip = AZ_CRC("ToolTip", 0xa1b95fb0); ///< Add a tooltip for a method/event/property
const static AZ::Crc32 Category = AZ_CRC("Category", 0x064c19c1); ///< Provide a category to allow for partitioning/sorting/ordering of the element
const static AZ::Crc32 Deprecated = AZ_CRC("Deprecated", 0xfe49a138); ///< Marks a reflected class, method, EBus or property as deprecated.
const static AZ::Crc32 DisallowBroadcast = AZ_CRC("DisallowBroadcast", 0x389b0ac7); ///< Marks a reflected EBus as not allowing Broadcasts, only Events.
const static AZ::Crc32 ClassConstantValue = AZ_CRC_CE("ClassConstantValue"); ///< Indicates the property is backed by a constant value
static constexpr AZ::Crc32 Ignore = AZ_CRC_CE("ScriptIgnore"); ///< Don't use the element in the script reflection
static constexpr AZ::Crc32 ClassNameOverride = AZ_CRC_CE("ScriptClassNameOverride"); ///< Provide a custom name for script reflection, that doesn't match the behavior Context name
static constexpr AZ::Crc32 MethodOverride = AZ_CRC_CE("ScriptFunctionOverride"); ///< Use a custom function in the attribute instead of the function
static constexpr AZ::Crc32 ConstructorOverride = AZ_CRC_CE("ConstructorOverride"); ///< You can provide a custom constructor to be called when created from Lua script
static constexpr AZ::Crc32 EventHandlerCreationFunction = AZ_CRC_CE("EventHandlerCreationFunction"); ///< helps create a handler for any script target so that script functions can be used for AZ::Event signals
static constexpr AZ::Crc32 GenericConstructorOverride = AZ_CRC_CE("GenericConstructorOverride"); ///< You can provide a custom constructor to be called when creating a script
static constexpr AZ::Crc32 ReaderWriterOverride = AZ_CRC_CE("ReaderWriterOverride"); ///< paired with \ref ScriptContext::CustomReaderWriter allows you to customize read/write to Lua VM
static constexpr AZ::Crc32 ConstructibleFromNil = AZ_CRC_CE("ConstructibleFromNil"); ///< Applied to classes. Value (bool) specifies if the class be default constructed when nil is provided.
static constexpr AZ::Crc32 ToolTip = AZ_CRC_CE("ToolTip"); ///< Add a tooltip for a method/event/property
static constexpr AZ::Crc32 Category = AZ_CRC_CE("Category"); ///< Provide a category to allow for partitioning/sorting/ordering of the element
static constexpr AZ::Crc32 Deprecated = AZ_CRC_CE("Deprecated"); ///< Marks a reflected class, method, EBus or property as deprecated.
static constexpr AZ::Crc32 DisallowBroadcast = AZ_CRC_CE("DisallowBroadcast"); ///< Marks a reflected EBus as not allowing Broadcasts, only Events.
static constexpr AZ::Crc32 ClassConstantValue = AZ_CRC_CE("ClassConstantValue"); ///< Indicates the property is backed by a constant value
static constexpr AZ::Crc32 UseClassIndexAllowNil = AZ_CRC_CE("UseClassIndexAllowNil"); ///< Use the Class__IndexAllowNil method, which will not report an error on accessing undeclared values (allows for nil)
//! Attribute which stores BehaviorAzEventDescription structure which contains
//! the script name of an AZ::Event and the name of it's parameter arguments
@ -39,11 +40,11 @@ namespace AZ
static constexpr AZ::Crc32 EventParameterTypes = AZ_CRC_CE("EventParameterTypes");
///< Recommends that the Lua runtime look up the member function in the meta table of the first argument, rather than in the original table
const static AZ::Crc32 TreatAsMemberFunction = AZ_CRC("TreatAsMemberFunction", 0x64be831a);
static constexpr AZ::Crc32 TreatAsMemberFunction = AZ_CRC_CE("TreatAsMemberFunction");
///< This attribute can be attached to the EditContext Attribute of a reflected class, the BehaviorContext Attribute of a reflected class, method, ebus or property.
///< ExcludeFlags can be used to prevent elements from appearing in List, Documentation, etc...
const static AZ::Crc32 ExcludeFrom = AZ_CRC("ExcludeFrom", 0xa98972fe);
static constexpr AZ::Crc32 ExcludeFrom = AZ_CRC_CE("ExcludeFrom");
enum ExcludeFlags : AZ::u64
{
List = 1 << 0, //< The reflected item will be excluded from any list (e.g. node palette)
@ -54,7 +55,7 @@ namespace AZ
};
//! Used to specify the usage of a Behavior Context element (e.g. Class or EBus) designed for automation scripts
const static AZ::Crc32 Scope = AZ_CRC("Scope", 0x00af55d3);
static constexpr AZ::Crc32 Scope = AZ_CRC_CE("Scope");
enum class ScopeFlags : AZ::u64
{
Launcher = 1 << 0, //< a type meant for game run-time Launcher client (default value)
@ -63,15 +64,15 @@ namespace AZ
};
//! Provide a partition hierarchy in a string dotted notation to namespace a script element
const static AZ::Crc32 Module = AZ_CRC("Module", 0x0c242628);
static constexpr AZ::Crc32 Module = AZ_CRC_CE("Module");
//! Provide an alternate name for script elements such as helpful PEP8 Python methods and property aliases
const static AZ::Crc32 Alias = AZ_CRC("Alias", 0xe16c6b94);
static constexpr AZ::Crc32 Alias = AZ_CRC_CE("Alias");
const static AZ::Crc32 EnableAsScriptEventParamType = AZ_CRC("ScriptEventParam", 0xa41e4cb0);
const static AZ::Crc32 EnableAsScriptEventReturnType = AZ_CRC("ScriptEventReturn", 0xf89b5337);
static constexpr AZ::Crc32 EnableAsScriptEventParamType = AZ_CRC_CE("ScriptEventParam");
static constexpr AZ::Crc32 EnableAsScriptEventReturnType = AZ_CRC_CE("ScriptEventReturn");
const static AZ::Crc32 Storage = AZ_CRC("ScriptStorage", 0xcd95b44d);
static constexpr AZ::Crc32 Storage = AZ_CRC_CE("ScriptStorage");
enum class StorageType
{
ScriptOwn, // default, Host allocated memory, Lua will destruct object, Lua will free host-memory via host-supplied function
@ -79,7 +80,7 @@ namespace AZ
Value, // Object is Lua allocated memory, Lua will destruct object, Lua will free Lua-memory
};
const static AZ::Crc32 Operator = AZ_CRC("ScriptOperator", 0xfee681b6);
static constexpr AZ::Crc32 Operator = AZ_CRC_CE("ScriptOperator");
enum class OperatorType
{
// note storage policy can be T*,T (only if we store raw pointers), shared_ptr<T>, intrusive pointer<T>
@ -100,7 +101,7 @@ namespace AZ
IndexWrite, // given a key/index and a value, you can store it in the class
};
const static AZ::Crc32 AssetType = AZ_CRC("AssetType", 0xabbf8d5f); ///< Provide an asset type for a generic AssetId method
static constexpr AZ::Crc32 AssetType = AZ_CRC_CE("AssetType"); ///< Provide an asset type for a generic AssetId method
} // Attributes
} // Script

@ -24,7 +24,6 @@ namespace AZ
//=========================================================================
AZStd::string ExtractUserMessage(const ScriptDataContext& dc)
{
AZStd::string userMessage = "Condition failed";
const int argCount = dc.GetNumArguments();
if (argCount > 0 && dc.IsString(argCount - 1))
{
@ -33,12 +32,12 @@ namespace AZ
{
if (value)
{
userMessage = value;
return value;
}
}
}
return userMessage;
return "ExtractUserMessage from print/Debug.Log/Warn/Error/Assert failed. Consider wrapping your argument in tostring().";
}
//=========================================================================

@ -19,7 +19,7 @@
#include <Builder/ScriptCanvasBuilderWorker.h>
#include <LyViewPaneNames.h>
// Undo this
// Undo this
AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option")
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Assets/ScriptCanvasAsset.h>
@ -119,7 +119,7 @@ namespace ScriptCanvasEditor
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> EditorAssetSystemComponent::LoadAsset(AZStd::string_view graphPath)
{
auto outcome = ScriptCanvasBuilder::LoadEditorAsset(graphPath);
auto outcome = ScriptCanvasBuilder::LoadEditorAsset(graphPath, AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
if (outcome.IsSuccess())
{

@ -21,8 +21,10 @@ namespace ScriptCanvas
void RuntimeAssetSystemComponent::Reflect(AZ::ReflectContext* context)
{
ScriptCanvas::RuntimeData::Reflect(context);
ScriptCanvas::SubgraphInterfaceData::Reflect(context);
RuntimeData::Reflect(context);
RuntimeDataOverrides::Reflect(context);
SubgraphInterfaceData::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<RuntimeAssetSystemComponent, AZ::Component>()

@ -0,0 +1,376 @@
/*
* 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 <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <Builder/ScriptCanvasBuilder.h>
#include <Builder/ScriptCanvasBuilderWorker.h>
#include <ScriptCanvas/Assets/ScriptCanvasAsset.h>
#include <ScriptCanvas/Components/EditorGraphVariableManagerComponent.h>
#include <ScriptCanvas/Grammar/AbstractCodeModel.h>
namespace ScriptCanvasBuilderCpp
{
void AppendTabs(AZStd::string& result, size_t depth)
{
for (size_t i = 0; i < depth; ++i)
{
result += "\t";
}
}
}
namespace ScriptCanvasBuilder
{
void BuildVariableOverrides::Clear()
{
m_source.Reset();
m_variables.clear();
m_entityIds.clear();
m_dependencies.clear();
}
void BuildVariableOverrides::CopyPreviousOverriddenValues(const BuildVariableOverrides& source)
{
for (auto& overriddenValue : m_overrides)
{
auto iter = AZStd::find_if(source.m_overrides.begin(), source.m_overrides.end(), [&overriddenValue](const auto& candidate) { return candidate.GetVariableId() == overriddenValue.GetVariableId(); });
if (iter != source.m_overrides.end())
{
overriddenValue.DeepCopy(*iter);
overriddenValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide);
overriddenValue.SetAllowSignalOnChange(false);
// check that a name update is not necessary anymore
}
}
//////////////////////////////////////////////////////////////////////////
// #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one.
// the above will provide the data to handle the cases where only certain dependency nodes were removed
// until then we do a sanity check, if any part of the depenecies were altered, assume no overrides are valid.
if (m_dependencies.size() != source.m_dependencies.size())
{
return;
}
else
{
for (size_t index = 0; index != m_dependencies.size(); ++index)
{
if (m_dependencies[index].m_source != source.m_dependencies[index].m_source)
{
return;
}
}
}
//////////////////////////////////////////////////////////////////////////
for (size_t index = 0; index != m_dependencies.size(); ++index)
{
m_dependencies[index].CopyPreviousOverriddenValues(source.m_dependencies[index]);
}
}
bool BuildVariableOverrides::IsEmpty() const
{
return m_variables.empty() && m_entityIds.empty() && m_dependencies.empty();
}
void BuildVariableOverrides::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<BuildVariableOverrides>()
->Version(0)
->Field("source", &BuildVariableOverrides::m_source)
->Field("variables", &BuildVariableOverrides::m_variables)
->Field("entityId", &BuildVariableOverrides::m_entityIds)
->Field("overrides", &BuildVariableOverrides::m_overrides)
->Field("dependencies", &BuildVariableOverrides::m_dependencies)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class< BuildVariableOverrides>("Variables", "Variables exposed by the attached Script Canvas Graph")
->ClassElement(AZ::Edit::ClassElements::Group, "Variable Fields")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &BuildVariableOverrides::m_overrides, "Variables", "Array of Variables within Script Canvas Graph")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &BuildVariableOverrides::m_dependencies, "Dependencies", "Variables in Dependencies of the Script Canvas Graph")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
}
}
// use this to initialize the new data, and make sure they have a editor graph variable for proper editor display
void BuildVariableOverrides::PopulateFromParsedResults(const ScriptCanvas::Grammar::ParsedRuntimeInputs& inputs, const ScriptCanvas::VariableData& variables)
{
for (auto& variable : inputs.m_variables)
{
auto graphVariable = variables.FindVariable(variable.first);
if (!graphVariable)
{
AZ_Error("ScriptCanvasBuilder", false, "Missing Variable from graph data that was just parsed");
continue;
}
m_variables.push_back(*graphVariable);
auto& buildVariable = m_variables.back();
buildVariable.DeepCopy(*graphVariable); // in case of BCO, a new one needs to be created
// copy to override list for editor display
m_overrides.push_back(*graphVariable);
auto& overrideValue = m_overrides.back();
overrideValue.DeepCopy(*graphVariable);
overrideValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide);
overrideValue.SetAllowSignalOnChange(false);
}
for (auto& entityId : inputs.m_entityIds)
{
m_entityIds.push_back(entityId);
if (!ScriptCanvas::Grammar::IsParserGeneratedId(entityId.first))
{
auto graphEntityId = variables.FindVariable(entityId.first);
if (!graphEntityId)
{
AZ_Error("ScriptCanvasBuilder", false, "Missing EntityId from graph data that was just parsed");
continue;
}
// copy to override list for editor display
if (graphEntityId->IsComponentProperty())
{
m_overrides.push_back(*graphEntityId);
auto& overrideValue = m_overrides.back();
overrideValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide);
overrideValue.SetAllowSignalOnChange(false);
}
}
}
}
EditorAssetTree* EditorAssetTree::ModRoot()
{
if (!m_parent)
{
return this;
}
return m_parent->ModRoot();
}
void EditorAssetTree::SetParent(EditorAssetTree& parent)
{
m_parent = &parent;
}
AZStd::string EditorAssetTree::ToString(size_t depth) const
{
AZStd::string result;
ScriptCanvasBuilderCpp::AppendTabs(result, depth);
result += m_asset.GetId().ToString<AZStd::string>();
result += m_asset.GetHint();
depth += m_dependencies.empty() ? 0 : 1;
for (const auto& dependency : m_dependencies)
{
result += "\n";
ScriptCanvasBuilderCpp::AppendTabs(result, depth);
result += dependency.ToString(depth);
}
return result;
}
ScriptCanvas::RuntimeDataOverrides ConvertToRuntime(const BuildVariableOverrides& buildOverrides)
{
ScriptCanvas::RuntimeDataOverrides runtimeOverrides;
runtimeOverrides.m_runtimeAsset = AZ::Data::Asset<ScriptCanvas::RuntimeAsset>
(AZ::Data::AssetId(buildOverrides.m_source.GetId().m_guid, AZ_CRC("RuntimeData", 0x163310ae)), azrtti_typeid<ScriptCanvas::RuntimeAsset>(), {});
runtimeOverrides.m_runtimeAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
runtimeOverrides.m_variableIndices.resize(buildOverrides.m_variables.size());
for (size_t index = 0; index != buildOverrides.m_variables.size(); ++index)
{
auto& variable = buildOverrides.m_variables[index];
auto iter = AZStd::find_if
( buildOverrides.m_overrides.begin()
, buildOverrides.m_overrides.end()
, [&variable](auto& candidate) { return candidate.GetVariableId() == variable.GetVariableId(); });
if (iter != buildOverrides.m_overrides.end())
{
if (iter->GetDatum())
{
runtimeOverrides.m_variables.push_back(ScriptCanvas::RuntimeVariable(iter->GetDatum()->ToAny()));
runtimeOverrides.m_variableIndices[index] = true;
}
else
{
AZ_Warning("ScriptCanvasBuilder", false, "build overrides missing variable override, Script may not function properly");
runtimeOverrides.m_variableIndices[index] = false;
}
}
else
{
runtimeOverrides.m_variableIndices[index] = false;
}
}
for (auto& entity : buildOverrides.m_entityIds)
{
auto& variableId = entity.first;
auto iter = AZStd::find_if(buildOverrides.m_overrides.begin(), buildOverrides.m_overrides.end(), [&variableId](auto& candidate) { return candidate.GetVariableId() == variableId; });
if (iter != buildOverrides.m_overrides.end())
{
// the entity was overridden on the instance
if (iter->GetDatum() && iter->GetDatum()->GetAs<AZ::EntityId>())
{
runtimeOverrides.m_entityIds.push_back(*iter->GetDatum()->GetAs<AZ::EntityId>());
}
else
{
AZ_Warning("ScriptCanvasBuilder", false, "build overrides missing EntityId, Script may not function properly");
runtimeOverrides.m_entityIds.push_back(AZ::EntityId{});
}
}
else
{
// the entity is overridden, as part of the required process of to instantiation
runtimeOverrides.m_entityIds.push_back(entity.second);
}
}
for (auto& buildDependency : buildOverrides.m_dependencies)
{
runtimeOverrides.m_dependencies.push_back(ConvertToRuntime(buildDependency));
}
return runtimeOverrides;
}
AZ::Outcome<EditorAssetTree, AZStd::string> LoadEditorAssetTree(AZ::Data::AssetId editorAssetId, AZStd::string_view assetHint, EditorAssetTree* parent)
{
EditorAssetTree result;
AZ::Data::AssetInfo assetInfo;
AZStd::string watchFolder;
bool resultFound = false;
if (!AzToolsFramework::AssetSystemRequestBus::FindFirstHandler())
{
return AZ::Failure(AZStd::string("LoadEditorAssetTree found no handler for AzToolsFramework::AssetSystemRequestBus."));
}
AzToolsFramework::AssetSystemRequestBus::BroadcastResult
( resultFound
, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourceUUID
, editorAssetId.m_guid
, assetInfo
, watchFolder);
if (!resultFound)
{
return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to get engine relative path from %s-%.*s.", editorAssetId.ToString<AZStd::string>().c_str(), aznumeric_cast<int>(assetHint.size()), assetHint.data()));
}
AZStd::vector<AZ::Data::AssetId> dependentAssets;
auto filterCB = [&dependentAssets](const AZ::Data::AssetFilterInfo& filterInfo)->bool
{
if (filterInfo.m_assetType == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>())
{
dependentAssets.push_back(AZ::Data::AssetId(filterInfo.m_assetId.m_guid, 0));
}
else if (filterInfo.m_assetType == azrtti_typeid<ScriptCanvasEditor::ScriptCanvasAsset>())
{
dependentAssets.push_back(filterInfo.m_assetId);
}
return true;
};
auto loadAssetOutcome = ScriptCanvasBuilder::LoadEditorAsset(assetInfo.m_relativePath, editorAssetId, filterCB);
if (!loadAssetOutcome.IsSuccess())
{
return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s-%s: %s", editorAssetId.ToString<AZStd::string>().c_str(), assetHint.data(), loadAssetOutcome.GetError().c_str()));
}
for (auto& dependentAsset : dependentAssets)
{
auto loadDependentOutcome = LoadEditorAssetTree(dependentAsset, "", &result);
if (!loadDependentOutcome.IsSuccess())
{
return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load dependent graph from %s-%s: %s", editorAssetId.ToString<AZStd::string>().c_str(), assetHint.data(), loadDependentOutcome.GetError().c_str()));
}
result.m_dependencies.push_back(loadDependentOutcome.TakeValue());
}
if (parent)
{
result.SetParent(*parent);
}
result.m_asset = loadAssetOutcome.TakeValue();
return AZ::Success(result);
}
AZ::Outcome<BuildVariableOverrides, AZStd::string> ParseEditorAssetTree(const EditorAssetTree& editorAssetTree)
{
auto buildEntity = editorAssetTree.m_asset->GetScriptCanvasEntity();
if (!buildEntity)
{
return AZ::Failure(AZStd::string("No entity from source asset"));
}
auto variableComponent = AZ::EntityUtils::FindFirstDerivedComponent<ScriptCanvas::GraphVariableManagerComponent>(buildEntity);
if (!variableComponent)
{
return AZ::Failure(AZStd::string("No GraphVariableManagerComponent in source Entity"));
}
const ScriptCanvas::VariableData* variableData = variableComponent->GetVariableDataConst(); // get this from the entity
if (!variableData)
{
return AZ::Failure(AZStd::string("No variableData in source GraphVariableManagerComponent"));
}
auto parseOutcome = ScriptCanvasBuilder::ParseGraph(*buildEntity, "");
if (!parseOutcome.IsSuccess() || !parseOutcome.GetValue())
{
return AZ::Failure(AZStd::string("graph failed to parse"));
}
BuildVariableOverrides result;
result.m_source = editorAssetTree.m_asset;
result.PopulateFromParsedResults(parseOutcome.GetValue()->GetRuntimeInputs(), *variableData);
// recurse...
for (auto& dependentAsset : editorAssetTree.m_dependencies)
{
// #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one.
auto parseDependentOutcome = ParseEditorAssetTree(dependentAsset);
if (!parseDependentOutcome.IsSuccess())
{
return AZ::Failure(AZStd::string::format
("ParseEditorAssetTree failed to parse dependent graph from %s-%s: %s"
, dependentAsset.m_asset.GetId().ToString<AZStd::string>().c_str()
, dependentAsset.m_asset.GetHint().c_str()
, parseDependentOutcome.GetError().c_str()));
}
result.m_dependencies.push_back(parseDependentOutcome.TakeValue());
}
return AZ::Success(result);
}
}

@ -0,0 +1,82 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Variable/VariableCore.h>
namespace ScriptCanvas
{
namespace Grammar
{
struct ParsedRuntimeInputs;
}
}
namespace ScriptCanvasEditor
{
class ScriptCanvasAsset;
}
namespace ScriptCanvasBuilder
{
class BuildVariableOverrides
{
public:
AZ_TYPE_INFO(BuildVariableOverrides, "{8336D44C-8EDC-4C28-AEB4-3420D5FD5AE2}");
AZ_CLASS_ALLOCATOR(BuildVariableOverrides, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext);
void Clear();
// use this to preserve old values that may have been overridden on the instance, and are still valid in the parsed graph
void CopyPreviousOverriddenValues(const BuildVariableOverrides& source);
bool IsEmpty() const;
// use this to initialize the new data, and make sure they have a editor graph variable for proper editor display
void PopulateFromParsedResults(const ScriptCanvas::Grammar::ParsedRuntimeInputs& inputs, const ScriptCanvas::VariableData& variables);
// #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one.
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> m_source;
// all of the variables here are overrides
AZStd::vector<ScriptCanvas::GraphVariable> m_variables;
// the values here may or may not be overrides
AZStd::vector<AZStd::pair<ScriptCanvas::VariableId, AZ::EntityId>> m_entityIds;
// this is all that gets exposed to the edit context
AZStd::vector<ScriptCanvas::GraphVariable> m_overrides;
// AZStd::vector<size_t> m_entityIdRuntimeInputIndices; since all of the entity ids need to go in, they may not need indices
AZStd::vector<BuildVariableOverrides> m_dependencies;
};
class EditorAssetTree
{
public:
AZ_CLASS_ALLOCATOR(EditorAssetTree, AZ::SystemAllocator, 0);
EditorAssetTree* m_parent = nullptr;
AZStd::vector<EditorAssetTree> m_dependencies;
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> m_asset;
EditorAssetTree* ModRoot();
void SetParent(EditorAssetTree& parent);
AZStd::string ToString(size_t depth = 0) const;
};
// copy the variables overridden during editor / prefab build time back to runtime data
ScriptCanvas::RuntimeDataOverrides ConvertToRuntime(const BuildVariableOverrides& overrides);
AZ::Outcome<EditorAssetTree, AZStd::string> LoadEditorAssetTree(AZ::Data::AssetId editorAssetId, AZStd::string_view assetHint, EditorAssetTree* parent = nullptr);
AZ::Outcome<BuildVariableOverrides, AZStd::string> ParseEditorAssetTree(const EditorAssetTree& editorAssetTree);
}

@ -10,6 +10,7 @@
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <AzCore/std/containers/map.h>
#include <AzToolsFramework/ToolsComponents/ToolsAssetCatalogBus.h>
#include <Builder/ScriptCanvasBuilder.h>
#include <Builder/ScriptCanvasBuilderComponent.h>
#include <Builder/ScriptCanvasBuilderWorker.h>
#include <ScriptCanvas/Asset/Functions/RuntimeFunctionAssetHandler.h>
@ -163,6 +164,8 @@ namespace ScriptCanvasBuilder
void PluginComponent::Reflect(AZ::ReflectContext* context)
{
BuildVariableOverrides::Reflect(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<PluginComponent, AZ::Component>()

@ -70,6 +70,7 @@ namespace ScriptCanvasBuilder
AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data());
return;
}
AZStd::vector<AZ::u8> fileBuffer(ioStream.GetLength());
size_t bytesRead = ioStream.Read(fileBuffer.size(), fileBuffer.data());
if (bytesRead != ioStream.GetLength())
@ -210,7 +211,7 @@ namespace ScriptCanvasBuilder
bool pathFound = false;
AZStd::string relativePath;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult
( pathFound
(pathFound
, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetRelativeProductPathFromFullSourceOrProductPath
, request.m_fullPath.c_str(), relativePath);

@ -55,6 +55,8 @@ namespace ScriptCanvasBuilder
DependencyArguments,
DependencyRequirementsData,
AddAssetDependencySearch,
PrefabIntegration,
CorrectGraphVariableVersion,
// add new entries above
Current,
};
@ -130,10 +132,12 @@ namespace ScriptCanvasBuilder
int GetBuilderVersion();
AZ::Outcome<AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>, AZStd::string> LoadEditorAsset(AZStd::string_view graphPath);
AZ::Outcome<AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>, AZStd::string> LoadEditorAsset(AZStd::string_view graphPath, AZ::Data::AssetId assetId, AZ::Data::AssetFilterCB assetFilterCB = {});
AZ::Outcome<AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset>, AZStd::string> LoadEditorFunctionAsset(AZStd::string_view graphPath);
AZ::Outcome<ScriptCanvas::Grammar::AbstractCodeModelConstPtr, AZStd::string> ParseGraph(AZ::Entity& buildEntity, AZStd::string_view graphPath);
AZ::Outcome<void, AZStd::string> ProcessTranslationJob(ProcessTranslationJobInput& input);
ScriptCanvasEditor::Graph* PrepareSourceGraph(AZ::Entity* const buildEntity);

@ -17,9 +17,7 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Script/ScriptComponent.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <Builder/ScriptCanvasBuilderWorker.h>
#include <ScriptCanvas/Asset/Functions/RuntimeFunctionAssetHandler.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Asset/RuntimeAssetHandler.h>
@ -32,7 +30,6 @@
#include <ScriptCanvas/Grammar/AbstractCodeModel.h>
#include <ScriptCanvas/Results/ErrorText.h>
#include <ScriptCanvas/Utils/BehaviorContextUtils.h>
#include <Source/Components/SceneComponent.h>
namespace ScriptCanvasBuilder
@ -62,6 +59,26 @@ namespace ScriptCanvasBuilder
}
}
AZ::Outcome<ScriptCanvas::Grammar::AbstractCodeModelConstPtr, AZStd::string> ParseGraph(AZ::Entity& buildEntity, AZStd::string_view graphPath)
{
AZStd::string fileNameOnly;
AzFramework::StringFunc::Path::GetFullFileName(graphPath.data(), fileNameOnly);
ScriptCanvas::Grammar::Request request;
request.graph = PrepareSourceGraph(&buildEntity);
if (!request.graph)
{
return AZ::Failure(AZStd::string("build entity did not have source graph components"));
}
request.rawSaveDebugOutput = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFileAtPrefabTime;
request.printModelToConsole = ScriptCanvas::Grammar::g_printAbstractCodeModelAtPrefabTime;
request.name = fileNameOnly.empty() ? fileNameOnly : "BuilderGraph";
request.addDebugInformation = false;
return ScriptCanvas::Translation::ParseGraph(request);
}
AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> CreateLuaAsset(AZ::Entity* buildEntity, AZ::Data::AssetId scriptAssetId, AZStd::string_view rawLuaFilePath)
{
AZStd::string fullPath(rawLuaFilePath);
@ -72,7 +89,7 @@ namespace ScriptCanvasBuilder
auto sourceGraph = PrepareSourceGraph(buildEntity);
ScriptCanvas::Grammar::Request request;
request.assetId = scriptAssetId;
request.scriptAssetId = scriptAssetId;
request.graph = sourceGraph;
request.name = fileNameOnly;
request.rawSaveDebugOutput = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile;
@ -82,7 +99,7 @@ namespace ScriptCanvasBuilder
bool pathFound = false;
AZStd::string relativePath;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult
( pathFound
(pathFound
, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetRelativeProductPathFromFullSourceOrProductPath
, fullPath.c_str(), relativePath);
@ -396,7 +413,7 @@ namespace ScriptCanvasBuilder
;
}
AZ::Outcome < AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>, AZStd::string> LoadEditorAsset(AZStd::string_view filePath)
AZ::Outcome < AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>, AZStd::string> LoadEditorAsset(AZStd::string_view filePath, AZ::Data::AssetId assetId, AZ::Data::AssetFilterCB assetFilterCB)
{
AZStd::shared_ptr<AZ::Data::AssetDataStream> assetDataStream = AZStd::make_shared<AZ::Data::AssetDataStream>();
@ -425,9 +442,9 @@ namespace ScriptCanvasBuilder
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> asset;
asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
asset.Create(assetId);
if (editorAssetHandler.LoadAssetData(asset, assetDataStream, AZ::Data::AssetFilterCB{}) != AZ::Data::AssetHandler::LoadResult::LoadComplete)
if (editorAssetHandler.LoadAssetData(asset, assetDataStream, assetFilterCB) != AZ::Data::AssetHandler::LoadResult::LoadComplete)
{
return AZ::Failure(AZStd::string::format("Failed to load ScriptCavas asset: %s", filePath.data()));
}
@ -513,10 +530,7 @@ namespace ScriptCanvasBuilder
}
}
if (buildEntity->GetState() == AZ::Entity::State::Constructed)
{
buildEntity->Init();
}
ScriptCanvas::ScopedAuxiliaryEntityHandler entityHandler(buildEntity);
if (buildEntity->GetState() == AZ::Entity::State::Init)
{
@ -542,7 +556,7 @@ namespace ScriptCanvasBuilder
request.path = input.fullPath;
request.name = input.fileNameOnly;
request.namespacePath = input.namespacePath;
request.assetId = input.assetID;
request.scriptAssetId = input.assetID;
request.graph = sourceGraph;
request.rawSaveDebugOutput = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile;
request.printModelToConsole = ScriptCanvas::Grammar::g_printAbstractCodeModel;
@ -728,6 +742,6 @@ namespace ScriptCanvasBuilder
ScriptCanvas::Translation::Result TranslateToLua(ScriptCanvas::Grammar::Request& request)
{
request.translationTargetFlags = ScriptCanvas::Translation::TargetFlags::Lua;
return ScriptCanvas::Translation::ParseGraph(request);
return ScriptCanvas::Translation::ParseAndTranslateGraph(request);
}
}

@ -19,19 +19,30 @@
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Core/ScriptCanvasBus.h>
#include <Editor/Assets/ScriptCanvasAssetTrackerBus.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Assets/ScriptCanvasAsset.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Components/EditorGraph.h>
#include <ScriptCanvas/Components/EditorGraphVariableManagerComponent.h>
#include <ScriptCanvas/Components/EditorScriptCanvasComponent.h>
#include <ScriptCanvas/Core/Node.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/PerformanceStatisticsBus.h>
namespace EditorScriptCanvasComponentCpp
{
enum Version
{
PrefabIntegration = 10,
// add description above
Current
};
}
namespace ScriptCanvasEditor
{
static bool EditorScriptCanvasComponentVersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement)
@ -74,6 +85,63 @@ namespace ScriptCanvasEditor
rootElement.RemoveElementByName(AZ_CRC("m_variableEntityIdMap", 0xdc6c75a8));
}
if (rootElement.GetVersion() <= EditorScriptCanvasComponentCpp::Version::PrefabIntegration)
{
auto variableDataElementIndex = rootElement.FindElement(AZ_CRC_CE("m_variableData"));
if (variableDataElementIndex == -1)
{
AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: 'm_variableData' index was missing");
return false;
}
auto& variableDataElement = rootElement.GetSubElement(variableDataElementIndex);
ScriptCanvas::EditableVariableData editableData;
if (!variableDataElement.GetData(editableData))
{
AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: could not retrieve old 'm_variableData'");
return false;
}
auto scriptCanvasAssetHolderElementIndex = rootElement.FindElement(AZ_CRC_CE("m_assetHolder"));
if (scriptCanvasAssetHolderElementIndex == -1)
{
AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: 'm_assetHolder' index was missing");
return false;
}
auto& scriptCanvasAssetHolderElement = rootElement.GetSubElement(scriptCanvasAssetHolderElementIndex);
ScriptCanvasAssetHolder assetHolder;
if (!scriptCanvasAssetHolderElement.GetData(assetHolder))
{
AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: could not retrieve old 'm_assetHolder'");
return false;
}
rootElement.RemoveElement(variableDataElementIndex);
if (!rootElement.AddElementWithData(serializeContext, "runtimeDataIsValid", true))
{
AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'runtimeDataIsValid'");
return false;
}
ScriptCanvasBuilder::BuildVariableOverrides overrides;
overrides.m_source = AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>(assetHolder.GetAssetId(), assetHolder.GetAssetType(), assetHolder.GetAssetHint());;
for (auto& variable : editableData.GetVariables())
{
overrides.m_overrides.push_back(variable.m_graphVariable);
}
if (!rootElement.AddElementWithData(serializeContext, "runtimeDataOverrides", overrides))
{
AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'runtimeDataOverrides'");
return false;
}
}
return true;
}
@ -83,10 +151,11 @@ namespace ScriptCanvasEditor
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorScriptCanvasComponent, EditorComponentBase>()
->Version(8, &EditorScriptCanvasComponentVersionConverter)
->Version(EditorScriptCanvasComponentCpp::Version::Current, &EditorScriptCanvasComponentVersionConverter)
->Field("m_name", &EditorScriptCanvasComponent::m_name)
->Field("m_assetHolder", &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder)
->Field("m_variableData", &EditorScriptCanvasComponent::m_editableData)
->Field("runtimeDataIsValid", &EditorScriptCanvasComponent::m_runtimeDataIsValid)
->Field("runtimeDataOverrides", &EditorScriptCanvasComponent::m_variableOverrides)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
@ -104,7 +173,7 @@ namespace ScriptCanvasEditor
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/script-canvas/")
->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder, "Script Canvas Asset", "Script Canvas asset associated with this component")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_editableData, "Properties", "Script Canvas Graph Properties")
->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_variableOverrides, "Properties", "Script Canvas Graph Properties")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
}
@ -133,6 +202,11 @@ namespace ScriptCanvasEditor
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
}
const AZStd::string& EditorScriptCanvasComponent::GetName() const
{
return m_name;
}
void EditorScriptCanvasComponent::UpdateName()
{
AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId();
@ -208,18 +282,7 @@ namespace ScriptCanvasEditor
if (fileAssetId.IsValid())
{
AssetTrackerNotificationBus::Handler::BusConnect(fileAssetId);
ScriptCanvasMemoryAsset::pointer memoryAsset;
AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, fileAssetId);
if (memoryAsset && memoryAsset->GetAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready)
{
OnScriptCanvasAssetReady(memoryAsset);
}
else
{
AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, m_scriptCanvasAssetHolder.GetAssetId(), m_scriptCanvasAssetHolder.GetAssetType(), nullptr);
}
AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
}
}
@ -233,81 +296,67 @@ namespace ScriptCanvasEditor
EditorComponentBase::Deactivate();
//EditorScriptCanvasAssetNotificationBus::Handler::BusDisconnect();
EditorScriptCanvasComponentRequestBus::Handler::BusDisconnect();
EditorContextMenuRequestBus::Handler::BusDisconnect();
}
//=========================================================================
void EditorScriptCanvasComponent::BuildGameEntity(AZ::Entity* gameEntity)
void EditorScriptCanvasComponent::BuildGameEntityData()
{
AZ::Data::AssetId editorAssetId = m_scriptCanvasAssetHolder.GetAssetId();
using namespace ScriptCanvasBuilder;
m_runtimeDataIsValid = false;
if (!editorAssetId.IsValid())
auto assetTreeOutcome = LoadEditorAssetTree(m_scriptCanvasAssetHolder.GetAssetId(), m_scriptCanvasAssetHolder.GetAssetHint());
if (!assetTreeOutcome.IsSuccess())
{
AZ_Warning("ScriptCanvas", false, "EditorScriptCanvasComponent::BuildGameEntityData failed: %s", assetTreeOutcome.GetError().c_str());
return;
}
AZ::Data::AssetId runtimeAssetId(editorAssetId.m_guid, AZ_CRC("RuntimeData", 0x163310ae));
AZ::Data::Asset<ScriptCanvas::RuntimeAsset> runtimeAsset(runtimeAssetId, azrtti_typeid<ScriptCanvas::RuntimeAsset>(), {});
EditorAssetTree& editorAssetTree = assetTreeOutcome.GetValue();
/*
This defense against creating useless runtime components is pending changes the slice update system.
It also would require better abilities to check asset integrity when building assets that depend
on ScriptCanvas assets.
AZ::Data::AssetInfo assetInfo;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, runtimeAssetId);
if (assetInfo.m_assetType == AZ::Data::s_invalidAssetType)
auto parseOutcome = ParseEditorAssetTree(editorAssetTree);
if (!parseOutcome.IsSuccess())
{
AZ_Warning("ScriptCanvas", false, "No ScriptCanvas Runtime Asset information for Entity ('%s' - '%s') Graph ('%s'), asset may be in error or deleted"
, gameEntity->GetName().c_str()
, GetEntityId().ToString().c_str()
, GetName().c_str());
AZ_Warning("ScriptCanvas", false, "EditorScriptCanvasComponent::BuildGameEntityData failed: %s", parseOutcome.GetError().c_str());
return;
}
AzFramework::AssetSystem::AssetStatus statusResult = AzFramework::AssetSystem::AssetStatus_Unknown;
AzFramework::AssetSystemRequestBus::BroadcastResult(statusResult, &AzFramework::AssetSystem::AssetSystemRequests::GetAssetStatusById, runtimeAssetId);
auto& variableOverrides = parseOutcome.GetValue();
if (statusResult != AzFramework::AssetSystem::AssetStatus_Compiled)
if (!m_variableOverrides.IsEmpty())
{
AZ_Warning("ScriptCanvas", false, "No ScriptCanvas Runtime Asset for Entity ('%s' - '%s') Graph ('%s'), compilation may have failed or not completed"
, gameEntity->GetName().c_str()
, GetEntityId().ToString().c_str()
, GetName().c_str());
return;
variableOverrides.CopyPreviousOverriddenValues(m_variableOverrides);
}
*/
// #functions2 dependency-ctor-args make recursive
auto executionComponent = gameEntity->CreateComponent<ScriptCanvas::RuntimeComponent>(runtimeAsset);
ScriptCanvas::VariableData varData;
m_variableOverrides = parseOutcome.TakeValue();
m_runtimeDataIsValid = true;
}
for (const auto& varConfig : m_editableData.GetVariables())
void EditorScriptCanvasComponent::BuildGameEntity(AZ::Entity* gameEntity)
{
if (varConfig.m_graphVariable.GetDatum()->Empty())
if (!m_runtimeDataIsValid)
{
AZ_Error("ScriptCanvas", false, "Data loss detected for GraphVariable ('%s') on Entity ('%s' - '%s') Graph ('%s')"
, varConfig.m_graphVariable.GetVariableName().data()
, gameEntity->GetName().c_str()
, GetEntityId().ToString().c_str()
, GetName().c_str());
// this is fine, there could have been no graph set, or set to a graph that failed to compile
return;
}
else
// build everything again as a sanity check against dependencies. All of the variable overrides that were valid will be copied over
BuildGameEntityData();
if (!m_runtimeDataIsValid)
{
varData.AddVariable(varConfig.m_graphVariable.GetVariableName(), varConfig.m_graphVariable);
}
AZ_Error("ScriptCanvasBuilder", false, "Runtime information did not build for ScriptCanvas Component using asset: %s", m_scriptCanvasAssetHolder.GetAssetId().ToString<AZStd::string>().c_str());
return;
}
executionComponent->SetVariableOverrides(varData);
auto runtimeComponent = gameEntity->CreateComponent<ScriptCanvas::RuntimeComponent>();
auto runtimeOverrides = ConvertToRuntime(m_variableOverrides);
runtimeComponent->SetRuntimeDataOverrides(runtimeOverrides);
}
void EditorScriptCanvasComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
{
// If we removed out asset due to the catalog removing. Just set it back.
if (m_removedCatalogId == assetId)
{
if (!m_scriptCanvasAssetHolder.GetAssetId().IsValid())
@ -317,12 +366,9 @@ namespace ScriptCanvasEditor
}
}
}
void EditorScriptCanvasComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& removedAssetId, const AZ::Data::AssetInfo& /*assetInfo*/)
{
AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId();
// If the Asset gets removed from disk while the Editor is loaded clear out the asset reference.
if (assetId == removedAssetId)
{
m_removedCatalogId = assetId;
@ -355,8 +401,6 @@ namespace ScriptCanvasEditor
}
}
AzToolsFramework::ScopedUndoBatch undo("Update Entity With New SC Graph");
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, GetEntityId());
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
}
@ -448,7 +492,6 @@ namespace ScriptCanvasEditor
{
// Invalidate the previously removed catalog id if we are setting a new asset id
m_removedCatalogId.SetInvalid();
SetPrimaryAsset(assetId);
}
}
@ -468,126 +511,18 @@ namespace ScriptCanvasEditor
void EditorScriptCanvasComponent::OnScriptCanvasAssetReady(const ScriptCanvasMemoryAsset::pointer memoryAsset)
{
if (memoryAsset->GetFileAssetId() == m_scriptCanvasAssetHolder.GetAssetId())
{
LoadVariables(memoryAsset);
UpdateName();
}
}
/*! Start Variable Block Implementation */
void EditorScriptCanvasComponent::AddVariable(AZStd::string_view varName, const ScriptCanvas::GraphVariable& graphVariable)
{
// We only add component properties to the component
if (!graphVariable.IsComponentProperty())
{
return;
}
const auto& variableId = graphVariable.GetVariableId();
ScriptCanvas::EditableVariableConfiguration* originalVarNameValuePair = m_editableData.FindVariable(variableId);
if (!originalVarNameValuePair)
{
m_editableData.AddVariable(varName, graphVariable);
originalVarNameValuePair = m_editableData.FindVariable(variableId);
}
if (!originalVarNameValuePair)
{
AZ_Error("Script Canvas", false, "Unable to find variable with id %s and name %s on the ScriptCanvas Component. There is an issue in AddVariable",
variableId.ToString().data(), varName.data());
return;
}
// Update the variable name as it may have changed
originalVarNameValuePair->m_graphVariable.SetVariableName(varName);
originalVarNameValuePair->m_graphVariable.SetExposureCategory(graphVariable.GetExposureCategory());
originalVarNameValuePair->m_graphVariable.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide);
originalVarNameValuePair->m_graphVariable.SetAllowSignalOnChange(false);
}
void EditorScriptCanvasComponent::AddNewVariables(const ScriptCanvas::VariableData& graphVarData)
{
for (auto&& variablePair : graphVarData.GetVariables())
{
AddVariable(variablePair.second.GetVariableName(), variablePair.second);
}
}
void EditorScriptCanvasComponent::RemoveVariable(const ScriptCanvas::VariableId& varId)
{
m_editableData.RemoveVariable(varId);
}
void EditorScriptCanvasComponent::RemoveOldVariables(const ScriptCanvas::VariableData& graphVarData)
{
AZStd::vector<ScriptCanvas::VariableId> oldVariableIds;
for (auto varConfig : m_editableData.GetVariables())
{
const auto& variableId = varConfig.m_graphVariable.GetVariableId();
// We only add component sourced graph properties to the script canvas component, so if this variable was switched to a graph-only property remove it.
// Also be sure to remove this variable if it's been deleted entirely.
auto graphVariable = graphVarData.FindVariable(variableId);
if (!graphVariable || !graphVariable->IsComponentProperty())
{
oldVariableIds.push_back(variableId);
}
}
for (const auto& oldVariableId : oldVariableIds)
{
RemoveVariable(oldVariableId);
}
}
bool EditorScriptCanvasComponent::UpdateVariable(const ScriptCanvas::GraphVariable& graphDatum, ScriptCanvas::GraphVariable& updateDatum, ScriptCanvas::GraphVariable& originalDatum)
{
// If the editable datum is the different than the original datum, then the "variable value" has been overridden on this component
// Variable values only propagate from the Script Canvas graph to this component if the original "variable value" has not been overridden
// by the editable "variable value" on this component and the "variable value" on the graph is different than the variable value on this component
auto isNotOverridden = (*updateDatum.GetDatum()) == (*originalDatum.GetDatum());
auto scGraphIsModified = (*originalDatum.GetDatum()) != (*graphDatum.GetDatum());
if (isNotOverridden && scGraphIsModified)
{
ScriptCanvas::ModifiableDatumView originalDatumView;
originalDatum.ConfigureDatumView(originalDatumView);
originalDatumView.AssignToDatum((*graphDatum.GetDatum()));
ScriptCanvas::ModifiableDatumView updatedDatumView;
updateDatum.ConfigureDatumView(updatedDatumView);
updatedDatumView.AssignToDatum((*graphDatum.GetDatum()));
return true;
}
return false;
}
void EditorScriptCanvasComponent::LoadVariables(const ScriptCanvasMemoryAsset::pointer memoryAsset)
{
auto assetData = memoryAsset->GetAsset();
AZ::Entity* scriptCanvasEntity = assetData->GetScriptCanvasEntity();
AZ_Assert(scriptCanvasEntity, "This graph must have a valid entity");
auto variableComponent = scriptCanvasEntity ? AZ::EntityUtils::FindFirstDerivedComponent<ScriptCanvas::GraphVariableManagerComponent>(scriptCanvasEntity) : nullptr;
if (variableComponent)
{
// Add properties from the SC Asset to the SC Component if they do not exist on the SC Component
AddNewVariables(*variableComponent->GetVariableData());
RemoveOldVariables(*variableComponent->GetVariableData());
}
BuildGameEntityData();
AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
UpdateName();
}
}
void EditorScriptCanvasComponent::ClearVariables()
{
m_editableData.Clear();
m_variableOverrides.Clear();
}
/* End Variable Block Implementation*/
}

@ -19,8 +19,15 @@ namespace ScriptCanvas
namespace ScriptCanvasEditor
{
using LoadedInterpretedDependencies = AZStd::vector<AZStd::pair<AZStd::string, ScriptCanvas::Translation::LuaAssetResult>>;
AZ_INLINE LoadedInterpretedDependencies LoadInterpretedDepencies(const ScriptCanvas::DependencySet& dependencySet);
struct LoadedInterpretedDependency
{
AZStd::string path;
AZ::Data::Asset<ScriptCanvas::RuntimeAsset> runtimeAsset;
ScriptCanvas::Translation::LuaAssetResult luaAssetResult;
AZStd::vector<LoadedInterpretedDependency> dependencies;
};
AZ_INLINE AZStd::vector<LoadedInterpretedDependency> LoadInterpretedDepencies(const ScriptCanvas::DependencySet& dependencySet);
AZ_INLINE LoadTestGraphResult LoadTestGraph(AZStd::string_view path);
@ -55,4 +62,5 @@ namespace ScriptCanvasEditor
AZ_INLINE void SimulateSeconds(const DurationSpec& duration);
AZ_INLINE void SimulateTicks(const DurationSpec& duration);
} // ScriptCanvasEditor
#include <Editor/Framework/ScriptCanvasGraphUtilities.inl>

@ -26,9 +26,25 @@ namespace ScriptCanvasEditor
{
using namespace ScriptCanvas;
AZ_INLINE LoadedInterpretedDependencies LoadInterpretedDepencies(const ScriptCanvas::DependencySet& dependencySet)
// The runtime context (appropriately) always assumes that EntityIds are overridden, this step copies the values from the runtime data
// over to the override data to simulate build step that does this when building prefabs
AZ_INLINE void CopyAssetEntityIdsToOverrides(RuntimeDataOverrides& runtimeDataOverrides)
{
LoadedInterpretedDependencies loadedAssets;
runtimeDataOverrides.m_entityIds.reserve(runtimeDataOverrides.m_runtimeAsset->GetData().m_input.m_entityIds.size());
for (auto& varEntityPar : runtimeDataOverrides.m_runtimeAsset->GetData().m_input.m_entityIds)
{
runtimeDataOverrides.m_entityIds.push_back(varEntityPar.second);
}
for (auto& dependency : runtimeDataOverrides.m_dependencies)
{
CopyAssetEntityIdsToOverrides(dependency);
}
}
AZ_INLINE AZStd::vector<LoadedInterpretedDependency> LoadInterpretedDepencies(const ScriptCanvas::DependencySet& dependencySet)
{
AZStd::vector<LoadedInterpretedDependency> loadedAssets;
if (!dependencySet.empty())
{
@ -69,7 +85,8 @@ namespace ScriptCanvasEditor
}
const ScriptCanvas::Translation::LuaAssetResult& luaAssetResult = luaAssetOutcome.GetValue();
loadedAssets.push_back({ modulePath, luaAssetResult });
// #functions2_recursive_unit_tests
loadedAssets.push_back({ modulePath, loadResult.m_runtimeAsset, luaAssetResult, {} });
}
}
@ -182,7 +199,7 @@ namespace ScriptCanvasEditor
RuntimeData runtimeDataBuffer;
AZStd::vector<RuntimeData> dependencyDataBuffer;
LoadedInterpretedDependencies dependencies;
AZStd::vector<LoadedInterpretedDependency> dependencies;
if (runGraphSpec.runSpec.execution == ExecutionMode::Interpreted)
{
@ -202,9 +219,12 @@ namespace ScriptCanvasEditor
{
dependencies = LoadInterpretedDepencies(luaAssetResult.m_dependencies.source.userSubgraphs);
RuntimeDataOverrides runtimeDataOverrides;
runtimeDataOverrides.m_runtimeAsset = loadResult.m_runtimeAsset;
if (!dependencies.empty())
{
// eventually, this will need to be recursive, or the full asset handling system will need to be integrated into the testing framework
// #functions2_recursive_unit_tests eventually, this will need to be recursive, or the full asset handling system will need to be integrated into the testing framework
// in order to test functionality with a dependency stack greater than 2
// load all script assets, and their dependencies, initialize statics on all those dependencies if it is the first time loaded
@ -215,7 +235,7 @@ namespace ScriptCanvasEditor
for (auto& dependency : dependencies)
{
inMemoryModules.emplace_back(dependency.first, dependency.second.m_scriptAsset);
inMemoryModules.emplace_back(dependency.path, dependency.luaAssetResult.m_scriptAsset);
}
AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::UseInMemoryRequireHook, inMemoryModules, AZ::ScriptContextIds::DefaultScriptContextId);
@ -224,7 +244,11 @@ namespace ScriptCanvasEditor
for (size_t index = 0; index < dependencies.size(); ++index)
{
auto& dependency = dependencies[index];
const ScriptCanvas::Translation::LuaAssetResult& depencyAssetResult = dependency.second;
const ScriptCanvas::Translation::LuaAssetResult& depencyAssetResult = dependency.luaAssetResult;
RuntimeDataOverrides dependencyRuntimeDataOverrides;
dependencyRuntimeDataOverrides.m_runtimeAsset = dependency.runtimeAsset;
runtimeDataOverrides.m_dependencies.push_back(dependencyRuntimeDataOverrides);
RuntimeData& dependencyData = dependencyDataBuffer[index];
dependencyData.m_input = depencyAssetResult.m_runtimeInputs;
@ -239,7 +263,9 @@ namespace ScriptCanvasEditor
loadResult.m_runtimeAsset.Get()->GetData().m_script = loadResult.m_scriptAsset;
loadResult.m_runtimeAsset.Get()->GetData().m_input = luaAssetResult.m_runtimeInputs;
loadResult.m_runtimeAsset.Get()->GetData().m_debugMap = luaAssetResult.m_debugMap;
loadResult.m_runtimeComponent = loadResult.m_entity->CreateComponent<ScriptCanvas::RuntimeComponent>(loadResult.m_runtimeAsset);
loadResult.m_runtimeComponent = loadResult.m_entity->CreateComponent<ScriptCanvas::RuntimeComponent>();
CopyAssetEntityIdsToOverrides(runtimeDataOverrides);
loadResult.m_runtimeComponent->SetRuntimeDataOverrides(runtimeDataOverrides);
Execution::Context::InitializeActivationData(loadResult.m_runtimeAsset->GetData());
Execution::InitializeInterpretedStatics(loadResult.m_runtimeAsset->GetData());
}

@ -8,14 +8,14 @@
#pragma once
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <Builder/ScriptCanvasBuilder.h>
#include <Editor/Assets/ScriptCanvasAssetHolder.h>
#include <ScriptCanvas/Assets/ScriptCanvasAssetHandler.h>
#include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <ScriptCanvas/Variable/VariableData.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
namespace ScriptCanvasEditor
{
@ -27,7 +27,6 @@ namespace ScriptCanvasEditor
which it uses to maintain the asset data in memory. Therefore removing an open ScriptCanvasAsset from the file system
will remove the reference from the EditorScriptCanvasComponent, but not the reference from the MainWindow allowing the
ScriptCanvas graph to still be modified while open
Finally per graph instance variables values are stored on the EditorScriptCanvasComponent and injected into the runtime ScriptCanvas component in BuildGameEntity
*/
class EditorScriptCanvasComponent
@ -54,7 +53,6 @@ namespace ScriptCanvasEditor
void Deactivate() override;
//=====================================================================
//=====================================================================
// EditorComponentBase
void BuildGameEntity(AZ::Entity* gameEntity) override;
@ -71,7 +69,7 @@ namespace ScriptCanvasEditor
void CloseGraph();
void SetName(const AZStd::string& name) { m_name = name; }
const AZStd::string& GetName() const { return m_name; };
const AZStd::string& GetName() const;
AZ::EntityId GetEditorEntityId() const { return GetEntity() ? GetEntityId() : AZ::EntityId(); }
AZ::NamedEntityId GetNamedEditorEntityId() const { return GetEntity() ? GetNamedEntityId() : AZ::NamedEntityId(); }
@ -119,12 +117,8 @@ namespace ScriptCanvasEditor
(void)incompatible;
}
//=====================================================================
// AssetCatalogEventBus
void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override;
void OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) override;
//=====================================================================
void OnScriptCanvasAssetChanged(AZ::Data::AssetId assetId);
void UpdateName();
@ -133,21 +127,15 @@ namespace ScriptCanvasEditor
void OnScriptCanvasAssetReady(const ScriptCanvasMemoryAsset::pointer asset);
//=====================================================================
void AddVariable(AZStd::string_view varName, const ScriptCanvas::GraphVariable& varDatum);
void AddNewVariables(const ScriptCanvas::VariableData& graphVarData);
void RemoveVariable(const ScriptCanvas::VariableId& varId);
void RemoveOldVariables(const ScriptCanvas::VariableData& graphVarData);
bool UpdateVariable(const ScriptCanvas::GraphVariable& graphDatum, ScriptCanvas::GraphVariable& updateDatum, ScriptCanvas::GraphVariable& originalDatum);
void LoadVariables(const ScriptCanvasMemoryAsset::pointer memoryAsset);
void BuildGameEntityData();
void ClearVariables();
private:
AZ::Data::AssetId m_removedCatalogId;
AZ::Data::AssetId m_previousAssetId;
AZStd::string m_name;
ScriptCanvasAssetHolder m_scriptCanvasAssetHolder;
ScriptCanvas::EditableVariableData m_editableData;
bool m_runtimeDataIsValid = false;
ScriptCanvasBuilder::BuildVariableOverrides m_variableOverrides;
};
}

@ -335,7 +335,7 @@ namespace ScriptCanvasEditor
if (mapIter->second == graphIdentifier)
{
foundMatch = true;
AZ_Error("ScriptCanvas", false, "Received a duplicated registration callback.");
AZ_Warning("ScriptCanvas", false, "Received a duplicated registration callback.");
}
}

@ -523,7 +523,7 @@ namespace ScriptCanvasEditor
// Creation Actions
{
m_createScriptCanvas = new QToolButton();
m_createScriptCanvas->setIcon(QIcon(ScriptCanvas::AssetDescription::GetIconPath<ScriptCanvasAsset>()));
m_createScriptCanvas->setIcon(QIcon(":/ScriptCanvasEditorResources/Resources/create_graph.png"));
m_createScriptCanvas->setToolTip("Creates a new Script Canvas Graph");
QObject::connect(m_createScriptCanvas, &QToolButton::clicked, this, &MainWindow::OnFileNew);

@ -12,6 +12,7 @@
<file>Resources/capture_offline.png</file>
<file>Resources/create_function_input.png</file>
<file>Resources/create_function_output.png</file>
<file>Resources/create_graph.png</file>
<file>Resources/CollapseAll_Icon.png</file>
<file>Resources/edit_icon.png</file>
<file>Resources/error_icon.png</file>

@ -15,17 +15,28 @@ namespace ScriptCanvasRuntimeAssetCpp
{
AddDependencies = 3,
ChangeScriptRequirementToAsset,
// add your entry above
// add description above
Current
};
enum class RuntimeDataOverridesVersion : unsigned int
{
Initial = 0,
AddRuntimeAsset,
// add description above
Current,
};
enum class FunctionRuntimeDataVersion
{
MergeBackEnd2dotZero,
AddSubgraphInterface,
RemoveLegacyData,
RemoveConnectionToRuntimeData,
// add your entry above
// add description above
Current
};
}
@ -97,6 +108,80 @@ namespace ScriptCanvas
return !m_cloneSources.empty();
}
bool RuntimeDataOverrides::IsPreloadBehaviorEnforced(const RuntimeDataOverrides& overrides)
{
if (overrides.m_runtimeAsset.GetAutoLoadBehavior() != AZ::Data::AssetLoadBehavior::PreLoad)
{
return false;
}
for (auto& dependency : overrides.m_dependencies)
{
if (!IsPreloadBehaviorEnforced(dependency))
{
return false;
}
}
return true;
}
void RuntimeDataOverrides::EnforcePreloadBehavior()
{
m_runtimeAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
for (auto& dependency : m_dependencies)
{
dependency.EnforcePreloadBehavior();
}
}
void RuntimeDataOverrides::Reflect(AZ::ReflectContext* context)
{
RuntimeVariable::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<RuntimeDataOverrides>()
->Version(static_cast<unsigned int>(ScriptCanvasRuntimeAssetCpp::RuntimeDataOverridesVersion::Current))
->Field("runtimeAsset", &RuntimeDataOverrides::m_runtimeAsset)
->Field("variables", &RuntimeDataOverrides::m_variables)
->Field("variableIndices", &RuntimeDataOverrides::m_variableIndices)
->Field("entityIds", &RuntimeDataOverrides::m_entityIds)
->Field("dependencies", &RuntimeDataOverrides::m_dependencies)
;
}
}
RuntimeVariable::RuntimeVariable(const AZStd::any& source)
: value(source)
{
}
RuntimeVariable::RuntimeVariable(AZStd::any&& source)
: value(AZStd::move(source))
{
}
void RuntimeVariable::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<RuntimeVariable>()
->Field("value", &RuntimeVariable::value)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<RuntimeVariable>("RuntimeVariable", "RuntimeVariable")
->DataElement(AZ::Edit::UIHandlers::Default, &RuntimeVariable::value, "value", "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, true)
;
}
}
}
////////////////////////
// SubgraphInterfaceData

@ -10,6 +10,7 @@
#include <AzCore/Script/ScriptAsset.h>
#include <ScriptCanvas/Asset/AssetDescription.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Core/SubgraphInterface.h>
#include <ScriptCanvas/Core/GraphData.h>
#include <ScriptCanvas/Grammar/DebugMap.h>
@ -21,6 +22,7 @@
namespace ScriptCanvas
{
class RuntimeAsset;
struct RuntimeVariable;
class RuntimeAssetDescription : public AssetDescription
{
@ -41,7 +43,7 @@ namespace ScriptCanvas
"Script Canvas Runtime",
"Script Canvas Runtime",
"Icons/ScriptCanvas/Viewport/ScriptCanvas.png",
AZ::Color(1.0f,0.0f,0.0f,1.0f),
AZ::Color(1.0f, 0.0f, 0.0f, 1.0f),
false
)
{}
@ -82,6 +84,24 @@ namespace ScriptCanvas
bool static RequiresDependencyConstructionParametersRecurse(const RuntimeData& data);
};
struct RuntimeDataOverrides
{
AZ_TYPE_INFO(RuntimeDataOverrides, "{CE3C0AE6-4EBA-43B2-B2D5-7AC24A194E63}");
AZ_CLASS_ALLOCATOR(RuntimeDataOverrides, AZ::SystemAllocator, 0);
static bool IsPreloadBehaviorEnforced(const RuntimeDataOverrides& overrides);
static void Reflect(AZ::ReflectContext* reflectContext);
AZ::Data::Asset<RuntimeAsset> m_runtimeAsset;
AZStd::vector<RuntimeVariable> m_variables;
AZStd::vector<bool> m_variableIndices;
AZStd::vector<AZ::EntityId> m_entityIds;
AZStd::vector<RuntimeDataOverrides> m_dependencies;
void EnforcePreloadBehavior();
};
class RuntimeAssetBase
: public AZ::Data::AssetData
{
@ -94,7 +114,6 @@ namespace ScriptCanvas
{
}
};
template <typename DataType>
class RuntimeAssetTyped
@ -165,7 +184,7 @@ namespace ScriptCanvas
"Script Canvas Function Interface",
"Script Canvas Function Interface",
"Icons/ScriptCanvas/Viewport/ScriptCanvas_Function.png",
AZ::Color(1.0f,0.0f,0.0f,1.0f),
AZ::Color(1.0f, 0.0f, 0.0f, 1.0f),
false
)
{}

@ -5,8 +5,8 @@
*
*/
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
@ -17,6 +17,33 @@
namespace ScriptCanvas
{
ScopedAuxiliaryEntityHandler::ScopedAuxiliaryEntityHandler(AZ::Entity* buildEntity)
: m_buildEntity(buildEntity)
, m_wasAdded(false)
{
if (AZ::Interface<AZ::ComponentApplicationRequests>::Get() != nullptr)
{
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RemoveEntity(buildEntity);
}
if (buildEntity->GetState() == AZ::Entity::State::Constructed)
{
buildEntity->Init();
m_wasAdded = true;
}
}
ScopedAuxiliaryEntityHandler::~ScopedAuxiliaryEntityHandler()
{
if (!m_wasAdded)
{
if (AZ::Interface<AZ::ComponentApplicationRequests>::Get() != nullptr)
{
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->AddEntity(m_buildEntity);
}
}
}
bool IsNamespacePathEqual(const NamespacePath& lhs, const NamespacePath& rhs)
{
if (lhs.size() != rhs.size())
@ -128,4 +155,3 @@ namespace ScriptCanvas
runtimeVersion = RuntimeVersion::Current;
}
}

@ -15,6 +15,7 @@
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/any.h>
#include <AzCore/std/hash.h>
#include <AzCore/Component/EntityUtils.h>
#include <AzCore/Component/NamedEntityId.h>
@ -205,6 +206,25 @@ namespace ScriptCanvas
using ScriptCanvasId = AZ::EntityId;
enum class AzEventIdentifier : size_t {};
struct RuntimeVariable
{
AZ_TYPE_INFO(RuntimeVariable, "{6E969359-5AF5-4ECA-BE89-A96AB30A624E}");
AZ_CLASS_ALLOCATOR(RuntimeVariable, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext);
AZStd::any value;
RuntimeVariable() = default;
RuntimeVariable(const RuntimeVariable&) = default;
RuntimeVariable(RuntimeVariable&&) = default;
explicit RuntimeVariable(const AZStd::any& source);
explicit RuntimeVariable(AZStd::any&& source);
RuntimeVariable& operator=(const RuntimeVariable&) = default;
RuntimeVariable& operator=(RuntimeVariable&&) = default;
};
struct NamespacePathHasher
{
AZ_FORCE_INLINE size_t operator()(const NamespacePath& path) const
@ -245,6 +265,17 @@ namespace ScriptCanvas
};
using ScriptCanvasSettingsRequestBus = AZ::EBus<ScriptCanvasSettingsRequests>;
class ScopedAuxiliaryEntityHandler
{
public:
ScopedAuxiliaryEntityHandler(AZ::Entity* buildEntity);
~ScopedAuxiliaryEntityHandler();
private:
bool m_wasAdded = false;
AZ::Entity* m_buildEntity = nullptr;
};
}
namespace AZStd

@ -17,15 +17,55 @@
#include <AzCore/Math/Transform.h>
#include <ScriptCanvas/Data/DataRegistry.h>
#include <ScriptCanvas/Core/GraphScopedTypes.h>
#include "DatumBus.h"
namespace DatumHelpers
{
enum Version
{
JSONSerializerSupport = 6,
// label your entry above
Current
};
using namespace ScriptCanvas;
bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& rootDataElementNode)
{
if (rootDataElementNode.GetVersion() <= Version::JSONSerializerSupport)
{
auto storageElementIndex = rootDataElementNode.FindElement(AZ_CRC_CE("m_datumStorage"));
if (storageElementIndex == -1)
{
AZ_Error("ScriptCanvas", false, "Datum Version conversion failed: 'm_datumStorage' was missing.");
return false;
}
auto& storageElement = rootDataElementNode.GetSubElement(storageElementIndex);
AZStd::any previousStorage;
if (!storageElement.GetData(previousStorage))
{
AZ_Error("ScriptCanvas", false, "Datum Version conversion failed: Could not retrieve old version of 'm_datumStorage'.");
return false;
}
rootDataElementNode.RemoveElement(storageElementIndex);
RuntimeVariable newStorage(previousStorage);
if (!rootDataElementNode.AddElementWithData(context, "m_datumStorage", newStorage))
{
AZ_Error("ScriptCanvas", false, "Datum Version conversion failed: Could not add new version of 'm_datumStorage'.");
return false;
}
}
return true;
}
template<typename t_Value>
struct ImplicitConversionHelp
{
@ -169,7 +209,7 @@ namespace DatumHelpers
}
else if (typeID == azrtti_typeid<AZ::Vector2>())
{
target = BehaviorContextObject::Create<AZ::Vector2>(AZ::Vector2(static_cast<float>(sourceVector.GetX()), static_cast<float>(sourceVector.GetY())), behaviorClass);
target = BehaviorContextObject::Create<AZ::Vector2>(AZ::Vector2((sourceVector.GetX()), (sourceVector.GetY())), behaviorClass);
}
else if (typeID == azrtti_typeid<AZ::Vector4>())
{
@ -224,7 +264,7 @@ namespace DatumHelpers
}
else if (typeID == azrtti_typeid<AZ::Vector2>())
{
target = BehaviorContextObject::Create<AZ::Vector2>(AZ::Vector2(static_cast<float>(sourceVector.GetX()), static_cast<float>(sourceVector.GetY())), behaviorClass);
target = BehaviorContextObject::Create<AZ::Vector2>(AZ::Vector2((sourceVector.GetX()), (sourceVector.GetY())), behaviorClass);
}
else if (typeID == azrtti_typeid<AZ::Vector4>())
{
@ -1153,7 +1193,7 @@ namespace DatumHelpers
if (parameterDesc.m_typeId == azrtti_typeid<char>() && (parameterDesc.m_traits & (AZ::BehaviorParameter::TR_POINTER | AZ::BehaviorParameter::TR_CONST)))
{
AZStd::string_view parameterString = *reinterpret_cast<const char* const *>(source);
AZStd::string_view parameterString = *reinterpret_cast<const char* const*>(source);
return AZ::Success(AZStd::string(parameterString));
}
else if (parameterDesc.m_typeId == azrtti_typeid<AZStd::string_view>())
@ -1161,7 +1201,7 @@ namespace DatumHelpers
const AZStd::string_view* parameterString = nullptr;
if (parameterDesc.m_traits & AZ::BehaviorParameter::TR_POINTER)
{
parameterString = *reinterpret_cast<const AZStd::string_view* const *>(source);
parameterString = *reinterpret_cast<const AZStd::string_view* const*>(source);
}
else
{
@ -1227,7 +1267,7 @@ namespace ScriptCanvas
Datum::Datum(const AZ::BehaviorValueParameter& value)
: Datum(value,
!(value.m_traits & (AZ::BehaviorParameter::TR_POINTER | AZ::BehaviorParameter::TR_REFERENCE)) ? eOriginality::Original : eOriginality::Copy,
!(value.m_traits& (AZ::BehaviorParameter::TR_POINTER | AZ::BehaviorParameter::TR_REFERENCE)) ? eOriginality::Original : eOriginality::Copy,
value.m_value)
{
}
@ -1268,15 +1308,15 @@ namespace ScriptCanvas
if (classIter != behaviorContext->m_typeToClassMap.end())
{
BehaviorContextObjectPtr sourceObjectPtr = (*AZStd::any_cast<BehaviorContextObjectPtr>(&source.m_storage));
BehaviorContextObjectPtr sourceObjectPtr = (*AZStd::any_cast<BehaviorContextObjectPtr>(&source.m_storage.value));
BehaviorContextObjectPtr newObjectPtr = sourceObjectPtr->CloneObject((*classIter->second));
m_storage = AZStd::move(newObjectPtr);
BehaviorContextObjectPtr newSourceObjectPtr = (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage));
m_storage.value = AZStd::move(newObjectPtr);
BehaviorContextObjectPtr newSourceObjectPtr = (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage.value));
}
}
else
{
m_storage = source.m_storage;
m_storage.value = source.m_storage.value;
m_conversionStorage = source.m_conversionStorage;
}
@ -1339,7 +1379,7 @@ namespace ScriptCanvas
void Datum::Clear()
{
m_storage.clear();
m_storage.value.clear();
m_class = nullptr;
m_type = Data::Type::Invalid();
}
@ -1352,12 +1392,12 @@ namespace ScriptCanvas
{
if (m_pointer)
{
DatumHelpers::FromBehaviorContextNumber(resultType.m_typeId, m_pointer, m_storage);
DatumHelpers::FromBehaviorContextNumber(resultType.m_typeId, m_pointer, m_storage.value);
}
}
else
{
DatumHelpers::FromBehaviorContextNumber(resultType.m_typeId, reinterpret_cast<const void*>(&m_conversionStorage), m_storage);
DatumHelpers::FromBehaviorContextNumber(resultType.m_typeId, reinterpret_cast<const void*>(&m_conversionStorage), m_storage.value);
}
}
else if (IS_A(Data::Type::String()) && !Data::IsString(resultType.m_typeId) && AZ::BehaviorContextHelper::IsStringParameter(resultType))
@ -1365,7 +1405,7 @@ namespace ScriptCanvas
void* storageAddress = (resultType.m_traits & AZ::BehaviorParameter::TR_POINTER) ? reinterpret_cast<void*>(&m_pointer) : AZStd::any_cast<void>(&m_conversionStorage);
if (auto stringOutcome = DatumHelpers::ConvertBehaviorContextString(resultType, storageAddress))
{
m_storage = stringOutcome.GetValue();
m_storage.value = stringOutcome.GetValue();
}
}
else if (m_type.GetType() == Data::eType::BehaviorContextObject
@ -1373,7 +1413,7 @@ namespace ScriptCanvas
{
if (m_pointer)
{
m_storage = BehaviorContextObject::CreateReference(resultType.m_typeId, m_pointer);
m_storage.value = BehaviorContextObject::CreateReference(resultType.m_typeId, m_pointer);
}
}
}
@ -1388,58 +1428,58 @@ namespace ScriptCanvas
switch (m_type.GetType())
{
case ScriptCanvas::Data::eType::AABB:
return DatumHelpers::FromBehaviorContextAABB(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextAABB(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::BehaviorContextObject:
return FromBehaviorContextObject(m_class, source);
case ScriptCanvas::Data::eType::Boolean:
return DatumHelpers::FromBehaviorContextBool(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextBool(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Color:
return DatumHelpers::FromBehaviorContextColor(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextColor(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::CRC:
return DatumHelpers::FromBehaviorContextCRC(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextCRC(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::EntityID:
return DatumHelpers::FromBehaviorContextEntityID(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextEntityID(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Matrix3x3:
return DatumHelpers::FromBehaviorContextMatrix3x3(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextMatrix3x3(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Matrix4x4:
return DatumHelpers::FromBehaviorContextMatrix4x4(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextMatrix4x4(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Number:
return DatumHelpers::FromBehaviorContextNumber(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextNumber(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::OBB:
return DatumHelpers::FromBehaviorContextOBB(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextOBB(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Plane:
return DatumHelpers::FromBehaviorContextPlane(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextPlane(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Quaternion:
return DatumHelpers::FromBehaviorContextQuaternion(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextQuaternion(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::String:
return DatumHelpers::FromBehaviorContextString(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextString(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Transform:
return DatumHelpers::FromBehaviorContextTransform(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextTransform(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Vector2:
return DatumHelpers::FromBehaviorContextVector2(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextVector2(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Vector3:
return DatumHelpers::FromBehaviorContextVector3(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextVector3(typeID, source, m_storage.value);
case ScriptCanvas::Data::eType::Vector4:
return DatumHelpers::FromBehaviorContextVector4(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextVector4(typeID, source, m_storage.value);
}
}
else if (DatumHelpers::ConvertImplicitlyChecked(type, source, m_type, m_storage, m_class))
else if (DatumHelpers::ConvertImplicitlyChecked(type, source, m_type, m_storage.value, m_class))
{
return true;
}
@ -1455,14 +1495,14 @@ namespace ScriptCanvas
bool Datum::FromBehaviorContextNumber(const void* source, const AZ::Uuid& typeID)
{
return DatumHelpers::FromBehaviorContextNumber(typeID, source, m_storage);
return DatumHelpers::FromBehaviorContextNumber(typeID, source, m_storage.value);
}
bool Datum::FromBehaviorContextObject(const AZ::BehaviorClass* behaviorClass, const void* source)
{
if (behaviorClass)
{
m_storage = BehaviorContextObject::CreateReference(behaviorClass->m_typeId, const_cast<void*>(source));
m_storage.value = BehaviorContextObject::CreateReference(behaviorClass->m_typeId, const_cast<void*>(source));
return true;
}
@ -1471,10 +1511,10 @@ namespace ScriptCanvas
const void* Datum::GetValueAddress() const
{
return !m_storage.empty()
return !m_storage.value.empty()
? m_type.GetType() != Data::eType::BehaviorContextObject
? AZStd::any_cast<void>(&m_storage)
: (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage))->Get()
? AZStd::any_cast<void>(&m_storage.value)
: (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage.value))->Get()
: nullptr;
}
@ -1554,13 +1594,13 @@ namespace ScriptCanvas
bool Datum::InitializeAABB(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::AABBType*>(source) : Data::Traits<Data::AABBType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::AABBType*>(source) : Data::Traits<Data::AABBType>::GetDefault();
return true;
}
bool Datum::InitializeAssetId(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::AssetIdType*>(source) : Data::Traits<Data::AssetIdType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::AssetIdType*>(source) : Data::Traits<Data::AssetIdType>::GetDefault();
return true;
}
@ -1621,11 +1661,11 @@ namespace ScriptCanvas
if (m_originality == eOriginality::Original)
{
m_storage = BehaviorContextObject::Create(behaviorClass, source);
m_storage.value = BehaviorContextObject::Create(behaviorClass, source);
}
else
{
m_storage = BehaviorContextObject::CreateReference(behaviorClass.m_typeId, const_cast<void*>(source));
m_storage.value = BehaviorContextObject::CreateReference(behaviorClass.m_typeId, const_cast<void*>(source));
}
return true;
@ -1636,55 +1676,55 @@ namespace ScriptCanvas
bool Datum::InitializeBool(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::BooleanType*>(source) : Data::Traits<Data::BooleanType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::BooleanType*>(source) : Data::Traits<Data::BooleanType>::GetDefault();
return true;
}
bool Datum::InitializeColor(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::ColorType*>(source) : Data::Traits<Data::ColorType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::ColorType*>(source) : Data::Traits<Data::ColorType>::GetDefault();
return true;
}
bool Datum::InitializeCRC(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::CRCType*>(source) : Data::Traits<Data::CRCType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::CRCType*>(source) : Data::Traits<Data::CRCType>::GetDefault();
return true;
}
bool Datum::InitializeEntityID(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::EntityIDType*>(source) : Data::Traits<Data::EntityIDType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::EntityIDType*>(source) : Data::Traits<Data::EntityIDType>::GetDefault();
return true;
}
bool Datum::InitializeNamedEntityID(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::NamedEntityIDType*>(source) : Data::Traits<Data::NamedEntityIDType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::NamedEntityIDType*>(source) : Data::Traits<Data::NamedEntityIDType>::GetDefault();
return true;
}
bool Datum::InitializeMatrix3x3(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::Matrix3x3Type*>(source) : Data::Traits<Data::Matrix3x3Type>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::Matrix3x3Type*>(source) : Data::Traits<Data::Matrix3x3Type>::GetDefault();
return true;
}
bool Datum::InitializeMatrix4x4(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::Matrix4x4Type*>(source) : Data::Traits<Data::Matrix4x4Type>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::Matrix4x4Type*>(source) : Data::Traits<Data::Matrix4x4Type>::GetDefault();
return true;
}
bool Datum::InitializeNumber(const void* source, const AZ::Uuid& sourceTypeID)
{
m_storage = Data::Traits<Data::NumberType>::GetDefault();
return (source && DatumHelpers::FromBehaviorContextNumber(sourceTypeID, source, m_storage)) || true;
m_storage.value = Data::Traits<Data::NumberType>::GetDefault();
return (source && DatumHelpers::FromBehaviorContextNumber(sourceTypeID, source, m_storage.value)) || true;
}
bool Datum::InitializeOBB(const void* source)
{
m_storage = source
m_storage.value = source
? *reinterpret_cast<const Data::OBBType*>(source)
: Data::Traits<Data::OBBType>::GetDefault();
return true;
@ -1692,12 +1732,12 @@ namespace ScriptCanvas
bool Datum::InitializePlane(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::PlaneType*>(source) : Data::Traits<Data::PlaneType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::PlaneType*>(source) : Data::Traits<Data::PlaneType>::GetDefault();
return true;
}
bool Datum::InitializeQuaternion(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::QuaternionType*>(source) : Data::Traits<Data::QuaternionType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::QuaternionType*>(source) : Data::Traits<Data::QuaternionType>::GetDefault();
return true;
}
@ -1707,49 +1747,49 @@ namespace ScriptCanvas
{
if (sourceTypeID == azrtti_typeid<AZStd::string_view>())
{
m_storage = Data::StringType(*reinterpret_cast<const AZStd::string_view*>(source));
m_storage.value = Data::StringType(*reinterpret_cast<const AZStd::string_view*>(source));
}
else if (sourceTypeID == azrtti_typeid<char>())
{
m_storage = Data::StringType(reinterpret_cast<const char*>(source));
m_storage.value = Data::StringType(reinterpret_cast<const char*>(source));
}
else
{
m_storage = *reinterpret_cast<const Data::StringType*>(source);
m_storage.value = *reinterpret_cast<const Data::StringType*>(source);
}
}
else
{
m_storage = Data::Traits<Data::StringType>::GetDefault();
m_storage.value = Data::Traits<Data::StringType>::GetDefault();
}
return true;
}
bool Datum::InitializeTransform(const void* source)
{
m_storage = source ? *reinterpret_cast<const Data::TransformType*>(source) : Data::Traits<Data::TransformType>::GetDefault();
m_storage.value = source ? *reinterpret_cast<const Data::TransformType*>(source) : Data::Traits<Data::TransformType>::GetDefault();
return true;
}
bool Datum::InitializeVector2(const void* source, const AZ::Uuid& sourceTypeID)
{
m_storage = Data::Traits<Data::Vector2Type>::GetDefault();
m_storage.value = Data::Traits<Data::Vector2Type>::GetDefault();
// return a success regardless, but do the initialization first if source is not null
return (source && DatumHelpers::FromBehaviorContextVector2(sourceTypeID, source, m_storage)) || true;
return (source && DatumHelpers::FromBehaviorContextVector2(sourceTypeID, source, m_storage.value)) || true;
}
bool Datum::InitializeVector3(const void* source, const AZ::Uuid& sourceTypeID)
{
m_storage = Data::Traits<Data::Vector3Type>::GetDefault();
m_storage.value = Data::Traits<Data::Vector3Type>::GetDefault();
// return a success regardless, but do the initialization first if source is not null
return (source && DatumHelpers::FromBehaviorContextVector3(sourceTypeID, source, m_storage)) || true;
return (source && DatumHelpers::FromBehaviorContextVector3(sourceTypeID, source, m_storage.value)) || true;
}
bool Datum::InitializeVector4(const void* source, const AZ::Uuid& sourceTypeID)
{
m_storage = Data::Traits<Data::Vector4Type>::GetDefault();
m_storage.value = Data::Traits<Data::Vector4Type>::GetDefault();
// return a success regardless, but do the initialization first if source is not null
return (source && DatumHelpers::FromBehaviorContextVector4(sourceTypeID, source, m_storage)) || true;
return (source && DatumHelpers::FromBehaviorContextVector4(sourceTypeID, source, m_storage.value)) || true;
}
void Datum::SetType(const Data::Type& dataType)
@ -1787,7 +1827,7 @@ namespace ScriptCanvas
auto dataTraitIt = typeIdTraitMap.find(m_type.GetType());
if (dataTraitIt != typeIdTraitMap.end())
{
return dataTraitIt->second.m_dataTraits.IsDefault(m_storage, m_type);
return dataTraitIt->second.m_dataTraits.IsDefault(m_storage.value, m_type);
}
AZ_Error("Script Canvas", m_isOverloadedStorage, "Unsupported ScriptCanvas Data type");
@ -1797,8 +1837,8 @@ namespace ScriptCanvas
void* Datum::ModResultAddress()
{
return m_type.GetType() != Data::eType::BehaviorContextObject
? AZStd::any_cast<void>(&m_storage)
: (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage))->Mod();
? AZStd::any_cast<void>(&m_storage.value)
: (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage.value))->Mod();
}
void* Datum::ModValueAddress() const
@ -1821,12 +1861,12 @@ namespace ScriptCanvas
InitializeOverloadedStorage(source.m_type, m_originality);
m_class = AZStd::move(source.m_class);
m_type = AZStd::move(source.m_type);
if (!source.m_storage.empty())
if (!source.m_storage.value.empty())
{
m_storage = AZStd::move(source.m_storage);
m_storage.value = AZStd::move(source.m_storage.value);
}
}
else if (!DatumHelpers::ConvertImplicitlyChecked(source.GetType(), source.GetValueAddress(), m_type, m_storage, m_class))
else if (!DatumHelpers::ConvertImplicitlyChecked(source.GetType(), source.GetValueAddress(), m_type, m_storage.value, m_class))
{
AZ_Error("Script Canvas", false, "Failed to convert from %s to %s", GetName(source.GetType()).c_str(), GetName(m_type).c_str());
}
@ -1852,9 +1892,9 @@ namespace ScriptCanvas
InitializeOverloadedStorage(source.m_type, m_originality);
m_class = source.m_class;
m_type = source.m_type;
m_storage = source.m_storage;
m_storage.value = source.m_storage.value;
}
else if (!DatumHelpers::ConvertImplicitlyChecked(source.GetType(), source.GetValueAddress(), m_type, m_storage, m_class))
else if (!DatumHelpers::ConvertImplicitlyChecked(source.GetType(), source.GetValueAddress(), m_type, m_storage.value, m_class))
{
AZ_Error("Script Canvas", false, "Failed to convert from %s to %s", GetName(source.GetType()).c_str(), GetName(m_type).c_str());
}
@ -2028,7 +2068,7 @@ namespace ScriptCanvas
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<Datum>()
->Version(6)
->Version(DatumHelpers::Version::Current, &DatumHelpers::VersionConverter)
->EventHandler<SerializeContextEventHandler>()
->Field("m_isUntypedStorage", &Datum::m_isOverloadedStorage)
->Field("m_type", &Datum::m_type)
@ -2079,7 +2119,7 @@ namespace ScriptCanvas
auto dataTraitIt = typeIdTraitMap.find(m_type.GetType());
if (dataTraitIt != typeIdTraitMap.end())
{
m_storage = dataTraitIt->second.m_dataTraits.GetDefault(m_type);
m_storage.value = dataTraitIt->second.m_dataTraits.GetDefault(m_type);
}
else
{
@ -2129,12 +2169,12 @@ namespace ScriptCanvas
{
if (m_type.GetType() == Data::eType::BehaviorContextObject)
{
BehaviorContextObjectPtr ptr = (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage));
BehaviorContextObjectPtr ptr = (*AZStd::any_cast<BehaviorContextObjectPtr>(&m_storage.value));
return ptr->ToAny();
}
else
{
return m_storage;
return m_storage.value;
}
}
@ -2148,7 +2188,7 @@ namespace ScriptCanvas
const auto targetType = Data::FromAZType(destination.m_typeId);
const bool success =
( (IS_A(targetType) || IsConvertibleTo(targetType)) || (IS_A(Data::Type::String()) && AZ::BehaviorContextHelper::IsStringParameter(destination)) )
((IS_A(targetType) || IsConvertibleTo(targetType)) || (IS_A(Data::Type::String()) && AZ::BehaviorContextHelper::IsStringParameter(destination)))
&& DatumHelpers::ToBehaviorContext(m_type, GetValueAddress(), destination, destinationBehaviorClass);
AZ_Error("Script Canvas", success, "Cannot push Datum with type %s into BehaviorValueParameter expecting type %s", GetName(m_type).c_str(), GetName(targetType).c_str());
@ -2426,7 +2466,7 @@ namespace ScriptCanvas
AZStd::string Datum::ToStringAABB(const Data::AABBType& aabb) const
{
return AZStd::string::format
( "(Min: %s, Max: %s)"
("(Min: %s, Max: %s)"
, ToStringVector3(aabb.GetMin()).c_str()
, ToStringVector3(aabb.GetMax()).c_str());
}
@ -2438,7 +2478,7 @@ namespace ScriptCanvas
AZStd::string Datum::ToStringColor(const Data::ColorType& c) const
{
return AZStd::string::format("(r=%.7f,g=%.7f,b=%.7f,a=%.7f)", static_cast<float>(c.GetR()), static_cast<float>(c.GetG()), static_cast<float>(c.GetB()), static_cast<float>(c.GetA()));
return AZStd::string::format("(r=%.7f,g=%.7f,b=%.7f,a=%.7f)", (c.GetR()), (c.GetG()), (c.GetB()), (c.GetA()));
}
bool Datum::ToStringBehaviorClassObject(Data::StringType& stringOut) const
@ -2474,7 +2514,7 @@ namespace ScriptCanvas
AZStd::string Datum::ToStringMatrix3x3(const AZ::Matrix3x3& m) const
{
return AZStd::string::format
( "(%s, %s, %s)"
("(%s, %s, %s)"
, ToStringVector3(m.GetColumn(0)).c_str()
, ToStringVector3(m.GetColumn(1)).c_str()
, ToStringVector3(m.GetColumn(2)).c_str());
@ -2484,7 +2524,7 @@ namespace ScriptCanvas
AZStd::string Datum::ToStringMatrix4x4(const AZ::Matrix4x4& m) const
{
return AZStd::string::format
( "(%s, %s, %s, %s)"
("(%s, %s, %s, %s)"
, ToStringVector4(m.GetColumn(0)).c_str()
, ToStringVector4(m.GetColumn(1)).c_str()
, ToStringVector4(m.GetColumn(2)).c_str()
@ -2495,7 +2535,7 @@ namespace ScriptCanvas
AZStd::string Datum::ToStringOBB(const Data::OBBType& obb) const
{
return AZStd::string::format
( "(Position: %s, AxisX: %s, AxisY: %s, AxisZ: %s, halfLengthX: %.7f, halfLengthY: %.7f, halfLengthZ: %.7f)"
("(Position: %s, AxisX: %s, AxisY: %s, AxisZ: %s, halfLengthX: %.7f, halfLengthY: %.7f, halfLengthZ: %.7f)"
, ToStringVector3(obb.GetPosition()).c_str()
, ToStringVector3(obb.GetAxisX()).c_str()
, ToStringVector3(obb.GetAxisY()).c_str()
@ -2514,10 +2554,10 @@ namespace ScriptCanvas
{
AZ::Vector3 eulerRotation = AZ::ConvertTransformToEulerDegrees(AZ::Transform::CreateFromQuaternion(source));
return AZStd::string::format
( "(Pitch: %5.2f, Roll: %5.2f, Yaw: %5.2f)"
, static_cast<float>(eulerRotation.GetX())
, static_cast<float>(eulerRotation.GetY())
, static_cast<float>(eulerRotation.GetZ()));
("(Pitch: %5.2f, Roll: %5.2f, Yaw: %5.2f)"
, (eulerRotation.GetX())
, (eulerRotation.GetY())
, (eulerRotation.GetZ()));
}
AZStd::string Datum::ToStringTransform(const Data::TransformType& source) const
@ -2527,18 +2567,18 @@ namespace ScriptCanvas
float scale = copy.ExtractUniformScale();
AZ::Vector3 rotation = AZ::ConvertTransformToEulerDegrees(copy);
return AZStd::string::format
( "(Position: X: %f, Y: %f, Z: %f,"
("(Position: X: %f, Y: %f, Z: %f,"
" Rotation: X: %f, Y: %f, Z: %f,"
" Scale: %f)"
, static_cast<float>(pos.GetX()), static_cast<float>(pos.GetY()), static_cast<float>(pos.GetZ())
, static_cast<float>(rotation.GetX()), static_cast<float>(rotation.GetY()), static_cast<float>(rotation.GetZ())
, (pos.GetX()), (pos.GetY()), (pos.GetZ())
, (rotation.GetX()), (rotation.GetY()), (rotation.GetZ())
, scale);
}
AZStd::string Datum::ToStringVector2(const AZ::Vector2& source) const
{
return AZStd::string::format
( "(X: %f, Y: %f)"
("(X: %f, Y: %f)"
, source.GetX()
, source.GetY());
}
@ -2546,20 +2586,20 @@ namespace ScriptCanvas
AZStd::string Datum::ToStringVector3(const AZ::Vector3& source) const
{
return AZStd::string::format
( "(X: %f, Y: %f, Z: %f)"
, static_cast<float>(source.GetX())
, static_cast<float>(source.GetY())
, static_cast<float>(source.GetZ()));
("(X: %f, Y: %f, Z: %f)"
, (source.GetX())
, (source.GetY())
, (source.GetZ()));
}
AZStd::string Datum::ToStringVector4(const AZ::Vector4& source) const
{
return AZStd::string::format
("(X: %f, Y: %f, Z: %f, W: %f)"
, static_cast<float>(source.GetX())
, static_cast<float>(source.GetY())
, static_cast<float>(source.GetZ())
, static_cast<float>(source.GetW()));
, (source.GetX())
, (source.GetY())
, (source.GetZ())
, (source.GetW()));
}
AZ::Outcome<void, AZStd::string> Datum::CallBehaviorContextMethod(const AZ::BehaviorMethod* method, AZ::BehaviorValueParameter* params, unsigned int numExpectedArgs)
@ -2608,5 +2648,4 @@ namespace ScriptCanvas
{
return datum != nullptr && !datum->Empty();
}
}

@ -9,8 +9,8 @@
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/std/any.h>
#include <AzCore/std/string/string_view.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvas/Data/DataTrait.h>
#include <ScriptCanvas/Data/BehaviorContextObject.h>
@ -204,18 +204,18 @@ namespace ScriptCanvas
{
static_assert(!AZStd::is_pointer<t_Value>::value, "no pointer types in the Datum::GetAsHelper<t_Value, false>");
if (datum.m_storage.empty())
if (datum.m_storage.value.empty())
{
// rare, but can be caused by removals or problems with reflection to BehaviorContext, so must be checked
return nullptr;
}
else if (datum.m_type.GetType() == Data::eType::BehaviorContextObject)
{
return (*AZStd::any_cast<BehaviorContextObjectPtr>(&datum.m_storage))->CastConst<t_Value>();
return (*AZStd::any_cast<BehaviorContextObjectPtr>(&datum.m_storage.value))->CastConst<t_Value>();
}
else
{
return AZStd::any_cast<const t_Value>(&datum.m_storage);
return AZStd::any_cast<const t_Value>(&datum.m_storage.value);
}
}
};
@ -253,12 +253,12 @@ namespace ScriptCanvas
// eOriginality records the graph source of the object
eOriginality m_originality = eOriginality::Copy;
// storage for the datum, regardless of ScriptCanvas::Data::Type
AZStd::any m_storage;
RuntimeVariable m_storage;
// This contains the editor label for m_storage.
// This contains the editor label for m_storage.value.
AZStd::string m_datumLabel;
// This contains the editor visibility for m_storage.
// This contains the editor visibility for m_storage.value.
AZ::Crc32 m_visibility{ AZ::Edit::PropertyVisibility::ShowChildrenOnly };
// storage for implicit conversions, when needed
AZStd::any m_conversionStorage;
@ -384,7 +384,7 @@ namespace ScriptCanvas
bool Datum::Empty() const
{
return m_storage.empty() || GetValueAddress() == nullptr;
return m_storage.value.empty() || GetValueAddress() == nullptr;
}
template<typename t_Value>
@ -492,7 +492,7 @@ namespace ScriptCanvas
{
if (Data::IsValueType(m_type))
{
m_storage = value;
m_storage.value = value;
return true;
}
else

@ -136,10 +136,7 @@ namespace ScriptCanvas
{
if (nodeEntity)
{
if (nodeEntity->GetState() == AZ::Entity::State::Constructed)
{
nodeEntity->Init();
}
ScriptCanvas::ScopedAuxiliaryEntityHandler entityHandler(nodeEntity);
if (auto* node = AZ::EntityUtils::FindFirstDerivedComponent<Node>(nodeEntity))
{
@ -155,10 +152,7 @@ namespace ScriptCanvas
{
if (connectionEntity)
{
if (connectionEntity->GetState() == AZ::Entity::State::Constructed)
{
connectionEntity->Init();
}
ScriptCanvas::ScopedAuxiliaryEntityHandler entityHandler(connectionEntity);
}
}
@ -1036,10 +1030,10 @@ namespace ScriptCanvas
}
}
// for (auto connectionId : removableConnections)
// {
// DisconnectById(connectionId);
// }
// for (auto connectionId : removableConnections)
// {
// DisconnectById(connectionId);
// }
if (!removableConnections.empty())
{

@ -79,6 +79,7 @@ namespace ScriptCanvas
behaviorContext->Class<Nodeable>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::Script::Attributes::UseClassIndexAllowNil, AZ::AttributeIsValid::IfPresent)
->Constructor<ExecutionStateWeakPtr>()
->Method("Deactivate", &Nodeable::Deactivate)
->Method("InitializeExecutionState", &Nodeable::InitializeExecutionState)

@ -756,10 +756,9 @@ namespace ScriptCanvas
{
auto runtimeComponent = (*graphIter);
if (graphIdentifier.m_assetId.m_guid == runtimeComponent->GetAsset().GetId().m_guid)
if (graphIdentifier.m_assetId.m_guid == runtimeComponent->GetRuntimeDataOverrides().m_runtimeAsset.GetId().m_guid)
{
// TODO: Gate on ComponentId
// \todo chcurran restore this functionality
// runtimeComponent->SetIsGraphObserved(observedState);
runtimeComponents.erase(graphIter);
break;

@ -7,6 +7,7 @@
#include <AzCore/Component/EntityUtils.h>
#include <AzCore/Script/ScriptSystemBus.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Core/Nodeable.h>
@ -19,13 +20,13 @@
namespace ExecutionContextCpp
{
void TypeCopy(AZ::BehaviorValueParameter& lhs, const AZ::BehaviorValueParameter& rhs)
void CopyTypeInformationOnly(AZ::BehaviorValueParameter& lhs, const AZ::BehaviorValueParameter& rhs)
{
lhs.m_typeId = rhs.m_typeId;
lhs.m_azRtti = rhs.m_azRtti;
}
void ValueCopy(AZ::BehaviorValueParameter& lhs, const AZ::BehaviorValueParameter& rhs)
void CopyTypeAndValueSource(AZ::BehaviorValueParameter& lhs, const AZ::BehaviorValueParameter& rhs)
{
lhs.m_typeId = rhs.m_typeId;
lhs.m_azRtti = rhs.m_azRtti;
@ -37,21 +38,25 @@ namespace ScriptCanvas
{
namespace Execution
{
ActivationData::ActivationData(const RuntimeComponent& component, ActivationInputArray& storage)
: entityId(component.GetEntityId())
, variableOverrides(component.GetVariableOverrides())
, runtimeData(component.GetAsset()->GetData())
ActivationData::ActivationData(const RuntimeDataOverrides& variableOverrides, ActivationInputArray& storage)
: variableOverrides(variableOverrides)
, runtimeData(variableOverrides.m_runtimeAsset->GetData())
, storage(storage)
{}
ActivationData::ActivationData(const AZ::EntityId entityId, const VariableData& variableOverrides, const RuntimeData& runtimeData, ActivationInputArray& storage)
: entityId(entityId)
, variableOverrides(variableOverrides)
, runtimeData(runtimeData)
, storage(storage)
{}
const void* ActivationData::GetVariableSource(size_t index, size_t& overrideIndexTracker) const
{
if (variableOverrides.m_variableIndices[index])
{
return AZStd::any_cast<void>(&variableOverrides.m_variables[overrideIndexTracker++].value);
}
else
{
return runtimeData.m_input.m_variables[index].second.GetAsDanger();
}
}
ActivationInputRange Context::CreateActivateInputRange(ActivationData& activationData)
ActivationInputRange Context::CreateActivateInputRange(ActivationData& activationData, [[maybe_unused]] const AZ::EntityId& forSliceSupportOnly)
{
const RuntimeData& runtimeData = activationData.runtimeData;
ActivationInputRange rangeOut = runtimeData.m_activationInputRange;
@ -60,74 +65,45 @@ namespace ScriptCanvas
AZ_Assert(rangeOut.totalCount <= activationData.storage.size(), "Too many initial arguments for activation. "
"Consider increasing size, source of ActivationInputArray, or breaking up the source graph");
// nodeables
// nodeables - until the optimization is required, every instance gets their own copy
{
auto sourceVariableIter = runtimeData.m_activationInputRange.inputs;
const auto sourceVariableSentinel = runtimeData.m_activationInputRange.inputs + runtimeData.m_activationInputRange.nodeableCount;
auto destVariableIter = rangeOut.inputs;
for (; sourceVariableIter != sourceVariableSentinel; ++sourceVariableIter, ++destVariableIter)
{
ExecutionContextCpp::ValueCopy(*destVariableIter, *sourceVariableIter);
ExecutionContextCpp::CopyTypeAndValueSource(*destVariableIter, *sourceVariableIter);
}
}
// (possibly overridden) variables
// (possibly overridden) variables, only the overrides are saved in on the component, otherwise they are taken from the runtime asset
{
auto sourceVariableIter = runtimeData.m_activationInputRange.inputs + runtimeData.m_activationInputRange.nodeableCount;
auto destVariableIter = rangeOut.inputs + runtimeData.m_activationInputRange.nodeableCount;
for (auto& idDatumPair : runtimeData.m_input.m_variables)
size_t overrideIndexTracker = 0;
const size_t sentinel = runtimeData.m_input.m_variables.size();
for (size_t index = 0; index != sentinel; ++index, ++destVariableIter, ++sourceVariableIter)
{
ExecutionContextCpp::TypeCopy(*destVariableIter, *sourceVariableIter);
auto variableOverride = activationData.variableOverrides.FindVariable(idDatumPair.first);
const Datum* datum = variableOverride ? variableOverride->GetDatum() : &idDatumPair.second;
destVariableIter->m_value = const_cast<void*>(datum->GetAsDanger());
++destVariableIter;
++sourceVariableIter;
ExecutionContextCpp::CopyTypeInformationOnly(*destVariableIter, *sourceVariableIter);
destVariableIter->m_value = const_cast<void*>(activationData.GetVariableSource(index, overrideIndexTracker));
}
}
// (must always be re-mapped) EntityId
if (!runtimeData.m_input.m_entityIds.empty())
{
AZ::SliceComponent::EntityIdToEntityIdMap loadedEntityIdMap;
AzFramework::EntityContextId owningContextId = AzFramework::EntityContextId::CreateNull();
AzFramework::EntityIdContextQueryBus::EventResult(owningContextId, activationData.entityId, &AzFramework::EntityIdContextQueries::GetOwningContextId);
if (!owningContextId.IsNull())
// (always overridden) EntityIds
{
AzFramework::SliceEntityOwnershipServiceRequestBus::EventResult(loadedEntityIdMap, owningContextId, &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::GetLoadedEntityIdMap);
}
AZ::BehaviorValueParameter* destVariableIter = rangeOut.inputs
+ runtimeData.m_activationInputRange.nodeableCount
+ runtimeData.m_activationInputRange.variableCount;
const auto entityIdTypeId = azrtti_typeid<Data::EntityIDType>();
for (auto& idEntityPair : runtimeData.m_input.m_entityIds)
for (auto& entityId : activationData.variableOverrides.m_entityIds)
{
destVariableIter->m_typeId = entityIdTypeId;
destVariableIter->m_value = destVariableIter->m_tempData.allocate(sizeof(Data::EntityIDType), AZStd::alignment_of<Data::EntityIDType>::value, 0);
auto entityIdValuePtr = reinterpret_cast<AZStd::decay_t<Data::EntityIDType>*>(destVariableIter->m_value);
if (auto variableOverride = activationData.variableOverrides.FindVariable(idEntityPair.first))
{
*entityIdValuePtr = *variableOverride->GetDatum()->GetAs<Data::EntityIDType>();
}
else
{
auto iter = loadedEntityIdMap.find(idEntityPair.second);
if (iter != loadedEntityIdMap.end())
{
*entityIdValuePtr = iter->second;
}
else
{
*entityIdValuePtr = Data::EntityIDType();
}
}
*entityIdValuePtr = entityId;
++destVariableIter;
}
}

@ -12,9 +12,9 @@
namespace ScriptCanvas
{
class RuntimeComponent;
class VariableData;
struct RuntimeData;
struct RuntimeDataOverrides;
namespace Execution
{
@ -22,13 +22,13 @@ namespace ScriptCanvas
struct ActivationData
{
ActivationData(const RuntimeComponent& component, ActivationInputArray& storage);
ActivationData(const AZ::EntityId entityId, const VariableData& variableOverrides, const RuntimeData& runtimeData, ActivationInputArray& storage);
const AZ::EntityId entityId;
const VariableData& variableOverrides;
const RuntimeDataOverrides& variableOverrides;
const RuntimeData& runtimeData;
ActivationInputArray& storage;
ActivationData(const RuntimeDataOverrides& variableOverrides, ActivationInputArray& storage);
const void* GetVariableSource(size_t index, size_t& overrideIndexTracker) const;
};
struct ActivationInputRange
@ -47,7 +47,7 @@ namespace ScriptCanvas
AZ_TYPE_INFO(Context, "{2C137581-19F4-42EB-8BF3-14DBFBC02D8D}");
AZ_CLASS_ALLOCATOR(Context, AZ::SystemAllocator, 0);
static ActivationInputRange CreateActivateInputRange(ActivationData& activationData);
static ActivationInputRange CreateActivateInputRange(ActivationData& activationData, const AZ::EntityId& forSliceSupportOnly);
static void InitializeActivationData(RuntimeData& runtimeData);
static void UnloadData(RuntimeData& runtimeData);

@ -34,16 +34,16 @@ namespace ScriptCanvas
switch (selection)
{
case Grammar::InterpretedPure:
case Grammar::ExecutionStateSelection::InterpretedPure:
return AZStd::make_shared<ExecutionStateInterpretedPure>(config);
case Grammar::InterpretedPureOnGraphStart:
case Grammar::ExecutionStateSelection::InterpretedPureOnGraphStart:
return AZStd::make_shared<ExecutionStateInterpretedPureOnGraphStart>(config);
case Grammar::InterpretedObject:
case Grammar::ExecutionStateSelection::InterpretedObject:
return AZStd::make_shared<ExecutionStateInterpretedPerActivation>(config);
case Grammar::InterpretedObjectOnGraphStart:
case Grammar::ExecutionStateSelection::InterpretedObjectOnGraphStart:
return AZStd::make_shared<ExecutionStateInterpretedPerActivationOnGraphStart>(config);
default:
@ -54,7 +54,7 @@ namespace ScriptCanvas
AZ::Data::AssetId ExecutionState::GetAssetId() const
{
return m_component->GetAsset().GetId();
return m_component->GetRuntimeDataOverrides().m_runtimeAsset.GetId();
}
AZ::EntityId ExecutionState::GetEntityId() const
@ -82,9 +82,9 @@ namespace ScriptCanvas
return m_component->GetScriptCanvasId();
}
const VariableData& ExecutionState::GetVariableOverrides() const
const RuntimeDataOverrides& ExecutionState::GetRuntimeDataOverrides() const
{
return m_component->GetVariableOverrides();
return m_component->GetRuntimeDataOverrides();
}
void ExecutionState::Reflect(AZ::ReflectContext* reflectContext)
@ -92,6 +92,8 @@ namespace ScriptCanvas
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
{
behaviorContext->Class<ExecutionState>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AZ::AttributeIsValid::IfPresent)
->Method("GetEntityId", &ExecutionState::GetEntityId)
->Method("GetScriptCanvasId", &ExecutionState::GetScriptCanvasId)
->Method("ToString", &ExecutionState::ToString)

@ -71,7 +71,7 @@ namespace ScriptCanvas
AZ::EntityId GetScriptCanvasId() const;
const VariableData& GetVariableOverrides() const;
const RuntimeDataOverrides& GetRuntimeDataOverrides() const;
virtual void Initialize() = 0;

@ -358,8 +358,7 @@ namespace ScriptCanvas
++current;
*data = (value0 << 4) | value1;
}
while ((++data) != sentinel);
} while ((++data) != sentinel);
return id;
}
@ -370,7 +369,6 @@ namespace ScriptCanvas
/**
Here is the function in Lua for easier reading
function OverrideNodeableMetatable(userdata, class_mt)
local proxy = setmetatable({}, class_mt) -- class_mt from the user graph definition
local instance_mt = {
@ -388,7 +386,6 @@ namespace ScriptCanvas
--]]
return setmetatable(userdata instance_mt) -- can't be done from Lua
end
--[[
userdata to Nodeable before:
getmetatable(userdata).__index == Nodeable
@ -399,7 +396,6 @@ namespace ScriptCanvas
local SubGraph = getmetatable(proxy).__index
getmetatable(SubGraph.__index) == Nodeable)
--]]
*/
// \note: all other metamethods ignored for now
@ -680,9 +676,9 @@ namespace ScriptCanvas
struct DependencyConstructionPack
{
ExecutionStateInterpreted* executionState;
AZStd::vector<AZ::Data::Asset<RuntimeAsset>>* dependentAssets;
const size_t dependentAssetsIndex;
RuntimeData& runtimeData;
AZStd::vector<RuntimeDataOverrides>* dependencies;
const size_t dependenciesIndex;
RuntimeDataOverrides& runtimeOverrides;
};
DependencyConstructionPack UnpackDependencyConstructionArgsSanitize(lua_State* lua)
@ -690,27 +686,26 @@ namespace ScriptCanvas
auto executionState = AZ::ScriptValue<ExecutionStateInterpreted*>::StackRead(lua, 1);
AZ_Assert(executionState, "Error in compiled lua file, 1st argument to UnpackDependencyArgs is not an ExecutionStateInterpreted");
AZ_Assert(lua_islightuserdata(lua, 2), "Error in compiled lua file, 2nd argument to UnpackDependencyArgs is not userdata (AZStd::vector<AZ::Data::Asset<RuntimeAsset>>*), but a :%s", lua_typename(lua, 2));
auto dependentAssets = reinterpret_cast<AZStd::vector<AZ::Data::Asset<RuntimeAsset>>*>(lua_touserdata(lua, 2));
auto dependentOverrides = reinterpret_cast<AZStd::vector<RuntimeDataOverrides>*>(lua_touserdata(lua, 2));
AZ_Assert(lua_isinteger(lua, 3), "Error in compiled Lua file, 3rd argument to UnpackDependencyArgs is not a number");
const size_t dependentAssetsIndex = aznumeric_caster(lua_tointeger(lua, 3));
return DependencyConstructionPack{ executionState, dependentAssets, dependentAssetsIndex, (*dependentAssets)[dependentAssetsIndex].Get()->m_runtimeData };
const size_t dependencyIndex = aznumeric_caster(lua_tointeger(lua, 3));
return DependencyConstructionPack{ executionState, dependentOverrides, dependencyIndex, (*dependentOverrides)[dependencyIndex] };
}
int Unpack(lua_State* lua, DependencyConstructionPack& args)
{
ActivationInputArray storage;
ActivationData data(args.executionState->GetEntityId(), args.executionState->GetVariableOverrides(), args.runtimeData, storage);
ActivationInputRange range = Execution::Context::CreateActivateInputRange(data);
ActivationData data(args.runtimeOverrides, storage);
ActivationInputRange range = Execution::Context::CreateActivateInputRange(data, args.executionState->GetEntityId());
PushActivationArgs(lua, range.inputs, range.totalCount);
return range.totalCount;
}
int UnpackDependencyConstructionArgs(lua_State* lua)
{
// Lua: executionState, dependentAssets, dependentAssetsIndex
// Lua: executionState, dependent overrides, index into dependent overrides
DependencyConstructionPack pack = UnpackDependencyConstructionArgsSanitize(lua);
lua_pushlightuserdata(lua, const_cast<void*>(reinterpret_cast<const void*>(&pack.runtimeData.m_requiredAssets)));
lua_pushlightuserdata(lua, const_cast<void*>(reinterpret_cast<const void*>(&pack.runtimeOverrides.m_dependencies)));
return 1 + Unpack(lua, pack);
}
@ -721,5 +716,4 @@ namespace ScriptCanvas
return Unpack(lua, constructionArgs);
}
}
}

@ -20,6 +20,7 @@ namespace ExecutionStateInterpretedCpp
AZ::Data::Asset<RuntimeAsset> GetSubgraphAssetForDebug(const AZ::Data::AssetId& id)
{
// #functions2 this may have to be made recursive
auto asset = AZ::Data::AssetManager::Instance().GetAsset<SubgraphInterfaceAsset>(id, AZ::Data::AssetLoadBehavior::PreLoad);
asset.BlockUntilLoadComplete();
return asset;
@ -40,8 +41,8 @@ namespace ScriptCanvas
const Grammar::DebugExecution* ExecutionStateInterpreted::GetDebugSymbolIn(size_t index) const
{
return index < m_component->GetAssetData().m_debugMap.m_ins.size()
? &(m_component->GetAssetData().m_debugMap.m_ins[index])
return index < m_component->GetRuntimeAssetData().m_debugMap.m_ins.size()
? &(m_component->GetRuntimeAssetData().m_debugMap.m_ins[index])
: nullptr;
}
@ -55,8 +56,8 @@ namespace ScriptCanvas
const Grammar::DebugExecution* ExecutionStateInterpreted::GetDebugSymbolOut(size_t index) const
{
return index < m_component->GetAssetData().m_debugMap.m_outs.size()
? &(m_component->GetAssetData().m_debugMap.m_outs[index])
return index < m_component->GetRuntimeAssetData().m_debugMap.m_outs.size()
? &(m_component->GetRuntimeAssetData().m_debugMap.m_outs[index])
: nullptr;
}
@ -70,8 +71,8 @@ namespace ScriptCanvas
const Grammar::DebugExecution* ExecutionStateInterpreted::GetDebugSymbolReturn(size_t index) const
{
return index < m_component->GetAssetData().m_debugMap.m_returns.size()
? &(m_component->GetAssetData().m_debugMap.m_returns[index])
return index < m_component->GetRuntimeAssetData().m_debugMap.m_returns.size()
? &(m_component->GetRuntimeAssetData().m_debugMap.m_returns[index])
: nullptr;
}
@ -85,8 +86,8 @@ namespace ScriptCanvas
const Grammar::DebugDataSource* ExecutionStateInterpreted::GetDebugSymbolVariableChange(size_t index) const
{
return index < m_component->GetAssetData().m_debugMap.m_variables.size()
? &(m_component->GetAssetData().m_debugMap.m_variables[index])
return index < m_component->GetRuntimeAssetData().m_debugMap.m_variables.size()
? &(m_component->GetRuntimeAssetData().m_debugMap.m_variables[index])
: nullptr;
}
@ -131,6 +132,8 @@ namespace ScriptCanvas
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
{
behaviorContext->Class<ExecutionStateInterpreted>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AZ::AttributeIsValid::IfPresent)
;
}
}
@ -148,5 +151,4 @@ namespace ScriptCanvas
luaL_unref(m_luaState, LUA_REGISTRYINDEX, m_luaRegistryIndex);
m_luaRegistryIndex = LUA_NOREF;
}
}

@ -45,15 +45,15 @@ namespace ScriptCanvas
AZ::Internal::LuaClassToStack(lua, this, azrtti_typeid<ExecutionStateInterpretedPerActivation>(), AZ::ObjectToLua::ByReference, AZ::AcquisitionOnPush::None);
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>
Execution::ActivationInputArray storage;
Execution::ActivationData data(*m_component, storage);
Execution::ActivationInputRange range = Execution::Context::CreateActivateInputRange(data);
Execution::ActivationData data(m_component->GetRuntimeDataOverrides(), storage);
Execution::ActivationInputRange range = Execution::Context::CreateActivateInputRange(data, m_component->GetEntityId());
if (range.requiresDependencyConstructionParameters)
{
lua_pushlightuserdata(lua, const_cast<void*>(reinterpret_cast<const void*>(&data.runtimeData.m_requiredAssets)));
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, dependencies
lua_pushlightuserdata(lua, const_cast<void*>(reinterpret_cast<const void*>(&data.variableOverrides.m_dependencies)));
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, runtimeDataOverrides
Execution::PushActivationArgs(lua, range.inputs, range.totalCount);
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, dependencies, args...
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, runtimeDataOverrides, args...
AZ::Internal::LuaSafeCall(lua, aznumeric_caster(2 + range.totalCount), 1);
}
else
@ -139,5 +139,4 @@ namespace ScriptCanvas
;
}
}
}

@ -52,8 +52,8 @@ namespace ScriptCanvas
AZ::Internal::LuaClassToStack(lua, this, azrtti_typeid<ExecutionStateInterpretedPureOnGraphStart>(), AZ::ObjectToLua::ByReference, AZ::AcquisitionOnPush::None);
// Lua: graph_VM, graph_VM['k_OnGraphStartFunctionName'], userdata<ExecutionState>
Execution::ActivationInputArray storage;
Execution::ActivationData data(*m_component, storage);
Execution::ActivationInputRange range = Execution::Context::CreateActivateInputRange(data);
Execution::ActivationData data(m_component->GetRuntimeDataOverrides(), storage);
Execution::ActivationInputRange range = Execution::Context::CreateActivateInputRange(data, m_component->GetEntityId());
Execution::PushActivationArgs(lua, range.inputs, range.totalCount);
// Lua: graph_VM, graph_VM['k_OnGraphStartFunctionName'], userdata<ExecutionState>, args...
const int result = Execution::InterpretedSafeCall(lua, aznumeric_caster(1 + range.totalCount), 0);

@ -24,9 +24,12 @@
namespace RuntimeComponentCpp
{
enum Version
enum class RuntimeComponentVersion : unsigned int
{
ForceAssetPreloads = 5,
AddRuntimeDataOverrides,
PrefabSupport,
RemoveRuntimeAsset,
// add description above
Current,
@ -40,17 +43,11 @@ namespace ScriptCanvas
return GraphInfo(scriptCanvasId, graphIdentifier);
}
DatumValue CreateDatumValue(ScriptCanvasId /*scriptCanvasId*/, const GraphVariable& variable)
DatumValue CreateDatumValue([[maybe_unused]] ScriptCanvasId scriptCanvasId, const GraphVariable& variable)
{
return DatumValue::Create(GraphVariable((*variable.GetDatum()), variable.GetVariableId()));
}
RuntimeComponent::RuntimeComponent(AZ::Data::Asset<RuntimeAsset> runtimeAsset)
: m_runtimeAsset(runtimeAsset)
{
m_runtimeAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
}
void RuntimeComponent::Activate()
{
InitializeExecution();
@ -66,18 +63,13 @@ namespace ScriptCanvas
AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::ScriptCanvas, "RuntimeComponent::Execute (%s)", m_runtimeAsset.GetId().ToString<AZStd::string>().c_str());
AZ_Assert(m_executionState, "RuntimeComponent::Execute called without an execution state");
SC_EXECUTION_TRACE_GRAPH_ACTIVATED(CreateActivationInfo());
SCRIPT_CANVAS_PERFORMANCE_SCOPE_EXECUTION(m_executionState->GetScriptCanvasId(), m_runtimeAsset.GetId());
SCRIPT_CANVAS_PERFORMANCE_SCOPE_EXECUTION(m_executionState->GetScriptCanvasId(), m_runtimeOverrides.m_runtimeAsset.GetId());
m_executionState->Execute();
}
const AZ::Data::Asset<RuntimeAsset>& RuntimeComponent::GetAsset() const
{
return m_runtimeAsset;
}
const RuntimeData& RuntimeComponent::GetAssetData() const
const RuntimeData& RuntimeComponent::GetRuntimeAssetData() const
{
return m_runtimeAsset->GetData();
return m_runtimeOverrides.m_runtimeAsset->GetData();
}
ExecutionMode RuntimeComponent::GetExecutionMode() const
@ -87,7 +79,7 @@ namespace ScriptCanvas
GraphIdentifier RuntimeComponent::GetGraphIdentifier() const
{
return GraphIdentifier(AZ::Data::AssetId(m_runtimeAsset.GetId().m_guid, 0), 0);
return GraphIdentifier(AZ::Data::AssetId(m_runtimeOverrides.m_runtimeAsset.GetId().m_guid, 0), 0);
}
AZ::EntityId RuntimeComponent::GetScriptCanvasId() const
@ -95,37 +87,43 @@ namespace ScriptCanvas
return m_scriptCanvasId;
}
const VariableData& RuntimeComponent::GetVariableOverrides() const
const RuntimeDataOverrides& RuntimeComponent::GetRuntimeDataOverrides() const
{
return m_variableOverrides;
return m_runtimeOverrides;
}
void RuntimeComponent::SetRuntimeDataOverrides(const RuntimeDataOverrides& overrideData)
{
m_runtimeOverrides = overrideData;
m_runtimeOverrides.EnforcePreloadBehavior();
}
void RuntimeComponent::Init()
{
m_scriptCanvasId = AZ::Entity::MakeId();
AZ_Assert(m_runtimeAsset.GetAutoLoadBehavior() == AZ::Data::AssetLoadBehavior::PreLoad, "RuntimeComponent::m_runtimeAsset Auto load behavior MUST be set to AZ::Data::AssetLoadBehavior::PreLoad");
AZ_Assert(RuntimeDataOverrides::IsPreloadBehaviorEnforced(m_runtimeOverrides), "RuntimeComponent::m_runtimeAsset Auto load behavior MUST be set to AZ::Data::AssetLoadBehavior::PreLoad");
}
void RuntimeComponent::InitializeExecution()
{
#if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK)
if (!m_runtimeAsset.Get())
if (!m_runtimeOverrides.m_runtimeAsset.Get())
{
AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeAsset.GetId().ToString<AZStd::string>().data());
AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString<AZStd::string>().data());
return;
}
#else
AZ_Assert(m_runtimeAsset.Get(), "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeAsset.GetId().ToString<AZStd::string>().data());
AZ_Assert(m_runtimeAsset.Get(), "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString<AZStd::string>().data());
#endif
AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::ScriptCanvas, "RuntimeComponent::InitializeExecution (%s)", m_runtimeAsset.GetId().ToString<AZStd::string>().c_str());
SCRIPT_CANVAS_PERFORMANCE_SCOPE_INITIALIZATION(m_scriptCanvasId, m_runtimeAsset.GetId());
m_executionState = ExecutionState::Create(ExecutionStateConfig(m_runtimeAsset, *this));
SCRIPT_CANVAS_PERFORMANCE_SCOPE_INITIALIZATION(m_scriptCanvasId, m_runtimeOverrides.m_runtimeAsset.GetId());
m_executionState = ExecutionState::Create(ExecutionStateConfig(m_runtimeOverrides.m_runtimeAsset, *this));
#if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK)
if (!m_executionState)
{
AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run", m_runtimeAsset.GetId().ToString<AZStd::string>().data());
AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString<AZStd::string>().data());
return;
}
#else
@ -151,24 +149,18 @@ namespace ScriptCanvas
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<RuntimeComponent, AZ::Component>()
->Version(RuntimeComponentCpp::Version::Current, &RuntimeComponent::VersionConverter)
->Field("m_runtimeAsset", &RuntimeComponent::m_runtimeAsset)
->Field("m_variableOverrides", &RuntimeComponent::m_variableOverrides)
->Version(static_cast<unsigned int>(RuntimeComponentCpp::RuntimeComponentVersion::Current), &RuntimeComponent::VersionConverter)
->Field("runtimeOverrides", &RuntimeComponent::m_runtimeOverrides)
;
}
}
void RuntimeComponent::SetVariableOverrides(const VariableData& overrideData)
{
m_variableOverrides = overrideData;
}
void RuntimeComponent::StopExecution()
{
if (m_executionState)
{
m_executionState->StopExecution();
SCRIPT_CANVAS_PERFORMANCE_FINALIZE_TIMER(GetScriptCanvasId(), m_runtimeAsset.GetId());
SCRIPT_CANVAS_PERFORMANCE_FINALIZE_TIMER(GetScriptCanvasId(), m_runtimeOverrides.m_runtimeAsset.GetId());
SC_EXECUTION_TRACE_GRAPH_DEACTIVATED(CreateActivationInfo());
}
}

@ -17,9 +17,6 @@
#include <ScriptCanvas/Execution/ExecutionStateDeclarations.h>
#include <ScriptCanvas/Grammar/PrimitivesDeclarations.h>
#include "RuntimeComponent.h"
namespace ScriptCanvas
{
using VariableIdMap = AZStd::unordered_map<VariableId, VariableId>;
@ -45,11 +42,8 @@ namespace ScriptCanvas
RuntimeComponent() = default;
RuntimeComponent(AZ::Data::Asset<RuntimeAsset> runtimeAsset);
const AZ::Data::Asset<RuntimeAsset>& GetAsset() const;
const RuntimeData& GetAssetData() const;
// used to provide debug symbols, usually coming in the form of Node/Slot/Variable IDs
const RuntimeData& GetRuntimeAssetData() const;
GraphIdentifier GetGraphIdentifier() const;
@ -57,9 +51,9 @@ namespace ScriptCanvas
AZ::EntityId GetScriptCanvasId() const;
const VariableData& GetVariableOverrides() const;
const RuntimeDataOverrides& GetRuntimeDataOverrides() const;
void SetVariableOverrides(const VariableData& overrideData);
void SetRuntimeDataOverrides(const RuntimeDataOverrides& overrideData);
protected:
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
@ -94,15 +88,8 @@ namespace ScriptCanvas
void StopExecution();
private:
AZ::Data::Asset<RuntimeAsset> m_runtimeAsset;
ExecutionStatePtr m_executionState;
AZ::EntityId m_scriptCanvasId;
//! Per instance variable data overrides for the runtime asset
//! This is serialized when building this component from the EditorScriptCanvasComponent
// \todo remove the names from this data, and make it more lightweight
// it only needs variable id and value
// move the other information to the runtime system component
VariableData m_variableOverrides;
RuntimeDataOverrides m_runtimeOverrides;
};
}

@ -7,6 +7,7 @@
#include <AzCore/std/containers/unordered_map.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <Builder/ScriptCanvasBuilder.h>
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Core/EBusHandler.h>
#include <ScriptCanvas/Core/Graph.h>
@ -41,7 +42,7 @@ namespace AbstractCodeModelCpp
using namespace ScriptCanvas::Grammar;
AZStd::unordered_set< const Nodes::Core::FunctionDefinitionNode*> Intersection
( const AZStd::unordered_multimap<const Nodes::Core::FunctionDefinitionNode*, ExecutionTreePtr>& lhs
(const AZStd::unordered_multimap<const Nodes::Core::FunctionDefinitionNode*, ExecutionTreePtr>& lhs
, const AZStd::unordered_set< const Nodes::Core::FunctionDefinitionNode*>& rhs)
{
AZStd::unordered_set< const Nodes::Core::FunctionDefinitionNode*> intersection;
@ -424,7 +425,7 @@ namespace ScriptCanvas
}
void AbstractCodeModel::AddExecutionMapIn
( UserInParseTopologyResult /*result*/
(UserInParseTopologyResult /*result*/
, ExecutionTreeConstPtr root
, const AZStd::vector<ExecutionTreeConstPtr>& outCalls
, AZStd::string_view defaultOutName
@ -697,7 +698,7 @@ namespace ScriptCanvas
}
AZStd::string AbstractCodeModel::CheckUniqueInterfaceNames
( AZStd::string_view candidate
(AZStd::string_view candidate
, AZStd::string_view defaultName
, AZStd::unordered_set<AZStd::string>& uniqueNames
, const AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>& nodelingsOut)
@ -755,7 +756,7 @@ namespace ScriptCanvas
}
AZStd::vector<Grammar::VariableConstPtr> AbstractCodeModel::CombineVariableLists
( const AZStd::vector<Nodeable*>& constructionNodeables
(const AZStd::vector<Nodeable*>& constructionNodeables
, const AZStd::vector<AZStd::pair<VariableId, Datum>>& constructionInputVariables
, const AZStd::vector<AZStd::pair<VariableId, Data::EntityIDType>>& entityIds) const
{
@ -766,7 +767,7 @@ namespace ScriptCanvas
const void* nodeableAsVoidPtr = nodeable;
auto iter = AZStd::find_if
( m_nodeablesByNode.begin()
(m_nodeablesByNode.begin()
, m_nodeablesByNode.end()
, [&](const auto& candidate)
{
@ -784,7 +785,7 @@ namespace ScriptCanvas
for (const auto& variable : entityIds)
{
auto iter = AZStd::find_if( m_variables.begin(), m_variables.end(), [&](const auto& candidate) {
auto iter = AZStd::find_if(m_variables.begin(), m_variables.end(), [&](const auto& candidate) {
if (candidate->m_datum.GetType() == Data::Type::EntityID())
{
bool isVariableIdMatch = candidate->m_sourceVariableId == variable.first;
@ -836,7 +837,7 @@ namespace ScriptCanvas
{
ExecutionTreePtr child = AZStd::make_shared<ExecutionTree>();
child->SetParent(parent);
child->SetId({node, slot});
child->SetId({ node, slot });
child->SetScope(parent ? parent->ModScope() : m_graphScope);
return child;
}
@ -1222,11 +1223,11 @@ namespace ScriptCanvas
if (m_uniqueInNames.contains(displayName))
{
AddError
( nodeling->GetEntityId()
(nodeling->GetEntityId()
, nullptr
, AZStd::string::format
( "%s is the name of multiple In Nodelings in a subgraph,\n"
"this will result in a difficult or impossible to use Function Node when used in another graph", displayName.data()));
"this will result in a difficult or impossible to use Function Node when used in another graph", displayName.c_str()));
return;
}
else
@ -1258,7 +1259,7 @@ namespace ScriptCanvas
AddError(nodeling->GetEntityId()
, nullptr
, AZStd::string::format
( "%s is the name of multiple In Nodelings in a subgraph,\n"
("%s is the name of multiple In Nodelings in a subgraph,\n"
"this will result in a difficult or impossible to use Function Node when used in another graph", displayName.data()));
}
else
@ -1355,7 +1356,7 @@ namespace ScriptCanvas
{
AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format
( "Execution cycle detected (see connections to %s-%s. Use a looping node like While or For"
, node.GetDebugName().data(), outSlot.GetName().data()).data()));
, node.GetDebugName().c_str(), outSlot.GetName().c_str()).c_str()));
return true;
}
@ -1477,7 +1478,7 @@ namespace ScriptCanvas
return slot && candidate.second == slot;
});
return iter != scriptCanvasNodesConnectedToInput.end() ? *iter : EndpointResolved{nullptr, nullptr};
return iter != scriptCanvasNodesConnectedToInput.end() ? *iter : EndpointResolved{ nullptr, nullptr };
};
for (size_t childIndex = 0; childIndex < outputSource->GetChildrenCount(); ++childIndex)
@ -1570,7 +1571,7 @@ namespace ScriptCanvas
VariableConstPtr AbstractCodeModel::FindVariable(const AZ::EntityId& sourceNodeId) const
{
auto resultIter = AZStd::find_if
( m_variables.begin()
(m_variables.begin()
, m_variables.end()
, [&sourceNodeId](const VariableConstPtr& candidate) { return candidate->m_nodeableNodeId == sourceNodeId; });
@ -1580,7 +1581,7 @@ namespace ScriptCanvas
VariableConstPtr AbstractCodeModel::FindVariable(const VariableId& sourceVariableId) const
{
auto resultIter = AZStd::find_if
( m_variables.begin()
(m_variables.begin()
, m_variables.end()
, [&sourceVariableId](const VariableConstPtr& candidate) { return candidate->m_sourceVariableId == sourceVariableId; });
@ -1591,7 +1592,7 @@ namespace ScriptCanvas
{
if (IsUserNodeable(variable))
{
auto iter = AZStd::find_if(m_nodeablesByNode.begin(), m_nodeablesByNode.end(), [&variable](auto& candidate){ return candidate.second->m_nodeable == variable; });
auto iter = AZStd::find_if(m_nodeablesByNode.begin(), m_nodeablesByNode.end(), [&variable](auto& candidate) { return candidate.second->m_nodeable == variable; });
if (iter != m_nodeablesByNode.end())
{
return iter->second->m_simpleName;
@ -1604,7 +1605,7 @@ namespace ScriptCanvas
const AZStd::pair<VariableConstPtr, AZStd::string>* AbstractCodeModel::FindStaticVariable(VariableConstPtr variable) const
{
auto iter = AZStd::find_if
( m_staticVariableNames.begin()
(m_staticVariableNames.begin()
, m_staticVariableNames.end()
, [&](const auto& candidate) { return candidate.first == variable; });
@ -1622,7 +1623,7 @@ namespace ScriptCanvas
else
{
const_cast<AbstractCodeModel*>(this)->AddError(execution, aznew ParseError(slot.GetNodeId(), AZStd::string::format
( "Failed to find member variable for Variable Reference in slot: %s Id: %s"
("Failed to find member variable for Variable Reference in slot: %s Id: %s"
, slot.GetName().data()
, slot.GetVariableReference().ToString().data())));
}
@ -2237,7 +2238,7 @@ namespace ScriptCanvas
{
ExecutionTreePtr child = CreateChild(parent, node, outSlot);
child->SetScope(AZStd::make_shared<Scope>());
child->ModScope()->m_parent = parent ? parent->ModScope(): m_graphScope;
child->ModScope()->m_parent = parent ? parent->ModScope() : m_graphScope;
return child;
}
@ -2258,12 +2259,16 @@ namespace ScriptCanvas
m_variableScopeMeaning = VariableScopeMeaning_LegacyFunctions::ValueInitialization;
}
#endif
// The Order Matters: begin
// add all data to the ACM for easy look up in input/output processing for ACM nodes
AddAllVariablesPreParse();
if (!IsErrorFree())
{
return;
}
// parse basic editor nodes as they may add implicit variables
for (auto& nodeEntity : m_source.m_graphData->m_nodes)
{
if (nodeEntity)
@ -2296,18 +2301,27 @@ namespace ScriptCanvas
return;
}
// parse the implicit variables added by ebus handling syntax sugar
ParseAutoConnectedEBusHandlerVariables();
// all possible data is available, now parse execution, starting with "main", currently keyed to RuntimeComponent::Activate
Parse(m_startNodes);
// parse any function introduced by nodes other than On Graph Start/"main"
for (auto node : m_possibleExecutionRoots)
{
ParseExecutionTreeRoots(*node);
}
// parse functions introduced by variable change events
ParseVariableHandling();
// parse all user function and function object signatures
ParseUserFunctionTopology();
ParseConstructionInputVariables();
// culls unused variables, and determine whether the the graph defines an object or static functionality
ParseExecutionCharacteristics();
// now that variables have been culled, determined what data needs to be initialized by an external source
ParseConstructionInputVariables();
// now that externally initialized data has been identified, associate local, static initializers with individual functions
ParseFunctionLocalStaticUseage();
// The Order Matters: end
// from here on, nothing more needs to happen during simple parsing
// for example, in the editor, to get validation on syntax based effects for the view
@ -2315,7 +2329,10 @@ namespace ScriptCanvas
if (IsErrorFree())
{
// the graph could have used several user graphs which required construction, and maybe multiple instances of the same user asset
// this will create indices for those nodes to be able to pass in the proper entry in the construction argument tree at translation and runtime
ParseDependenciesAssetIndicies();
// protect all names against keyword collision and language naming violations
ConvertNamesToIdentifiers();
if (m_source.m_addDebugInfo)
@ -2629,7 +2646,7 @@ namespace ScriptCanvas
// create a variable declaration
ExecutionTreePtr variableConstruction = CreateChild(inPreviouslyExecutedScopeResult.m_mostParent->ModParent(), nullptr, nullptr);
variableConstruction->AddInput({ nullptr , newInputResultOfAssignment, DebugDataSource::FromInternal()});
variableConstruction->AddInput({ nullptr , newInputResultOfAssignment, DebugDataSource::FromInternal() });
variableConstruction->SetSymbol(Symbol::VariableDeclaration);
// splice the variable declaration right before the most parent for loop is executed
@ -2701,7 +2718,7 @@ namespace ScriptCanvas
case VariableConstructionRequirement::InputVariable:
{
auto variableID = variable->m_sourceVariableId.IsValid() ? variable->m_sourceVariableId : VariableId::MakeVariableId();
auto variableID = variable->m_sourceVariableId.IsValid() ? variable->m_sourceVariableId : MakeParserGeneratedId(m_generatedIdCount++);
inputVariableIds.push_back(variableID);
inputVariablesById.insert({ variableID, variable });
// sort revealed a datum copy issue: type is not preserved, workaround below
@ -2755,7 +2772,7 @@ namespace ScriptCanvas
{
auto& localStatics = ModStaticVariablesNames(staticVariable->m_source);
auto iter = AZStd::find_if
( localStatics.begin()
(localStatics.begin()
, localStatics.end()
, [&](const auto& candidate) { return candidate.first == staticVariable; });
@ -2900,7 +2917,7 @@ namespace ScriptCanvas
if (dependencies.userSubgraphs.find(m_source.m_namespacePath) != dependencies.userSubgraphs.end())
{
AZStd::string circularDependency = AZStd::string::format
( ParseErrors::CircularDependencyFormat
(ParseErrors::CircularDependencyFormat
, m_source.m_name.data()
, node.GetDebugName().data()
, m_source.m_name.data());
@ -2908,6 +2925,7 @@ namespace ScriptCanvas
AddError(nullptr, aznew Internal::ParseError(node.GetEntityId(), circularDependency));
}
// #functions2 make this use an identifier for the node, for property window display and easier find/replace updates
// this part must NOT recurse, the dependency tree should remain a tree and not be flattened
m_orderedDependencies.source.MergeWith(dependencies);
}
@ -2950,11 +2968,32 @@ namespace ScriptCanvas
{
if (!input->m_sourceVariableId.IsValid() && IsEntityIdThatRequiresRuntimeRemap(input))
{
input->m_sourceVariableId = VariableId::MakeVariableId();
input->m_sourceVariableId = MakeParserGeneratedId(m_generatedIdCount++);
input->m_source = nullptr;
// promote to member variable for at this stage, optimizations on data flow will occur later
input->m_isMember = true;
input->m_name = m_graphScope->AddVariableName(input->m_name);
AZStd::string entityVariableName;
if (slotAndVariable.m_slot)
{
if (execution->GetId().m_node)
{
entityVariableName.append(execution->GetId().m_node->GetNodeName());
entityVariableName.append(".");
entityVariableName.append(slotAndVariable.m_slot->GetName());
}
else
{
entityVariableName.append(slotAndVariable.m_slot->GetName());
}
}
else
{
entityVariableName = input->m_name;
}
input->m_name = m_graphScope->AddVariableName(entityVariableName);
AddVariable(input);
}
}
@ -4167,6 +4206,32 @@ namespace ScriptCanvas
ParseExecutionLoop(execution);
}
void AbstractCodeModel::ParseFunctionLocalStaticUseage()
{
for (auto execution : ModAllExecutionRoots())
{
if (auto localVariables = GetLocalVariables(execution))
{
for (auto variable : *localVariables)
{
if (const AZStd::pair<VariableConstPtr, AZStd::string>* pair = FindStaticVariable(variable))
{
auto& localStatics = ModStaticVariablesNames(execution);
auto iter = AZStd::find_if
( localStatics.begin()
, localStatics.end()
, [&](const auto& candidate) { return candidate.first == variable; });
if (iter == localStatics.end())
{
localStatics.push_back(*pair);
}
}
}
}
}
}
void AbstractCodeModel::ParseImplicitVariables(const Node& node)
{
if (IsCycle(node))
@ -4314,7 +4379,7 @@ namespace ScriptCanvas
for (auto sourceNodeAndSlot : nodes)
{
AddError(nullptr, aznew ScopedDataConnectionEvent
( execution->GetNodeId()
(execution->GetNodeId()
, targetNode
, targetSlot
, *sourceNodeAndSlot.first
@ -4364,7 +4429,7 @@ namespace ScriptCanvas
{
auto node2 = execution->GetId().m_node;
AddError(execution, aznew ParseError(node2->GetEntityId(), AZStd::string::format
( "Failed to find member variable for Node: %s Id: %s"
("Failed to find member variable for Node: %s Id: %s"
, node2->GetNodeName().data()
, node2->GetEntityId().ToString().data()).data()));
}
@ -4394,7 +4459,7 @@ namespace ScriptCanvas
{
auto node2 = execution->GetId().m_node;
AddError(execution, aznew ParseError(node2->GetEntityId(), AZStd::string::format
( "Failed to find member variable for Node: %s Id: %s"
("Failed to find member variable for Node: %s Id: %s"
, node2->GetNodeName().data()
, node2->GetEntityId().ToString().data()).data()));
}
@ -5164,7 +5229,7 @@ namespace ScriptCanvas
if (!IsConnectedToUserIn(nodeling))
{
const auto report = AZStd::string::format
( "Nodeling Out (%s) not connected to Nodeling In, functionality cannot be executed", nodeling->GetDisplayName().data());
("Nodeling Out (%s) not connected to Nodeling In, functionality cannot be executed", nodeling->GetDisplayName().data());
AddError(nullptr, aznew Internal::ParseError(nodeling->GetEntityId(), report));
}
@ -5210,27 +5275,8 @@ namespace ScriptCanvas
TraverseTree(execution, listener);
const auto& usage = listener.GetUsedVariables();
const bool usesOnlyLocalVariables = usage.memberVariables.empty() && usage.implicitMemberVariables.empty();
m_variableUse.localVariables.insert(usage.localVariables.begin(), usage.localVariables.end());
m_variableUse.memberVariables.insert(usage.memberVariables.begin(), usage.memberVariables.end());
for (auto variable : m_variableUse.localVariables)
{
if (const AZStd::pair<VariableConstPtr, AZStd::string>* pair = FindStaticVariable(variable))
{
auto& localStatics = ModStaticVariablesNames(execution);
auto iter = AZStd::find_if
(localStatics.begin()
, localStatics.end()
, [&](const auto& candidate) { return candidate.first == variable; });
if (iter == localStatics.end())
{
localStatics.push_back(*pair);
}
}
}
m_variableUseByExecution.emplace(execution, listener.MoveUsedVariables());
return (!usage.usesExternallyInitializedVariables) && usesOnlyLocalVariables && listener.IsPure();
}
@ -5342,7 +5388,5 @@ namespace ScriptCanvas
{
return type == Data::eType::BehaviorContextObject;
}
}
}

@ -71,7 +71,7 @@ namespace ScriptCanvas
AZStd::optional<AZStd::pair<size_t, Grammar::DependencyInfo>> CheckUserNodeableDependencyConstructionIndex(VariableConstPtr nodeable) const;
AZStd::vector<VariableConstPtr> CombineVariableLists
( const AZStd::vector<Nodeable*>& constructionNodeables
(const AZStd::vector<Nodeable*>& constructionNodeables
, const AZStd::vector<AZStd::pair<VariableId, Datum>>& constructionInputVariableIds
, const AZStd::vector<AZStd::pair<VariableId, Data::EntityIDType>>& entityIds) const;
@ -150,8 +150,6 @@ namespace ScriptCanvas
bool IsUserNodeable(VariableConstPtr variable) const;
bool HasUserNodeableDependenciesInVariables() const;
template<typename T>
AZStd::vector<Grammar::VariableConstPtr> ToVariableList(const AZStd::vector<AZStd::pair<VariableId, T>>& source) const;
@ -210,7 +208,7 @@ namespace ScriptCanvas
bool CheckCreateRoot(const Node& node);
AZStd::string CheckUniqueInterfaceNames
( AZStd::string_view candidate
(AZStd::string_view candidate
, AZStd::string_view defaultName
, AZStd::unordered_set<AZStd::string>& uniqueNames
, const AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>& nodelingsOut);
@ -368,6 +366,8 @@ namespace ScriptCanvas
void ParseExecutionWhileLoop(ExecutionTreePtr execution);
void ParseFunctionLocalStaticUseage();
void ParseImplicitVariables(const Node& node);
void ParseInputData(ExecutionTreePtr execution);
@ -473,7 +473,7 @@ namespace ScriptCanvas
}
void AddExecutionMapIn
( UserInParseTopologyResult result
(UserInParseTopologyResult result
, ExecutionTreeConstPtr root
, const AZStd::vector<ExecutionTreeConstPtr>& outCalls
, AZStd::string_view defaultOutName
@ -505,6 +505,7 @@ namespace ScriptCanvas
static UserInParseTopologyResult ParseUserInTolopology(size_t nodelingsOutCount, size_t leavesWithoutNodelingsCount);
size_t m_outIndexCount = 0;
size_t m_generatedIdCount = 0;
ExecutionTreePtr m_start;
AZStd::vector<const Nodes::Core::Start*> m_startNodes;
ScopePtr m_graphScope;
@ -621,7 +622,7 @@ namespace ScriptCanvas
for (const auto& variable : source)
{
auto iter = AZStd::find_if
( m_variables.begin()
(m_variables.begin()
, m_variables.end()
, [&](const auto& candidate) { return candidate->m_sourceVariableId == variable.first; });
@ -633,7 +634,5 @@ namespace ScriptCanvas
return variables;
}
}
}

@ -47,6 +47,10 @@ namespace ParsingUtilitiesCpp
using namespace ScriptCanvas;
using namespace ScriptCanvas::Grammar;
const AZ::u64 k_parserGeneratedMask = 0x7FC0616C94E7465F;
const size_t k_maskIndex = 0;
const size_t k_countIndex = 1;
class PrettyPrinter
: public ExecutionTreeTraversalListener
{
@ -97,7 +101,7 @@ namespace ParsingUtilitiesCpp
m_result += "\n";
}
void EvaluateRoot(ExecutionTreeConstPtr node, const Slot* )
void EvaluateRoot(ExecutionTreeConstPtr node, const Slot*)
{
m_result += "\nRoot:\n";
}
@ -1001,10 +1005,16 @@ namespace ScriptCanvas
return true;
}
bool IsParserGeneratedId(const ScriptCanvas::VariableId& id)
{
using namespace ParsingUtilitiesCpp;
return reinterpret_cast<const AZ::u64*>(id.m_id.data)[k_maskIndex] == k_parserGeneratedMask;
}
bool IsPropertyExtractionSlot(const ExecutionTreeConstPtr& execution, const Slot* outputSlot)
{
auto iter = AZStd::find_if
( execution->GetPropertyExtractionSources().begin()
(execution->GetPropertyExtractionSources().begin()
, execution->GetPropertyExtractionSources().end()
, [&](const auto& iter) { return iter.first == outputSlot; });
@ -1120,6 +1130,16 @@ namespace ScriptCanvas
return AZStd::string::format("%s%s", k_memberNamePrefix, name.data());
}
VariableId MakeParserGeneratedId(size_t count)
{
using namespace ParsingUtilitiesCpp;
AZ::Uuid parserGenerated;
reinterpret_cast<AZ::u64*>(parserGenerated.data)[k_maskIndex] = k_parserGeneratedMask;
reinterpret_cast<AZ::u64*>(parserGenerated.data)[k_countIndex] = count;
return ScriptCanvas::VariableId(parserGenerated);
}
VariableConstructionRequirement ParseConstructionRequirement(VariableConstPtr variable)
{
if (IsEntityIdThatRequiresRuntimeRemap(variable))
@ -1216,7 +1236,7 @@ namespace ScriptCanvas
result += AZStd::string::format("Variable: %s, Type: %s, Scope: %s, \n"
, variable->m_name.data()
, Data::GetName(variable->m_datum.GetType()).data()
, variable->m_isMember ? "Member" : "Local" );
, variable->m_isMember ? "Member" : "Local");
}
auto roots = model.GetAllExecutionRoots();

@ -144,6 +144,8 @@ namespace ScriptCanvas
bool IsOnSelfEntityActivated(const AbstractCodeModel& model, ExecutionTreeConstPtr execution);
bool IsParserGeneratedId(const VariableId& id);
bool IsPropertyExtractionSlot(const ExecutionTreeConstPtr& execution, const Slot* outputSlot);
bool IsPropertyExtractionNode(const ExecutionTreeConstPtr& execution);
@ -178,6 +180,8 @@ namespace ScriptCanvas
bool IsWrittenMathExpression(const ExecutionTreeConstPtr& execution);
VariableId MakeParserGeneratedId(size_t count);
AZStd::string MakeMemberVariableName(AZStd::string_view name);
VariableConstructionRequirement ParseConstructionRequirement(Grammar::VariableConstPtr value);
@ -204,5 +208,4 @@ namespace ScriptCanvas
void TraverseTree(const ExecutionTreeConstPtr& execution, ExecutionTreeTraversalListener& listener);
}
}

@ -216,8 +216,7 @@ namespace ScriptCanvas
count = iter->second;
break;
}
}
while ((ns = AZStd::const_pointer_cast<Scope>(ns->m_parent)));
} while ((ns = AZStd::const_pointer_cast<Scope>(ns->m_parent)));
auto iter = m_baseNameToCount.find(name);
if (iter == m_baseNameToCount.end())
@ -235,7 +234,7 @@ namespace ScriptCanvas
const VariableData Source::k_emptyVardata{};
Source::Source
( const Graph& graph
(const Graph& graph
, const AZ::Data::AssetId& id
, const GraphData& graphData
, const VariableData& variableData
@ -277,8 +276,8 @@ namespace ScriptCanvas
AzFramework::StringFunc::Path::StripExtension(namespacePath);
return AZ::Success(Source
( *request.graph
, request.assetId
(*request.graph
, request.scriptAssetId
, *graphData
, *sourceVariableData
, name
@ -300,15 +299,15 @@ namespace ScriptCanvas
Variable::Variable(const Datum& datum, const AZStd::string& name, TraitsFlags traitsFlags)
: m_datum(datum)
, m_name(name)
, m_isConst(traitsFlags & TraitsFlags::Const)
, m_isMember(traitsFlags & TraitsFlags::Member)
, m_isConst(traitsFlags& TraitsFlags::Const)
, m_isMember(traitsFlags& TraitsFlags::Member)
{}
Variable::Variable(Datum&& datum, AZStd::string&& name, TraitsFlags&& traitsFlags)
: m_datum(datum)
, m_name(name)
, m_isConst(traitsFlags & TraitsFlags::Const)
, m_isMember(traitsFlags & TraitsFlags::Member)
, m_isConst(traitsFlags& TraitsFlags::Const)
, m_isMember(traitsFlags& TraitsFlags::Member)
{}
void Variable::Reflect(AZ::ReflectContext* reflectContext)

@ -12,7 +12,9 @@ namespace ScriptCanvas
namespace Grammar
{
AZ_CVAR(bool, g_disableParseOnGraphValidation, false, {}, AZ::ConsoleFunctorFlags::Null, "In case parsing the graph is interfering with opening a graph, disable parsing on validation");
AZ_CVAR(bool, g_printAbstractCodeModel, false, {}, AZ::ConsoleFunctorFlags::Null, "Print out the Abstract Code Model at the end of parsing for debug purposes.");
AZ_CVAR(bool, g_saveRawTranslationOuputToFile, false, {}, AZ::ConsoleFunctorFlags::Null, "Save out the raw result of translation for debug purposes.");
AZ_CVAR(bool, g_printAbstractCodeModel, true, {}, AZ::ConsoleFunctorFlags::Null, "Print out the Abstract Code Model at the end of parsing for debug purposes.");
AZ_CVAR(bool, g_printAbstractCodeModelAtPrefabTime, false, {}, AZ::ConsoleFunctorFlags::Null, "Print out the Abstract Code Model at the end of parsing (at prefab time) for debug purposes.");
AZ_CVAR(bool, g_saveRawTranslationOuputToFile, true, {}, AZ::ConsoleFunctorFlags::Null, "Save out the raw result of translation for debug purposes.");
AZ_CVAR(bool, g_saveRawTranslationOuputToFileAtPrefabTime, false, {}, AZ::ConsoleFunctorFlags::Null, "Save out the raw result of translation (at prefab time) for debug purposes.");
}
}

@ -147,7 +147,7 @@ namespace ScriptCanvas
};
// default to a pure, interpreted function
enum ExecutionStateSelection : AZ::u32
enum class ExecutionStateSelection : AZ::u32
{
InterpretedPure,
InterpretedPureOnGraphStart,
@ -247,7 +247,9 @@ namespace ScriptCanvas
AZ_CVAR_EXTERNED(bool, g_disableParseOnGraphValidation);
AZ_CVAR_EXTERNED(bool, g_printAbstractCodeModel);
AZ_CVAR_EXTERNED(bool, g_printAbstractCodeModelAtPrefabTime);
AZ_CVAR_EXTERNED(bool, g_saveRawTranslationOuputToFile);
AZ_CVAR_EXTERNED(bool, g_saveRawTranslationOuputToFileAtPrefabTime);
struct DependencyInfo
{
@ -258,7 +260,7 @@ namespace ScriptCanvas
struct Request
{
AZ::Data::AssetId assetId;
AZ::Data::AssetId scriptAssetId;
const Graph* graph = nullptr;
AZStd::string_view name;
AZStd::string_view path;
@ -291,7 +293,7 @@ namespace ScriptCanvas
Source() = default;
Source
( const Graph& graph
(const Graph& graph
, const AZ::Data::AssetId& id
, const GraphData& graphData
, const VariableData& variableData

@ -0,0 +1,101 @@
/*
* 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/Serialization/Json/JsonSerialization.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Serialization/ScriptUserDataSerializer.h>
using namespace ScriptCanvas;
namespace AZ
{
AZ_CLASS_ALLOCATOR_IMPL(ScriptUserDataSerializer, SystemAllocator, 0);
JsonSerializationResult::Result ScriptUserDataSerializer::Load
( void* outputValue
, [[maybe_unused]] const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context)
{
namespace JSR = JsonSerializationResult;
AZ_Assert(outputValueTypeId == azrtti_typeid<RuntimeVariable>(), "ScriptUserDataSerializer Load against output typeID that was not RuntimeVariable");
AZ_Assert(outputValue, "ScriptUserDataSerializer Load against null output");
auto outputVariable = reinterpret_cast<RuntimeVariable*>(outputValue);
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
AZ::Uuid typeId = AZ::Uuid::CreateNull();
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeIdMember == inputValue.MemberEnd())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, AZStd::string::format("ScriptUserDataSerializer::Load failed to load the %s member", JsonSerialization::TypeIdFieldIdentifier));
}
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
if (typeId.IsNull())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "ScriptUserDataSerializer::Load failed to load the AZ TypeId of the value");
}
outputVariable->value = context.GetSerializeContext()->CreateAny(typeId);
if (outputVariable->value.empty() || outputVariable->value.type() != typeId)
{
return context.Report(result, "ScriptUserDataSerializer::Load failed to load a value matched the reported AZ TypeId. The C++ declaration may have been deleted or changed.");
}
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&outputVariable->value), typeId, inputValue, "value", context));
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "ScriptUserDataSerializer Load finished loading RuntimeVariable"
: "ScriptUserDataSerializer Load failed to load RuntimeVariable");
}
JsonSerializationResult::Result ScriptUserDataSerializer::Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, [[maybe_unused]] const Uuid& valueTypeId
, JsonSerializerContext& context)
{
namespace JSR = JsonSerializationResult;
AZ_Assert(valueTypeId == azrtti_typeid<RuntimeVariable>(), "RuntimeVariable Store against value typeID that was not RuntimeVariable");
AZ_Assert(inputValue, "RuntimeVariable Store against null inputValue pointer ");
auto inputScriptDataPtr = reinterpret_cast<const RuntimeVariable*>(inputValue);
auto defaultScriptDataPtr = reinterpret_cast<const RuntimeVariable*>(defaultValue);
auto inputAnyPtr = &inputScriptDataPtr->value;
auto defaultAnyPtr = defaultScriptDataPtr ? &defaultScriptDataPtr->value : nullptr;
if (defaultAnyPtr)
{
ScriptCanvas::Datum inputDatum(ScriptCanvas::Data::FromAZType(inputAnyPtr->type()), ScriptCanvas::Datum::eOriginality::Copy, AZStd::any_cast<void>(inputAnyPtr), inputAnyPtr->type());
ScriptCanvas::Datum defaultDatum(ScriptCanvas::Data::FromAZType(defaultAnyPtr->type()), ScriptCanvas::Datum::eOriginality::Copy, AZStd::any_cast<void>(defaultAnyPtr), defaultAnyPtr->type());
if (inputDatum == defaultDatum)
{
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "ScriptUserDataSerializer Store used defaults for RuntimeVariable");
}
}
JSR::ResultCode result(JSR::Tasks::WriteValue);
outputValue.SetObject();
{
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, inputAnyPtr->type(), context));
outputValue.AddMember(rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier), AZStd::move(typeValue), context.GetJsonAllocator());
}
result.Combine(ContinueStoringToJsonObjectField(outputValue, "value", AZStd::any_cast<void>(inputAnyPtr), AZStd::any_cast<void>(defaultAnyPtr), inputAnyPtr->type(), context));
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "ScriptUserDataSerializer Store finished saving RuntimeVariable"
: "ScriptUserDataSerializer Store failed to save RuntimeVariable");
}
}

@ -0,0 +1,36 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/Memory.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
class ScriptUserDataSerializer
: public BaseJsonSerializer
{
public:
AZ_RTTI(ScriptUserDataSerializer, "{7E5FC193-8CDB-4251-A68B-F337027381DF}", BaseJsonSerializer);
AZ_CLASS_ALLOCATOR_DECL;
private:
JsonSerializationResult::Result Load
( void* outputValue
, const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context) override;
JsonSerializationResult::Result Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, const Uuid& valueTypeId, JsonSerializerContext& context) override;
};
}

@ -162,7 +162,7 @@ namespace ScriptCanvas
void GraphToX::WriteCopyright(Writer& writer)
{
OpenBlockComment(writer);
writer.WriteLine(GetAmazonCopyright());
writer.WriteLine(GetCopyright());
CloseBlockComment(writer);
}

@ -30,7 +30,6 @@ namespace TranslationCPP
AZ::Outcome<AZStd::pair<AZStd::string, AZStd::string>, AZStd::pair<AZStd::string, AZStd::string>> ToCPlusPlus(const Grammar::AbstractCodeModel& model, bool rawSave = false)
{
AZStd::string dotH, dotCPP;
auto outcome = GraphToCPlusPlus::Translate(model, dotH, dotCPP);
if (outcome.IsSuccess())
{
@ -48,13 +47,11 @@ namespace TranslationCPP
{
saveOutcome = SaveDotCPP(model.GetSource(), dotCPP);
}
if (!saveOutcome.IsSuccess())
{
AZ_TracePrintf("Save failed %s", saveOutcome.GetError().data());
}
}
return AZ::Success(AZStd::make_pair(AZStd::move(dotH), AZStd::move(dotCPP)));
}
else
@ -96,16 +93,28 @@ namespace ScriptCanvas
{
namespace Translation
{
Result ParseGraph(const Grammar::Request& request)
AZ::Outcome<Grammar::AbstractCodeModelConstPtr, AZStd::string> ParseGraph(const Grammar::Request& request)
{
AZ::Outcome<Grammar::Source, AZStd::string> sourceOutcome = Grammar::Source::Construct(request);
if (!sourceOutcome.IsSuccess())
{
return Result(sourceOutcome.TakeError());
return AZ::Failure(sourceOutcome.TakeError());
}
Grammar::AbstractCodeModelConstPtr model = Grammar::AbstractCodeModel::Parse(sourceOutcome.TakeValue());
return AZ::Success(model);
}
Result ParseAndTranslateGraph(const Grammar::Request& request)
{
auto parseOutcome = ParseGraph(request);
if (!parseOutcome.IsSuccess())
{
return Result(parseOutcome.TakeError());
}
Grammar::AbstractCodeModelConstPtr model = parseOutcome.TakeValue();
Translations translations;
Errors errors;
@ -124,37 +133,33 @@ namespace ScriptCanvas
}
}
// if (targetFlags & (TargetFlags::Cpp | TargetFlags::Hpp))
// {
// auto outcomeCPP = TranslationCPP::ToCPlusPlus(*model.get(), rawSave);
// if (outcomeCPP.IsSuccess())
// {
// auto hppAndCpp = outcomeCPP.TakeValue();
//
// TargetResult cppResult;
// cppResult.m_text = AZStd::move(hppAndCpp.first);
// translations.emplace(TargetFlags::Hpp, AZStd::move(cppResult));
// TargetResult hppResult;
// hppResult.m_text = AZStd::move(hppAndCpp.second);
// translations.emplace(TargetFlags::Cpp, AZStd::move(hppResult));
// }
// else
// {
// auto hppAndCpp = outcomeCPP.TakeError();
// errors.emplace(TargetFlags::Hpp, AZStd::move(hppAndCpp.first));
// errors.emplace(TargetFlags::Cpp, AZStd::move(hppAndCpp.second));
// }
// }
// Translation to C++ (executed via BehaviorContext calls) has been demonstrated in the past and is partially in progress.
// These calls allow for users to execute multiple translations from the same abstract code model.
// More work is required to complete all the latest features of the ACM, and do integrate output files into the build.
//
// if (targetFlags & (TargetFlags::Cpp | TargetFlags::Hpp))
// {
// auto outcomeCPP = TranslationCPP::ToCPlusPlus(*model.get(), rawSave);
// if (outcomeCPP.IsSuccess())
// {
// auto hppAndCpp = outcomeCPP.TakeValue();
//
// TargetResult cppResult;
// cppResult.m_text = AZStd::move(hppAndCpp.first);
// translations.emplace(TargetFlags::Hpp, AZStd::move(cppResult));
// TargetResult hppResult;
// hppResult.m_text = AZStd::move(hppAndCpp.second);
// translations.emplace(TargetFlags::Cpp, AZStd::move(hppResult));
// }
// else
// {
// auto hppAndCpp = outcomeCPP.TakeError();
// errors.emplace(TargetFlags::Hpp, AZStd::move(hppAndCpp.first));
// errors.emplace(TargetFlags::Cpp, AZStd::move(hppAndCpp.second));
// }
// }
}
else
{
ValidationResults results;
for (auto& test : model->GetValidationEvents())
{
results.AddValidationEvent(test.get());
}
}
return Result(model, AZStd::move(translations), AZStd::move(errors));
}
@ -163,22 +168,21 @@ namespace ScriptCanvas
{
Grammar::Request toBoth = request;
toBoth.translationTargetFlags = TargetFlags::Lua | TargetFlags::Cpp;
return ParseGraph(toBoth);
return ParseAndTranslateGraph(toBoth);
}
Result ToCPlusPlus(const Grammar::Request& request)
{
Grammar::Request toCpp = request;
toCpp.translationTargetFlags = TargetFlags::Cpp;
return ParseGraph(toCpp);
return ParseAndTranslateGraph(toCpp);
}
Result ToLua(const Grammar::Request& request)
{
Grammar::Request toLua = request;
toLua.translationTargetFlags = TargetFlags::Lua;
return ParseGraph(toLua);
return ParseAndTranslateGraph(toLua);
}
}
}

@ -18,7 +18,9 @@ namespace ScriptCanvas
namespace Translation
{
Result ParseGraph(const Grammar::Request& request);
AZ::Outcome<Grammar::AbstractCodeModelConstPtr, AZStd::string> ParseGraph(const Grammar::Request& request);
Result ParseAndTranslateGraph(const Grammar::Request& request);
Result ToCPlusPlus(const Grammar::Request& request);
@ -27,5 +29,4 @@ namespace ScriptCanvas
Result ToLua(const Grammar::Request& request);
}
}

@ -51,10 +51,13 @@ namespace ScriptCanvas
static void Reflect(AZ::ReflectContext* reflectContext);
Grammar::ExecutionStateSelection m_executionSelection = Grammar::ExecutionStateSelection::InterpretedPure;
AZStd::vector<Nodeable*> m_nodeables;
AZStd::vector<AZStd::pair<VariableId, Datum>> m_variables;
// either the entityId was a (member) variable in the source graph, or it got promoted to one during parsing
AZStd::vector<AZStd::pair<VariableId, Data::EntityIDType>> m_entityIds;
// Statics required for internal, local values that need non-code constructible initialization,
// when the system can't pass in the input from C++.
AZStd::vector<AZStd::pair<VariableId, AZStd::any>> m_staticVariables;
@ -98,6 +101,7 @@ namespace ScriptCanvas
const AZStd::sys_time_t m_translationDuration;
Result(AZStd::string invalidSourceInfo);
Result(Result&& source);
Result(Grammar::AbstractCodeModelConstPtr model);
Result(Grammar::AbstractCodeModelConstPtr model, Translations&& translations, Errors&& errors);
@ -117,7 +121,5 @@ namespace ScriptCanvas
AZStd::sys_time_t m_parseDuration;
AZStd::sys_time_t m_translationDuration;
};
}
}

@ -166,7 +166,7 @@ namespace ScriptCanvas
return TranslationUtilitiesCPP::k_namespaceNameNative;
}
AZStd::string_view GetAmazonCopyright()
AZStd::string_view GetCopyright()
{
return
"* 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.\n"

@ -34,7 +34,7 @@ namespace ScriptCanvas
AZStd::string EntityIdValueToString(const AZ::EntityId& entityId, const Configuration& config);
AZStd::string_view GetAmazonCopyright();
AZStd::string_view GetCopyright();
AZStd::string_view GetAutoNativeNamespace();

@ -102,6 +102,9 @@ namespace ScriptCanvas
classElement.RemoveElementByName(AZ_CRC_CE("Scope"));
classElement.AddElementWithData<VariableFlags::InitialValueSource>(context, "InitialValueSource", VariableFlags::InitialValueSource::Component);
}
classElement.RemoveElementByName(AZ_CRC("ExposeAsInput", 0x0f7879f0));
classElement.RemoveElementByName(AZ_CRC("Exposure", 0x398f29cd));
}
else
if (classElement.GetVersion() < 3)
@ -121,11 +124,8 @@ namespace ScriptCanvas
VariableFlags::Scope scope = VariableFlags::Scope::Graph;
if ((exposureType & VariableFlags::Deprecated::Exposure::Exp_InOut) == VariableFlags::Deprecated::Exposure::Exp_InOut)
{
scope = VariableFlags::Scope::Graph;
}
else if (exposureType & VariableFlags::Deprecated::Exposure::Exp_Input)
if (((exposureType & VariableFlags::Deprecated::Exposure::Exp_InOut) == VariableFlags::Deprecated::Exposure::Exp_InOut)
|| exposureType & VariableFlags::Deprecated::Exposure::Exp_Input)
{
scope = VariableFlags::Scope::Graph;
}
@ -203,8 +203,8 @@ namespace ScriptCanvas
editContext->Class<GraphVariable>("Variable", "Represents a Variable field within a Script Canvas Graph")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, &GraphVariable::GetVisibility)
->Attribute(AZ::Edit::Attributes::ChildNameLabelOverride, &GraphVariable::GetDisplayName)
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &GraphVariable::GetDisplayName)
->Attribute(AZ::Edit::Attributes::ChildNameLabelOverride, &GraphVariable::GetVariableName)
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &GraphVariable::GetVariableName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &GraphVariable::GetDescriptionOverride)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &GraphVariable::m_InitialValueSource, "Initial Value Source", "Variables can get their values from within the graph or through component properties.")

@ -9,10 +9,11 @@
#include <AzCore/Component/EntityUtils.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
#include <Libraries/Libraries.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Core/Contract.h>
#include <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Core/Node.h>
@ -21,6 +22,7 @@
#include <ScriptCanvas/Execution/ExecutionPerformanceTimer.h>
#include <ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Serialization/ScriptUserDataSerializer.h>
#include <ScriptCanvas/SystemComponent.h>
#include <ScriptCanvas/Variable/GraphVariableManagerComponent.h>
@ -53,7 +55,6 @@ namespace ScriptCanvasSystemComponentCpp
namespace ScriptCanvas
{
void SystemComponent::Reflect(AZ::ReflectContext* context)
{
Nodeable::Reflect(context);
@ -83,11 +84,16 @@ namespace ScriptCanvas
}
}
if (AZ::JsonRegistrationContext* jsonContext = azrtti_cast<AZ::JsonRegistrationContext*>(context))
{
jsonContext->Serializer<AZ::ScriptUserDataSerializer>()
->HandlesType<RuntimeVariable>();
}
#if defined(SC_EXECUTION_TRACE_ENABLED)
ExecutionLogData::Reflect(context);
ExecutionLogAsset::Reflect(context);
#endif//defined(SC_EXECUTION_TRACE_ENABLED)
}
void SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)

@ -588,6 +588,8 @@ set(FILES
Include/ScriptCanvas/Profiler/Aggregator.cpp
Include/ScriptCanvas/Profiler/DrillerEvents.h
Include/ScriptCanvas/Profiler/DrillerEvents.cpp
Include/ScriptCanvas/Serialization/ScriptUserDataSerializer.h
Include/ScriptCanvas/Serialization/ScriptUserDataSerializer.cpp
Include/ScriptCanvas/Data/DataTrait.cpp
Include/ScriptCanvas/Data/DataTrait.h
Include/ScriptCanvas/Data/PropertyTraits.cpp
@ -620,5 +622,4 @@ set(SKIP_UNITY_BUILD_INCLUSION_FILES
Include/ScriptCanvas/Libraries/Core/FunctionCallNode.h
Include/ScriptCanvas/Libraries/Core/FunctionCallNodeIsOutOfDate.h
Include/ScriptCanvas/Libraries/Core/FunctionCallNodeIsOutOfDate.cpp
)

@ -7,6 +7,8 @@
set(FILES
Builder/BuilderSystemComponent.h
Builder/ScriptCanvasBuilder.cpp
Builder/ScriptCanvasBuilder.h
Builder/ScriptCanvasBuilderComponent.cpp
Builder/ScriptCanvasBuilderComponent.h
Builder/ScriptCanvasBuilderWorker.cpp

Loading…
Cancel
Save