Welcome to your next quest.
In this quest, we are going to want to add some things to our effect context.
You see in the exec calc, we've determined whether we got a successful debuff, but now we need to
get that information on through.
I'd like to send that info through to the attribute set and the effect context.
So for your quest, I'd like you to add some variables to the effect context.
We want to know whether or not it was a successful debuff by the time we hit the attribute set.
So add a boolean for a successful debuff, call it b is successful debuff and add some floats as well.
We need to send the debuff damage as well as the debuff duration and the debuff frequency.
Now if you'd like a bonus, see if you can send the damage type as well.
So add that to the effect context if you want an extra challenge.
Now the damage type is going to be trickier because these variables need to be serialized.
They need to be added to net serialized.
Right.
So that's part of your challenge, not just adding these variables, but taking care of serializing
them as well as adding getters and setters for them.
And if you want to take it above and beyond add functions in or a ability system library for getting
and setting them.
So damage type is an gameplay tag that's more complicated than serializing a boolean or a float.
So if you feel like that extra challenge, add the damage type and I'll give you a hint for the damage
type.
If you don't want to hear that, pause the video now.
But if you want the hint, here it is.
Take a look at how a hit result is serialized.
So pause the video and conquer this quest now.
So our challenge is to add some more variables to our custom effect context class.
So I'm going to close all my tabs and open aura ability types dot h, and we're going to add some more
variables here.
So down in the protected section, they can come in down here.
I'm going to add a new boolean called B is successful debuff and it'll be set to false by default and
it needs to be a boolean.
Now in addition to this boolean, we need some floats.
I need a float called debuff damage.
It'll be zero by default.
I need a float called debuff duration.
That'll be zero by default and I need a float called debuff frequency that will be zero by default as
well.
And I'll put you property macros on every single one of these.
So that's step one.
If only this challenge were that easy.
Step two is making sure that these are serialized.
That's step two.
So we can break step two down into sub steps.
First, we need to look at our ability types dot cpp and see how we're serializing everything else.
If we're saving, then we're flipping bits and we're kind of going in order here.
The order sort of matters, right?
And at the very end we're flipping bits seven and eight for B is blocked hit and B is critical hit.
We're going to flip more bits.
Now we need to flip a bit to represent whether or not we should serialize B is successful debuff and
we should only flip it if b is successful.
Debuff is true, otherwise we can save on some bandwidth.
So I'm going to place an if and say if b is successful debuff, then we'll flip the next bit.
So we're going to take rep bits.
We're going to use a bitwise or equals and we'll use one left shift nine.
So only if it's a successful debuff we'll flip that ninth bit.
We can use the same optimization techniques for the debuff variables.
If they're zero, there's no point in replicating.
So we can flip bits ten, 11 and 12 only if these are nonzero.
In fact, if they're greater than zero it doesn't make sense for debuff damage, duration or frequency
to be negative.
So I'm going to check if debuff and I want to go in order.
Debuff damage is greater than zero.
Then I'll go ahead and flip the next bit.
I'll just copy this and paste it, but we're going to flip bit number ten.
Next we need debuff duration and frequency.
So I'm going to take the if statement copy, paste it and change this to debuff duration.
And we'll flip it 11 for that.
And then one more time, copy paste.
This will be debuff frequency.
And we'll flip the next bit, which is bit 12.
So that takes care of flipping the bits.
After that, we have the serialization part, the archiving into our archive.
So we're going to go all the way down to after we've archived be is critical hit and we're going to
archive the next one.
So first we check to see if the next bit has been flipped.
That's nine and then we archive B is successful debuff that one was pretty easy.
Next we check to see if the 10th bit has been flipped.
If so, we archive our debuff damage.
We have to go in order.
It doesn't have to be in the same order as the variables are declared.
It has to be in the same order that we flipped the bits up here because those bits represent these variables.
So it's debuff damage, duration and then frequency.
So here we got debuff damage.
Next we're going to check the 11th bit.
So change this to an 11 and this will be debuff duration.
And the frequency is last.
So we're going to get the if statement, copy it, change this to the 12th bit and this will be debuff
frequency.
And there we go.
We now have taken care of serialization for our four new variables, and we can add getters and setters.
But before we do that, I'm going to tackle the bonus challenge, serialize the gameplay tag for damage
type.
Now, this one is a little bit more complicated, but nothing we can't handle.
We can just take a look at how we did it for the f hit result and as you can see, the F hit result
here on our custom effect context is a protected member variable, which is a shared pointer.
It's a smart pointer.
So this is one of those few cases where you'll see a hit result stored as a pointer.
The member on the effect context is a shared pointer.
So that's what we're going to have in our ability types.
So we're going to have a shared pointer of type F gameplay tag instead of hit result, we're going to
call it damage type.
Now we don't give this a new property.
It's a shared pointer.
Garbage collection is not handled for shared pointers by you property.
The shared pointer and other associated smart pointers handles the automatic memory management.
So now that we have a gameplay tag, let's take a look first at way up here where we have our hit result.
We're just checking to see if it's a valid hit result before flipping the bit.
We're going to do that here.
So we're going to say if and we're going to use damage type dot is valid.
If it's a valid pointer, then we'll flip bit 13.
And then down here we can see what's going on for the hit result.
If that bit has been flipped, we do something.
If we're loading, if we're in the loading mode, then think about this.
We're not saving, we're loading, which means the hit result has already been serialized.
Otherwise we wouldn't be inside this if statement and we're about to unserialize it.
So what we do is check if that hit result pointer is valid.
If it's not, then we create a new one.
We dynamically allocate a completely new shared pointer for the hit results because there doesn't exist
one yet.
After that we can take that hit result and call net serialize on it and that takes care of the archive
business.
Right.
It's like doing this for all types.
That archive is overloaded.
The left shift operator for archive doesn't have the left shift operator overloaded for hit results,
but hit results can handle it.
It takes the archive, the map and the boolean in as input parameters.
We're going to follow this same pattern for our gameplay tag so we can copy this whole if statement.
And all the way down at the end.
We're going to check to see if that 13th bit has been flipped.
And we're going to also see if the archive is loading and then we'll check our damage type.
We're going to say if damage type is valid.
If it's not, notice the negation operator, then we create a new damage type in a shared pointer of
type F gameplay tag.
And we create dynamically a new gameplay tag in this shared pointer.
And by the way, Ryder says you can make this with make shared if you wanted to do that.
Now, after we've created that new shared pointer and assigned it to damage type, if we're in the loading
mode, then we take damage type and net serialize.
We do that whether we're saving or loading.
But if we're loading, we had to create a new one.
Okay, so now that we're serializing these based on rep bits, it's very important that we come back
up to our serialized bits because we're now serializing more than just nine before we were serializing
nine of those bits.
Now we have.
For more.
So now that it's a total of 13, we have to pass that in to serialized bits.
So this will now be a 13.
All right.
So now we've handled net serialize for our damage type gameplay tag.
And the last thing to do, at least in this struct, is to create some setters and getter functions
in our ability types.
So we'll go up here and we'll have setters and getters for each of our new variables.
So first the getters we're going to make a bool called is successful debuff.
It'll be const and return that boolean b is successful debuff simple enough.
We'll also have a float returning function called get debuff damage.
Const and it will return debuff damage.
Let's make a float called get debuff duration, which is const and returns debuff duration.
We'll have a float called get debuff frequency.
Const return debuff frequency and we'll have a function that returns a shared pointer of type F gameplay
tag called get damage type.
This will be const and we'll return damage type.
So there's our new getters.
We need setters as well.
So we're going to have void set is successful debuff.
Which will take in a bull called B and is debuff.
We'll just call it that.
And we'll set b is successful debuff equal to b and is debuff.
We'll have a void function called set debuff damage.
Which takes a float called in damage.
And sets debuff damage to end damage.
We'll have a void function set debuff.
Duration, which takes a float called in duration and sets debuff duration.
Equal to in duration.
We'll have a void set debuff frequency.
Taking in a float in frequency and setting debuff frequency to in frequency.
So with that, we have setters and getters.
And perhaps the last step of all of this is to add some functions to our aura ability system library
that can set these by taking in input parameters, including a gameplay effect context.
So we'll go ahead and open up our ability system library and all the way up at the top is where I'm
interested because we have a couple of functions.
Actually, it's not exactly at the top.
We have is blocked, hit is critical, hit and so on.
I'm going to make getters that take in effect context handles that correspond to my getters here is
successful, debuff get debuff damage and so on.
So I'm going to take is blocked hit, I'm going to copy it and paste it and I'll have a static bool
that is called is successful debuff.
And it can have all the same stuff.
Same category.
Blueprint pure.
All of that.
I'll also declare a new function that returns a float.
And this will be called git debuff damage and I'll make three more functions that return a float that
get the other debuff parameters.
Get debuff duration.
Get debuff frequency.
And I think.
Is that it?
Okay.
That's all of the debuff functions.
The last one would be get damage type.
I'd like jet damage type to just return a gameplay tag for me, so I'm going to go ahead and make another
function, but this will just return a gameplay tag.
We'll handle all the pointer business in the function to make it easy.
So this will be get damage type.
Okay, so we have a number of new functions.
Five to be exact.
Let's highlight them all and generate definitions for all of them.
Now these are going to be similar to their counterparts like is blocked hit, for example.
We're going to get our aura effect context use a static cast to for a gameplay effect context and then
return the value that we retrieve from the getter function on the aura effect context.
So really I can just copy that, paste it over here and call is successful debuff we'll do something
similar for get debuff damage.
The difference here is we're going to have to call get debuff damage and if this, if fails we have
to return a float.
So it's got to be zero.
So I'll copy this, we'll paste it in get debuff duration only we're calling get debuff duration and
we'll paste it in get debuff frequency only we're calling get debuff frequency.
Now the gameplay tag situation is a little bit different.
So how are we going to handle that?
Well, let's start by copy pasting and what we return down here would be an F gameplay tag.
Right.
An empty one.
But here is where we're going to do something a little different.
What we have to do is check if we take the or effect context, we get damage type.
What we call is valid on it got to be valid.
And if it is valid then it's safe to dereference that pointer.
So we say return and we dereference or effect context get damage type.
That way we safely dereference and if we get to the end we return an empty gameplay tag.
Okay, let's go ahead and compile and make sure that we haven't made any mistakes.
And with that we have a successful compile and we now have some easy to use ability system library functions
that we can pass in an effect context handle to set these parameters.
We know that our effect context and our ability types has some additional parameters in particular ones
related to debuff and it also knows its own damage type.
This is going to be really useful because we can pass that info along in the effect context and use
it later in the damage pipeline.
Excellent job.
We'll continue with this in the next video.