All right.
Welcome back.
I now have my attribute menu widget controller open, and we're interested in binding callbacks to dependencies
and broadcasting initial values because we'd like to inform the widget, the attribute menu widget that
is of the values that it should display.
In other words, we want to broadcast info to it and that's why we made our aura attribute info struct
which we created in our data asset.
Let's go ahead and clean up our tabs.
I'm going to close other tabs and open up that data asset which exists in public ability system data.
Attribute info.
Here's that attribute info struct or attribute info.
Now, when we want to broadcast info to the attribute menu, we want to broadcast one of these and then
the attribute menu or any of its associated widgets can receive this broadcast and it can check its
own data.
Perhaps it has its own gameplay tag against the gameplay tag here.
That's how I'd like to set this up.
So the first thing I'm going to do is an attribute menu widget controller.
I'd like to first of all get our attribute set and find out the value of, say, one of its attributes
like strength.
So how can we get that attribute set?
Well, that's pretty easy.
We already have an attribute set variable.
It's called attribute set.
Now its type is you attribute set.
So we're going to need to cast it.
So I can say you aura attribute set pointer called, we'll just call it as for now and I'll set it equal
to the result of a cast, but I'll use cast checked so we don't have to worry about using a check assertion
and I'll cast to you or attribute set and writer includes the header for me there and it needs to cast
attribute set.
We need that to be in the parentheses there and it looks like I typoed here.
It needs to be your attribute set there.
And now we have our attribute set.
So we have that.
That's great.
I'd like to get the value of one of our attributes.
Now we're going to be taking this at first from a very naive approach.
We're going to just get strength, right and see what that is and then broadcast info up to our attribute
menu widget so we can say as get strength.
And now we know the value of strength.
So how are we going to use this value?
How are we going to broadcast info up to our attribute menu widget?
Well, to broadcast we need a delegate, don't we?
So I'd like to declare a delegate capable of sending our aura attribute info this aura attribute info
struct up to our widgets.
So let's make a delegate.
And because our widgets are going to want to bind to this and I'd want potentially multiple widgets
to be able to bind to it, we want a dynamic multicast delegate, so I'm going to declare dynamic.
Multicast delegate and we want to broadcast one value, one struct value.
So it's going to be one param and I'm going to call this F attribute info signature.
And its single input parameter type will be a const reference to F or a attribute info.
I'm going to add a forward declaration to it like so, and we'll have it with the name info and it has
to be a reference.
Otherwise we can't forward declare it.
So now that we have this delegate, we can have a member variable of this type F attribute info signature
and we're going to say attribute info delegate.
We'll call it that.
And it needs to be blueprint assignable.
So it gets a new property with Blueprint Assignable, and I'll go ahead and give it a category as well.
We'll have the category gas with the pipe symbol attribute.
We'll just say attributes.
Okay.
So we have this delegate.
We can broadcast so we can broadcast the value of strength.
But really, any of our widgets can bind to this.
And I'd like multiple widgets to bind to this.
And because we're broadcasting an aura attribute info, we need to fill one of those in with info.
Right?
Well, we have a data asset.
We can use a data asset that already has the name, the description, and a value field that we can
fill in with our strength value here.
So that means our attribute menu widget controller needs one of those data assets.
Our attribute info.
Right.
So let's make a.
Protected section and add a t object pointer of type you attribute info.
That's our data asset type and this will be called attribute info.
Now I want to set this from the blueprint, so I'm going to give it a new property with edits.
We'll make it edit defaults only and as long as we set this then we can use it to look up our attribute
info based on the gameplay tag.
So back in our widget controller cpp file we can first of all check make sure our attribute info is
set and valid.
And if it is, then we can take our attribute info and call the function find attribute info for tag
and we need to pass in the tag.
Right.
Well, we can always get the tag.
It's a native tag.
We can get it from our aura gameplay tags, but we have to include that header don't we?
So let's include aura gameplay tags and we can use F or a gameplay tags.
Get to get the aura gameplay tags and from there we can choose the attributes primary strength gameplay
tag and find attribute info for tag Returns an F or a attribute info.
Let's go ahead and it's not going to be const, we're just going to make an aura attribute info.
We'll call it info and it's not const because we need to set its attribute value so we can say info
dot and here's the attribute value we need to set that and we have it here.
It's as get strength.
So everything else was set.
We set it in the blueprint for the data asset, but we didn't expose the attribute value to the data
asset because we want it to be the correct value that we get from our attribute set at the time that
we broadcast it.
So now that we have correct attribute info, we can broadcast it using our attribute info delegate.
Let's go ahead and make that broadcast attribute info delegate dot broadcast and we can broadcast that
info not window but info.
So in broadcast initial values we're going to broadcast info and our widgets need to bind to this attribute
info delegate before we broadcast our initial values.
That's important.
So there are a couple things to do in blueprint.
First, we need our attribute info set on attribute Widget Controller, our attribute menu, widget
Controller and then we need to make sure that we bind to this delegate in order to receive this info
on the blueprint side.
So let's run in debug mode, we'll compile and launch and we'll take care of those things and see if
we can receive that attribute info.
Delegate And it looks like I have a compiler error.
You attribute info undeclared identifier here in attribute menu widget controller and that means I need
to forward declare you attribute info.
Let's go ahead and do that up here at the top.
I'll do it first class.
You attribute info.
Let's go ahead and compile again.
It's very common to forget these little details when you're working with a lot of moving parts.
So I don't worry when I forget little details like that, and neither should you.
Okay.
Let's go ahead and run this.
And I'll go ahead and open up our asset editors.
We have a few things open, but I do want to go to UI, widget controller and attribute menu Widget
Controller.
Now we have an exposed property here, the attribute info and we can select our data asset attribute
info and compile and save that.
Now our widget controller has it and now it can use that from here in broadcast initial values when
it broadcasts the delegate.
So a couple things we need to bind to the delegate and decide when to call broadcast initial values.
So first, why don't we go to our attribute menu widget and let's look at what we need to receive.
Each of these rows needs to receive data whenever its corresponding attribute changes or when we broadcast
initial values.
And we want to assign an attribute to each one.
For example, I'd like this one here to be assigned the value of strength and this one to be intelligence
and so on.
So each of these should have its own gameplay tag for the attribute.
It should have an attribute tag.
Now this top one is for something else.
This is for how many attribute points we have.
We don't have a variable for that yet.
We don't have an attribute or a variable.
But for these we do have attributes in our attribute set.
So there's a few things we need to handle.
We need to handle adding an attribute tag to each of these.
But for now, I just like to respond to that delegate.
I'd like to subscribe to it from my widgets so I can at least see something.
So here's what I'd like to do.
I'd like to go to my text value button row class that's going to be in Blueprints UI attribute menu,
and we have a text value button row.
I'm going to open that.
And here in the graph I'd like to set my own widget controller an event construct right here.
So I'm going to call get attribute menu Widget controller using self as a world context object passing
in self here and from this widget controller.
I can search for.
Assign, attribute info, delegate and on event construct, I can assign an event for this.
Now each of these should have its own tag that it checks from the info.
But for now all I want to do is take my info, drag off of it and break it so I can see that information,
and then I can start setting things on this row.
For example, I have text and a numerical value that I'd like to set.
Well, I don't really have access to the text or the number, but I know that the parent class does
and it can expose an inherited function for us.
So the parent class is text value row, which does have access to the attribute we can check is variable
for the text block attribute.
We can rename this text block underscore, we'll call it label.
And for the number we have a WP framed value for now, let's just take our text block label and let's
make a function to set its text.
So we'll go to our graph, we'll create a new function, add function, and we'll call this set label
text and we'll get our label text block label and we'll call, set, text the function.
Like so and we'll have an input for our set label text of type text.
So let's add an input, choose text and call this label text and we'll simply pass that in.
And now our base class has a set label text function and our text value button row now has the ability
to set it.
So as soon as this broadcast happens, we can call our inherited function set label text.
We'll do that and we'll pass in our attribute name.
Like.
So now we can compile.
And now this will be set for our attribute menu.
Whenever our delegate gets broadcast from the attribute menu Widget Controller.
So I'm going to save all and press play.
Now, we're not going to see anything because we're not broadcasting that delegate That happens once
we call broadcast initial values.
So here in our attribute menu, we need to decide when to broadcast initial values.
Well, we can do so after our widget controller is set.
That should be fine.
So on our widget controller, which is an attribute menu widget controller, we need to call broadcast
initial values.
But that is not an exposed function, is it?
So why don't we close our editor and go to our attribute menu widget controller.
We know broadcast initial values is a virtual override, so we need to go to our base class in UI,
widget controller or a widget controller and find broadcast initial values.
Here it is.
And we want this to be a blueprint callable function.
So let's just really quickly make that happen.
Now it's blueprint callable.
Now we can run the editor and we can call broadcast initial values so we can get that delegate broadcast.
Okay, let's open up our asset editors and we'll go to Attribute Menu.
And right here, after we've set our widget controller, we can get that widget controller and call
broadcast initial values.
And now that delegate will be broadcast and all of our text value button rows will have their attribute
info delegate event bound to that delegate and they will receive that attribute info.
And by the way, it's just strength.
So all we're doing is getting the attribute info for the strength attribute.
But this is just getting things working, making sure that we can connect all the pieces.
So if we press play and open our menu now, all of our text value button rows have strength.
Look at that.
So this is a great step in the right direction.
Now, of course we have problems, don't we?
We have to be able to set the strength value.
And also anything else that's not assigned strength should not show strength here.
These should show the other attributes.
Don't worry.
We'll get to all that.
We have to take this one step at a time.
The next step is to show the strength value which we should have access to, right?
We should be able to get that from the attribute info struct right here.
The attribute value.
We could print a string here with the attribute value and I'm going to make this visible for five seconds.
I'm going to make it pinkish red and there's another print string that I want to get rid of here in
attribute Menu.
We're printing the widget controller's name.
I don't want that anymore.
So I'm going to press play and open attributes.
And they're all four of these are printing the value of strength.
So we have access to it.
We need to be able to set the strength, numerical value and really quickly we can just make that happen
before we move on.
We can go into our base class text value row and make a function for setting the numerical value.
So let's go ahead and create a new function.
We'll say add function, and for this new function we'll call this set.
Numerical value.
And we may wish to have two versions one that can set the value to an integer without decimals and one
that can set the value to a floating point with maybe 1 or 2 decimals.
So why don't we say set numerical value INT and this will take an integer.
So integer and we'll call this new value.
But what can this do?
Well, we have to access our widget here called the Framed value.
And the frame value needs a way to set its numerical value as well.
So the frame value should be checked is variable here.
And if we get the framed value, we need a way to set its numerical value.
Let's find that framed value.
Here it is.
And the number is called text block value.
It's set to is variable here.
So from here in text value row, we're getting our framed value.
If we search for text block value here.
And call, set, text the function, not the setter.
Then we can set our text using this integer and we have to take this integer and use to text using to
text integer.
We can pass it in there, so we'll hook that up.
And now that we have a set numerical value and we can compile and save.
And now our text value button row when we receive our delegate broadcast, can simply call set numerical.
Value.
INT And that means we'll take our attribute value and convert it to an int.
That's going to truncate any decimals there.
So if we compile this press play, open the menu.
We see tens for all four primary attributes.
The reason we don't see it for the secondary attributes is these are not using the text value button
row, they're just using the text value row without the button.
And we're binding to this delegate only in text value button row.
Right?
So and this is just to get it working, just to show that we actually are broadcasting those values
from the widget controller.
And that's thanks to our attribute menu, taking our widget controller and calling broadcast initial
values on it.
So we're getting there.
We just have a couple things left to do.
We have to make sure that each of these rows knows what attribute it's supposed to display.
So when it receives the broadcast, it can check that incoming attribute tag against its own tag.
So in the next video, we're going to assign tags for each of these in our attribute menu.
Here it is.
We're going to assign attribute tags to each of them.
So we'll do that next.
Great job and I'll see you soon.