Welcome back.
In this video, we're concerned with receiving the target data.
We know that we're sending it client side up to the server now.
We need to listen for it.
So we have our to do here.
Now, when target data reaches the server, there's a delegate broadcast, as we've said, and we can
get that delegate through the ability system component.
So I'm going to say ability system component dot get and I'm going to call a function ability target
data set delegate.
Now this returns the target data set delegate, but it's the delegate for a given ability slash prediction
key pair.
In other words, it needs to know that prediction key associated with the target data.
So in order to know that information, the function we're calling here needs the spec handle for the
ability that's associated with this specific task.
So we need to get that spec handle.
Now we can call get ability spec handle for that.
Next, we need the prediction key and that's the activation prediction key as this says original, right?
That's the activation prediction key we can pass in get activation prediction key.
Now this function gives us the delegate and from the delegate right here at the very end, we can hit
the dot and we can bind a function to it.
We can use add you object, or we could bind a lambda to it.
If we wanted to do that, we could say add lambda, right?
Let's go ahead and make a function that we can bind to it just so that we can encapsulate that functionality
into a little function.
So I'm going to go to target data under mouse dot H and make that function.
Now the function needs to have a specific signature and we're going to make sure that it has one.
So it's going to be a void function.
I'd like to call it on target data replicated callback, just so it's clear that this is a callback
and this callback has to have the correct signature, right?
Because it's going to be bound to this target data set delegate.
Now target data set is going to broadcast two things.
It's going to broadcast the target data handle and it's going to broadcast that activation tag associated
with it.
Now we're just sending an empty tag, but it's still going to come through.
So this function needs to take both of those.
The first is a const reference to gameplay ability target data handle.
That's a const reference and we'll call this data handle.
And the second input is a gameplay tag just passed by value.
And this is called activation tag.
So we'll generate this callback.
So we have it down here and this is the function will bind to the delegate.
Up here we'll use add to object.
So passing in this for the user object and the address of you target data under mouse on target data
replicated callback.
So we're binding that function to it.
So that's good.
So as soon as activate is called on the server, the server will bind its callback to this delegate.
But what happens if we're too late and the target data has already been sent and the delegate has already
been broadcast?
Well, in that case we should call that callback anyway.
So there's a way to check, or at least a way to call that target data delegate if it's already received
target data.
So we can do that through the ability system component.
So we'll use ability system component dot get and the function is call replicated target data delegate
if set.
Now this requires the spec handle.
Now I'm just going to create a local gameplay ability spec handle called spec handle here just so I
don't have to keep calling that getter function.
So I'm going to say spec handle equals, get ability spec handle and pass that in both here and here.
And then our activation prediction key, I'm going to do the same thing.
I'm going to make an F prediction key called activation prediction key and call get activation prediction
key and simply pass that in right here and right here.
Then we don't have to call those getters twice.
And there we go.
So this will ensure that we're calling that function.
Now, this returns a boolean that will be true or false, depending on if that delegate had already
been set and if we should still listen for it so we can go to the function call replicated target data
if set.
And we see that there's this local bool called delegate set to false, but it's set to true if the broadcast
is made right because we're broadcasting the target set delegate here.
If target data has already reached the server and in that case, well cool, the server will now receive
that data.
So this function returns a boolean, we can store it in a const bool called be called delegate.
And the reason I'm doing this is because we need to tell the server to wait for player data to come
through.
So if it's already been set and we're broadcasting it well, we don't have to care about anything anymore.
Otherwise though, if be called delegate is false.
In other words, if not be called delegate, then we need to call set waiting on remote player data
and that's going to tell the server, look, we're still waiting for remote player data and we can go
to this definition to see what it does.
It just sets a wait flag and tells the ability, Look, we're waiting for player data.
So in our task, if we did not call this delegate, that means it hasn't reached the server yet.
So we'll be waiting for that data to come back.
Okay.
And these both can be const variables here.
Since we're not going to change them.
All right.
So the last thing is to decide how on target data replicated callback will behave.
What is it going to do?
Well, if we go into this function, we know this function will be called in response to receiving target
data, receiving replicated target data.
Now, I know we've mentioned early on in the course that replication only happens from server to client,
but in gas you'll see a lot of functions that kind of use the term both ways.
Replicated data being sent from client to server via Rpcs.
Sometimes the gas system refers to that as replicated data, so that's something to be aware of.
But this function will be called on the server when replicated data has been received.
And in that case we need to broadcast it so that our ability task in the game play ability will have
its valid data execution pin executed.
So what we can do is we can broadcast that data, but we also need to make sure that the ability system
component knows that that data has been received because when replicated target data is received by
the server, it's stored in a specific data structure and we can tell the ability system component we
have received the data.
You don't need to store it, you don't need to keep it cached anymore.
So we do that by taking the ability system component and calling consume client replicated target data.
And this requires the ability spec handle so we can call get ability spec handle and it requires the
ability original prediction key that's get activation prediction key.
So this tells the ability system.
Okay, target data has been received, don't keep it stored.
We don't need to keep that cached.
And if we go to the definition of this, we see that through the ability spec handle and the prediction
key, the ability system component is able to find something called ability replicated data cache.
And this is inside of the ability target data map.
So this map associates the ability spec handle and prediction key with target data.
And so for each ability spec handle and prediction key, there is a target data in that cached data
data structure that will be cleared when we call consume client replicated target data.
And it also has Target confirmed and Target canceled Booleans so that it knows whether or not the target
data has been sent or received and so on.
So consume is going to tell the ASC we've received the data, don't worry about it anymore, just clear
it from your cache for this specific ability, spec and prediction key.
So now that we've done that, we can broadcast the delegate, but of course we should check should broadcast
ability task delegates.
So just like we did up here in send mouse cursor data, we're going to check first before broadcasting
the delegate just like that.
And we're just broadcasting that data handle straight on through.
Okay.
So our task is looking pretty much complete.
We're almost ready to test it out.
But there's one last step that we have to do in our project before we can even use target data.
And this is a very important step.
If you had tried to use target data by play testing in the last video, you might have run into an issue.
In fact, let's see what that issue is.
Let's go ahead and just compile and run and debug mode.
Okay.
So I'm going to go ahead and open up the ability.
Now, this target data under mouse is no longer valid.
We've changed it quite a bit.
So I'm going to go ahead and right click refresh nodes.
And now we get a data handle when target data under mouse is activated and from the data handle, if
we drag off and we can type target data, hit and say get hit, result from target data that returns
us a hit result and from the hit result we can break that hit result and get location.
And or impact point either one hook that in to draw debug sphere.
Okay so we think that's going to work.
All right, let's press play.
And click on the client.
Actually, we need to click on an enemy.
And look what happened.
Interesting.
And you might not really even realize what's happened.
Look at what's happened.
If I fullscreen the client, it's in a completely new game instance.
The server character is gone.
And if we look at the server, look, the client is gone.
What happened?
The client got disconnected.
Let's see what happens in the output log.
Going to press play here on the client.
I'm going to click on an enemy.
Oh, there was some red.
Let's look at that red text that we got there and we got kind of a few things.
But look at our first log ability.
System error could not find gameplay ability target data, single target hit in script struct cache.
So we get errors related to target data because I told you there was something we need to do.
That's very important.
In order for our target data to work.
We can't use target data without performing this very, very important step.
And that very important step is to go into our class or asset manager and in fact we need to go into
the CPP file for it and right here and start initial loading.
There's something we have to do that's very, very important if we want to use target data and that
is to use you ability system globals and call the function.
First of all, get because this is a singleton and call the function init global data.
So why do we have to do that?
Well, if we go to init global data then we'll see that it initializes some things, including target
data.
Specifically it calls init target data script struct cache.
That's what that error was talking about.
It couldn't find the script struct cache.
If we go to this definition, we see that there's something called a target data script struct cache
and it's initializing it for game playability target data.
It's calling static struct on there to get that struct.
So this is a very important step.
We won't get into the details of what this is doing until we get more into data serialization, which
we will in videos to come.
But now that we've called this very important function in our asset manager, we can use target data.
So it might even be worth it.
Sticking a comment in here and say this is required to use target data.
It just might be worth it to do that.
So now that we've called init Global Data, we can test this out and see how it works.
All right.
We're back in the editor.
And all we're doing in our ability is drawing a debug sphere once we get that target data and then ending
the ability.
So why don't we give this a try?
We'll press play.
And really, first things first, we're going to check this out on the client.
So here on the client, I'm going to click and we see that sphere over there.
Do we see it on the server?
Oh, yes, we do.
We definitely do.
So here I'm on the client.
I'm going to click on this guy over here.
Boom, Look at that.
We see it both on client and on server.
We're successfully sending target data up to the server and that target data just contains a hit result.
But this is huge because now our clients are sending data to the server and now we're both on the same
page.
Both client and server knows where that target data is.
Now don't worry about other clients.
They shouldn't really even need to know where that target data is on this client.
If I click over here, no, we're not doing it over on that client over there.
That's not really necessary.
All we care about is getting that data up to the server.
I just want my target data sent to the server so the server can know where I'm clicking and then the
server can launch that authoritative fireball in the correct direction.
So I'm going to go ahead and close the output log and we now know which direction to send that fireball
and that's going to be what we're concerned with next, is launching the fireball in the correct direction.
So great job.
We'll continue with this in the next video.