Welcome back.
Now I'd like a way to access our widget controllers for our project, At least those that should only
exist as a single instance.
There shouldn't be copies constructed all over the place.
That would be our overlay and our attribute menu widget controllers.
If we go into attribute menu and open up our attribute menu, then I'd like to be able to go into the
attribute menu, into the event graph, right click and type something like get attribute menu, widget
controller or something like that.
And I'd love if it popped up right here.
A nice little function with this name that returns the attribute menu widget controller.
And then as soon as this attribute menu gets constructed, say in event construct, for example, I'd
like it to set its own widget controller.
I'd like this because I don't really want to have to do that.
From the overlay class.
You see, the overlay overlay could set the widget controller as soon as we click the attribute menu
button because we're constructing the attribute menu widget here, we could take it and say set widget
controller.
But I really would like if the attribute menu could handle that itself as soon as we create it.
Now, we can't really do that with some of the widgets in the overlay, such as our Health and Mana
globes, because timing is important here and the widget controller for the overlay is set at a specific
time and the Health and Mana Globes share that widget controller.
So we do want to time this correctly.
We want to make sure that our overlay widget controller is set before our Globes widget controllers
are set.
So in this case, the overlay can set those widget controllers.
But for the attribute menu, as soon as we click that button, we're constructing a new attribute menu.
I'd like the attribute menu to handle setting its own widget controller, especially because it's a
different widget controller than the overlay has.
The overlay uses the overlay widget controller class Attribute menu is now going to use its own attribute
menu widget controller class.
So for that reason I'd like to create a blueprint function library.
What's a blueprint function library?
Well, if you right click in the event graph and type get ability system component for example.
And select that and hover over it.
You see that the target is Ability System Blueprint Library.
That's a blueprint function library.
It's a bunch of static functions, usually static, that are declared in a class such as the ability
system, blueprint, library, class and usually expose to blueprint in the form of these blueprint
nodes.
This is a blueprint, pure function, and we've already looked into the insides of this function and
seen how it accesses ability system components.
When it's given an actor, we're going to make our own ability system Blueprint library for our project.
So I'd like to do that.
Now let's go into C plus plus classes ora public and we need to decide where we'd like this function
library.
And really it could go anywhere if we're going to call this something with ability system in the name,
perhaps we should stick it in the ability system folder and we could just put it right here next to
the ability system component and attribute set classes.
So I'd like to do that.
Let's make a new class.
I'm going to right click new C plus plus class, choose all classes.
And now we need to ask ourselves what is the C plus plus class for a blueprint function library.
Well, typing in blueprint function library is a great start and there it is.
Blueprint function Library.
Let's create this and I'd like to call this class aura ability system.
Library.
So we have our own ability system library called aura ability system library.
We could call it aura ability system, blueprint, library like that.
But then again, no, we can't because the class creation wizard here is telling us we can't go above
32 characters.
So aura ability system library it is.
Let's create the class and close the editor.
Go ahead and save everything there and we should get our new ability system Blueprint Library class.
Why don't we open it up first?
I'm going to close everything else, close all tabs and open up the CPP and open up the dot h.
And here we have it.
So now we have a blueprint function library.
Pretty cool.
Now I'm going to add a public section and the first thing I'm going to do is add a getter for the widget
controller, the overlay widget controller that already exists, just so we can test out our new function
library and see if it works in Blueprint.
Now, with Blueprint function libraries, we usually make these static functions.
In fact, we always make them static functions because we don't plan on creating a instance of this
class.
We just plan on calling it static functions.
So we make a static function and this function is going to return the you overlay widget controller
type.
Now it's asking if we want to include or forward declare, we're going to forward declare because we
just need a function declaration here and we're going to call this get overlay widget controller.
Now here's the thing.
This is a static function and if we're going to trace our way all the way up to the HUD, somehow we
need to trace up to the HUD using an object that exists.
But a static function cannot access any objects that exist in the world.
Why?
Because the class itself that the static function belongs to, may not exist in the world.
The static function can be called directly, and this is the reason why many function libraries in the
engine require a world context object.
It needs a reference that it can use to trace its way up somehow, some way to something in the world
that we want to affect.
So our get overlay widget controller class needs a world context object, some kind of object that we
can use to have context for the world that we're in.
This is going to be a const uobject pointer called World Context Object.
So we have a static function declaration.
Great.
But I'd like this to be exposed to blueprint.
It'll be a new function.
And this can be blueprint pure.
It doesn't need an execution pin or anything like that.
It's just going to perform some kind of operation and return a result.
And we'll give it a category as well.
And the category can be I'll have aura, ability, system, library and a subcategory of widget controller.
So that looks nice and neat.
So we'll generate the definition.
And here we need to somehow, someway get the widget controller and return it to the caller.
So how do we do that?
Well, we need the player controller.
So here's the thing.
We're planning on calling this from a widget most likely.
I don't really see any other reason to call this function.
Widgets need widget controllers.
So if we're calling this from within a widget, we're calling it from the perspective of a local player,
a widget will only exist for the local player and we'll want the player controller associated with that
game instance with that session.
In other words, we can get the first player controller.
So what I'm going to do is call the gameplay statics function you gameplay statics.
Get player controller.
And of course we need to include the gameplay statics header file if we want to call this function that's
in kismet.
So kismet slash gameplay statics dot H.
And what does this function require?
Well, it requires a world context object.
We just happen to have one because we made this a requirement to be passed in when we call the function
and get player controller needs an index and we're going to use zero.
So now that we have a player controller, we're going to store it, a player controller, we'll call
it PC for player controller, and we'll just check to make sure that this is not a null pointer.
And from the player controller, we can always access the HUD.
So we'll do this if check variable declaration trick again, we'll say if and in the if statement we'll
say A or a HUD we're going to cast to or a HUD.
So we're going to say HUD equals cast to a or a HUD because we want that class and we're going to use
PC get HUD because the player controller can always get the HUD.
And we need to alt enter a writer trick or just include or a HUD.
And now we have access to the or a HUD.
But we're only inside this if if we succeed and we should now we have the HUD we want to call get overlay
widget controller on the HUD.
Right?
We want to say Aura HUD get overlay widget controller.
But this getter requires an F widget controller params.
We need this struct and we need to fill it in with the four key variables, which means we need to make
sure we have those.
So before we get ahead of ourselves and try to call that function, we need those four variables.
We already have the player controller, but we also need the player state.
We can get that from the player controller.
We can say A or a player state A or a player state.
We'll call this PS and we can get that from PC by calling get Player State.
Now, the reason I made it an Or player state is because get player state can take an input template
parameter.
So we can just specify or a player state right there.
And now we have the player state.
Now we also need the ability system component and the attribute set.
Well we cast to or player state or a player state has functions for both of those.
So we can say PS, get attribute set, get ability system component, how convenient.
So let's make a new ability system component pointer called ASC and we'll initialize it with PS, get
ability system component and we'll make a new attribute set as well.
That's a pointer.
We'll call it a s and we'll use P get attribute set.
So now we have the four key variables.
We can make those widget controller params.
Let's make a const f widget controller params called widget controller params.
And this struct has a constructor that takes the four key variables in the following order.
Player controller player state ability system component attribute set.
And we have all four here.
Now this is an incomplete type, isn't it?
Because where is it defined?
F widget controller params.
Well, let's remind ourselves.
Let's go to a widget controller and back into the header file.
Here it is.
F Widget controller params.
It's an aura widget controller.
So here in our blueprint library, let's include or a widget controller we don't need or a player controller.
So I'm going to go ahead and just replace this, include with aura widget controller which exists in
actually UI slash widget controller slash aura widget controller.
And now we have our widget controller params.
All we need to do now is get our HUD and call get overlay widget controller passing in widget controller
params and this function needs to return that overlay widget controller.
So we just need to return that and we're done.
And by the end of this, if we make it to the end and we shouldn't, as long as we've reached this return,
if we make it to the end, we'll return a null pointer, no big deal.
So now we have this blueprint, pure function that we can call from a blueprint to get the overlay widget
controller.
Why don't we just test it out?
Let's go ahead and run.
I'm going to run in debug mode.
And I'll go ahead and open the last blueprint I had open.
And here in overlay, I'm going to just zoom in anywhere and right click and type in git overlay and
look at that.
We have get overlay widget controller under the category or ability system library, sub category widget
controller.
And if we click that it's a blueprint, pure function, it requires a world context object we can pass
in usually this or self here in blueprint.
If I wanted to get a reference to self and pass that in and the return value is an overlay widget controller
object reference.
So we're getting the overlay widget controller and we're getting it by calling the HUD function get
overlay widget controller, which as we know will return the one and only overlay widget controller
if it exists.
But if it does not exist yet, it will construct a new one, initializing it with the four key variables.
That's why we have to pass those in.
So now that we know how to do this and we've done it with the overlay widget controller, what's stopping
us from doing it?
For the attribute menu Widget controller We have all the tools.
We can do it, so we're going to do that next.
So excellent job.
I'm going to go ahead and save all in the editor.
Close out and I'll see you in the next video.