Welcome back.
So we have click to run and auto running and that's all implemented nicely and we're ready to move on.
But before we do, I'd like to clean up the player controller just a little bit.
There are a couple of things that we could make a little bit better.
For one, we're getting the hit results under the cursor twice every frame when we're holding down the
left mouse button.
So we can see that if we go to ability input tag held, we see that we're getting the hit result here,
but we're already getting that hit result in cursor trace all the way up here.
So we already have that value.
We can just store that every frame if we're going to be using it, every frame, and then other functions
that need it can access it.
And this can be used even later on.
If we want to do something like show a decal at the cursor, hit location or something like that.
So I'd like to make a cursor hit member variable.
So instead of making a local variable here in cursor trace, I'm going to take this F hit result Ctrl
X to cut it and go into the player controller header file and just under cursor trace and these I enemy
interfaces, I'm going to have an F hit result cursor hit right here and that way we're just filling
in our member variable and get hit result under cursor.
And if we search for get hit results under cursor we'll find where we're using it here and ability input
tag held.
We don't need to get it again.
We just need to access the impact point from the one we already have.
So rather than creating a new hit result here, let's get our cursor hit and we can check to see if
it has a blocking hit so we can say cursor hit, dot blocking hit and then we can get our impact point
from cursor hit here so we don't have to go and do another trace.
That work has already been done, so that's a nice optimization.
And the rest of the stuff I'd like to do in player controller is just kind of clean it up and make sure
that it looks concise and nice.
So I'm going to scroll down and if I see anything that I think can be cleaned up, I'm going to clean
it.
Now, here's something.
The cursor trace function itself has a lot of code here that really could be condensed down.
Now, we made these comments for educational purposes, right?
We wanted to make sure we understand that we've covered all of the scenarios that can happen when we're
highlighting.
I don't think we need that comment anymore.
And I also think that all of these cases with these empty comments are unnecessary.
This can actually be condensed down quite a bit.
So I'm going to go ahead and remove it.
Now.
How can we write this in the most concise way possible?
Well, really, we just care if this actor and last actor are not the same right?
If we say if last actor.
We'll check last actor first.
Because if last actor is not equal to this actor, they're different.
Well, then we should do something.
If these pointers are valid, we can say if last actor.
Well, we know that last actor is not this actor and last actor is valid, which means we should unhighlight
it because this actor, whether it's null or not, is not last actor.
So if last actor is a valid pointer, we can take last actor and call Unhighlight actor on it.
Now we also want to check if this actor so if this actor is valid and we know it's not equal to last
actor, then we should highlight it so we can say this actor highlight actor.
So we've now just condensed a lot of code into a really small area.
And yes, I have my if statement all come packed onto a single line, but it only needs to do one thing.
So I think that's fine and it looks a lot cleaner.
So cursor trace is looking a lot better.
And we'll just do a quick test before we end the video to make sure it's still working correctly and
in our ability input tag functions, we can actually do the same thing with these.
If statements that do a single thing, a single line, we can condense these onto a single line and
take up less space.
And I think that that will make them a little bit cleaner.
So that's just a kind of a personal style preference.
The Unreal Engine coding Standards document actually discourages doing this.
It says you should always have a body with curly braces, but there are a number of standards in there
that are treated more like guidelines by many developers, and this is one of them.
I kind of like compact if statements when I only have a single.
Line and I don't plan on adding more.
So I'll go ahead and come down to ability input tag held and compact these single line if statements
here as well.
So doing it there, doing it here.
And that's looking good.
And we can even do that here with this if check.
It's just a quick blocking hit check.
So that looks good.
And we'll get rid of some empty space in between there and just doing a quick scan.
Everything else looks good.
The move function could be made const.
I'm not too worried about that.
Writer tells you every single instance of when anything could be const and to be technically const correct
you would follow its advice every time.
I'll go ahead and remove a space from there in the constructor and I think our player controller is
looking a lot cleaner, a lot smaller, less lines of code to do the same thing, which is always good.
And before we do a quick test, I'd like to just remove any debug drawing that we're doing as we're
done drawing debug shapes.
So I'm going to remove draw debug sphere.
I'm going to quickly add const to this controlled pawn local variable and I see that I'm not drawing
anything else so this looks good.
Let's go ahead and give this a quick test before we move on.
Okay.
So we'll quickly test.
I'll test in multiplayer.
Let's click play and I'm going to click and hold.
Running works.
I'm going to click and release.
Auto running works as well.
If I click on the pillar, we'll go around the pillar.
If we click in the base of the pillar, we'll move to a location and stop.
And if we highlight an enemy, it works.
And we can also try duplicating an enemy, having two next to each other and we can try highlighting.
One and then directly onto another that looks like it works.
And we can try.
Behavior on the server.
And it's working.
Everything works as expected.
Now, one thing actually that doesn't behave as expected is that our clients don't get those messages
popped up like our server does.
So let's just really quickly figure out why and fix that.
And that's going to have to do with our ability system component.
If we go to our ability system component header file, we'll see that we have this effect applied.
When is that called?
Well, we have our ability actor info set, which is where we bind this callback to on gameplay effect
delegate to self.
And if we go to declaration or usages for this, we see that the comment and ability system component
says called on server.
Whenever a gameplay effect is applied to self.
That's why we only get this callback fired off on the server and not on clients.
So how do we make sure that it fires off on clients as well?
Well, it turns out that's actually pretty easy.
You see, if we take this effect applied callback and make it an RPC, specifically a client RPC, then
it'll be called on the server, but it'll also be executed on the owning client.
So client Rpcs are designed to be called on the server and executed on the client.
Now, if it's being called for the server owned ability system component, the hosting player, then
the client RPC will just be called on the server and it won't be replicated down to the owning client
as the owning client is on the server.
Right.
So what we're going to do is we're going to go to our ability system component and we're going to take
this effect applied and make this an RPC.
We do that by giving it a new function and saying client here.
So it's now a client RPC and we're going to make it reliable.
Reliable means it's guaranteed to reach the client even in the case of packet loss, it'll be sent until
it receives confirmation that it has been received.
Now, typical convention is to prefix a client RPC with client in the name, and if we make this an
RPC, then our implementation here in the CPP file has to have underscore implementation in the name.
So it's now going to be called client effect applied underscore implementation.
And this function client effect applied is now what we're going to bind to this delegate, not just
effect applied but client effect applied.
So now this is a client RPC.
And once this delegate is broadcast on the server, it'll be called in the server and executed on the
client.
So this takes care of both server and client behavior for those messages.
And that's how we're getting the messages, is we're broadcasting the asset tags for any applied effect
and our widget controller receives them and handles it from there.
So let's just quickly test this out and make sure we're now getting those messages on the HUD on clients.
Okay, so we have our number of players.
Let's set it to three.
I'd like to test this out with three players.
So we have two clients and a server.
I'm going to take this first client and pick up something.
And there's the message.
Looking good, Looking good.
I'm going to try it on this other client.
Also looking good and we'll try it on the server.
Also looking good.
Perfect.
I'll go ahead and set that back to one player.
Actually, let's test two players on a dedicated server.
That's this player's client.
Let's give that a try.
And that works for both clients.
Perfect.
I'll set this back to listen server and we'll keep it at one for now.
I'm going to save all close out and we've done some good refactoring.
Things are working and it's time to move on.
Excellent job.
See you in the next video.