WEBVTT

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

00:08.160 --> 00:13.920
Now that we have a function to save the world, we need a function to load the world.

00:13.920 --> 00:16.200
So let's go to aura game mode base.

00:16.200 --> 00:21.240
And just under save World state we'll make a new function called Load World State.

00:22.620 --> 00:27.990
And this can also take in a you world pointer called world.

00:29.670 --> 00:33.480
Let's go ahead and generate the definition for this.

00:36.820 --> 00:40.990
And let's think about how we can go about loading the world state.

00:41.140 --> 00:44.380
Well, first of all, we need to know what that world name is.

00:44.380 --> 00:49.930
And just like we did up here and save world State, we're going to get the world name through git map

00:49.930 --> 00:54.430
name and remove from the start of it the streaming levels prefix.

00:55.010 --> 00:57.680
So let's get those two lines right here.

00:57.800 --> 01:00.920
And I'd also like the game instance.

01:00.920 --> 01:06.470
So I'm going to get these two lines where I'm getting or a game instance as well.

01:06.470 --> 01:08.060
We'll go ahead and get those.

01:08.060 --> 01:13.880
And next I want to check to see if the save game exists.

01:13.880 --> 01:16.850
It has to exist if we hope to load it.

01:16.850 --> 01:21.350
So we're going to check if you gameplay statics.

01:23.690 --> 01:31.370
Does save game exist and we're going to check for the slot name using Aura Jai.

01:33.120 --> 01:40.020
Load slot name and or a GI load slot index.

01:41.610 --> 01:49.710
If this save game object exists, we can then proceed to iterate over the actors in the world, at least

01:49.710 --> 01:54.300
those that implement our save interface, and we can load them.

01:54.300 --> 02:02.670
We can do anything we wish, such as restore those serialized variables that we serialized and perhaps

02:02.670 --> 02:04.470
call a load function on them.

02:04.470 --> 02:06.420
They have an interface, after all.

02:06.420 --> 02:10.680
So what we're going to do is iterate, just like we did up here.

02:10.800 --> 02:16.380
We're going to use f actor iterator, iterating over the actors in the world.

02:16.380 --> 02:20.220
I'm going to copy the line where we dereference the iterator as well.

02:21.290 --> 02:24.380
We're just going to need a closing curly brace there.

02:24.560 --> 02:29.990
And once we have that actor, we can filter out actors that don't implement the interface.

02:29.990 --> 02:38.660
We can say if not actor implements the you save interface.

02:38.690 --> 02:40.850
Don't forget your parentheses there.

02:40.850 --> 02:42.830
And we can use continue.

02:43.010 --> 02:49.100
And that way we only continue for actors that do implement the interface.

02:49.430 --> 02:50.060
Okay.

02:50.060 --> 02:51.170
So what next.

02:51.170 --> 02:58.850
Well I want to get all the actors in the array for the f saved map that has this map name in our save

02:58.850 --> 03:00.080
game object.

03:00.080 --> 03:02.000
So where's our save game object.

03:02.000 --> 03:03.410
We need to get that don't we.

03:03.410 --> 03:08.120
Right here inside of does save game exist our if statement.

03:08.360 --> 03:09.740
Let's load it.

03:09.740 --> 03:13.730
Let's use you load screen save game.

03:13.730 --> 03:20.990
We'll call it save game and we'll cast to you load screen save game.

03:20.990 --> 03:22.430
What are we going to cast?

03:22.430 --> 03:23.840
Well let's load it with you.

03:23.840 --> 03:25.460
Gameplay statics.

03:27.710 --> 03:33.020
Load game from slot using our aura GI.

03:34.610 --> 03:40.880
Load slot name and our aura GI load slot index.

03:42.580 --> 03:44.530
Don't forget your semicolon.

03:44.530 --> 03:47.650
Now we have our load screen save game here.

03:47.650 --> 03:48.280
Right.

03:48.280 --> 03:49.630
Let's check if it's null.

03:49.630 --> 03:54.190
Let's say if save game equals null pointer.

03:54.190 --> 03:58.660
And let's go ahead and log an error.

03:58.660 --> 04:02.290
Let's use u log log ora.

04:04.430 --> 04:13.940
Error text and we'll just go ahead and say failed to load slot and we'll return.

04:16.070 --> 04:18.020
So something's gone wrong.

