Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

[Closed] GetNodeInstance returns the wrong node for TimeLimit decorator


We've been having problems with decorators not aborting lower priority tasks when they should. After an extensive debugging session we think we've found the issue, but are unsure of the solution. We'll try to describe the the consequence and the source of the problem:


In BehaviorTreeInstance::Initialize the line (BehaviorTreeTypes.cpp)

 UBTDecorator* InstancedDecoratorOb = Cast(DecoratorOb->GetNodeInstance(OwnerComp, DecoratorMemory));

returns a wrong pointer when DecoratorOb is TimeLimit decorator. Subsequently the child index for this InstancedDecoratorOb is incorrectly overwritten on the next line: (BehaviorTreeTypes.cpp)


When the instanced decorator with the incorrect child index then triggers and requests execution the line

 RequestedOn->DoDecoratorsAllowExecution(*this, InstanceIdx, RequestedByChildIndex);

in (BehaviorTreeComponent.cpp) then checks the decorators on a different node than the one triggering this check because RequestedByChildIndex is wrong.

Suspected cause

UBTNode::GetNodeInstance seems to make the assumption that if GetSpecialNodeMemory returns a valid pointer that the node itself is instanced. Looking at the implementation of UBTNode::GetSpecialMemorySize() this seems to be a valid assumption, but this method is overridden in UBTAuxiliaryNode in the following manner:

 uint16 UBTAuxiliaryNode::GetSpecialMemorySize() const
     return bTickIntervals ? sizeof(FBTAuxiliaryMemory) : Super::GetSpecialMemorySize();

which invalidates the assumption for AuxiliaryNodes that have bTickIntervals set to true (e.g. BTDecorator_TimeLimit).

Could you confirm this bug? And do you have a suggested fix for this? We are unsure if the caller of GetNodeInstance should be responsible for checking if the node is actually instanced, or that GetNodeInstance should just return nullptr if it is not instanced. Or perhaps we are misreading the intentions of this code?

Best regards, Steijn

Product Version: Not Selected
more ▼

asked Sep 07 '16 at 08:25 PM in C++ Programming

avatar image

Answers.Archive STAFF
1.9k 209 316 688

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

The question has been closed Sep 07 '16 at 08:26 PM by AndrewHurley for the following reason:

The question is answered, right answer was accepted

1 answer: sort voted first

Great find! UBTAuxiliaryNode::GetSpecialMemorySize() was meant to extend memory block with tick intervals data. Without initialization data will be zeroed and potentially give valid object instance which belongs to different node.

UBTNode::InitializeMemory() override shouldn't touch SpecialMemory block, there's no guarantee that parent class implementation will be called. Usually it's not - main reason why part of data is extracted into SpecialMemory block.

I'd say that best place for change would be inside UBTNode::InitializeInSubtree() function. If node doesn't want instancing ( bCreateNodeInstance == false ), try accessing SpecialMemory block and setting NodeIdx to INDEX_NONE before calling node's InitializeMemory(). Same order of operations as instancing case.

For now, I'll enter new bug report, but fix will probably look as described above.

more ▼

answered Sep 07 '16 at 08:25 PM

avatar image

Answers.Archive STAFF
1.9k 209 316 688

avatar image Answers.Archive STAFF Sep 07 '16 at 08:25 PM

Thank you for your response. We've changed the else case of UBTNode::InitializeInSubtree (`bCreateNodeInstance == false`) to:

         if (FBTInstancedNodeMemory* MyMemory = GetSpecialNodeMemory(NodeMemory))
             MyMemory->NodeIdx = INDEX_NONE;
         InitializeMemory(OwnerComp, NodeMemory, InitType);

which fixed the problem.

I do wonder why UBTNode::GetNodeInstance does not test on bCreateNodeInstance explicitly as its documentation says returns node instance if bCreateNodeInstance was set. I feel a test on this variable would be more explicit and safe some unnecessary work in this function.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question