WEBVTT

00:07.380 --> 00:08.160
All right.

00:08.160 --> 00:09.090
Welcome back.

00:09.090 --> 00:16.080
Now in our widget controller for the overlay, we have a to do and on initialize startup abilities,

00:16.080 --> 00:25.020
we want to loop through all of our ability system components, activatable abilities, and we want to

00:25.020 --> 00:28.700
look up their info from our data asset ability info.

00:28.710 --> 00:34.170
Now I don't want to reach in and get that gameplay tag container and loop through it right here.

00:34.170 --> 00:40.440
I'd rather do it in a more self-contained way where we don't have to expose the contents of the ability

00:40.440 --> 00:42.270
system component so much.

00:42.270 --> 00:51.150
So what I'd rather do is make a delegate that I can bind a callback or a lambda to and pass that over

00:51.150 --> 00:57.660
to the ability system component, which can then loop through all of its activatable abilities and do

00:57.660 --> 00:58.890
something for me.

00:59.040 --> 01:00.600
So here's what I mean.

01:00.930 --> 01:08.530
I'm going to go over to aura ability system component and make a delegate for each ability.

01:09.040 --> 01:17.530
So I'm going to declare and I'm not even going to make this multicast, I'm just going to declare delegate

01:17.980 --> 01:20.140
and it's going to be one param.

01:21.160 --> 01:27.970
Now I'm going to call this for each ability and it's going to take a single input.

01:27.970 --> 01:32.980
It's going to be a const reference to an gameplay ability spec.

01:34.400 --> 01:39.980
Because as we loop over all of our activatable abilities, those are ability specs.

01:39.980 --> 01:45.260
So I want a way to loop over all of those abilities.

01:45.620 --> 01:52.730
In other words, I want a function on the ability system component that can take in one of these for

01:52.730 --> 01:58.610
each abilities, which will have a function bound to it and loop over all of my abilities and call that

01:58.610 --> 02:00.460
function that's bound to this delegate.

02:00.470 --> 02:02.360
So I'm going to create that function here.

02:02.360 --> 02:09.950
It's going to be public and I'm going to call it for each ability, void for each ability, and it's

02:09.950 --> 02:17.420
going to take this delegate for each ability and it's going to take it by const reference and I'm going

02:17.420 --> 02:19.340
to call it simply delegate.

02:20.030 --> 02:23.900
And what does for each ability need to do?

02:23.930 --> 02:27.590
It needs to loop through all of its activatable abilities.

02:27.590 --> 02:28.880
So we'll have a for loop.

02:28.880 --> 02:36.300
We're going to say for const F gameplay ability spec const reference of course, and this will be called

02:36.300 --> 02:40.850
ability spec and we're looping through all of our activatable abilities.

02:40.860 --> 02:43.890
We can get those with get activatable abilities.

02:44.340 --> 02:51.360
And what we're going to do is if that delegate has a callback bound to it, we're going to execute that

02:51.360 --> 02:52.110
delegate.

02:52.110 --> 03:00.450
So we'll take the delegate and call execute and we can call execute if bound and pass in the ability

03:00.480 --> 03:08.010
spec as this delegate requires the ability spec now execute if bound will return a boolean.

03:08.010 --> 03:14.940
If the delegate has no callback bound to it, then we can get that false value.

03:14.940 --> 03:20.700
So we'll say if and we can say if not execute if bound.

03:20.820 --> 03:23.430
So this will still execute it if it is bound.

03:23.430 --> 03:27.690
But if it's not bound we'll get that false value returned.

03:27.690 --> 03:35.070
And in that case we can log, we can log an error, we can say Yui log, we can use our new fancy log

03:35.070 --> 03:35.850
aura.

03:36.210 --> 03:44.430
Remember autocomplete included my aura log channels when I typed that we're going to log an error and

03:44.430 --> 03:50.340
it's going to say failed to execute delegate in.

03:50.340 --> 04:00.660
And if we want to log the name of a function, we can use percent s and what are we going to pass for

04:00.690 --> 04:03.350
that double underscore function?

04:03.360 --> 04:04.680
Double underscore.