04:18.020 --> 04:20.330
If we haven't been able to load.

04:20.330 --> 04:27.560
Now that we have our save game down here, let's iterate over its map that has the world name that we

04:27.560 --> 04:28.310
want.

04:28.430 --> 04:38.120
So in other words, let's say for f saved actor, saved actor and save game and we have a function get

04:38.120 --> 04:43.760
saved map with map name passing in world name.

04:44.270 --> 04:52.370
Now this is the F saved map, which contains the array of saved actors which we can access through the

04:52.370 --> 04:54.650
dot operator like so.

04:54.650 --> 04:56.750
So we're getting our save game object.

04:56.750 --> 05:01.580
We're getting the map with this name and looping over it saved actors.

05:01.580 --> 05:04.970
And for each saved actor we're getting that data.

05:04.970 --> 05:11.570
And this is already inside of a for loop looping over all the actors, at least those that implement

05:11.570 --> 05:12.410
the interface.

05:12.410 --> 05:14.510
So let's check if the names coincide.

05:14.510 --> 05:23.210
Let's say if saved actor dot actor name equals actor get f name.

05:23.390 --> 05:26.090
That's how we got it in the first place, after all.

05:26.390 --> 05:31.100
And if these actors have the same name, we want to load it up.

05:31.100 --> 05:33.500
Now remember we saved the transform.

05:33.500 --> 05:36.110
But my checkpoints are not mobile.

05:36.110 --> 05:39.440
They're not something that we should update the transform for.

05:39.440 --> 05:40.640
That's okay.

05:40.640 --> 05:46.610
We can give our save interface a function that can return a boolean.

05:46.610 --> 05:51.740
If we want to know whether or not we should update the transform for whatever reason, right.

05:51.740 --> 06:01.130
So we can take our saved interface and create a bool returning function should load transform and we

06:01.130 --> 06:02.240
can give it a new function.

06:02.240 --> 06:04.340
Let's give it blueprint callable.

06:04.340 --> 06:06.680
Let's give it blueprint native event.

06:08.020 --> 06:09.520
To make it easy to call.

06:09.520 --> 06:12.940
And let's give our checkpoint the function.

06:12.940 --> 06:20.350
Let's go ahead and make a comment here that says save interface.

06:20.350 --> 06:23.830
Let's close it off with end save interface.

06:24.160 --> 06:31.660
And let's override bool should load transform implementation override.

06:31.660 --> 06:34.870
And for this I'm just going to implement it here.

06:34.870 --> 06:36.010
Return false.

06:36.010 --> 06:39.310
And this should have the virtual specifier of course.

06:39.310 --> 06:40.990
So for checkpoints it's easy.

06:40.990 --> 06:42.040
Don't do it right.

06:42.040 --> 06:45.400
Don't update transform on load.

06:45.400 --> 06:47.950
And here in the Or game mode we can check that.

06:47.950 --> 06:57.040
We can say if and we'll use I save interface execute should load transform passing in the actor.

06:58.310 --> 07:01.400
It has to be the actor, not the saved actor, right?

07:01.400 --> 07:04.160
The saved actor is just a puny little struct.

07:04.160 --> 07:06.650
This function needs the real actor.

07:06.650 --> 07:11.180
And if we should, which our checkpoints are returning false.

07:11.180 --> 07:21.350
Here we're going to take the actor and set actor transform to the transform and our saved actor struct.

07:21.950 --> 07:29.600
So just there, in case you happen to have actors you do want to update the transform for, just remember

07:29.600 --> 07:32.630
you have to implement should load transform.

07:32.630 --> 07:35.180
If you implemented it this way that we did here.

07:35.180 --> 07:44.180
Now we also are going to want to deserialize all those variables that we serialized using the fancy

07:44.180 --> 07:45.560
archives above.

07:45.560 --> 07:51.290
Now, those fancy archives kind of work the same way in reverse.

07:51.290 --> 07:54.170
So we make an F memory reader.

07:56.680 --> 07:59.380
We can call it memory reader.

07:59.380 --> 08:10.600
We initialize it with the saved actor dot bytes, and we create an F object and name string proxy archive.

08:10.840 --> 08:15.160
We can call it archive and we initialize it with the memory reader.

08:15.160 --> 08:17.860
And true just like last time.

