WEBVTT

00:00.080 --> 00:00.920
Welcome back.

00:00.920 --> 00:06.650
Now we're going to be creating a menu system for saving and loading the game.

00:06.650 --> 00:15.260
And this is going to involve some new technology, a new plugin for using the mVVM software architecture

00:15.260 --> 00:16.070
pattern.

00:16.130 --> 00:22.190
And this project was initially created in Unreal Engine 5.2.

00:22.190 --> 00:26.690
And as soon as 5.3 came around, it broke the project.

00:26.690 --> 00:32.270
So there were changes made to the mVVM plugin between 5.2 and 5.3.

00:32.300 --> 00:39.470
Now, the changes required to make this compatible with 5.3 are going to be outlined in this video.

00:39.470 --> 00:41.330
They're not huge changes.

00:41.330 --> 00:44.900
It's not a huge refactoring of the system by any means.

00:44.900 --> 00:48.590
It's just a couple additional pieces of code that we have to add.

00:48.590 --> 00:51.710
But this video is going to outline those changes.

00:51.710 --> 00:59.120
And as this video was created after the course was completed, it's going to be all about making those

00:59.120 --> 01:05.570
fixes to upgrade this to be compatible with 5.3 from the point of view of the finished project.

01:05.570 --> 01:08.690
So the answers are all here in this video.

01:08.690 --> 01:14.990
So if you're using 5.3 and above and you're following along with the creation of this menu system and

01:14.990 --> 01:19.250
you're getting blueprint runtime errors, well, the answers are all in this video.

01:19.250 --> 01:23.270
And you're going to come back to this video to figure out how to fix them.

01:23.270 --> 01:28.730
And this is just something that we have to deal with with rapidly changing software, especially when

01:28.730 --> 01:32.000
using plugins that are in the beta stage.

01:32.000 --> 01:36.560
So the good news is we do have a system that works in 5.3.

01:36.590 --> 01:42.320
There are just a couple of things that need to be changed from the original version of the project.

01:42.320 --> 01:49.760
So the best thing to do is to create this system, follow along with the videos and as the errors pop

01:49.760 --> 01:56.720
up, refer to this video to see why those errors pop up and how to fix them in order to make the system

01:56.720 --> 01:57.980
work in 5.3.

01:57.980 --> 01:59.330
And it's a really cool system.

01:59.330 --> 02:06.740
We can make a new game, we have save game slots here, and we can enter our name to create a new slot.

02:06.740 --> 02:10.670
We have a default map for our very first dungeon.

02:10.670 --> 02:16.190
Of course, we're going to be able to save our most recently reached map and our level, and we're going

02:16.190 --> 02:20.570
to later learn how to load in all of our abilities and stats.

02:20.570 --> 02:23.060
We can select a slot and we can try to delete it.

02:23.060 --> 02:24.920
We get an are you sure menu.

02:24.950 --> 02:26.810
We can cancel that operation.

02:26.810 --> 02:30.680
We can actually delete it from the Are you Sure menu.

02:30.710 --> 02:33.290
We can now have a vacant slot.

02:33.290 --> 02:35.240
We can enter our name again.

02:35.240 --> 02:40.370
We can choose the new slot, select it, press play, and then we can actually start a game.

02:40.370 --> 02:44.180
So it's quite a nice system that we have created.

02:44.180 --> 02:48.080
And we just need to make sure that it works with 5.3.

02:48.080 --> 02:53.450
So as you're developing it, if you run into blueprint runtime errors, jump back over to this video

02:53.450 --> 02:56.810
and watch it to see the changes that you have to make.

03:03.790 --> 03:04.870
Hello, everybody.

03:04.870 --> 03:05.440
Welcome.

03:05.440 --> 03:07.480
This is Stephen from the future here.

03:07.480 --> 03:10.810
And I have my aura project in front of me.

03:10.810 --> 03:15.820
And this project initially was created in Unreal Engine 5.2.

03:15.820 --> 03:25.600
And in 5.3, some changes have been made to the ViewModel plugin, and those changes have somewhat broken

03:25.600 --> 03:28.330
the project as we created it.

03:28.330 --> 03:34.060
So some changes need to be made to the project to make it work in Unreal Engine 5.3.

03:34.060 --> 03:40.600
So this video is going to go over those changes and talk about why those changes need to be made.

03:40.600 --> 03:47.260
So I have my aura project, and this is the exact project that is on the GitHub repo.

03:47.260 --> 03:54.310
Now I'm about to upgrade this project to Unreal Engine 5.3, as it's currently a 5.2 project.

03:54.310 --> 03:59.980
So what I'm going to do is simply switch Unreal Engine version to 5.3.

03:59.980 --> 04:01.180
I'm going to click okay.

04:01.360 --> 04:07.930
It's now going to generate the project files, and we'll go ahead and open up the project as is and

04:07.930 --> 04:09.100
see the problems.

04:09.100 --> 04:11.590
And we'll go ahead and fix those issues.

04:11.590 --> 04:15.580
So I'm going to go ahead and just open the project.

04:15.580 --> 04:18.970
I'll go ahead and rebuild the aura modules now.

04:19.450 --> 04:25.750
And I have my project loaded up and we're now in Unreal Engine version 5.3.

04:25.750 --> 04:31.000
So let's see what's broken in 5.3 in our project and let's see how to fix it.

04:31.000 --> 04:32.230
I'm going to press play.

04:33.070 --> 04:40.090
I'm going to go to the play button and it looks like I have something saved here in the first slot.

