Welcome back.
Now let's go back to our data table we just created in blueprints.
UI data.
Here it is.
And we added one row, but we didn't fill anything out.
But we did add four new gameplay tags to our project.
So for this first row, I'm going to set my message tag.
We have our messages and I'm going to set it to health crystal.
Now when we look up Rose to find a specific row in a data table, we can look them up by name.
So for my row name, I'm going to have the same name as my message tag.
So I'm going to double click on new row here and call this message dot Health Crystal.
And we're going to look this up by name.
Now, this method is a little bit error prone because you can have typos here, but as long as you type
it correctly, you should be fine.
For this reason, I often like to use data assets instead of data tables and we'll be using data assets
throughout the course as well.
But I think it's good to know how to use both data assets and data tables.
And we're going to use a data table for this particular application.
So we have a message tag.
We can also have a message.
And for my health, Crystal, I'm going to have the message picked up.
Health Crystal.
Now, we don't have a message widget just yet.
We still need to make one of those, but we can choose an image.
And in our project, if we search for t underscore health, we have a t health crystal.
And if I browse to it, it's in this UI pickups.
So now our image has the health crystal.
The only thing missing is the message widget.
So we're going to want to make that.
But until we've got that, we can add the rest of these rows.
I'd like four rows.
I'm going to add another one.
And for this next one, I'm going to go to message and choose Health Potion.
And this row will have the same name as the tag.
So message dot health potion and our message will be picked up a health potion.
And for this image, I'm going to search for t underscore potion and I'm going to find t potion red.
That will be the texture.
So I'll do this two more times.
I'll click add.
And for this one we're going to choose the message.
Tag message Manna Crystal.
I'm going to name the row message dot manna crystal.
I'm going to put the message into the text box.
Picked up a manna crystal and for the image, I'm going to search for Manna Crystal and choose that
texture.
And finally, one more and we'll give this row the tag message manna potion.
We'll name the row message dot manna potion.
I'll give it a texture.
I'll search for T potion blue and for the message I will say picked up manna potion.
Or picked up a mana potion.
I don't know how I worded the others.
Picked up health.
Crystal picked up a health potion.
Let's just say a in all of them picked up a health crystal, a mana potion, picked up a mana crystal
picked up a mana potion.
That looks good.
Okay, so there's data in all four of the rows and the row name is the same as the tag.
So we'll be looking things up by name.
So now that we have four rows, this is great.
I'd like to be able to look these up in our lambda in C plus plus.
But before we do that, I want our gameplay effects to each have these message tags.
So what I'm going to do is go into the blueprints folder into actor, and then we have Crystal and Potion.
We'll go into potion first and Open G potion Heal.
Now we added to the gameplay effect assets tags.
That's what we're sending over to the widget controller.
But we just added some tags that we had just because we had them.
I'm going to clear all and if I compile you'll see that removes it completely and I'll add to the added
tags.
We're going to go message and this is G potion heal.
So I'm going to choose message Health potion.
And if I compile, it goes up to the combined tags.
So we can save that and I can open potion mana.
I'm going to clear all.
And then for the added tags, I'm going to add message mana potion, compile and save, and then I can
go into my crystal folder and tag crystal heal and clear all I don't need to compile.
I was just doing that to show that combine tags will be updated, but I'm going to add to the added
tags.
This is crystal heal, so I'm going to choose message health crystal.
If I compile, you'll see that the old tag is gone.
The new tag is there and if I open Crystal Mana, it looks like I have nothing here.
I'm going to add to the added tags message mana crystal compile and we can even test this by pressing
play and picking up some crystals and some potions.
And we'll see that we get those message tags because we're receiving those.
So we know that that's working.
Everything's looking good on that front.
So we're done in the editor for now, I'm going to save all and close and we need the ability to look
up the correct row in our message widget data table.
Now, I'm only concerned right now with the overlay widget controller, so I'm going to right click
on the header file, close other tabs and then open the CPP with alt o or control k o.
And I'm back here in the CPP file.
Now we're still just in bind callbacks to dependencies right here in our lambda.
All we're doing is receiving the gameplay tag container that contains our asset tags for any effect
that has just been applied.
And we're printing a message to the screen.
That's all we're doing.
But now I'd like to make a lookup in our widget data table.
So how are we going to do that?
Well, I'd like to be able to find the data table row that corresponds to the gameplay tag, right?
This tag here as we're looping through all the tags in this gameplay tag container called asset tags,
I'd like to be able to take a data table and a gameplay tag and return the row.
So to do that I'd like a function, but I'd like this function to be sort of versatile.
I'd like it to be able to return any sort of row, any sort of data table row by just taking in a generic
data table and a gameplay tag.
So let's make that function.
I'll go back to the header file and in the protected section I'm going to make a really nice generic
function and the return type is going to be a data table row.
But I'd like this function to be able to return any type of data table row.
So I'm going to have the return type be t star, in other words, a pointer to type T, How can I do
that?
Well, this is going to be a template.
So template function we use template with angle brackets and we say type name followed by T and T is
going to be our type parameter.
In other words, this function can be called with any type and this function will be called get data
table row by tag.
And I'd like to be able to pass in a new data table that will be my pointer.
We'll call this data table I'd like to pass in a const gameplay tag reference called Tag.
So we have a template function here and it's going to take in a data table and a tag.
Find the row and return that row.
So let's generate a definition.
And if I let writer do it for me, it's going to make this definition right here inside the header file,
which is pretty common for template functions.
In fact, some compilers won't let you put it in the CPP file at all.
Some compilers are smart enough to look in there, but we're going to keep it right here and Visual
Studio should do the same.
And when you have the function definition, notice we still have template type name above it that's
required for template functions and this function is going to be designed to find a data table and return
the row no matter what the row type is.
Right?
So really, this is a more useful function than we should have in just the widget controller class.
This is the kind of thing that's worthy of being in a static function library of sorts, right?
So when we get to the point in this course where we make our own function libraries spoiler, we're
going to have things like this in it because this is more versatile than just our overlay widget controller
needs.
So anyway, we have our function and we want to find the row now.
Data table.
The U data table type has a function so we can take data table arrow operator and that function is called
Find Row.
Now find Row itself is a template function that requires a type.
Well, the type that we want to find is going to be T, and this function takes inputs.
It takes a row name, it takes a context string which we don't have to really worry about, and it takes
an optional BOOL that says Warn if row missing.
We'll leave that out.
It has a default value of true so we'll get a warning if we try to find a row that doesn't exist.
So the first input is the only one that really matters and that's going to be the name.
We're finding the row by name.
And remember, the data table row is going to be the same as the tag.
So what we can do is we can take the tag and we can use git tag name because git tag name returns an
F name and that's going to be the name of the tag that's identical with what we named our row.
So this will just happen to work.
Now we need a context string and the context string isn't used for anything.
We can just pass in an empty text string.
That's totally fine.
So find row returns us a look t star because find row is a template function as well.
It uses T and it finds the row and returns the T so we can store this in a local variable of type T
star.
We'll call it row like so.
And once we have the row, we can check because this is a pointer.
We can check to see if it's a valid pointer.
Right?
We can say if row return row row is a T star after all.
And if row is null, we'll return null.
In fact, this is the same thing as return row, same thing.
And in fact, this can just be condensed down to return.
This line, right?
So we really could just do this return.
This line.
So simple function.
You could argue that maybe you don't even need the function and you could just have all this, but this
is a bit of an ugly line.
So I think git data table row by tag is better and we're going to use that.
So here in our lambda, what we can do is we can call get data table row by tag.
And because this is a template function, we have to specify the type, we have to specify T and we
called our struct for our row f UI widget row.
So we're going to specify that.
And we also have to pass in the data table.
And we made that a variable, didn't we?
We made it right here.
It's message widget data table.
We're going to pass in that.
And then we need the tag.
We have the tag right here.
Where?
Inside this for loop.
So we're going to pass in the tag.
Okay.
So that's what we want to do in our lambda.
Now we get the red squiggles and if we hover over them, we see it says invalid use of function, says
the function name.
This is not captured.
Now, this is a very important aspect of lambdas.
When we have a lambda, this is, as we've said, an anonymous function, right?
And it has input parameters.
So we can pass in something like a gameplay tag container as we have here.
And we can do things like call a function on G engine because that's global.
But now we're trying to call a member function that exists on the overlay widget controller, and this
anonymous function doesn't know about the overlay widget controller.
It only knows about what we're passing in and perhaps anything global to the project like this function
it doesn't know about.
Get data table row by tag.
That's where these square brackets come in.
The square brackets are for captures.
If we want to access a member variable from something, then that thing, that class that has the member
variable must be captured within the lambda.
Now we can capture variables, we can capture things by reference, we can capture things by pointer.
And if we want to be able to access get data table row by tag, we have to capture this this object
that we're in.
So a pointer to this is simply the keyword this, right?
So notice as soon as I put this in the square brackets, we're now capturing this, the object that
we're in and that object has get data table row by tag.
It's now defined within the lambda scope within the body of the lambda.
So if you want to call a member function in a lambda, you have to capture that object of the class
that that function belongs to.
So now that we're capturing it, we can call get data table row by tag and that's great.
Now we have the row.
We can even store this in a local variable.
Get data table row by tag, returns a pointer to it so we'll have an UI widget row, we can call it
row.
And now that we have that, we have a pointer to the row and we can do with it what we please.
Now, what we please.
What we want to do is we want to send this row up to the widget.
We want to broadcast it up to the widget.
In other words, we want to delegate that can send through an UI widget row and we're going to do that
next.
So great job and I'll see you soon.