Files
o3de/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionContext.cpp
T
2021-12-17 12:36:05 -08:00

197 lines
9.1 KiB
C++

/*
* 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/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>
#include <ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include "ExecutionContext.h"
#include "AzCore/Slice/SliceComponent.h"
#include "AzFramework/Entity/SliceEntityOwnershipServiceBus.h"
namespace ExecutionContextCpp
{
void CopyTypeInformationOnly(AZ::BehaviorValueParameter& lhs, const AZ::BehaviorValueParameter& rhs)
{
lhs.m_typeId = rhs.m_typeId;
lhs.m_azRtti = rhs.m_azRtti;
}
void CopyTypeAndValueSource(AZ::BehaviorValueParameter& lhs, const AZ::BehaviorValueParameter& rhs)
{
lhs.m_typeId = rhs.m_typeId;
lhs.m_azRtti = rhs.m_azRtti;
lhs.m_value = rhs.m_value;
}
}
namespace ScriptCanvas
{
namespace Execution
{
ActivationData::ActivationData(const RuntimeDataOverrides& variableOverrides, ActivationInputArray& storage)
: variableOverrides(variableOverrides)
, runtimeData(variableOverrides.m_runtimeAsset->m_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, [[maybe_unused]] const AZ::EntityId& forSliceSupportOnly)
{
const RuntimeData& runtimeData = activationData.runtimeData;
ActivationInputRange rangeOut = runtimeData.m_activationInputRange;
rangeOut.inputs = activationData.storage.begin();
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 - 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::CopyTypeAndValueSource(*destVariableIter, *sourceVariableIter);
}
}
// (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;
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::CopyTypeInformationOnly(*destVariableIter, *sourceVariableIter);
destVariableIter->m_value = const_cast<void*>(activationData.GetVariableSource(index, overrideIndexTracker));
}
}
// (always overridden) EntityIds
{
AZ::BehaviorValueParameter* destVariableIter = rangeOut.inputs
+ runtimeData.m_activationInputRange.nodeableCount
+ runtimeData.m_activationInputRange.variableCount;
const auto entityIdTypeId = azrtti_typeid<Data::EntityIDType>();
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);
*entityIdValuePtr = entityId;
++destVariableIter;
}
}
return rangeOut;
}
void Context::IntializeActivationInputs(RuntimeData& runtimeData, AZ::BehaviorContext& behaviorContext)
{
AZStd::vector<AZ::BehaviorValueParameter>& parameters = runtimeData.m_activationInputStorage;
auto& range = runtimeData.m_activationInputRange;
range.requiresDependencyConstructionParameters = runtimeData.RequiresDependencyConstructionParameters();
parameters.reserve(runtimeData.m_input.GetConstructorParameterCount());
for (const Nodeable* nodeable : runtimeData.m_input.m_nodeables)
{
AZ::BehaviorValueParameter bvp;
bvp.m_typeId = azrtti_typeid(nodeable);
const auto classIter(behaviorContext.m_typeToClassMap.find(bvp.m_typeId));
AZ_Assert(classIter != behaviorContext.m_typeToClassMap.end(), "No class by typeID of %s in the behavior context!", bvp.m_typeId.ToString<AZStd::string>().c_str());
bvp.m_azRtti = classIter->second->m_azRtti;
bvp.m_value = const_cast<Nodeable*>(nodeable);
parameters.push_back(bvp);
}
for (auto& idDatumPair : runtimeData.m_input.m_variables)
{
const Datum* datum = &idDatumPair.second;
AZ::BehaviorValueParameter bvp;
bvp.m_typeId = datum->GetType().GetAZType();
const auto classIter(behaviorContext.m_typeToClassMap.find(bvp.m_typeId));
bvp.m_azRtti = classIter != behaviorContext.m_typeToClassMap.end() ? classIter->second->m_azRtti : nullptr;
bvp.m_value = const_cast<void*>(datum->GetAsDanger());
parameters.push_back(bvp);
}
const size_t entityIdSize = runtimeData.m_input.m_entityIds.size();
for (size_t i = 0; i < entityIdSize; ++i)
{
AZ::BehaviorValueParameter bvp;
bvp.m_typeId = azrtti_typeid<Data::EntityIDType>();
parameters.push_back(bvp);
}
range.inputs = parameters.begin();
range.nodeableCount = runtimeData.m_input.m_nodeables.size();
range.variableCount = runtimeData.m_input.m_variables.size();
range.entityIdCount = runtimeData.m_input.m_entityIds.size();
range.totalCount = range.nodeableCount + range.variableCount + range.entityIdCount;
}
void Context::InitializeActivationData(RuntimeData& runtimeData)
{
AZ::BehaviorContext* behaviorContext(nullptr);
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (!behaviorContext)
{
AZ_Error("Behavior Context", false, "A behavior context is required!");
return;
}
// \todo, the stack push functions could be retrieved here
IntializeActivationInputs(runtimeData, *behaviorContext);
IntializeStaticCloners(runtimeData, *behaviorContext);
}
// This does not have to recursively initialize dependent assets, as this is called by asset handler
void Context::IntializeStaticCloners(RuntimeData& runtimeData, AZ::BehaviorContext& behaviorContext)
{
runtimeData.m_cloneSources.reserve(runtimeData.m_input.m_staticVariables.size());
for (AZStd::pair<VariableId, AZStd::any>& staticSource : runtimeData.m_input.m_staticVariables)
{
AZStd::any& anySource = staticSource.second;
auto bcClass = AZ::BehaviorContextHelper::GetClass(&behaviorContext, anySource.type());
AZ_Assert(bcClass, "BehaviorContext class for type %s was deleted", anySource.type().ToString<AZStd::string>().c_str());
runtimeData.m_cloneSources.emplace_back(*bcClass, AZStd::any_cast<void>(&anySource));
}
}
void Context::UnloadData(RuntimeData& runtimeData)
{
Execution::InterpretedUnloadData(runtimeData);
}
}
}