08:17.860 --> 08:19.630
And it's for a saved game.

08:19.630 --> 08:26.920
So we take archive dot R is save game and make that true.

08:27.040 --> 08:34.420
And then to deserialize our actor we take the actor and we call serialize on it.

08:34.420 --> 08:41.200
Yes, it's serialized and not deserialize, but in this case we are deserializing it.

08:41.200 --> 08:45.730
And all of those binary bytes are converted back into variables.

08:45.730 --> 08:51.730
We'll say converts binary bytes back bytes.

08:52.240 --> 08:54.100
I don't know why I want to put an L there.

08:54.100 --> 08:58.510
Bytes back into variables.

08:58.510 --> 08:59.320
There we go.

08:59.770 --> 09:00.400
Okay.

09:00.400 --> 09:03.310
So we've deserialized all those bytes.

09:03.310 --> 09:09.190
And the last thing we can do is anything else we want to do when loading something.

09:09.190 --> 09:09.820
Right.

09:09.820 --> 09:14.620
For instance our checkpoint has a reached variable.

09:14.620 --> 09:21.490
And if we want that checkpoint to be glowing and disabled as far as its overlap sphere is concerned,

09:21.700 --> 09:28.060
as soon as we load it, then we can have a function on our save interface for loading up the actor.

09:28.060 --> 09:31.990
So we can say right here and save interface, we can make a new function.

09:31.990 --> 09:38.260
By the way, I forgot my semicolon there, but we can make a new function called void load actor, for

09:38.260 --> 09:39.100
example.

09:40.570 --> 09:47.290
And let's just make this a blueprint callable blueprint native event and go ahead and implement this

09:47.290 --> 09:48.460
in the checkpoint.

09:48.460 --> 09:56.590
So right here next to our other save interface function it'll be virtual void load actor implementation.

09:56.590 --> 10:04.330
And here in load actor implementation let's just say we want to check our be reached variable.

10:04.330 --> 10:11.950
We can say if be reached then we can just start glowing and deactivate basically everything we did in

10:11.950 --> 10:14.680
Handle Glow effects sphere collision enabled.

10:14.680 --> 10:16.360
Set that to no collision.

10:16.360 --> 10:21.850
Replace the material with the dynamic material instance and then call checkpoint reached, which is

10:21.850 --> 10:25.840
a blueprint implementable event that will run a timeline and glow.

10:25.840 --> 10:33.190
So load actor implementation if reached is true, we can simply call handle glow effects.

10:37.150 --> 10:45.040
So now that there's this load actor interface function, whenever we load an actor, we can call that

10:45.040 --> 10:52.930
we can take I save, interface and execute load actor and pass that actor in the real actor, not the

10:52.930 --> 10:55.390
saved actor struct proxy.

10:55.390 --> 10:56.110
All right.

10:56.110 --> 10:59.980
So now we have functions to save and to load world state.

10:59.980 --> 11:02.860
And the crazy thing is these could both be const.

11:02.860 --> 11:06.460
So we might as well be const correct here.

11:06.460 --> 11:09.160
And make them both const while we're here.

11:09.160 --> 11:13.870
So we can add those to both the function declaration and the definition.

11:13.870 --> 11:15.190
There's save world state.

11:15.190 --> 11:16.510
Here's load world state.

11:16.510 --> 11:19.840
And now that we have these we need to decide when to call them.

11:19.960 --> 11:23.650
Now I'd like to save the world state every time we reach a checkpoint.

11:23.650 --> 11:30.160
So in on sphere overlap when we're telling our player interface execute save progress.

11:30.160 --> 11:36.160
So basically for our aura character we're telling it go ahead and save your progress.

11:36.160 --> 11:37.510
Handle glow effects.

11:37.510 --> 11:44.470
While I'm at it, I'd like to first of all, first things first set be reached to true.

11:44.950 --> 11:50.020
Because if we save world state before setting this boolean, it will not be serialized.

11:50.020 --> 11:57.310
So we have to do that first and then after setting be reached to true, I'd like to get the game mode

11:57.310 --> 12:00.490
and tell it to save the world state.

12:00.490 --> 12:01.810
Let's do that.

12:01.810 --> 12:05.080
We'll make sure after we set be reach to true.

12:05.080 --> 12:16.360
So we're going to say a aura game mode base header included their aura GM equals cast to A or a game

