As it stands, FStateTreeNodeBase
have access to DataViewIndex
, and InstanceIndex
, however a node is lacking a reference to its own position in the UStateTree::Nodes
list. This makes function like UStateTree::GetNode(const int32 NodeIndex)
unusable.
Maybe the NodeIndex
could be added to the nodes in this method (also conditions, and evaluators)?
bool FStateTreeCompiler::CreateTask(UStateTreeState* State, const FStateTreeEditorNode& TaskNode)
{
if (!TaskNode.Node.IsValid())
{
return false;
}
// Create binding source struct descriptor.
FStateTreeBindableStructDesc StructDesc;
StructDesc.ID = TaskNode.ID;
StructDesc.Name = TaskNode.Node.GetScriptStruct()->GetFName();
StructDesc.DataSource = EStateTreeBindableStructSource::Task;
// Check that node has valid instance initialized.
if (!TaskNode.Instance.IsValid() && TaskNode.InstanceObject == nullptr)
{
Log.Reportf(EMessageSeverity::Error, StructDesc,
TEXT("Malformed task, missing instance value."));
return false;
}
// Copy the task
IDToNode.Add(TaskNode.ID, Nodes.Num());
FInstancedStruct& Node = Nodes.Add_GetRef(TaskNode.Node);
InstantiateStructSubobjects(Node);
FStateTreeTaskBase& Task = Node.GetMutable<FStateTreeTaskBase>();
FStateTreeDataView InstanceDataView;
if (TaskNode.Instance.IsValid())
{
// Struct Instance
const int32 InstanceIndex = InstanceStructs.Add(TaskNode.Instance);
InstantiateStructSubobjects(InstanceStructs[InstanceIndex]);
// Create binding source struct descriptor.
StructDesc.Struct = TaskNode.Instance.GetScriptStruct();
StructDesc.Name = Task.Name;
if (const auto Validation = UE::StateTree::Compiler::IsValidIndex16(InstanceIndex); Validation.DidFail())
{
Validation.Log(Log, TEXT("InstanceIndex"), StructDesc);
return false;
}
Task.InstanceIndex = FStateTreeIndex16(InstanceIndex);
Task.bInstanceIsObject = false;
InstanceDataView = FStateTreeDataView(InstanceStructs[InstanceIndex]);
}
else
{
// Object Instance
check(TaskNode.InstanceObject != nullptr);
UObject* Instance = DuplicateObject(TaskNode.InstanceObject, StateTree);
const int32 InstanceIndex = InstanceObjects.Add(Instance);
// Create binding source struct descriptor.
StructDesc.Struct = Instance->GetClass();
StructDesc.Name = Task.Name;
if (const auto Validation = UE::StateTree::Compiler::IsValidIndex16(InstanceIndex); Validation.DidFail())
{
Validation.Log(Log, TEXT("InstanceIndex"), StructDesc);
return false;
}
Task.InstanceIndex = FStateTreeIndex16(InstanceIndex);
Task.bInstanceIsObject = true;
InstanceDataView = FStateTreeDataView(Instance);
}
if (!CompileAndValidateNode(State, StructDesc, Node, InstanceDataView))
{
return false;
}
// Mark the instance as binding source.
const int32 SourceStructIndex = BindingsCompiler.AddSourceStruct(StructDesc);
// Check that the bindings for this struct are still all valid.
TArray<FStateTreePropertyPathBinding> Bindings;
if (!GetAndValidateBindings(StructDesc, InstanceDataView, Bindings))
{
return false;
}
// Compile batch copy for this struct, we pass in all the bindings, the compiler will pick up the ones for the target structs.
int32 BatchIndex = INDEX_NONE;
if (!BindingsCompiler.CompileBatch(StructDesc, Bindings, BatchIndex))
{
return false;
}
if (const auto Validation = UE::StateTree::Compiler::IsValidIndex16(BatchIndex); Validation.DidFail())
{
Validation.Log(Log, TEXT("BatchIndex"), StructDesc);
return false;
}
Task.BindingsBatch = FStateTreeIndex16(BatchIndex);
if (const auto Validation = UE::StateTree::Compiler::IsValidIndex16(SourceStructIndex); Validation.DidFail())
{
Validation.Log(Log, TEXT("SourceStructIndex"), StructDesc);
return false;
}
Task.DataViewIndex = FStateTreeIndex16(SourceStructIndex);
return true;
}
At the very least the index could be provided in the FStateTreeNodeBase::Compile(FStateTreeDataView InstanceDataView, TArray<FText>& ValidationMessages)
, so that people who want to it can store it in the node then.