04:40.090 --> 04:43.540
I'm going to go ahead and just remove that now.

04:43.540 --> 04:48.040
As soon as I hit stop, I see the errors that have been generated.

04:48.040 --> 04:50.230
So we're going to talk about those.

04:50.230 --> 04:57.340
But let's go ahead and just open up our saved folder and go to save games.

04:57.340 --> 04:59.200
There's that load slot zero.

04:59.200 --> 05:01.570
I'm going to go ahead and just remove that.

05:01.570 --> 05:05.170
And now we'll start with no saved games.

05:05.470 --> 05:08.140
So we have no games saved here.

05:08.140 --> 05:11.230
I'm going to try to click plus to create a new game and I can't.

05:11.230 --> 05:12.160
It's broken.

05:12.160 --> 05:14.980
So let's go ahead and see what those errors are.

05:15.370 --> 05:18.130
They're actually blueprint runtime errors.

05:18.250 --> 05:24.130
Now what they say is access none trying to read property BP load screen view model.

05:24.130 --> 05:26.230
So this is related to the view model.

05:26.350 --> 05:31.810
And we got those errors when I tried to click on new game.

05:31.810 --> 05:36.130
So the new game button pressed function accessed none for the view model.

05:36.130 --> 05:45.430
And before we even did that the enter name and the vacant slots also had these errors where we got none

05:45.430 --> 05:51.010
trying to read property calling this function set BP load slot view model.

05:51.010 --> 05:56.860
If I click on that we're going to get this function set BP load slot view model.

05:56.860 --> 06:04.000
Now this is an auto generated function that gets created when you add a view model to any given widget.

06:04.000 --> 06:08.710
In our case the load slot enter name widget has a view model.

06:08.710 --> 06:14.260
If we go to the designer tab, we can see that it has its view models here, and it has a load slot

06:14.260 --> 06:15.100
view model.

06:15.100 --> 06:17.950
And we gave it the load screen view model.

06:17.950 --> 06:25.990
Now the reason that function was accessing none is because we were unable to successfully set the view

06:25.990 --> 06:29.860
model for this particular widget manually.

06:29.860 --> 06:37.090
If we select our load slot view model, we'll see that its creation type is manual, which means that

06:37.090 --> 06:44.470
that view model is created somewhere externally, and the view model should be set manually for this

06:44.470 --> 06:45.370
widget.

06:45.370 --> 06:47.800
And we're doing that in the widget switcher.

06:47.800 --> 06:53.140
So when we try to set the view model manually for this, we're failing to do so.

06:53.170 --> 06:58.090
Now if we go to that widget switcher it's our WB load slot.

06:58.090 --> 07:02.170
Widget switcher we have a function on this class.

07:02.170 --> 07:04.720
It's called initialize slot.

07:04.810 --> 07:10.150
And what this function is doing is it's calling find load screen view model.

07:10.150 --> 07:16.210
This accesses the load screen view model and it's calling our blueprint callable function get load slot

07:16.210 --> 07:17.680
view model by index.

07:17.680 --> 07:21.160
And those load slot view models are being created.

07:21.160 --> 07:22.630
We're creating them in C plus.

07:22.630 --> 07:28.510
Plus we can see where that's happening if we open up our project in our IDE.

07:29.450 --> 07:36.800
We're actually creating those load slot view models right here in initialise load slots in the load

07:36.800 --> 07:37.820
screen view model.

07:37.820 --> 07:43.370
Here in UVM load screen, we're using new object to create those load slots.

07:43.370 --> 07:48.440
So they are being created and we are successfully retrieving them here.

07:48.440 --> 07:56.390
Each time the widget switcher tries to set the load slot view model on its child widgets the widgets

07:56.390 --> 07:57.560
in the widget switcher.

07:57.560 --> 08:02.060
Here it does have a valid load slot view model.

08:02.060 --> 08:08.510
By this point, we can prove that by getting the name of that load slot view model, we can call get

08:08.510 --> 08:14.660
object Name and we can use a print string, node, print string, and print the name of that view model.

08:14.750 --> 08:23.810
So if I go ahead and play test the game by pressing play and going to this menu, we see those load

08:23.810 --> 08:24.830
slot view models.

08:24.830 --> 08:27.500
They are valid and they have been created.

08:27.500 --> 08:29.600
So that's not the problem.

08:29.600 --> 08:35.780
The problem is that we're failing to set the load slot view model here.

08:36.110 --> 08:37.490
So why is that?

08:37.490 --> 08:38.690
Why are we failing?

08:38.690 --> 08:44.690
If we go to our message log and we take a look at these errors where we're accessing none and follow

08:44.690 --> 08:48.410
them to this function, the set BP load slot view model.

08:48.410 --> 08:49.940
This is where we're failing.

08:49.940 --> 08:53.120
We're actually not able to set that view model.

08:53.120 --> 08:54.740
And that's this function here.

08:54.740 --> 08:56.390
Set BP load slot view model.

08:56.390 --> 08:57.650
Why is that failing.

08:57.650 --> 09:02.150
Well the answer is tied to the change in 5.3.

09:02.150 --> 09:08.270
And it's because we have a view model assigned to these widgets without any field notifies bound on

09:08.270 --> 09:09.290
those widgets.

09:09.290 --> 09:15.470
So we can go to the load slot, enter name here and we can check out here.

09:15.470 --> 09:22.100
In the designer, we can see that we do have a couple of view models assigned, but for the load slot