12:16.360 --> 12:19.180
mode base, and we'll get it with you.

12:19.180 --> 12:19.660
Gameplay.

12:19.660 --> 12:20.770
Statics.

12:22.560 --> 12:24.030
Get game mode.

12:24.360 --> 12:26.490
Passing in a world context object.

12:26.490 --> 12:27.720
You know what it is.

12:27.720 --> 12:28.920
And.

12:30.350 --> 12:31.820
If this is valid.

12:34.290 --> 12:39.150
We'll take Aurum and call save world state.

12:39.150 --> 12:42.210
And it takes a world so we can pass in get world.

12:42.840 --> 12:46.710
So on sphere overlap, we'll go ahead and save the world state.

12:46.740 --> 12:48.210
Now when do we load it?

12:48.240 --> 12:53.910
Well, let's go ahead and load the world state when we're loading up all of our player variables in

12:53.910 --> 12:59.280
the character class, let's go to private character or a character dot cpp.

13:00.030 --> 13:03.180
Oh, I'm noticing I have a dead include here for the game instance.

13:03.180 --> 13:11.670
I'm going to get that out and I'm going to find possessed by where we're calling load progress.

13:11.670 --> 13:17.850
Right here is where I'd like to actually call load World State as well.

13:17.850 --> 13:21.000
I'm going to copy this line where we're getting our game mode.

13:21.000 --> 13:22.920
I'm going to wrap it in an if statement.

13:25.050 --> 13:32.730
And take our A game mode and call load world state passing in get world.

13:32.880 --> 13:35.070
And with that we're saving.

13:35.070 --> 13:36.090
We're loading.

13:36.630 --> 13:39.720
All we have to do is test things out.

13:40.110 --> 13:41.880
So let's compile and launch.

13:42.240 --> 13:43.140
Okay.

13:43.140 --> 13:51.330
So I'm going to first of all go into my maps and to load menu I'm going to press play.

13:51.330 --> 13:54.000
And I'm going to delete this slot and make a new one.

13:55.580 --> 13:57.440
Select it, press play.

13:57.440 --> 14:00.020
Let's go ahead and reach a checkpoint.

14:00.530 --> 14:01.610
There we go.

14:01.610 --> 14:06.320
We can exit, come back, select that slot and press play.

14:06.320 --> 14:07.460
And look at that.

14:07.460 --> 14:09.650
It's starting to glow now.

14:09.650 --> 14:17.270
The cool thing is I can go over to this checkpoint over here and reach it and exit and come back.

14:18.320 --> 14:23.570
And not only are we at this checkpoint, but it's already glowing and we can come back and check the

14:23.570 --> 14:28.340
other checkpoint we've previously reached, and it's glowing as well.

14:28.340 --> 14:30.140
So we're saving the world state.

14:30.140 --> 14:33.230
We're saving that breached boolean.

14:33.230 --> 14:41.150
And you know, we went through an awful lot of effort just to serialize and save one single boolean.

14:41.150 --> 14:44.450
But the implications are much vaster than that.

14:44.450 --> 14:50.330
We can now save an arbitrary number of variables that have the save game specifier.

14:50.330 --> 14:59.210
And we can save not only an arbitrary number of actors per level that have our save interface implemented,

14:59.210 --> 15:06.050
but we can also save different actors in different levels, because that's my whole goal here, is to

15:06.050 --> 15:13.940
be able to transition from one level to another and back again, and load up all of the saved data for

15:13.940 --> 15:14.930
each world.

15:14.930 --> 15:21.110
I'd like to be able to remember which actors we've saved, which checkpoints we've reached, in which

15:21.110 --> 15:21.740
level.

15:21.740 --> 15:23.630
That's what I'm interested in.

15:23.630 --> 15:29.360
If I reach this beacon here, then go off to another level and then come back, I want this beacon to

15:29.360 --> 15:30.020
be reached.

15:30.020 --> 15:30.560
Still.

15:30.560 --> 15:34.910
I want it to still be lit up because I've reached it already.

15:35.060 --> 15:37.640
So that's what we'll do in the videos to come.

15:37.640 --> 15:44.210
We'll develop a system to travel from level to level and remember what we've saved.

15:44.600 --> 15:46.400
Great job and I'll see you soon.