04:05.100 --> 04:11.610
This is a nice handy way to just log the name of the function we're in for each ability.

04:11.640 --> 04:12.950
Pretty nifty.

04:12.960 --> 04:18.330
So we now have this for each ability and it loops over get activatable abilities.

04:18.330 --> 04:24.240
Now there's another reason for doing this in the ability system component and not in the widget controller.

04:24.240 --> 04:30.150
And that is as we're looping over abilities, we have to be careful because abilities can change status.

04:30.150 --> 04:36.300
They can become no longer activatable for example, maybe they're blocked by a certain gameplay tag,

04:36.300 --> 04:37.130
etcetera.

04:37.140 --> 04:45.090
So a good practice when looping over this container is to lock that activatable abilities container

04:45.090 --> 04:53.790
until this for loop is done and we can do that with F scoped ability list lock and create an active

04:53.790 --> 04:54.690
scope lock.

04:54.690 --> 04:56.580
We're going to call it active scope lock.

04:56.580 --> 05:02.580
And this requires the ability system component, not by pointer but by reference.

05:02.580 --> 05:05.670
So we need to dereference this and pass it in.

05:06.030 --> 05:13.770
So with this we'll be safe to loop over all of our activatable abilities because the list will be locked

05:13.770 --> 05:21.090
and it'll keep track of any abilities that are attempted to be removed or added and wait until this

05:21.090 --> 05:25.470
scope has finished before going and mutating that list.

05:25.470 --> 05:32.310
So this is a safe way to do it and this is something I'd rather just handle here in the ability system

05:32.310 --> 05:36.680
component rather than from outside of it makes sense.

05:36.680 --> 05:43.850
Okay, so now we have this for each ability and back in our overlay widget controller, I'd like to

05:43.850 --> 05:45.860
do something for each ability.

05:45.860 --> 05:52.400
So what I'm going to do is create a lambda to bind to for each ability.

05:52.580 --> 06:00.740
So we'll make an F for each ability here called, I'll just call it broadcast delegate and I'm going

06:00.740 --> 06:02.180
to bind a lambda to it.

06:02.180 --> 06:08.480
Broadcast delegate dot bind, lambda and what can I bind to it?

06:08.780 --> 06:10.130
I'm going to bind a lambda.

06:10.130 --> 06:17.180
So we're going to use square brackets, parentheses and a function body like we usually do.

06:17.480 --> 06:25.970
And I'm going to put those curly brackets on their own lines so we can kind of better see what the function

06:25.970 --> 06:26.900
body looks like.

06:26.900 --> 06:30.560
I can go ahead and keep that closing parentheses there.

06:30.560 --> 06:33.350
And here I want to do something.

06:33.930 --> 06:35.370
For each ability.

06:36.090 --> 06:41.610
Now, what I want to do for each ability we have the to do right here, we want to get information about

06:41.610 --> 06:45.900
all the given abilities by looking up their ability info.

06:45.930 --> 06:48.000
Now our ability info.

06:48.030 --> 06:55.560
It's a variable here on the widget controller and it has that function we made find ability info for

06:55.560 --> 06:56.400
tag.

06:56.490 --> 07:04.020
So if we have the tag for a given ability, well then we can get its ability info.

07:04.020 --> 07:09.990
But all we really have here in this lambda is the ability spec.

07:10.020 --> 07:10.650
That's right.

07:10.650 --> 07:18.060
We need to make this lambda have the correct signature if it's going to be bound to broadcast delegate.

07:18.090 --> 07:25.050
This can only take something that can receive a const gameplay ability spec reference.

07:25.050 --> 07:25.620
Right?

07:25.650 --> 07:31.770
We're going to call it ability spec and here in our lambda we need to figure out how to get that ability

07:31.770 --> 07:38.710
tag from the ability spec and in addition ability info can't be accessed from within this lambda if

07:38.710 --> 07:41.560
we don't capture this right.

07:41.770 --> 07:47.500
But still we need a gameplay tag to pass in to find ability info for tag.

07:47.530 --> 07:59.380
So let's make another Todo here that says need a way to figure out the ability tag for a given ability