09:22.100 --> 09:28.070
view model it's creation type is manual, and we're failing to manually assign it because there are

09:28.070 --> 09:32.420
no field notifies bound to any widgets on load slot enter name.

09:32.420 --> 09:36.740
We can click on view bindings and see that there are no bindings for this view model.

09:36.740 --> 09:38.690
So the fix is quite simple.

09:38.690 --> 09:44.330
We have to have at least one field notify bound on this widget, and we can basically bind really any

09:44.330 --> 09:50.120
of them as load slot view model has a few field notifies depending on where you are in the course.

09:50.120 --> 09:57.140
As you watch this video, you may not have field notifies just yet, but we can easily add a field notify

09:57.140 --> 10:04.100
to this view model class in C plus plus and make sure that any widgets that have this view model assigned

10:04.100 --> 10:11.630
which are using the manual creation type, at least bind to one field notify on that class.

10:11.630 --> 10:14.420
So we need to add a field notify to this class.

10:14.420 --> 10:16.670
So what I'm going to do is close the editor.

10:16.670 --> 10:18.830
And I'm going to go back to that class.

10:18.830 --> 10:22.790
The load slot view model mVVM load slot.

10:22.790 --> 10:23.960
Here's the CPP.

10:23.960 --> 10:26.480
And here is the H file.

10:26.480 --> 10:29.390
And we just need a field notify that we can bind to.

10:29.390 --> 10:30.890
And it could be really anything.

10:30.890 --> 10:34.940
We could even turn load slot name into a field notify.

10:34.970 --> 10:41.330
Now if we do that, if we turn load slot name into a field notify, we're now going to need to create

10:41.330 --> 10:45.470
a getter and setter for it, just like our other field notifies down here.

10:45.470 --> 10:46.700
But that's not a big deal.

10:46.700 --> 10:47.570
We can do that.

10:47.570 --> 10:49.640
So what I'm going to do is take load slot name.

10:49.640 --> 10:53.150
I'm going to control X to cut it out of the public section.

10:53.150 --> 10:57.950
And I'll go ahead and just move it down to the private section with our other field notifies.

10:57.950 --> 11:03.170
And I'll go ahead and also give it the same view property that the other field notifies have.

11:03.170 --> 11:06.350
That way it's now a field notify.

11:06.350 --> 11:07.820
And with getter and setter.

11:07.820 --> 11:13.730
In the Uproperty macro we need public getters and setters, which means anywhere in our project where

11:13.730 --> 11:20.150
we're accessing load slot name as if it's a public variable that's now going to need to access the public

11:20.150 --> 11:22.160
getter for it that we're about to create.

11:22.190 --> 11:23.150
No big deal.

11:23.150 --> 11:24.320
We can do that.

11:24.320 --> 11:27.740
So let's create the getters and setters first.

11:27.770 --> 11:28.280
The setter.

11:28.280 --> 11:32.750
It's going to be void set load slot name.

11:32.750 --> 11:34.550
And this is an F string.

11:34.550 --> 11:39.110
It's going to take in an f string called in load slot name.

11:39.110 --> 11:41.480
And we'll go ahead and generate the definition.

11:41.480 --> 11:49.010
And we have to make sure that if this is a field notify that we're using our macro mVVM, set property

11:49.010 --> 11:49.520
value.

11:49.520 --> 11:54.740
And that will broadcast that field notify when it changes via this setter function.

11:54.740 --> 12:01.370
So the first input is the name of that field notify variable load slot name.

12:01.370 --> 12:04.910
And the second is the value that we're going to broadcast.

12:04.910 --> 12:08.150
It's going to be the input to this setter function.

12:08.240 --> 12:11.360
And again don't worry about those red squiggles.

12:11.360 --> 12:13.400
This is going to compile just fine.

12:13.400 --> 12:18.740
This is one of the few things that Ryder doesn't recognize but it's not an error.

12:18.740 --> 12:19.970
So we have the setter.

12:19.970 --> 12:22.100
Let's make that getter as well.

12:22.100 --> 12:24.140
It's going to return an F string.

12:24.140 --> 12:27.530
It's going to be get load slot name.

12:28.940 --> 12:33.980
It'll be const and it'll simply return load slot name.

12:35.030 --> 12:39.350
So we've now turned this load slot name into a field notify.

12:39.380 --> 12:44.240
Now this will create errors as we're making this a private variable now.

12:44.240 --> 12:50.810
So anywhere where we're trying to access this as if it were public that's going to need to change.

12:50.810 --> 12:54.530
We're going to need to call the public getter now instead.

12:54.530 --> 13:01.070
And then we need to decide when we want to actually broadcast the load slot name as well.

13:01.070 --> 13:08.180
So first let's try to compile and find all those errors where we're accessing load slot name when it's

13:08.180 --> 13:09.230
inaccessible.

13:09.230 --> 13:09.680
Okay.

13:09.680 --> 13:10.610
So here they are.

13:10.610 --> 13:11.360
The first one.

13:11.360 --> 13:12.590
We'll double click on it.

13:12.590 --> 13:16.040
And that's going to be in the game mode where we're accessing load slot name.

13:16.040 --> 13:16.640
Here.

13:16.640 --> 13:19.790
All we need to do is call the public getter instead.

13:19.790 --> 13:22.550
So we're going to say get load slot name.

13:22.550 --> 13:23.900
That's a function call.

13:23.900 --> 13:29.120
We'll go ahead and replace the variable access with the getter.

13:29.120 --> 13:30.800
Now we'll do that here.

