Welcome back.
Now our save system is working.
Except for the fact that we're not saving our abilities.
If I create a new slot and play.
Yes, I load in with my default abilities if it's the first time.
But if I go ahead and save the game and quit and come back and load in, there are no abilities because
we're not handling that case, only those default abilities if it's the first time.
So what we need to do is save our abilities.
Now.
Abilities are objects of type you gameplay ability, but we don't even really use that.
Most of the time we use ability specs, and for most of the stuff in our code base, we identify abilities
by a series of gameplay tags.
We have an ability tag, we have status tags, we have slot tags.
So really, if we want to save a gameplay ability, we also need to save the information pertaining
to that ability.
Now I'd like to create a struct to save all the pertinent data that we need for saving a gameplay ability.
Now we can define that here in load screen save game if we like.
So I'm going to make a struct here to store the information for an ability.
I'm going to make this struct called f saved.
Ability.
And I'd like this to be exposed.
With you struct, I'll make it a blueprint type and give it a generated body.
And it's going to have several pieces of information pertaining to an ability, the first of which is
the actual ability class.
A subclass of we're going to store that.
It's going to be a subclass of you gameplay ability.
We're going to forward declare that.
And we'll call this game playability.
Now this will get a new property.
We'll make it edit defaults only.
Blueprint read only.
Category class defaults.
Now, if we're going to save an ability, this is not enough.
We need to know other things about it.
We need to know the gameplay tag.
So we're going to have F gameplay tag called ability tag.
We'll set that equal to an empty F gameplay tag by default.
Either that or abilities none.
Either one.
We'll just make it an empty tag for now.
You property edit defaults only blueprint read.
Write.
Now we're going to need to include the header file.
Gameplay tag container.
But the ability tag isn't the only gameplay tag an ability has.
It also has an ability status.
Let's add that one.
It also has a slot.
What's its input tag.
Right.
We're going to call this ability slot.
And finally, if we're saving an ability, we need to know the ability level.
So we'll have an int 32 called level or rather ability level, either one.
And it could be an int 32 or a float.
Doesn't matter.
Ability levels are typically floats, but we can save it as an integer.
That's totally fine.
So we have this struct that defines all the information for saving an ability.
And here in our load screen save game, we want to save all of our abilities so we can have an array
of f saved abilities here saved in our save game data.
So let's go ahead and add a new comment that says abilities.
And we'll make a t array of our new struct type F saved ability called saved abilities.
Let's go ahead and give that a new property.
And now we need to save our abilities, right?
So how are we going to do that?
Well, we need to save this in our aura characters save function, that interface function.
Let's go to character in the private folder or a character and find our save function.
Save progress.
So we need to save some data here right.
Well if we're going to save some data here, we need to know how many abilities we have and all the
information about them.
That's all in the ability system component, isn't it?
If we go to our ability system component here in the cpp file, I'm going to remind you of a function
we made called for each ability.
Now for each ability takes in an F for each ability delegate.
What is that?
Well, we can go to the header file to see what it is.
It's a delegate one param that takes in a const reference to a gameplay ability spec.
What does it do?
Well, it loops over all of the activatable abilities, and for each of our abilities, it takes the
delegate passed in to this function and executes it, passing in the ability spec.
Essentially whatever we have bound to this delegate, which must accept an ability spec, it's executing
that functionality for every ability that's in Activatable abilities.
It's a for each loop.
For abilities, well, we can use for each ability in or a character when we want to save our abilities.
So before actually saving our data, we need to use F for each ability.
We're going to make an F for each ability called save ability delegate.
And we're going to bind a lambda to it.
We're going to take save ability delegate using bind lambda.
And we're going to bind a lambda to it.
Let's make that lambda.
And we're going to need an input parameter of const f gameplay ability spec reference called ability
spec.
So what are we going to do with that ability spec.
Just indenting here.
Well, I'd like to make an f saved ability.
We're going to say f saved ability.
Saved ability.
And we're going to set all the properties on our saved ability.
Looks like indentation doesn't want to play nice like that.
I'm going to go ahead and have it how it was.
So first of all, what properties on our saved ability do we need to set.
Well let's look at that struct.
We have the gameplay ability itself.
How are we going to get that?
Well, there's only one place that stores all of the gameplay ability classes the T sub class UVs and
associates them with ability tags.
That's our ability info data asset.
Well, we can get that ability info data asset from Aura Ability System library.
We can say you aura ability system library get ability info.
Now this requires a world context object.
No problem.
We can pass one in.
We just have to remember that get ability info is only going to return ability info on the server because
stores only the game mode has it.
This gets it from the game mode right?
So really we should only be on the server here.
In fact, let's just check for authority before we continue.
We'll say if not, has authority return.
So we won't even save the game if we're not authority.
Now get ability info has squiggles because this is not captured.
No problem, we'll capture this.
And now that we have ability info we can call a function on it.
Find ability info for tag passing in the ability tag.
So how do we get our ability tag when all we have is the ability spec?
Well let's look at our ability system component functions.
We have a lot of useful functions.
We have get ability tag from spec, and that can take an ability spec and give us the ability tag so
we can use that.
Now if we're going to use the ability system component, we need to capture it and we're going to have
to cast our ability system component to our ability system component.
And I'd like to do that before we enter the lambda.
And we can just capture that local variable.
So we're going to say you or a ability system component or a ASC will cast to it you or a ability system
component.
And we'll cast ability system component.
And then we'll just capture or ask in our capture list along with this.
And when we find ability info for tag, we can take or ask and call get ability tag from spec and pass
in ability spec.
Now this is a big line just to get the ability tag.
So I'm going to need to manage this a little bit.
I'm going to make a F gameplay tag.
This can be const and it's going to be ability tag.
So I'm going to use or ASC here.
So now I have the tag and now we have an ability tag to pass in here.
Now I'm also going to store my ability info in a pointer.
So let's get the ability tag and the ability info up here.
We'll also have you ability info called ability info equal to this line here.
Now that's just this function.
Call this one here.
Is what we can use to retrieve an F or a ability info.
We'll call it info that's going to be on ability info.
The data asset Findability info for tag.
Passing in.
Ability tag.
Okay, so we have the data assets.
We have the struct for the given ability tag.
And now we can set some things on our saved ability.
We can take saved ability.
Dot gameplay ability, and we can get the ability that we have in our ability info that we found for
the tag we can take info dot ability.
That's the subclass of.
Now saved ability has other things.
We have ability level.
Now we can get that from the ability spec.
Ability spec level.
We also have saved ability.
Dot here's ability slot.
Well we can get that from our aura ability system component.
So aura AC get slot from ability tag for example and pass in ability tag and we have the slot.
What else do we have saved ability dot here's ability status.
Well we can take aura AC.
And call git status from ability tag.
So we've done a whole bunch of work up front that's making our life a lot easier now, as we don't have
to go and make those functions.
So we have four pieces of information.
Let's look at load screen, save game and take a look at saved ability.
We have ability.
We have ability, tag ability, status ability slot ability level ability level slot status.
And here's our ability tag.
We can set that here to saved ability dot ability tag equals ability tag okay.
So we have a saved ability and we filled it out.
Great.
Now what do we do with it.
Well we need to capture save data and save data right here.
It's a save data pointer.
And we can pass that pointer into the capture list.
I'm going to pass it in by reference.
So we won't even copy that pointer.
And we're going to take save data and take its saved abilities array and add to it.
We're going to add saved ability.
So we have a lambda bound to this delegate.
And if it gets executed with an ability spec passed in then it's going to create a saved ability and
add it to save data which is captured.
Really we could capture by pointer.
It doesn't have to be reference.
That's fine.
Now after creating this lambda I want this lambda to be executed for each ability.
So that's why aura Ability, system component or ask has for each ability.
Because we can pass this save ability delegate in.
So after we've done this, our save game object save data is going to have all of our abilities added
to it in the form of an F saved ability.
That's all of them.
All the abilities in Activatable abilities, no matter what ability type they have, no matter what
their status is, no matter their slot or their ability tag.
Now I just said ability type.
And that reminds me, we're going to probably want to know the ability type, whether it's offensive
or passive or neither.
So let's go back to load screen save game and add one more gameplay tag for the ability type.
So this will be simply ability type.
And here in our character, we're going to set that to we're going to get saved ability.
Dot ability type.
And we can get or ask get ability type and we don't have get ability type do we.
That's okay.
The ability type is an ability info.
We can take info dot ability type.
That's fine.
So now we're saving that too.
So we're saving all this information.
And once we load up we can give ourselves those abilities from the save data.
And we're going to do that in the next video.
So let's go ahead and compile this.
Make sure there's nothing screaming out at us from the compiler.
So we have a successful compile.
And in the next video we'll go about loading our abilities from disk.
Great job.
I'll see you soon.