07:59.410 --> 08:00.370
spec.

08:00.850 --> 08:03.850
So how are we going to manage that?

08:04.090 --> 08:12.460
Well, as long as all of our abilities have a given tag in its ability tags, we can check if it has

08:12.460 --> 08:15.970
a parent tag and its tag hierarchy.

08:15.970 --> 08:23.320
So we could create a nice utility function on the ability system component for getting the tag for any

08:23.320 --> 08:24.520
given spec.

08:24.520 --> 08:29.470
So we're going to go into our ability system component and make a nice utility function that can do

08:29.470 --> 08:30.100
that.

08:30.100 --> 08:37.050
It's a function that I'd like to return and gameplay tag from and I'm going to call it get ability tag

08:37.050 --> 08:46.830
from spec and it's going to take in a const gameplay ability spec reference called ability spec and

08:46.830 --> 08:49.500
it's going to return its ability tag.

08:49.500 --> 08:55.460
So let's go ahead and create the definition for this and it's going to be relatively simple.

08:55.470 --> 09:01.230
We need to get the ability tags from this ability spec well to get the ability tags, we take the ability

09:01.230 --> 09:09.420
spec and it has a ability which is the actual ability and this ability is a t object pointer.

09:09.420 --> 09:14.760
So we can call, get on that and from that pointer we can get ability tags.

09:14.760 --> 09:21.330
So kind of a lot of indirection here and we should definitely make sure the ability is a valid pointer.

09:21.330 --> 09:28.920
So we'll say if ability spec dot ability, then we'll get the ability tags.

09:30.160 --> 09:34.620
And this is a gameplay tag container, so we're going to loop through it.

09:34.630 --> 09:41.170
We're going to say for gameplay tag tag in this container.

09:41.170 --> 09:45.490
So we're going to drag that up in here and what are we going to do for each tag?

09:45.490 --> 09:53.440
We want to see if it's an ability tag so we can say if tag dot matches tag and we're not going to use

09:53.440 --> 09:57.850
matches tag exact, we're just going to see if it contains ability in it.

09:57.850 --> 10:09.100
So we can say if gameplay tag request gameplay tag using the name of abilities.

10:11.170 --> 10:18.280
So basically for a given ability spec, we're going to look at that ability specs, ability tags and

10:18.280 --> 10:25.300
assuming it only has one ability tag that has abilities in it, then we're going to return that tag

10:26.380 --> 10:30.860
and if we reach the end, we're going to return an empty gameplay tag.

10:32.220 --> 10:34.650
And if you wanted to, you could log an error in that case.

10:34.650 --> 10:38.340
But I'm okay with just returning the tag if it's there.

10:38.370 --> 10:41.770
So now we have a nice function for returning an ability tag.

10:41.790 --> 10:47.930
In fact, this can even be a static function because it just takes in something and returns something.

10:47.940 --> 10:53.250
So really this could be marked static like that.

10:53.370 --> 10:58.350
Now that we have this handy function, let's go back to our widget controller where we have this line

10:58.350 --> 11:03.930
commented out where we're trying to find the ability info for a given tag and we have its spec.

11:03.930 --> 11:12.540
So we need to take our aura ability system component and call get ability tag from spec passing in our

11:12.540 --> 11:13.750
ability spec.

11:13.800 --> 11:20.720
Now we're trying to use aura ability system component in our lambda and that is not captured either.

11:20.730 --> 11:22.890
So we have to capture that.

11:22.920 --> 11:24.120
It's just a pointer.

11:24.120 --> 11:27.210
We can capture it by value, that's totally fine.

11:27.210 --> 11:33.420
And now that we have our ability tag, now it's possible to find the ability info.

11:33.430 --> 11:36.760
Now we have an aura ability, info struct.

11:36.760 --> 11:40.900
We're going to go ahead and create a local for ability info.

11:41.200 --> 11:42.670
We'll call it info.

11:43.600 --> 11:44.770
So now what do we do?

11:44.770 --> 11:45.610
We have the info.

11:45.640 --> 11:48.370
We want to broadcast that up to our widgets.

