Welcome back.
So we're setting up our ability system components and we've set our replication mode.
Now, something should still be bothering you at this point, and that is that our Aura character base
class has an ability system component pointer and an attribute set pointer.
And it's only on Aura Enemy that those pointers have been set with valid values for Aura character.
Those pointers are uninitialized because we constructed the ability system component and attribute set
on the player state instead for our player controlled character.
These pointers have valid values for the player state, but not for the character.
So I want that to keep bothering you.
Keep that in the back of your mind, because it's something we do want to fix.
Now, another thing we have to do is make sure that the ability system component itself knows who its
owner is.
Now, that could mean something different for our enemy versus our player controlled character, right?
Because for our enemy, the owner of the ability system component is clearly this enemy class.
But for the character, that's not necessarily the case, is it?
Because the player state is who actually constructs the ability system component?
So how do we decide who's the owner of it?
Let's talk about that.
Now the Ability system component has this concept of ability actor info.
That way, the ability system component can always know the actor info such as who owns this ability
system component.
But the ability system component also understands the concept that it might be owned by some actor,
by some pawn, or it could be owned by another type of entity such as a player state.
So for that reason, the ability system component has two variables an owner actor and an avatar actor.
You see, the owner actor is whatever class actually owns the ability system component.
But the Avatar actor is the representation in the world associated with this ability system component.
Now for our enemy character, these two are the same because our enemy character class is the class
that constructs our ability system component.
So the owner actor is the enemy character, and the avatar actor is also the enemy character.
That's what we see in the world.
That's the visual representation one.
Now for the player controlled character, this is a little different because our ability system component
is constructed by the player state, and that's the class we would like to think of as the owner for
the ability system component.
So the owner actor in this case should be the player state and the avatar actor, that actor that we
actually see in the world that should be the character.
So in this case, the owner, actor and Avatar actor are two different actors and the ability system
component distinguishes between those two.
So it's important to understand that the owner, actor and avatar actor may or may not be the same actor
in our project For the Enemy, they are the same.
And for the player controlled character, they are different.
Now we are the ones who decide these things.
We call the function to set the owner and avatar actors.
It's a function on the ability system component called init ability actor info.
So we need to initialize the ability system component with these actors ourselves.
Now where and when do we call this function?
Well, that's something that we have to give some thought to.
You see, it depends.
Now here are some rules of thumb and good places to do so in a multiplayer game, the first thing we
need to know is that calling init ability actor info must be done after possession.
In other words, the controller has to have been set for the pawn.
So it's important that we do this after the controller has been set for the pawn.
So when is that?
Well, for a player controlled character in which the ability system component lives on the pawn itself,
this would be if perhaps we had constructed the ability system component on a character instead of the
player state, which we're not doing.
But if we did a good place to call init ability actor info would be in the possessed by function on
the pawn.
This ensures that the ability system component is initialized with the avatar actor and owner actor
values on the server, but this function only applies on the server.
On the client.
We have to use a different function.
There's a function called acknowledge possession for that.
And in this function we know that possession has occurred.
Our pawn does have a valid controller.
So in this case, if we were to put our ability system component on the pawn or in our case the character
class itself, these two functions are where we would call init ability actor info in order to initialize
the ability system so it knows who its owners are.
Both.
The owner and the avatar.
And in this case, they would both be the same.
They would be the pawn itself.
Now, for player controlled characters in which the ability system component lives on the player state,
which is our case for Aura character, then we're going to call init ability actor info for the server
on possessed by.
But for the client we're not going to use acknowledge possession we're going to use on rep player state.
Why?
Because our AC our ability system component lives on the player state.
So not only do we need to make sure that our controller has been set, but we also need to make sure
that our player state is valid at this point in time as well.
Now on Rep, Player State is safe.
Both of those things will have been done by that point in time.
We'll have a valid controller and a valid player.
State Now on rep Player state is something called a rep.
Notify the rep notifies are functions that are called as a result of something being replicated.
In this case, the player state will have been set on the server and the player state is a replicated
entity, which means that as soon as that player state has been set for our pawn, that will be replicated
down, triggering this rep notify, which will be called in response to the replication happening.
And at that point we know that our player state has been set on the server and down here on the client
it's been replicated down and it's a valid pointer.
So that is where we will initialize ability actor info for our ability system component.
And in this case we'll be setting our owner actor to the player state and our avatar actor to the pawn
itself in our case, or a character.
So this is what we'll be doing for our player controlled character.
Now for the AI controlled characters, it's a bit more simple for our AI controlled characters.
We'll have our ability system component on the pawn itself.
That's our aura enemy.
And because of that we really only need to call init ability actor info and begin play.
We know that our AI controlled character is going to have a valid ability system component and controller
and we're just going to call init ability actor info and begin play.
This will work just fine for our AI controlled character.
So that's what we're going to do.
So if you're a note taker, if you like taking notes, this would be one of those important things to
write down so you can pause the video and write these things down because these are the functions that
you want to know about when it comes to calling an IT ability actor info and initializing it.
And now that we know what we're going to do to init ability actor info, it's time to actually do it
in our project.
And this is going to be your quest.
I want you to initialize the actor info by calling init ability actor info and you're going to do this
for the aura enemy class.
That's going to be easy.
You'll just do it and begin play right?
But also handle this for Aura character.
And remember, this one's a little bit more complicated.
And also remember the ASC.
The ability system component is on the player state, which means you're going to need to access the
player state.
And while you're at it, this is a great opportunity to set the Aura character's ability system component
and attribute set pointers.
Remember I told you that should be bothering you in the back of your mind.
Those pointers are uninitialized.
Well, as soon as we access the player state, we should then have access to the ability system component
and attribute sets.
The player state has getters for those and our Aura character will now have the ability to set those
pointers.
So pause the video and initialize your ability.
Actor info now.
Okay, so we're ready to init.
Ability actor info.
And I'd like to do the enemy first because that's the simplest case.
We're going to do this in begin play now.
Our enemy doesn't have begin play, which means we're going to need to override that here.
And while I'm at it, I'd like to make this a little more organized.
I'm going to put a comment up here above our interface functions because I know that this belongs to
our enemy interface.
So I'm going to say enemy interface right here.
And I'm going to put a comment below these two that says End enemy interface.
That way I know that these are from that interface and these are public.
Begin play is protected.
So we'll make a protected section and we'll override begin play down here.
So we're going to say virtual void begin play override.
Let's generate the definition, we'll get our super call and then we can init ability actor info here.
So to do that we access our ability system component pointer and we call init ability actor info and
we can see that the first input is the owner actor that will be this and the avatar actor will also
be this.
Now if you like, you can check the pointer first.
You can even put an assert such as check ability system component.
You can do that.
But if I get a crash on this line, then I know why.
It's because the ability system component pointer is null, but I don't expect it to be null because
I'm initializing that in the constructor.
So something is terribly wrong.
If I crash accessing this pointer, I'm confident enough to use it without checking.
Okay.
So that takes care of the enemy.
Now for the character, which is going to be a little more complicated, but not much.
Let's find our Aura character class, the CPP version, and we're going to want to override a couple
of functions.
I'll just pull up my slide here again and remind myself that this is the case where concerned with where
the ability system component lives on the player state, we're going to initialize ability actor info
in possessed by for the server and on player state for the client.
So we need to override those functions.
So that means I'm going to hit alt O or control k o on Visual Studio to come into Aura character, and
I'm going to override a couple of virtual functions.
First, we need possessed by so virtual void possessed by and if I right click and go to declaration
or usages, we'll see that this possessed by belongs to the a character class right here and if I go
to character should search for possessed by I can see that it is in the public section.
And by the way notice that we see this comment thing happening here for functions that belong to interfaces.
We're actually seeing the comment for parent classes being referred to as interfaces.
Now, we could do that too, if we want.
In fact, if you want to copy the same sort of comment style, you can do that as well.
It's up to you.
We can say begin interface and end interface.
So if you want to use that comment style, feel free.
But I wanted to see that possessed by is a public function and we're also going to want to override
virtual void on wrap player state and we can go ahead and generate the definitions for both of these
functions.
There they are.
And if we hit shift shift that allows us to search, we can search for on rep player state and we see
that that one belongs to the pawn class.
Here it is on rep player state.
And we see here in the pawn class that this function is also public.
So we'll go ahead and override that one.
Now that we have these two functions, we can do what we need to do, which is call init ability actor
info.
So we'll start with possessed by now.
Remember this one's for the server, so I'm going to make a comment.
So we remember init ability actor info for the server and remember we need to access the player state.
So I need to call get player state and we have a template version of this so we can pass in a or a player
state as the type and that will return the appropriate type.
Now I'm going to make a local or a player state variable.
I'm going to say A or a player state called or a player state.
And I'm going to wrap this in an if statement.
So if that way, if this is valid, which it should be at this point, in fact, it's kind of important.
Let's go ahead and just use an assert instead.
This should not be a null pointer.
We should be pretty confident.
So we'll say check or a player state and then we'll take or a player state and we're going to get the
ability system component from this.
We're going to call get ability system component.
And from that we now have the ability system component we can call init ability actor info and we can
pass in the owner, actor and the avatar actor.
Now in this case, the owner actor is going to be the player state.
So we're going to pass in or a player state for the owner actor and the Avatar actor will be the character
itself that's going to be this.
So that's the difference.
When you have the ask or ability system component on the player state.
But we have to set this here in possessed by because we need to be sure that we have a valid player
controller set already and that our player state is valid and accessible and we can call this function
here.
So that takes care of this.
But remember, we have the player state now that's a good opportunity to set the Aura character's ability
system component pointer.
So we're going to say ability system component equals and we'll take Aura player state and call get
ability system component.
We'll set that and we'll set our attribute set as well.
We'll say attribute set.
Equals or a player state.
Get attribute set.
And now we're starting to see the benefit of having those getter functions.
Okay, so these pointers are set here on the server and we've initialized ability actor info here on
the server.
We're going to want to initialize it for the client as well.
That's why we're doing it in on Rep Player State, which means we're going to do the very same thing
we did here.
We're going to get the player state, check it and call init ability actor info and set these to pointers.
We're going to do the same thing now rather than just repeating myself.
You may have heard of the dry principal dry.
Don't repeat yourself.
Rather than copying several lines of code and pasting them, I would like to instead create a function
that I can reuse in both of these.
So let's go ahead and go to Ora character here and make a private function that we can just call twice.
So I'm going to say void and I'll just call this init ability actor info.
That's really all it's doing.
So let's make a function definition and it's going to be these lines of code here.
So I'm going to go ahead and control X and control V.
Now we have a function that does these things for us.
We can call it here and possessed by and we can call it here and on Player state.
And we'll have a comment here that says init ability actor info for the client and that's it.
Now if you didn't do this refactor into a function, that's totally fine.
It's okay if you repeated yourself not a big deal.
I do recommend making a function, but you don't have to.
And now we've achieved a couple things.
For one, our ability system components know who their owner is.
They know who the owner actor is and they know who the Avatar actor is.
That's going to be very, very useful and convenient as we continue programming in gas throughout this
course, because there will be many, many times when we need to access those owners in our abilities
in our various gas classes.
So this is a very important and crucial step.
And before we end the video, I'm going to bring your attention back to the replication mode.
Again, remember, we set our ability system component for the player controlled character to mixed
replication mode.
And it's important to know a couple of details when you do this.
For mixed replication mode.
It's important to know that the owner actors, owner must be the controller.
Now, in our case the owner actor for our ability system component, at least for the player controlled
character that has mixed replication mode is the player state.
That's who we set as the owner actor in an ability actor info.
Now we don't need to set the player state's owner to the controller because that's what happens.
By default.
The player state's owner is automatically set to the controller, so we don't really need to do anything.
Similarly for pawns this is automatically set in possessed by.
So if the owner actor for the ability system component is the pawn well in possessed by the pawns owner
will be set to the controller.
But if your owner actor is not the player state and you're using mixed replication mode, you must call
set owner on the owner actor and set its owner to the controller.
So even though we don't need to worry about it because our owner actor is the player state and the player
state's owner is already set to the controller.
You need to know this because your owner actor may be some class that does not automatically get its
owner set to the controller.
In that case, you're going to want to make sure that it is if applicable.
You might have an ability system component on some actor that doesn't have a controller.
In that case, that's fine, don't worry about it.
But for mixed replication mode, the owner actor's owner must be the controller.
So keep this in mind.
This is not something that you'll worry about in this course, in this project, but keep it in mind
for your future gas projects where things might be different.
So just something you might want to jot down.
Okay.
Excellent job.
We'll continue with this in the next video.