13:30.800 --> 13:32.360
We'll do that here.

13:32.360 --> 13:35.570
So that fixes three of those errors already.

13:35.570 --> 13:41.570
And if I scroll down to where I see a red line here, I can see the next violation of this where we're

13:41.570 --> 13:43.160
trying to access it here.

13:43.160 --> 13:47.090
We'll change that to the getter as well.

13:47.090 --> 13:53.330
Now in my error log, we can see that we're making this violation in the game mode base.

13:53.330 --> 13:57.800
We fixed those but we're also trying to access it from mVVM load screen.

13:57.800 --> 13:58.790
Let's go to that.

13:58.790 --> 14:06.500
And we see that in initialize load slots we're actually setting these load slots accessing that public

14:06.500 --> 14:07.910
variable which is now private.

14:07.910 --> 14:14.390
So the way that we can set it is now through that setter we created which will actually broadcast that

14:14.390 --> 14:15.350
field notify.

14:15.350 --> 14:19.910
So any widgets that bind to it will receive that string value.

14:19.910 --> 14:24.920
So this time instead of replacing it with the getter, we're going to replace it with the setter set

14:24.920 --> 14:26.090
load slot name.

14:26.090 --> 14:31.100
We're going to set the value of the load slot name like that.

14:31.100 --> 14:34.310
So we're going to do that for all three load slots.

14:34.310 --> 14:40.100
We're going to replace load slot name with set load slot name calling the function now.

14:40.100 --> 14:42.350
So there's the second one.

14:42.350 --> 14:44.420
Here's the third one.

14:44.420 --> 14:49.400
And now we can just quickly try to compile and see if that fixes that issue.

14:49.910 --> 14:53.690
Looks like we're trying to do it in mVVM load screen elsewhere.

14:53.690 --> 14:54.440
Here it is.

14:54.440 --> 14:59.450
We're trying to access it in order to set the load slot name on the game instance.

14:59.450 --> 15:03.440
We're going to replace that with the get load slot name there.

15:04.600 --> 15:10.630
And if I look at the scroll bar, there are a few other instances of this.

15:10.660 --> 15:16.150
We're going to change this from load slot name to get load slot name in these cases as well.

15:16.150 --> 15:21.790
We're just replacing this with the getter as that is now a private variable.

15:21.790 --> 15:23.230
Let's try to compile again.

15:23.230 --> 15:27.970
I'm just going to run in debug mode and we have a successful compile.

15:28.240 --> 15:35.800
Now what we can do is we can go to all of those widgets that have the view model load slot, enter name

15:35.800 --> 15:36.850
is one of them.

15:36.850 --> 15:41.830
They all have the load slot view model with creation type set to manual.

15:42.070 --> 15:48.400
As soon as we bind to one of the field notifies on it, we'll now successfully be able to set that view

15:48.400 --> 15:53.410
model manually, so we'll start with the load slot enter name, but I'm going to get all three of them

15:53.410 --> 15:53.740
open.

15:53.740 --> 15:57.820
We have enter name we have taken I'll get that one open as well.

15:57.820 --> 16:01.180
And we have vacant I'll get that open as well.

16:01.180 --> 16:06.460
And we'll make sure that each of these has at least one field notify bound.

16:06.460 --> 16:08.560
Now the take in already does.

16:08.560 --> 16:14.590
If we go to view binding, we'll see that we're binding to the player name map value level value.

16:14.590 --> 16:16.990
So that one isn't violating that.

16:16.990 --> 16:23.680
But we'll just go ahead and add a text widget to each of these and bind to the load slot name anyway.

16:23.680 --> 16:27.790
And then we'll have something that shows the load slot name.

16:27.790 --> 16:31.570
And for a package build we can just hide that widget.

16:31.570 --> 16:32.560
So let's do it.

16:32.560 --> 16:34.360
We're going to go to load slot enter name.

16:34.360 --> 16:36.580
And I'm just going to find a text.

16:36.580 --> 16:39.160
I'm going to add a text widget to this.

16:39.160 --> 16:42.010
I'm going to bring it on over to the vertical box.

16:42.010 --> 16:45.460
And I'm going to stick it right there in the vertical box.

16:45.460 --> 16:46.960
We can have it on the top.

16:46.960 --> 16:49.270
Now I placed it just under vertical box.

16:49.270 --> 16:54.550
But notice if I hover my mouse cursor here there are two spaces here.

16:54.760 --> 16:59.500
That blue line has an arrow to the left pointing up and an arrow to the left pointing down.

16:59.500 --> 17:03.520
If I do the one pointing up, it's going to be right here on the vertical box.

17:03.520 --> 17:06.760
And if I set its vertical alignment to bottom, it's going to be down there.

17:06.760 --> 17:09.910
Now this is just to get a field notify bound here.

17:09.910 --> 17:12.610
So I'm going to make the text kind of small.

17:12.610 --> 17:19.270
And I'll set its color and opacity to something like magenta and change the font.

17:19.920 --> 17:21.750
I'm going to change it from bold to light.

17:21.750 --> 17:23.130
So it's nice and light.

17:23.130 --> 17:27.090
I'm going to set its size to something smaller like 12.

17:27.300 --> 17:29.130
So we just have text there.

17:29.130 --> 17:34.770
I'm going to set this text to by default say load slot name.

17:34.770 --> 17:43.230
And I'm going to change its name from text to text underscore load slot name I'm going to check is variable

17:43.230 --> 17:43.800
on it.

