x

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] BTNodes, Delegates, and BTNodeMemory

So we've been running into an issue over and over. We will make a BTNode (Task, Service, or Decorator) and make a memory for it, since it's not instanced. No problems there. But if we want that node to respond to a delegate from another system and store that info in BTMemory, that's where things tend to go down hill.

If we bind a function from our BTNode, to the delegate and it gets called. We have no access to the BTMemory. The other examples we've seen and have this issue, happen to have the data required to access the BTMemory passed into the delegate. Not all delegates are going to have the information required to get that memory. And we shouldn't be changing other systems to make sure its delegates pass information we need to work.

What I'm trying to do (but its turning into a mess) is allow the BTMemory to have a "delegate handler object" with a function that we can use to bind too. This handler can also store information we can use to get our memory. Using the EQS service as an example, I'm going to get the memory using this:

 FBTEQSServiceMemory* MyMemory = reinterpret_cast(BTComp->GetNodeMemory(this, BTComp->FindInstanceContainingNode(this)));

So I need to store the BTComp and my BTNode! Which is just gross:/ I could also just make it instanced, but it seems like the BT system would rather I not do that.

My questions are:

  • Is there a better way to get a node's memory, that I can store in my "Delegate Handler" object. Like a handle I can pass to a static function to get the memory pointer back? Like: UBehaviorTreeComponent::GetMemory(MyMemHandle)

  • Should I just go with an instanced BTNode in these cases. I can see some cases not being a huge deal, but other's I'd have a bigger issue with being not instanced

  • Is there some other slick idea you guys would do instead.

Thanks! :)

Product Version: Not Selected
Tags:
more ▼

asked May 31 '16 at 06:34 PM in C++ Programming

avatar image

Answers.Archive STAFF
2k 212 318 698

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

The question has been closed May 31 '16 at 06:35 PM by AndrewHurley for the following reason:

The question is answered, right answer was accepted


1 answer: sort voted first

Hey Troy,

There's a really cool feature UE4 delegates have that allows you to pass in some payload when binding to a delegate, and that could be a generic solution you're looking for here.

The way it works is you implement a function with a signature required by the delegate you want to bind to, and then append extra parameters you need. And then, when you bind to a delegate you simply specify values of the params the delegate doesn't support on it's own.

Code say a 1k words, I mean something like this:

 // delegate type declaration
 DECLARE_MULTICAST_DELEGATE_OneParam(FOnStateChanged, UObject&);
 
 ...
 
 // your function declaration, in some UMyClass
 void HandleSuff(UObject& InObject, const int32 MyStuff);
 
 ...
 
 // and bind values while binding the delegate
 OnStateChangedDeledateInstance..AddUObject(this, &UMyClass::HandleSuff, 1337);

And when HandleStuff gets called InObject will be whatever delegate's passing in, but MyStuff will be 1337.

In your case I'd suggest using TWeakObjectPtr, that will make it possible to validate if the value coming in is still valid, and if so get access to the memory. Never tried it with TWeakObjectPtr before, but done it multiple time with other types, so this should work as well.

My mind was blown when I've learned about it, hope yours blown as well ;) Give it a try and let me know if you run into issues.

Cheers,

more ▼

answered May 31 '16 at 06:34 PM

avatar image

Answers.Archive STAFF
2k 212 318 698

avatar image Answers.Archive STAFF May 31 '16 at 06:34 PM

Ah, I didn't know that. Didn't Boost have something like this at one point? That's a much better solution than my handler. This problem screams lambda captures, but the bind should work.

Do you know of a slicker way to get at the memory without having to store the BTComponent?

avatar image Answers.Archive STAFF May 31 '16 at 06:34 PM

You can store a raw pointer to a specific memory piece, but that's not safe. I suggested using BTComponent, since it gives you access to a lot more than just memory (including means of influencing BT flow, like finishing current task for example).

BTW, you can bind lambdas to our delegates as well. Just saying ;)

avatar image Answers.Archive STAFF May 31 '16 at 06:34 PM

I ended up going with the BTComp. You can bind lambdas? I'm going to have to give that a shot.

I got the weak ptr to work. But that will not work if my callback function has the FUNCTION macro on it. The generated file poops out. I didn't dive into the magic that is going on there. But I thought that was odd.

avatar image Answers.Archive STAFF May 31 '16 at 06:34 PM

UFUNCTIONs are special class citizens, yeah. There's extra stuff generated for them, and sometimes (if it's for example a "Reliable" ufunction) you don't even see the actual declarations. For blueprint-bindable delegates (which require function bound to be an UFunction) we have "dynamic" delegates, which are somehow magically different. I've never dug deep into that stuff to be honest, I'm just a consumer ;)

avatar image Answers.Archive STAFF May 31 '16 at 06:34 PM

Yeah, I started with the dynamic, but the AddDynamic macro function wouldn't allow me to bind the extra param. And there wasn't enough info in the comment block to explain how to do that with Dynamic. I didn't need to expose this to blueprint, so I went the non-dynamic route.

avatar image Answers.Archive STAFF May 31 '16 at 06:34 PM

I didn't know that :) I tend to stay away from dynamic delegates, they "feel" slower :D

(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