11:48.370 --> 11:49.090
Right?

11:49.090 --> 11:53.140
But we have to make sure it's all filled in completely.

11:53.170 --> 11:59.740
For one, we're not setting its input tag and we don't know what its input tag is.

11:59.860 --> 12:06.120
So yet again, we need a nice way to get that from our ability tag.

12:06.130 --> 12:10.120
Remember, the input tag is one of the dynamic ability tags.

12:10.150 --> 12:17.380
When we give the ability, we're adding to its dynamic ability tags the start up input tag.

12:17.380 --> 12:21.250
But that's only for our default abilities.

12:21.250 --> 12:26.830
Soon we'll be equipping abilities dynamically and we'll have to assign input tags to those.

12:26.830 --> 12:33.370
So I'd like another utility function to be able to get the input tag from the ability spec.

12:33.370 --> 12:38.710
So just like get ability tag from spec, we're going to have get input tag from spec.

12:38.710 --> 12:43.000
So let's make another function that returns an F gameplay tag.

12:44.020 --> 12:53.320
We'll call it get input tag from spec and just like get ability tag from spec, it's going to take in

12:53.320 --> 12:55.630
a const reference to the ability spec.

12:55.870 --> 12:59.230
Let's go ahead and just really quickly make this function.

12:59.470 --> 13:01.390
So how is this going to work?

13:01.390 --> 13:07.060
Well, we're going to loop over our dynamic ability tags this time because we know that the input tag

13:07.060 --> 13:09.730
is in that gameplay tag container.

13:09.730 --> 13:17.500
So we're going to say for F gameplay tag tag in ability spec and from the ability spec, we can get

13:17.500 --> 13:19.240
dynamic ability tags directly.

13:19.240 --> 13:24.160
We don't have to get it from the ability and with that we can match the tag.

13:24.160 --> 13:27.550
We can say if tag dot matches.

13:27.580 --> 13:33.280
Again, we're not using matches tag exact, we're just going to match against the input tag.

13:33.280 --> 13:42.130
So we're going to use f gameplay tag request gameplay tag f name.

13:42.910 --> 13:44.020
Input tag.

13:45.690 --> 13:48.940
And again, we should only have one input tag at a time.

13:48.960 --> 13:56.970
So just like our ability tags and we can go back to or a gameplay tags and remember we have our input

13:57.000 --> 13:58.380
tags, right?

13:58.470 --> 14:02.830
Input tag, LNB input tag, R&amp;B and so on.

14:02.850 --> 14:05.070
So we're going to return that tag.

14:05.070 --> 14:07.430
It's going to be return tag.

14:07.440 --> 14:15.170
And if we never return the tag, we have to return an empty gameplay tag like so.

14:15.180 --> 14:21.480
So now we have get input tag from spec and now we can call that to get our input tag so we can come

14:21.480 --> 14:30.210
back to our widget controller and we can take our info and set its input tag by getting our ability

14:30.210 --> 14:37.890
system component or a ability system component and calling our new function get input tag from spec

14:37.890 --> 14:47.080
passing in the ability spec and now our info struct has its input tag set and that's all great.

14:47.110 --> 14:52.450
Now the last thing we want to do is broadcast this for ability info.

14:52.450 --> 14:58.840
In other words, we need some kind of delegate to broadcast so that our widgets can respond to it.

14:58.930 --> 15:01.540
We need an ability info delegate.

15:01.570 --> 15:09.670
So yet again, we're going to make another delegate up here in our overlay widget controller that can

15:09.670 --> 15:11.710
broadcast ability info.

15:11.950 --> 15:19.630
Now I'd like this to be a dynamic multicast delegate as this will be bound to in blueprints and multiple

15:19.660 --> 15:21.010
blueprints to boot.

15:21.010 --> 15:24.160
So we're going to say declare dynamic.

15:25.620 --> 15:33.510
Multicast delegate and we're going to broadcast with one param because we want to broadcast that info

15:33.510 --> 15:38.040
struct and I'm going to call this F ability info delegate.

15:38.490 --> 15:44.670
Actually we can call it info signature and then we'll create a delegate of this type.