17:43.800 --> 17:46.710
And I'm going to bind it to a field notify.

17:46.740 --> 17:49.080
So I'm going to go to view bindings.

17:49.080 --> 17:53.310
And because I have it selected if I click the plus here it's going to add it.

17:53.310 --> 17:57.750
For this particular widget I'm going to bind its text property.

17:57.750 --> 18:01.050
Select that I'm going to use a conversion function.

18:01.050 --> 18:04.470
So conversion functions it's going to be two text from string.

18:04.470 --> 18:08.520
And I'm going to choose the field notify on load slot ViewModel.

18:08.520 --> 18:11.610
And I'm going to choose Load slot name I'm going to select that.

18:11.610 --> 18:17.340
And now we have at least one field notify bound to load slot ViewModel.

18:17.610 --> 18:19.620
So I'm going to compile and save that.

18:19.620 --> 18:24.510
And I'm going to go over to the taken slot which we know already has field notifies bound.

18:24.510 --> 18:30.210
But I'm going to just add a text widget and bind it to load slot name anyway.

18:30.210 --> 18:35.280
And this will be a sort of debug for us that we can check to see the load slot name and make sure it's

18:35.280 --> 18:35.880
correct.

18:35.880 --> 18:38.520
So I'm going to add a text to this one.

18:38.520 --> 18:41.190
I'm going to add it to the vertical box route.

18:41.190 --> 18:44.610
I'm going to hover so that that blue arrow is pointed upwards.

18:44.610 --> 18:45.750
So it's right there.

18:45.750 --> 18:49.260
It's not going to mess up the padding or alignment of anything.

18:49.260 --> 18:52.350
And I'm going to get that new text block.

18:52.350 --> 18:56.700
I'm going to rename it to text load slot name.

18:57.870 --> 18:59.310
I'm going to check is variable.

18:59.310 --> 19:01.890
I'm going to set vertical alignment to bottom.

19:01.890 --> 19:09.690
I'm going to set its color to a magenta color, change its font to light and a size of 12.

19:09.690 --> 19:11.280
And now we have this one.

19:11.280 --> 19:13.830
I'm going to go ahead and just create a binding to that.

19:13.830 --> 19:15.570
So I'm going to click View Bindings.

19:15.570 --> 19:20.670
Add a new binding I'm going to choose its text property.

19:21.000 --> 19:27.780
I'm going to set it to a conversion function to text from string and choose on load slot view model

19:27.780 --> 19:29.700
the load slot name.

19:29.700 --> 19:31.440
And now this one is bound.

19:31.440 --> 19:33.360
I'm going to compile and save that.

19:33.450 --> 19:36.570
And then I'll go to the vacant widget.

19:36.570 --> 19:40.530
So here in the vacant widget I'm going to find text.

19:40.530 --> 19:46.170
I'm going to put it right here on the vertical box using that up arrow so it doesn't mess up my padding.

19:46.170 --> 19:55.110
And I'll go ahead and select that rename it to text underscore load slot name check is variable.

19:55.110 --> 19:57.600
Change it to a magenta color.

19:57.600 --> 20:01.560
Change its font to light with a size of 12.

20:01.560 --> 20:07.650
Set its vertical alignment to bottom so its down there and we'll go ahead and bind it.

20:07.650 --> 20:08.850
View bindings.

20:08.850 --> 20:09.990
We'll add the binding.

20:09.990 --> 20:18.090
We'll choose its text property, and we'll use a conversion function to text from string and choose

20:18.090 --> 20:21.030
on the load slot view model our load slot name.

20:21.030 --> 20:23.250
We'll select that and now it's bound.

20:23.250 --> 20:25.800
And now I'm going to go ahead and save all.

20:25.800 --> 20:27.120
I'm going to press play.

20:27.120 --> 20:30.480
And I'm going to go to the load menu.

20:30.480 --> 20:34.380
And we see load slot zero, load slot one and load slot two.

20:34.410 --> 20:44.190
As we did broadcast this field notify from C plus plus in mVVM load screen in the initialize load slots.

20:44.190 --> 20:50.190
That's because we called the setter which results in the broadcast via that you mVVM macro.

20:50.190 --> 20:52.590
And if we click plus it works.

20:52.590 --> 20:54.810
If we enter a name, it works.

20:54.810 --> 21:00.870
If we select a slot, we can select it, but it looks like our widgets aren't quite properly working,

21:00.870 --> 21:02.970
so we'll need to see what's broken there.

21:02.970 --> 21:07.200
But if I hit stop, we've taken care of lots of errors.

21:07.200 --> 21:08.400
Now we still have one.

21:08.400 --> 21:09.450
We access none.

21:09.450 --> 21:12.450
Trying to read property BP load screen view model.

21:12.450 --> 21:13.200
This is different.

21:13.200 --> 21:14.520
This is not the load slot.

21:14.520 --> 21:15.390
View model.

21:15.390 --> 21:20.040
That's the load screen view model here in assign slot selected.

21:20.040 --> 21:23.100
And that's on WB load screen.

21:23.100 --> 21:30.180
So if we click on assign slot selected we'll see here that the BP load screen view model isn't valid

21:30.180 --> 21:30.630
here.

21:30.630 --> 21:32.100
We need to see why.

21:32.250 --> 21:36.660
So here on the load screen widget WB load screen.

21:36.660 --> 21:41.520
If we click on load screen view model we're using view model property path here.

21:41.520 --> 21:45.570
So why are we not getting a valid view model here.

21:45.570 --> 21:47.850
Right here on assign slot selected.

21:47.850 --> 21:50.040
Why isn't it valid by this point.

21:50.340 --> 21:54.870
Well let's see we're in event blueprint initialize widget.

21:54.870 --> 21:58.950
And we can just check to see if this is a valid view model.

21:58.950 --> 22:05.730
At this point we can use is valid and we can hook up is valid to what it was doing.

22:05.880 --> 22:08.340
But we can use the is not valid.

22:08.340 --> 22:11.730
We could print a string here and we can say.

22:12.380 --> 22:16.310
No valid load screen view model.

22:16.310 --> 22:18.830
And let's see if we get that print string here.

22:18.830 --> 22:20.450
Let's go and press play.

22:20.450 --> 22:22.670
It says no valid view model.

22:22.670 --> 22:25.430
So that's not valid okay.

22:25.430 --> 22:30.410
So where are we setting the Wbhp load screens view model.

22:30.410 --> 22:32.900
We know that it's set by property path.

22:32.900 --> 22:35.870
Let's go to the HUD folder and open load screen HUD.

22:35.870 --> 22:39.410
So we see here that we're creating our load screen widget.

22:39.410 --> 22:44.600
And we're calling add to viewport and then calling blueprint initialize widget.

22:44.600 --> 22:51.650
So let's see what happens if we just replace this BP load screen view model with our getter find load

22:51.650 --> 22:53.720
screen view model.

22:53.720 --> 22:55.670
Let's see if we can get it from that.

22:55.670 --> 22:57.080
Let's see if it's valid.

22:57.080 --> 22:58.670
We'll go ahead and hook that up.

22:58.670 --> 23:03.230
We'll hook it up to the is valid check and we'll hook it up to the binding here okay.

23:03.230 --> 23:04.850
So now we can test everything.

23:04.850 --> 23:07.280
We can take a slot and delete it okay.

23:07.280 --> 23:09.110
So the delete isn't working.

23:09.230 --> 23:10.880
And delete button pressed.

23:10.880 --> 23:15.710
If we go to it we're using BP load screen view model here.

23:15.710 --> 23:20.750
We're going to replace this with our find load screen view model.

23:20.750 --> 23:23.330
And we'll use it straight from that.

23:23.330 --> 23:27.710
And that way we shouldn't be using something that isn't valid.

23:27.710 --> 23:29.090
Let's give that a try.

23:29.090 --> 23:30.110
We'll select a slot.

23:30.110 --> 23:31.640
We'll delete it delete.

23:31.640 --> 23:32.540
It works.

23:32.540 --> 23:34.610
Let's create a new slot.

23:34.610 --> 23:36.230
Select it delete it.

23:36.230 --> 23:36.800
It works.

23:36.800 --> 23:38.810
Let's create a new slot with a name.

23:38.810 --> 23:39.650
Select it.

23:39.650 --> 23:41.480
Let's click play okay.

23:41.480 --> 23:43.430
So play isn't working either.

23:43.430 --> 23:49.220
And that must mean that that view model isn't going to be valid at that point either.

23:49.220 --> 23:56.240
We'll just go ahead and just find load screen view model at that point so we can go ahead and play test

23:56.240 --> 23:57.110
again.

23:57.350 --> 24:01.220
Select it press play and we're able to play.

24:01.340 --> 24:03.830
And we're loading all of our properties.

24:03.830 --> 24:04.940
We're preparing shaders.

24:04.940 --> 24:06.800
That's why we can't see that fireball yet.

24:06.800 --> 24:08.960
Now we can see those effects.

24:08.960 --> 24:10.370
And it looks great.

24:10.700 --> 24:12.800
Now does it ever become valid.

24:12.800 --> 24:14.390
Well we can check that.

24:14.900 --> 24:17.300
We can check an event tick.

24:17.300 --> 24:25.460
We can take that BP load screen view model, get BP load screen view model.

24:25.460 --> 24:30.140
And we can check is valid in tick and see if it ever does become valid.

24:30.140 --> 24:32.720
Let's go ahead and just print a string.

24:32.720 --> 24:37.220
If it is valid we'll say valid view model.

24:37.670 --> 24:46.580
And if it's not valid let's print not valid view model or no valid view model.

24:46.580 --> 24:49.130
Let's go ahead and press play okay.

24:49.130 --> 24:52.010
So it never actually becomes valid.

24:52.130 --> 24:55.340
We can go ahead and remove event tick there.

24:55.460 --> 24:58.760
So why isn't it actually being set.

24:58.760 --> 25:03.080
Well let's see what happens if we create a field notify and bind to it.

25:03.080 --> 25:08.030
Here I'm going to go ahead and close down the engine and go to mVVM load screen.

25:08.030 --> 25:10.100
And we're going to add a field notify.

25:10.100 --> 25:13.700
I can just steal one from our mVVM load slot.

25:16.690 --> 25:19.090
And an NVMe load screen.

25:19.090 --> 25:23.110
We'll just go ahead and add a new field notify.

25:23.110 --> 25:24.430
And this can be simple.

25:24.430 --> 25:26.350
Let's make it an INT 32.

25:26.350 --> 25:30.130
And we'll just call it num load slots.

25:30.400 --> 25:33.760
This way we can see visually how many slots we have.

25:33.760 --> 25:36.430
And we'll create public getters and setters for it.

25:36.430 --> 25:47.650
We'll have a void set num load slots that takes in int 32 called in num load slots, and we'll create