15:44.670 --> 15:47.540
And of course it needs to take one input parameter.

15:47.550 --> 15:53.280
We're going to use const f ora ability info.

15:53.280 --> 16:02.940
That's going to be forward declared because this is a reference and we can do a comma with the name

16:02.940 --> 16:04.710
of that input parameter.

16:04.710 --> 16:10.860
And now our ability info signature can be added as a blueprint.

16:10.860 --> 16:11.840
Assignable.

16:11.850 --> 16:15.750
We're going to call this ability info delegate.

16:16.830 --> 16:24.090
It'll be blueprint assignable and we can put it in the category gas messages and our overlay widget

16:24.090 --> 16:27.580
controller can simply broadcast ability info.

16:28.300 --> 16:32.080
Delegate passing in info.

16:35.330 --> 16:41.690
Now, all of this is just inside of a lambda which is being bound to broadcast delegate.

16:41.720 --> 16:43.220
We want to do this.

16:43.250 --> 16:46.840
We want to call this lambda for each ability, right?

16:46.850 --> 16:51.920
That's why we created that for each ability function on the ability system component.

16:51.920 --> 16:58.790
So we're going to take our ability system component for each ability call that function passing in our

16:58.790 --> 17:05.960
broadcast delegate So when on initialize startup abilities gets called, we create a broadcast delegate

17:05.960 --> 17:07.790
and bind a lambda to it.

17:07.790 --> 17:16.070
That lambda creates an aura ability info which is set by calling find ability info for tag on our ability

17:16.070 --> 17:17.540
info data asset.

17:17.570 --> 17:26.150
We need the tag for each of our ability specs and our lambda can receive an ability spec by const reference.

17:26.150 --> 17:32.240
So find ability info for tag needs that tag, which is why we created a function on the ability system

17:32.240 --> 17:36.720
component to get the ability tag by looking up an ability spec.

17:36.720 --> 17:43.590
Once we get that info we now have the aura ability info, but we need to set its input tag.

17:43.590 --> 17:49.860
So we created another function on the ability system component that can take an ability spec and look

17:49.860 --> 17:53.880
up its input tag from its dynamic gameplay tags.

17:54.000 --> 17:57.570
Once we have that, we set the input tag on that info.

17:57.660 --> 18:03.570
It's very important because we need to know which input tag is associated with which ability.

18:03.570 --> 18:09.780
So once we have that info struct, we're passing it into broadcast, broadcasting it so our widgets

18:09.810 --> 18:16.530
can then receive that broadcast and then do their own thing with that info After defining the lambda

18:16.530 --> 18:23.040
and binding it to our for each ability delegate, we call for each ability on the ability system component

18:23.040 --> 18:30.060
passing in that delegate and then the ability system component in for each ability is going to loop

18:30.060 --> 18:36.630
through its activatable abilities using an active scope lock and execute the delegate that we've passed

18:36.630 --> 18:37.170
in.

18:37.170 --> 18:44.070
So we're passing in one delegate and it'll be executed for all abilities in our Activatable abilities.

18:44.370 --> 18:52.440
Now get input tag from spec can also be marked static, so these two handy utility functions can both

18:52.470 --> 18:53.430
be static.

18:53.580 --> 18:57.060
So making sure that is there.

18:57.300 --> 19:06.030
And now things are all in place and the only thing left is to go into our widgets and register some

19:06.030 --> 19:12.120
kind of event to bind to the ability info delegate so it can receive that ability info.

19:12.150 --> 19:17.550
Now another thing is here we are creating a lambda and passing it into a function.

19:17.700 --> 19:26.090
So recall that we've done this before and we could easily replace that lambda with a function pointer.

19:26.100 --> 19:31.320
So that's something that I leave to you as an optional exercise if you'd like to do that.

19:31.320 --> 19:38.010
But for now, I think we're ready to start binding events to our delegate.

19:38.040 --> 19:42.300
We're going to broadcast for each of our abilities and we'll do that next.

19:42.750 --> 19:43.890
So excellent job.

19:43.890 --> 19:45.960
And I'll see you in the next video.