25:47.650 --> 25:57.070
an int 32 returning getter get num load slots, const return num load slots.

25:57.070 --> 25:59.710
And we'll generate the function definition.

25:59.710 --> 26:03.040
And we'll go ahead and steal this macro.

26:03.430 --> 26:11.740
We'll call that macro using num load slots and setting it to in num load slots.

26:11.890 --> 26:17.860
Now we have a field notify and we can simply broadcast that field notify right up here.

26:17.860 --> 26:22.990
After we initialize load slots we'll call set num load slots.

26:22.990 --> 26:26.410
And we'll go ahead and get our load slots map.

26:30.890 --> 26:32.660
And call num on it.

26:32.690 --> 26:35.840
That'll give us the number of elements in that map.

26:35.870 --> 26:38.930
Now that we have a field notify, let's bind to it.

26:39.170 --> 26:46.490
We'll go ahead and open up our asset editors, and we'll just add a text widget up here at the top.

26:46.520 --> 26:51.980
We'll call this text underscore num slots.

26:52.400 --> 26:57.260
And I'll just go ahead and wrap this in a horizontal box.

26:57.260 --> 26:59.360
And we'll add another text to this.

26:59.570 --> 27:04.370
And the first one is just going to say num slots.

27:04.430 --> 27:06.380
We'll go ahead and make it smaller.

27:06.380 --> 27:09.920
Let's make it 16 with light font.

27:09.920 --> 27:14.600
And then our text num slots will make it light font 16 as well.

27:15.720 --> 27:20.520
We'll give it a magenta color and it's going to say num slots.

27:20.550 --> 27:24.570
I'll make my horizontal box a little bigger and I'll take my num slots.

27:24.570 --> 27:27.750
Check is variable and we'll view bindings.

27:27.750 --> 27:29.340
We'll add a binding for it.

27:29.340 --> 27:31.860
We'll bind to its text value.

27:32.190 --> 27:37.020
And we're going to use a conversion function to text this time from integer.

27:37.020 --> 27:44.730
And for the value we're going to bind it by clicking on the chain icon and selecting the load screen

27:44.730 --> 27:47.940
view model and choose NUM Load Slots.

27:47.940 --> 27:51.720
We'll have a minimum number of digits and a maximum number of digits.

27:51.720 --> 27:54.840
We have some extra properties to set for an integer.

27:54.840 --> 28:00.420
So now that that is bound, we have a binding to our load screen view model.

28:00.420 --> 28:05.370
Let's see if we're successfully creating and setting our widget with the property path.

28:05.370 --> 28:07.410
We'll just check right away.

28:07.410 --> 28:12.960
In Event Blueprint Initialize widget, we'll get our BP load screen view model.

28:12.960 --> 28:17.670
We'll get object name and we'll see if it's a valid name or if it's none.

28:18.360 --> 28:20.220
So we'll print that string.

28:20.770 --> 28:22.540
And we'll see what happens here.

28:22.540 --> 28:25.180
So I'll press play press play again.

28:25.180 --> 28:28.120
And we have a valid load screen view model.

28:28.120 --> 28:29.320
We can select a slot.

28:29.320 --> 28:31.750
We can press play and we can play the game.

28:32.050 --> 28:39.910
So even if we're using a property path creation type we still are going to need at least one field notified

28:39.910 --> 28:40.300
bound.

28:40.300 --> 28:43.690
And I don't know if we even looked but let's press play.

28:43.690 --> 28:48.610
We see num slots is three because we have three slots and we broadcast that value.

28:48.610 --> 28:53.470
So WB load screen now has some debug text there for us.

28:53.470 --> 29:00.220
So the moral of the story is that in 5.3 if you have a view model you need at least one field notify

29:00.220 --> 29:01.060
bound to it.

29:01.060 --> 29:03.520
So that's something that is now enforced.

29:03.520 --> 29:09.460
Otherwise we won't be able to properly set the view model based on that creation type.

29:09.460 --> 29:11.980
Now we don't have to leave this debug text.

29:11.980 --> 29:13.300
We can hide it.

29:13.300 --> 29:18.190
We can take its opacity and set it down to zero.

29:18.190 --> 29:22.480
If we don't want to see that text in the game, that's not a big deal.

29:22.480 --> 29:27.940
It's not going to cause us a whole lot of overhead so we can just go into our load slot, enter name,

29:27.940 --> 29:34.330
get that text, set its opacity down to zero, we can get our load slot taken.

29:34.330 --> 29:35.710
Same thing.

29:35.800 --> 29:39.250
We'll hide that text and our load slot vacant.

29:39.250 --> 29:41.140
We'll hide that text as well.

29:41.140 --> 29:44.080
And that way each of these has a property.

29:44.080 --> 29:47.950
It's updated, but we don't have to actually see it.

29:47.950 --> 29:53.050
We're going to go ahead and we'll compile all of these make sure they're all compiled.

29:53.930 --> 29:58.070
Now we don't see those invisible widgets.

29:58.600 --> 30:04.480
So I'm going to go back to load slot taken and remove that event tick that was actually spamming the

30:04.480 --> 30:04.930
screen.

30:04.930 --> 30:08.920
We can now make sure that other print string is there and it works as well.

30:09.190 --> 30:15.100
So now we will have a load screen view model that's valid on our load screen.

30:15.100 --> 30:17.950
So we don't need to print the name of it anymore.

30:17.950 --> 30:23.140
We know it's valid and we also don't need to call find load screen view model every time.

30:23.140 --> 30:32.620
We can just get BP load screen view model and use that instead of calling that getter every time.

30:33.360 --> 30:34.920
I'm going to copy that.

30:36.730 --> 30:38.920
And we'll paste it here as well.

30:38.920 --> 30:41.770
We'll undo that little Band-Aid.

30:42.670 --> 30:45.940
And looks like I forgot to hook it up to the binding there.

30:45.940 --> 30:47.080
Now we're good.

30:47.080 --> 30:50.650
We can press play, select a slot, we can delete it.

30:50.650 --> 30:53.950
We can create a new slot, select it, press play.

30:53.950 --> 30:55.360
We can play the game.

30:55.900 --> 30:57.970
Things appear to be working.

30:57.970 --> 30:59.530
We can press the X.

30:59.530 --> 31:02.920
We can go ahead and quit and come back.

31:02.920 --> 31:03.970
Make a new slot.

31:03.970 --> 31:05.560
Select it delete it.

31:05.560 --> 31:08.200
Cancel delete delete.

31:08.200 --> 31:09.520
New slot.

31:10.160 --> 31:14.030
First dungeon, select it, press play and we can play.

31:14.030 --> 31:15.110
So everything works now.

31:15.110 --> 31:21.050
And now our project is working in Unreal Engine 5.3, so everything works.

31:21.050 --> 31:26.510
And we are now compatible with the latest Unreal Engine version.

31:26.510 --> 31:31.970
And our beautiful save system and menu system is all working properly.

31:31.970 --> 31:36.710
I'm going to go ahead and just delete those slots so that I can commit this to the GitHub.

31:36.710 --> 31:41.300
And you can see the project in a working state in all its glory.

31:41.300 --> 31:48.920
Now one last thing before we wrap up that I want to point out is that there is a warning.

31:49.830 --> 31:53.490
That says Detected Orphan Sound, which is not a one shot music.

31:53.490 --> 31:54.600
Main menu.

31:54.810 --> 31:59.340
Remember our main menu music is looping and sounds which are not one.

31:59.340 --> 32:02.730
Shots need to have audio components or they risk being orphaned.

32:02.730 --> 32:04.320
Well, we can easily fix that.

32:04.320 --> 32:11.280
Let's go back to our main menu and we can check out where we're playing that sound that's going to be

32:11.280 --> 32:12.600
in our actor here.

32:12.600 --> 32:13.830
We can browse to this asset.

32:13.830 --> 32:15.270
It's in blueprints main menu.

32:15.270 --> 32:17.250
It's BP or a main menu.

32:17.280 --> 32:18.990
We're calling Play Sound 2D.

32:18.990 --> 32:20.430
And this sound is getting orphaned.

32:20.430 --> 32:25.410
So instead of play sound 2D we're going to spawn sound 2D instead.

32:25.410 --> 32:28.770
This returns an audio component and we can store that.

32:28.770 --> 32:30.570
So it's not orphaned.

32:30.570 --> 32:32.400
It won't be garbage collected.

32:32.850 --> 32:37.410
And we can set it to music main menu by browsing to it and just setting it there.

32:37.410 --> 32:39.390
We'll go ahead and set the sound.

32:39.390 --> 32:44.070
We'll promote it to a variable and call this main menu music.

32:44.190 --> 32:48.420
And that way we're storing that and then it shouldn't be orphaned.

32:48.420 --> 32:50.580
And that'll take care of that issue.

32:50.580 --> 32:52.470
We'll compile save that.

32:52.470 --> 32:54.840
And we took care of that warning.

32:54.840 --> 32:57.630
And we still get the sound it plays.

32:57.630 --> 32:58.770
We get our music.

32:58.770 --> 33:00.390
Everything looks great.

33:01.090 --> 33:08.920
And one last error we have is this one input mode UI only attempting to focus non focus widget.

33:08.920 --> 33:12.280
And we see that that is in our load menu.

33:12.280 --> 33:13.690
Let's take a look at that.

33:13.690 --> 33:20.320
And we're setting input mode UI only here we're trying to focus on a non focusable widget.

33:20.320 --> 33:22.600
So we don't have to focus on that.

33:22.600 --> 33:26.920
We can just remove that not pass in anything for widget to focus.

33:26.920 --> 33:32.560
And we can go back to our main menu map, press play, go to our load menu.

33:32.560 --> 33:40.150
And we should still have the ability to use our menu and everything works fine.

33:40.150 --> 33:42.790
So that takes care of that issue okay.

33:42.790 --> 33:44.920
So that's going to wrap up this video.

33:44.920 --> 33:50.740
We've now converted the project and the mVVM system to work properly in 5.3.

33:50.740 --> 33:52.450
That was a good learning exercise.

33:52.450 --> 33:59.500
And I do apologize that the 5.2 version wasn't compatible with 5.3 until we made this fix.

33:59.500 --> 34:04.600
Now that we know how to fix it, we know a little bit more about how the mVVM system works, and it's

34:04.600 --> 34:07.930
a pretty nice system, and this is just what you have to deal with.

34:07.930 --> 34:13.000
With rapidly evolving and changing software, it's always going to be updating.

34:13.000 --> 34:19.030
Changing things become deprecated, and you have to make sure your software is compatible with the latest

34:19.030 --> 34:19.870
version.

34:19.870 --> 34:21.670
That's just part of development.

34:21.670 --> 34:27.130
So that's going to be something that we always have to deal with in our careers as developers.

34:27.130 --> 34:30.130
So excellent job and I'll see you soon.
