WEBVTT 1 00:00:24.100 --> 00:00:25.900 Hello, this is Youngho Lee 2 00:00:25.900 --> 00:00:29.400 We'll learn about actor replication in this unit 3 00:00:29.401 --> 00:00:32.460 It is the most important concept for Unreal Engine network 4 00:00:32.460 --> 00:00:36.680 First, we will learn property replication 5 00:00:36.681 --> 00:00:38.980 For this, we'll make a test actor 6 00:00:38.980 --> 00:00:43.680 and learn how to register the actor's replication option and owner 7 00:00:43.681 --> 00:00:46.400 Then, we'll learn how to sync its 8 00:00:46.400 --> 00:00:48.959 rotation and color on the network 9 00:00:48.960 --> 00:00:53.019 Next is RPC 10 00:00:53.020 --> 00:00:56.039 We'll learn what RPC is and its operation structure 11 00:00:56.039 --> 00:01:00.520 and use this to sync materials' color values 12 00:01:00.520 --> 00:01:03.000 First, let's learn property replication 13 00:01:03.580 --> 00:01:06.100 Property replication 14 00:01:10.320 --> 00:01:15.439 Property replication literally means replicating properties 15 00:01:15.439 --> 00:01:19.899 Property means member variable 16 00:01:22.799 --> 00:01:27.720 For this, I'll first make a C++ class 17 00:01:27.721 --> 00:01:31.780 Select C++ class and right click 18 00:01:31.780 --> 00:01:34.799 and choose new C++ class 19 00:01:35.879 --> 00:01:38.029 Here, I'll choose actor 20 00:01:38.029 --> 00:01:41.160 and next 21 00:01:41.160 --> 00:01:45.719 put the name as NetActor 22 00:01:47.599 --> 00:01:50.059 Then create class 23 00:01:51.919 --> 00:01:53.899 Then it opens on Visual Studio 24 00:01:53.900 --> 00:01:58.959 When this pop up shows up, load it and open it 25 00:01:58.959 --> 00:02:03.060 then go back to Unreal Editor 26 00:02:05.560 --> 00:02:09.400 and make NetActor as a blueprint and use it 27 00:02:09.401 --> 00:02:11.820 Right click NetActor 28 00:02:11.820 --> 00:02:14.940 and click on create blueprint class 29 00:02:16.000 --> 00:02:19.650 Blueprint in the NetTPS folder 30 00:02:19.650 --> 00:02:22.639 We'll save it there 31 00:02:22.639 --> 00:02:27.120 I'll name it BP_NetActor 32 00:02:28.440 --> 00:02:32.100 Click on create blueprint class 33 00:02:32.101 --> 00:02:34.700 and then we'll work with this blueprint class 34 00:02:34.700 --> 00:02:38.759 by adding a static mesh component 35 00:02:38.760 --> 00:02:41.560 Go to NetActor header file 36 00:02:41.560 --> 00:02:49.160 and on the very bottom add 'public new property' 37 00:02:51.240 --> 00:02:55.640 as visible anywhere 38 00:02:55.640 --> 00:03:01.000 Then class UStaticMeshComponent 39 00:03:01.000 --> 00:03:04.839 and meshComp 40 00:03:05.240 --> 00:03:10.279 Move to constructor function from header 41 00:03:10.279 --> 00:03:14.199 and here, we'll make a meshComp 42 00:03:14.199 --> 00:03:20.540 meshComp = CreateDefaultSubObject 43 00:03:24.360 --> 00:03:31.080 and put UStaticMeshComponent here 44 00:03:31.080 --> 00:03:34.760 then TEXT Mesh Comp 45 00:03:37.399 --> 00:03:42.019 And then we'll put this MeshComponent as RootComponent 46 00:03:45.499 --> 00:03:46.779 Like this 47 00:03:49.360 --> 00:03:52.660 Then the size 48 00:03:52.660 --> 00:03:55.720 Let's make this StaticMeshComponent a bit smaller 49 00:03:55.721 --> 00:03:57.921 by half 50 00:03:57.921 --> 00:04:07.839 We have SetRelativeScale3D on meshComp 51 00:04:07.839 --> 00:04:14.140 We'll put FVector here and set it as 0.5 52 00:04:17.279 --> 00:04:20.079 Then the scale of this Static MeshComponent 53 00:04:20.079 --> 00:04:22.220 will be set as 0.5 54 00:04:23.720 --> 00:04:24.739 Build and 55 00:04:28.479 --> 00:04:31.959 we'll turn off Unreal editor and turn it back on 56 00:04:38.300 --> 00:04:43.500 Unreal editor is on. From blueprint holder 57 00:04:43.500 --> 00:04:46.640 double click on NetActor to open it 58 00:04:49.660 --> 00:04:52.680 Here you can see that meshComp is in here 59 00:04:52.680 --> 00:04:55.030 but there's nothing here right now 60 00:04:55.030 --> 00:04:57.360 so it doesn't show on the view port window 61 00:04:57.360 --> 00:05:02.040 We'll register the static mesh that we'll use here 62 00:05:02.041 --> 00:05:05.060 There's static mesh on the detail window on the right 63 00:05:05.060 --> 00:05:12.720 We'll search sm_ball here as the static mesh that we'll use 64 00:05:12.720 --> 00:05:16.580 Select on sm ball 01 and you'll see this 65 00:05:17.440 --> 00:05:18.340 Good 66 00:05:18.340 --> 00:05:21.760 This is the static mesh that's on this one 67 00:05:21.761 --> 00:05:23.940 and when you click on compile 68 00:05:23.940 --> 00:05:27.559 you can see that the material is also assigned like this 69 00:05:27.560 --> 00:05:31.379 Then we'll put this BP NetActor 70 00:05:31.380 --> 00:05:34.379 and see if this shows on owner setting on the screen properly 71 00:05:34.379 --> 00:05:36.440 We'll go on and check that 72 00:05:36.440 --> 00:05:41.839 We'll add the part that outputs information on network state 73 00:05:41.840 --> 00:05:44.799 Come to Visual Studio 74 00:05:44.800 --> 00:05:47.999 and to NetActor.header file 75 00:05:47.999 --> 00:05:51.920 We'll add a function that outputs information on the very bottom 76 00:05:51.921 --> 00:05:56.021 We'll add void PrintNetLog 77 00:05:56.021 --> 00:05:58.340 Create implementation 78 00:05:58.340 --> 00:06:01.899 We'll do that on NetActor.cpp 79 00:06:01.900 --> 00:06:08.799 We'll also add a PrintLog calling code on tick 80 00:06:08.800 --> 00:06:11.759 On PrintNetLog 81 00:06:11.759 --> 00:06:15.559 we'll put the same that that did the information outputting on the player 82 00:06:15.560 --> 00:06:18.619 Go to NetTPSCharacter and there's PrintLog 83 00:06:18.619 --> 00:06:23.660 Take everything there 84 00:06:23.660 --> 00:06:28.800 and we'll put it here on NetActor.cpp 85 00:06:28.800 --> 00:06:33.359 There are no roles for local and remote 86 00:06:33.360 --> 00:06:36.999 so let's add them to include 87 00:06:36.999 --> 00:06:44.799 #include and add NetTPS.h here 88 00:06:44.799 --> 00:06:50.519 Then it'll all be in there with no errors 89 00:06:50.519 --> 00:06:52.069 Header file on the top 90 00:06:52.069 --> 00:06:55.115 Let's add the part that includes 91 00:06:55.115 --> 00:06:57.195 First let's build 92 00:06:59.839 --> 00:07:04.279 and once that's done, go to Unreal editor 93 00:07:07.600 --> 00:07:10.340 and put NetActor.cpp 94 00:07:10.340 --> 00:07:12.140 Take blueprint NetActor.cpp 95 00:07:12.140 --> 00:07:15.920 and put it here with drag and drop 96 00:07:15.921 --> 00:07:18.880 Out player is there 97 00:07:18.880 --> 00:07:21.340 Let's put it here so that we can see it from a bit closer 98 00:07:22.920 --> 00:07:25.519 And maybe a bit higher here 99 00:07:27.340 --> 00:07:31.100 Let's play it and see 100 00:07:31.100 --> 00:07:35.200 Then on this NetActor.cpp it shows the current state 101 00:07:35.200 --> 00:07:37.180 It shows the information on network 102 00:07:39.440 --> 00:07:42.540 Let's add a client 103 00:07:42.540 --> 00:07:46.559 and check it there as well 104 00:07:46.560 --> 00:07:50.259 When you do that, on the server 105 00:07:50.260 --> 00:07:52.919 Local Role is set as ROLE authority 106 00:07:52.919 --> 00:07:55.320 This exists in the server and Remote Role 107 00:07:55.321 --> 00:07:56.821 says ROLE none 108 00:07:56.821 --> 00:07:59.280 It means that remote is not there right now 109 00:07:59.280 --> 00:08:01.730 On the client state as well 110 00:08:01.730 --> 00:08:04.640 local role is none and remote role is 111 00:08:04.641 --> 00:08:06.240 authority, why? 112 00:08:06.241 --> 00:08:08.980 Because the part that syncs the network 113 00:08:08.980 --> 00:08:12.239 is not set yet 114 00:08:12.239 --> 00:08:14.639 So we'll set the owner 115 00:08:14.639 --> 00:08:17.959 and check these two parts now 116 00:08:17.960 --> 00:08:21.120 Then I'll add the part that sets the owner 117 00:08:21.120 --> 00:08:22.970 On the network connection structure 118 00:08:22.970 --> 00:08:26.480 The structure itself, there's a client 119 00:08:26.481 --> 00:08:29.900 and there's the server 120 00:08:29.900 --> 00:08:32.450 For these two to communicate, what's necessary is 121 00:08:32.450 --> 00:08:34.760 a PlayerController 122 00:08:34.760 --> 00:08:36.310 The server as well 123 00:08:36.310 --> 00:08:40.460 it needs a corresponding PlayerController that let's these communicate 124 00:08:40.461 --> 00:08:43.800 So ultimately, saying that they communicate through PlayerControllers 125 00:08:43.800 --> 00:08:45.780 Our character right now is a Pawn 126 00:08:47.000 --> 00:08:51.120 This guy is communicating using the net connection in the PlayerController 127 00:08:51.120 --> 00:08:56.599 The pawn is also using this to communicate 128 00:08:56.600 --> 00:09:00.999 But the actor that we made, NetActor 129 00:09:00.999 --> 00:09:04.359 is existent in both the server and the client 130 00:09:04.360 --> 00:09:06.560 So there's no owner right now 131 00:09:06.560 --> 00:09:10.519 It needs to communicate through this using the PlayerController 132 00:09:10.519 --> 00:09:14.280 but this part is blocked right now 133 00:09:14.280 --> 00:09:18.230 So we need that part the sets the owner 134 00:09:18.230 --> 00:09:20.639 to build a communication structure 135 00:09:20.640 --> 00:09:23.940 That way we can use the property replication 136 00:09:23.940 --> 00:09:26.220 to sync the data 137 00:09:27.799 --> 00:09:30.849 So, coming back to Visual Studio 138 00:09:30.849 --> 00:09:34.419 we'll head to NetActor header file 139 00:09:36.400 --> 00:09:39.950 We'll range check 140 00:09:39.950 --> 00:09:42.540 and within this range, the closest 141 00:09:43.720 --> 00:09:46.280 pawn will be set as the owner 142 00:09:46.280 --> 00:09:49.500 So first, let's add a range variable 143 00:09:51.600 --> 00:09:54.280 that can detect owner 144 00:09:54.280 --> 00:09:56.780 Come to u property and to let it be editable on web 145 00:09:56.780 --> 00:09:59.320 put it as edit anywhere 146 00:09:59.320 --> 00:10:04.400 and then we'll put float search distance 147 00:10:04.400 --> 00:10:05.960 Let's say about 2 meters 148 00:10:08.140 --> 00:10:11.680 So when pawn comes within 2 meters 149 00:10:11.680 --> 00:10:14.600 that will be set as the owner 150 00:10:17.680 --> 00:10:20.980 Then let's move to tick function 151 00:10:20.980 --> 00:10:22.760 On NetActor.cpp 152 00:10:22.760 --> 00:10:28.060 let's put this on tick 153 00:10:29.080 --> 00:10:31.139 Have the 154 00:10:33.400 --> 00:10:36.319 closest pawn 155 00:10:39.239 --> 00:10:40.400 as owner 156 00:10:42.080 --> 00:10:46.640 When it is within range 157 00:10:46.641 --> 00:10:50.500 Setting as the owner only when it's within the range that I'm checking 158 00:10:50.500 --> 00:10:53.119 We'll put that logic 159 00:10:53.120 --> 00:10:55.779 But there's one thing to keep in mind here 160 00:10:55.779 --> 00:10:59.579 If you set it as owner in client, there's no meaning in that 161 00:10:59.579 --> 00:11:00.099 Why? 162 00:11:00.100 --> 00:11:02.859 All these logics are managed by who? 163 00:11:02.859 --> 00:11:04.159 By the server 164 00:11:04.159 --> 00:11:07.679 If the client says 'I wanna set this one as the owner' 165 00:11:07.679 --> 00:11:10.579 but this does nothing 166 00:11:10.579 --> 00:11:13.631 These things must be set at the server 167 00:11:13.631 --> 00:11:17.300 so that the server does the managing and sets it as the owner 168 00:11:17.300 --> 00:11:19.800 So the client party shouldn't take charge of this part 169 00:11:19.800 --> 00:11:23.160 It has to be the server 170 00:11:24.400 --> 00:11:26.899 Only in the server 171 00:11:28.780 --> 00:11:33.360 Then what should the role be 172 00:11:33.361 --> 00:11:36.120 LocalRole must be Authority 173 00:11:36.120 --> 00:11:38.920 Only that way, we have the server 174 00:11:38.920 --> 00:11:46.319 I told you that HasAuthority is the function that let's us know about that 175 00:11:46.320 --> 00:11:48.819 Go to HasAuthority 176 00:11:48.820 --> 00:11:52.299 and it checks and let's us know 177 00:11:52.299 --> 00:11:54.599 if LocalRole is authority 178 00:11:54.599 --> 00:11:57.679 Then it will be the server 179 00:11:57.679 --> 00:12:02.320 So when this is the server, we'll do this 180 00:12:05.739 --> 00:12:07.089 Right 181 00:12:07.089 --> 00:12:10.939 And in this case, choose the closest one 182 00:12:10.939 --> 00:12:17.399 and we're trying to set that actor as the pawn, the owner 183 00:12:17.399 --> 00:12:23.280 To select that, we'll make AActor variable 184 00:12:23.280 --> 00:12:27.119 newOwner 185 00:12:27.520 --> 00:12:29.520 Make that one first 186 00:12:29.520 --> 00:12:35.280 and then make a float minimum distance variable 187 00:12:35.280 --> 00:12:38.030 and put an initial value for the search distance 188 00:12:38.030 --> 00:12:40.200 within range 189 00:12:40.200 --> 00:12:42.700 Then when it enters that range 190 00:12:42.700 --> 00:12:44.000 it will start the search 191 00:12:44.000 --> 00:12:46.200 and the one smaller than this one 192 00:12:46.200 --> 00:12:48.780 will be the owner 193 00:12:50.520 --> 00:12:55.520 Let's try it using for 194 00:12:57.100 --> 00:13:07.199 Here, TActorIterator ANetTPSCharacter, I'll find that only from the world 195 00:13:07.199 --> 00:13:11.440 The variable name is it, and put get world 196 00:13:11.440 --> 00:13:18.400 Then on the world, ANetTPSCharacter will be the only one I'll check 197 00:13:18.400 --> 00:13:20.239 Then when existent 198 00:13:23.000 --> 00:13:25.980 increase the pointer like this 199 00:13:25.981 --> 00:13:27.920 And the red line here 200 00:13:27.920 --> 00:13:31.760 is because ANetTPSCharacter is not included 201 00:13:31.760 --> 00:13:35.360 Another thing, to use this TActorIterator here 202 00:13:35.360 --> 00:13:41.260 you need to add this EngineUtils.h 203 00:13:41.260 --> 00:13:45.360 Like this, EngineUtils.h, then NetTPSCharacter.h 204 00:13:45.360 --> 00:13:49.120 You need to add these two with #include 205 00:13:49.120 --> 00:13:51.170 Coming back to tick 206 00:13:51.170 --> 00:13:54.659 and repeat by finding ANetTPSCharacter 207 00:13:54.660 --> 00:13:57.459 object and searching 208 00:13:57.459 --> 00:14:02.020 First, but actor for temporary variable 209 00:14:02.021 --> 00:14:04.180 and otherActor 210 00:14:04.180 --> 00:14:06.930 Then let's put it 211 00:14:06.930 --> 00:14:10.040 and float dist 212 00:14:10.041 --> 00:14:15.760 There's this function called GetDistanceTo 213 00:14:15.760 --> 00:14:17.810 and put otherActor here 214 00:14:17.810 --> 00:14:19.599 It'll show give you the distance between the NetActor 215 00:14:19.599 --> 00:14:22.520 and the otherActor 216 00:14:25.440 --> 00:14:28.420 Then, if 217 00:14:28.420 --> 00:14:34.480 dist is smaller than the min dist that we set above 218 00:14:36.940 --> 00:14:38.490 Then what happens? 219 00:14:38.490 --> 00:14:39.740 It's within the range 220 00:14:39.740 --> 00:14:45.159 and also closer in the range 221 00:14:45.159 --> 00:14:52.840 min dist is now updated as dist 222 00:14:52.841 --> 00:14:56.180 then the minimum value is updated 223 00:14:56.180 --> 00:15:01.400 Then on the newOwner that we had set above 224 00:15:01.400 --> 00:15:04.879 we'll put the otherActor that we found 225 00:15:07.760 --> 00:15:13.200 Like this, we can choose the close actor 226 00:15:13.201 --> 00:15:15.940 It'll repeat that until the for statement ends 227 00:15:15.940 --> 00:15:21.919 Then, here, under for, owner 228 00:15:21.919 --> 00:15:28.000 Let's set owner once for statement has ended 229 00:15:28.001 --> 00:15:32.020 It will have the closest ANetTPSCharacter type object 230 00:15:32.020 --> 00:15:34.080 saved on newOwner 231 00:15:34.080 --> 00:15:36.730 We'll set that one as the owner 232 00:15:36.730 --> 00:15:41.600 only when GetOwner is not the same 233 00:15:41.601 --> 00:15:45.640 because if they're the same, it doesn't need to be set again 234 00:15:45.640 --> 00:15:48.559 That's not necessary 235 00:15:48.560 --> 00:15:52.639 so we'll put newOwner in SetOwner 236 00:15:52.639 --> 00:15:56.119 Then it will be updated when owner is different 237 00:15:56.120 --> 00:15:57.859 When there's no owner it's null 238 00:15:57.859 --> 00:16:00.679 So these two won't be the same and it will put it 239 00:16:00.680 --> 00:16:03.459 So, finding the closest 240 00:16:03.459 --> 00:16:06.000 actor and putting it 241 00:16:06.001 --> 00:16:07.760 That was in the tick 242 00:16:07.760 --> 00:16:09.210 Let's build and run 243 00:16:09.210 --> 00:16:11.919 to see if owner properly gets updated 244 00:16:14.300 --> 00:16:15.720 Let's play 245 00:16:16.939 --> 00:16:19.289 Now, how does it look 246 00:16:19.289 --> 00:16:22.000 You can see that it says NoOwner 247 00:16:22.001 --> 00:16:24.980 Let's move forward, it's set as 2m 248 00:16:24.980 --> 00:16:31.119 It says BPThirdPerson character_C_0 on the owner Name 249 00:16:31.120 --> 00:16:32.919 Right? The ownerName is here 250 00:16:32.919 --> 00:16:37.159 You can see that this part here is working properly 251 00:16:37.160 --> 00:16:39.860 But this here doesn't show the boundary 252 00:16:39.860 --> 00:16:41.199 so it's a bit hard to test 253 00:16:41.199 --> 00:16:45.400 Let's visualize the boundary 254 00:16:45.400 --> 00:16:48.500 Go to Visual Studio 255 00:16:48.500 --> 00:16:51.280 and move to the very bottom of the tick function 256 00:16:51.280 --> 00:16:58.320 Right under authority, a visualization code Boundary visualization 257 00:16:58.320 --> 00:17:05.919 Let's use this one, DrawDebugSphere Put GetWorld 258 00:17:05.919 --> 00:17:12.840 and then put the NetActor location value and around that 259 00:17:12.841 --> 00:17:14.291 we'll draw a search circle 260 00:17:14.291 --> 00:17:18.770 We want to draw a circle that's the size of the search distance 261 00:17:18.770 --> 00:17:23.599 And the circle's segment is 30 262 00:17:23.599 --> 00:17:27.699 FColor, let's have the color as yellow 263 00:17:27.699 --> 00:17:30.349 and put false 264 00:17:30.349 --> 00:17:33.280 Whether it will be maintained, we'll have that as false 265 00:17:33.280 --> 00:17:39.719 and then for lifetime and priority, we'll put 0 266 00:17:39.719 --> 00:17:44.459 It'll be 0, 0, 1 267 00:17:44.460 --> 00:17:48.479 We'll have the line width of 1 268 00:17:48.479 --> 00:17:51.560 Now let's run it 269 00:17:53.000 --> 00:17:54.600 The boundary is showing now 270 00:17:54.600 --> 00:17:58.250 If you enter this boundary, it is set 271 00:17:58.250 --> 00:17:59.640 It's done 272 00:17:59.640 --> 00:18:01.399 Let's also run a client 273 00:18:03.900 --> 00:18:07.820 Great 274 00:18:07.820 --> 00:18:11.680 When the client enters, what happens to the owner? 275 00:18:11.680 --> 00:18:15.530 NoOwner, it's in the boundary 276 00:18:15.530 --> 00:18:18.059 but still there is no owner set 277 00:18:18.060 --> 00:18:20.260 It says NoOwner here 278 00:18:20.260 --> 00:18:23.519 On the server, it shows the ownerName right 279 00:18:23.519 --> 00:18:28.359 but to the client, it says NoOwner 280 00:18:28.360 --> 00:18:31.179 The reason is this 281 00:18:31.179 --> 00:18:34.329 in network, all actors like this 282 00:18:34.329 --> 00:18:37.560 wants to communicate 283 00:18:37.561 --> 00:18:39.761 It would be nice if that was automatic 284 00:18:39.761 --> 00:18:43.220 but then there would be a big waste in data 285 00:18:43.220 --> 00:18:47.680 So all the actors in here aren't synced 286 00:18:47.681 --> 00:18:52.860 Even if the owner is set, only the ones that are picked to be synced 287 00:18:52.860 --> 00:18:56.880 are synced in the network 288 00:18:56.881 --> 00:18:58.981 That we will learn later on 289 00:18:58.981 --> 00:19:00.740 For now 290 00:19:00.741 --> 00:19:03.060 we didn't put the part that assigns this one to be synced in network 291 00:19:03.060 --> 00:19:06.079 so it doesn't show up 292 00:19:06.080 --> 00:19:08.080 That's about it 293 00:19:08.080 --> 00:19:10.119 Let's just organize the functions a bit 294 00:19:10.119 --> 00:19:13.000 There are too much stuff in the tick 295 00:19:13.001 --> 00:19:17.160 so the code that we made for visualization 296 00:19:17.161 --> 00:19:18.140 This part 297 00:19:18.140 --> 00:19:22.040 I'll make a function and move it 298 00:19:22.041 --> 00:19:25.540 On the NetActor header file 299 00:19:25.540 --> 00:19:29.419 I'll make a function void FindOwner 300 00:19:33.099 --> 00:19:37.599 and move it here 301 00:19:40.420 --> 00:19:46.520 Here, from Has authority to boundary visualization 302 00:19:46.520 --> 00:19:50.800 Ctrl+X, so there's only print net log on tick 303 00:19:50.801 --> 00:19:54.400 We'll move them all to FindOwner 304 00:19:54.400 --> 00:19:59.000 Tick only needs to call FindOwner 305 00:19:59.000 --> 00:20:02.460 I'll move it like that 306 00:20:03.720 --> 00:20:06.700 Then, for data synchronization 307 00:20:06.700 --> 00:20:08.959 We call this replication 308 00:20:08.960 --> 00:20:12.639 So let's work on that option 309 00:20:12.639 --> 00:20:15.839 Go to NetActor cpp constructor function 310 00:20:15.839 --> 00:20:24.360 and on the very bottom, we'll add network syncing option activation 311 00:20:24.360 --> 00:20:26.280 We call this synchronization 312 00:20:26.280 --> 00:20:31.000 Actor Replication, right 313 00:20:31.000 --> 00:20:33.560 We're activating that 314 00:20:33.560 --> 00:20:37.160 There's this thing called bReplicate 315 00:20:38.440 --> 00:20:41.920 Have this as true 316 00:20:41.920 --> 00:20:45.220 and now, this NetActor will automatically 317 00:20:45.220 --> 00:20:47.639 sync in network 318 00:20:47.639 --> 00:20:51.360 once owner is set 319 00:20:51.360 --> 00:20:54.080 Right, let's build 320 00:20:54.080 --> 00:20:58.080 We'll turn Unreal editor off and turn it back on 321 00:20:58.080 --> 00:21:01.040 I'll do that just to be safe 322 00:21:03.000 --> 00:21:04.450 Great 323 00:21:04.450 --> 00:21:08.119 Let's play and test it 324 00:21:08.119 --> 00:21:10.860 and also a client as well 325 00:21:13.020 --> 00:21:15.840 Now, no matter the server or client, I'll enter the boundary 326 00:21:15.840 --> 00:21:17.340 I'll do it on the server 327 00:21:17.340 --> 00:21:20.400 When I do that, owner is set 328 00:21:20.400 --> 00:21:22.320 and let's check it from the client 329 00:21:22.320 --> 00:21:24.800 Check it from the client and how does it look 330 00:21:27.480 --> 00:21:30.930 This makes it easier to see 331 00:21:30.930 --> 00:21:32.080 You can see 332 00:21:34.720 --> 00:21:37.440 that here, on OwnerName, BP ThirdPersonCharacter 333 00:21:37.440 --> 00:21:39.720 is there 334 00:21:39.720 --> 00:21:41.959 Here, BP ThirdPersonCharacter 335 00:21:41.959 --> 00:21:44.959 You can check that it shows up 336 00:21:44.959 --> 00:21:48.360 That means b-replication option is activated as true 337 00:21:48.360 --> 00:21:52.879 so the network can be communicated 338 00:21:52.879 --> 00:21:55.779 Right, and 339 00:21:56.559 --> 00:21:59.279 what about local role? 340 00:21:59.279 --> 00:22:01.360 Just now, it said role none 341 00:22:01.360 --> 00:22:04.040 but now it says simulate proxy 342 00:22:04.040 --> 00:22:07.400 This is made in the server and managed in the server 343 00:22:07.400 --> 00:22:11.800 so on the client, it just simply says that 344 00:22:11.800 --> 00:22:13.000 it's simulated 345 00:22:13.000 --> 00:22:16.199 And the current owner is this 346 00:22:17.279 --> 00:22:20.680 Good Then now, the NetActor in the network 347 00:22:20.680 --> 00:22:25.199 has all the basic settings done for communication 348 00:22:25.199 --> 00:22:30.080 We'll use this to sync the property value 349 00:22:34.000 --> 00:22:37.559 First, we'll sync rotation 350 00:22:37.559 --> 00:22:42.679 We'll make the NetActor here spin 351 00:22:42.680 --> 00:22:45.599 and we'll make that be synced 352 00:22:45.599 --> 00:22:47.520 between the server and client 353 00:22:48.960 --> 00:22:51.239 Go to Visual Studio 354 00:22:52.839 --> 00:22:54.559 and to sync rotation 355 00:22:54.559 --> 00:22:57.320 we'll add a sync variable 356 00:22:57.320 --> 00:22:59.480 Go to NetActor header file 357 00:23:01.600 --> 00:23:05.960 and we'll add it on the very bottom 358 00:23:05.960 --> 00:23:13.039 public, and we'll add a rotation value sync variable 359 00:23:13.039 --> 00:23:16.600 UPROPERTY and 360 00:23:16.600 --> 00:23:20.839 here, float, the rotation value 361 00:23:20.839 --> 00:23:24.039 will be based on one axis 362 00:23:24.039 --> 00:23:29.639 It won't be all the values on X, Y, Z 363 00:23:29.639 --> 00:23:32.479 but just one 364 00:23:32.479 --> 00:23:34.960 so that there is less data packet 365 00:23:34.960 --> 00:23:39.320 So I'll put RotYaw here 366 00:23:39.320 --> 00:23:41.520 in lower case, RotYaw 367 00:23:41.520 --> 00:23:45.039 This is to sync the rotation Yaw value 368 00:23:45.039 --> 00:23:48.960 Doing only this 369 00:23:48.960 --> 00:23:52.119 will network sync all the data here 370 00:23:52.119 --> 00:23:55.160 which will then 371 00:23:55.160 --> 00:23:58.080 waste too much packets 372 00:23:58.080 --> 00:24:02.279 So in property replication, the property member variable 373 00:24:02.279 --> 00:24:04.160 that you're aiming to sync 374 00:24:04.160 --> 00:24:08.520 These member variables need a certain option 375 00:24:08.520 --> 00:24:12.720 What that is is you need this option in this UPROPERTY 376 00:24:12.720 --> 00:24:17.160 You put the option value of Replicated 377 00:24:17.160 --> 00:24:21.610 and then, this will be subject to network syncing 378 00:24:21.610 --> 00:24:22.900 That's what this is saying 379 00:24:24.800 --> 00:24:26.580 Then let's build 380 00:24:28.880 --> 00:24:30.440 Then 381 00:24:30.440 --> 00:24:33.800 you can see an error message 382 00:24:33.800 --> 00:24:37.920 It says error link 383 00:24:37.920 --> 00:24:42.040 and unverifiable external symbol and public virtual void 384 00:24:42.040 --> 00:24:48.920 It says that the function GetLifetimeReplicatedProps is not implemented 385 00:24:48.920 --> 00:24:52.160 This error because that is missing 386 00:24:52.160 --> 00:24:56.640 We just need to implement that here 387 00:24:56.640 --> 00:25:00.640 I'll take this part 388 00:25:00.640 --> 00:25:03.740 and put it down here 389 00:25:03.740 --> 00:25:09.760 GetLifetimeReplicatedProps 390 00:25:09.760 --> 00:25:12.519 I'll put that here 391 00:25:12.519 --> 00:25:19.140 and const, then this function is redefined 392 00:25:20.720 --> 00:25:26.640 Here, super, on GetLifetimeReplicatedProps 393 00:25:26.640 --> 00:25:28.740 I'll put this variable 394 00:25:30.040 --> 00:25:35.320 Now finally, the implementation part for syncing RotYaw will go in 395 00:25:35.320 --> 00:25:37.799 Here's where that goes 396 00:25:37.799 --> 00:25:43.000 The function used here is do replicate lifetime 397 00:25:43.000 --> 00:25:46.799 DOREPLIFETIME 398 00:25:46.799 --> 00:25:50.880 Put ANetActor, source here 399 00:25:50.880 --> 00:25:54.119 and then RotYaw 400 00:25:54.119 --> 00:25:57.519 What happens? 401 00:25:57.519 --> 00:26:00.640 The implementation that syncs this on network 402 00:26:00.640 --> 00:26:03.640 is added here 403 00:26:03.640 --> 00:26:10.399 Above net high, you need to include so that unreal network.hr can be used 404 00:26:10.399 --> 00:26:12.149 Then we'll implement rotation value setting 405 00:26:12.149 --> 00:26:15.359 for rotation syncing 406 00:26:15.359 --> 00:26:18.159 Under find owner 407 00:26:18.159 --> 00:26:22.540 we'll implement the part that does the rotation 408 00:26:24.000 --> 00:26:27.320 Let's first make it rotate 409 00:26:27.320 --> 00:26:34.440 How we do that is, there's this function add actor local rotation 410 00:26:34.440 --> 00:26:40.720 It says add, so it's a function that keeps adding rotation value 411 00:26:40.720 --> 00:26:44.040 We also have quaternion value 412 00:26:44.040 --> 00:26:48.880 and you can also put rotator value as well 413 00:26:48.880 --> 00:26:52.880 We'll put FRotator 414 00:26:52.880 --> 00:26:57.079 and the value will be Pitch Yaw Role 415 00:26:57.079 --> 00:26:58.929 so put Pitch Yaw Role 416 00:26:58.929 --> 00:27:01.760 and we'll put vallue in the 417 00:27:01.760 --> 00:27:04.799 parameter that says InYaw 418 00:27:04.799 --> 00:27:10.559 Rotation speed will be 50 multiplied by 419 00:27:10.559 --> 00:27:15.280 delta time 420 00:27:17.660 --> 00:27:21.000 and pitch and role will be 0 421 00:27:21.000 --> 00:27:24.920 Then it will rotate in this speed 422 00:27:24.920 --> 00:27:28.640 Let's check if this part works first 423 00:27:28.640 --> 00:27:31.279 It will rotate now 424 00:27:31.279 --> 00:27:33.880 Let's check that 425 00:27:33.880 --> 00:27:37.239 Click on the play button 426 00:27:37.239 --> 00:27:41.960 and you can see that our blueprint NetActor is rotating 427 00:27:44.160 --> 00:27:47.679 But let's see here 428 00:27:47.679 --> 00:27:51.679 First check the one on the server 429 00:27:51.679 --> 00:27:53.799 and then from the client 430 00:27:53.799 --> 00:27:56.399 It seems that both are rotating well 431 00:27:56.399 --> 00:27:58.320 But this part, strictly speaking 432 00:27:58.320 --> 00:28:00.520 isn't rotating because it's network synced 433 00:28:00.520 --> 00:28:02.079 Why? 434 00:28:02.079 --> 00:28:06.679 It's just each of them rotating this actor 435 00:28:06.679 --> 00:28:09.959 It's not that we want all clients to be rotating separately 436 00:28:09.959 --> 00:28:15.079 but for them to be synced to the 437 00:28:15.079 --> 00:28:17.079 rotation data value of the server 438 00:28:18.279 --> 00:28:23.480 Right, so strictly speaking, this part is wrong 439 00:28:23.480 --> 00:28:25.920 We need to make data on the server 440 00:28:25.920 --> 00:28:30.399 and then make all clients rotate 441 00:28:30.399 --> 00:28:33.040 with this data 442 00:28:33.040 --> 00:28:34.839 So we'll work on this rotation part 443 00:28:34.839 --> 00:28:36.639 by separating them to 444 00:28:36.639 --> 00:28:39.000 server and client each 445 00:28:39.000 --> 00:28:43.320 First, for server 446 00:28:43.320 --> 00:28:48.239 Rotate 447 00:28:49.959 --> 00:28:53.679 and then what 448 00:28:53.679 --> 00:28:56.619 Rotation value 449 00:28:58.679 --> 00:29:01.599 We'll remember that 450 00:29:01.599 --> 00:29:03.159 Remembering rotation value data means 451 00:29:03.159 --> 00:29:06.880 that this data will be sent to all clients 452 00:29:06.880 --> 00:29:10.100 And when it's not the server 453 00:29:10.100 --> 00:29:17.420 In that case, rotation synchronization with the rotation value 454 00:29:19.220 --> 00:29:23.619 received from the server 455 00:29:25.919 --> 00:29:30.119 Let's work on the server first 456 00:29:30.119 --> 00:29:32.400 As I mentioned until now, for the server 457 00:29:32.400 --> 00:29:39.280 it's the server if the if has authority function is true 458 00:29:39.280 --> 00:29:42.580 Here, the code that rotates and remembers the value 459 00:29:42.580 --> 00:29:43.920 will be in here 460 00:29:45.840 --> 00:29:47.000 This is the rotation 461 00:29:47.000 --> 00:29:49.880 and this will be the part that remembers the rotation value data 462 00:29:49.880 --> 00:29:55.479 Here we have the RotYaw function 463 00:29:55.479 --> 00:29:58.520 On that function 464 00:29:58.520 --> 00:30:02.799 we'll take the rotation information of the 465 00:30:02.799 --> 00:30:05.900 actor that's rotating right now 466 00:30:07.320 --> 00:30:09.799 What value? 467 00:30:09.799 --> 00:30:12.220 We'll put the Yaw value in 468 00:30:14.000 --> 00:30:17.159 What we're trying to sync is this Yaw value 469 00:30:17.159 --> 00:30:19.679 so we'll take that and sync it 470 00:30:21.719 --> 00:30:24.219 Then the client, if not the server 471 00:30:24.219 --> 00:30:25.719 it will be a client 472 00:30:28.359 --> 00:30:32.000 Here, we said that we sync rotation using the rotation value from the server 473 00:30:32.000 --> 00:30:36.200 That mean's that we'll put the RotYaw part on my rotation value 474 00:30:36.200 --> 00:30:39.640 We'll take that and remember it 475 00:30:43.960 --> 00:30:48.119 Frotator and newRot 476 00:30:48.119 --> 00:30:51.119 Take the getActorRotation value 477 00:30:51.119 --> 00:30:53.520 and save that 478 00:30:53.520 --> 00:30:58.840 Then on the Yaw value of newRot 479 00:30:58.840 --> 00:31:00.960 we'll put the RotYaw 480 00:31:00.960 --> 00:31:03.820 that we got synced from the server 481 00:31:03.820 --> 00:31:07.700 And on the setActorRotation value of the actor 482 00:31:10.440 --> 00:31:13.579 we'll have newRot 483 00:31:15.679 --> 00:31:19.400 Let's build and play 484 00:31:22.080 --> 00:31:24.679 Then there 485 00:31:24.679 --> 00:31:27.960 NetActor is rotating 486 00:31:27.960 --> 00:31:30.760 and adding a client 487 00:31:30.760 --> 00:31:34.200 we can see that it's rotating as well 488 00:31:34.200 --> 00:31:37.039 Right? They are synced 489 00:31:37.039 --> 00:31:38.520 in network 490 00:31:38.520 --> 00:31:40.960 This is done automatically 491 00:31:40.960 --> 00:31:43.400 in property replication 492 00:31:43.400 --> 00:31:45.000 Very simple 493 00:31:45.000 --> 00:31:49.640 But there's more to think here, why? 494 00:31:49.640 --> 00:31:53.760 Tick can be called every frame, that is 495 00:31:53.760 --> 00:31:57.280 60 times a second or 30, 60, or more than 100 times 496 00:31:57.280 --> 00:32:01.919 Receiving data from the server every time is a problem on its own 497 00:32:01.919 --> 00:32:04.440 but also the server will keep changing the data value 498 00:32:04.440 --> 00:32:07.840 But even when it doesn't 499 00:32:07.840 --> 00:32:12.880 Even when there's no change in the tick value 500 00:32:12.880 --> 00:32:17.080 the tick function will continue to update the value 501 00:32:17.080 --> 00:32:21.440 Right? We're wasting the CPU 502 00:32:21.440 --> 00:32:23.479 Even when it's not receiving data from the network 503 00:32:23.479 --> 00:32:27.719 tick will keep updating which is a problem 504 00:32:27.719 --> 00:32:32.080 So it will be more efficient if 505 00:32:32.080 --> 00:32:36.200 we have it be updated 506 00:32:36.200 --> 00:32:38.840 only when the rotYaw value is changed 507 00:32:38.840 --> 00:32:41.359 Let's learn that 508 00:32:41.359 --> 00:32:45.919 Go to netActor.h on Unreal Engine 509 00:32:45.919 --> 00:32:48.679 On the UPROPERTY option 510 00:32:48.679 --> 00:32:50.559 it says replicated 511 00:32:50.559 --> 00:32:54.320 We use not replicated but 512 00:32:54.320 --> 00:32:56.400 a different option 513 00:32:56.400 --> 00:33:00.799 I'll copy this and put it as annotation 514 00:33:00.799 --> 00:33:04.280 I'll say Replicated using here 515 00:33:04.280 --> 00:33:07.280 Then after that 516 00:33:07.280 --> 00:33:11.280 I can register an event call back function 517 00:33:11.280 --> 00:33:16.200 hat will be called when the rotYaw property value has changed 518 00:33:16.200 --> 00:33:18.159 It's basically a promise 519 00:33:18.159 --> 00:33:22.200 It starts with OnRep_ 520 00:33:22.200 --> 00:33:25.159 Put the variable name after that, RotYaw 521 00:33:25.159 --> 00:33:29.280 and then the function with that name will be called 522 00:33:29.280 --> 00:33:33.559 When the property rotYaw, the value changes 523 00:33:34.359 --> 00:33:39.599 the function OnRep RotYaw will be called 524 00:33:39.599 --> 00:33:43.080 Then this one will be registered like this on the engine 525 00:33:43.080 --> 00:33:44.919 and be called automatically 526 00:33:44.919 --> 00:33:46.919 so just function declaration isn't good 527 00:33:46.919 --> 00:33:51.679 We need to put UFUNCTION Macro 528 00:33:51.679 --> 00:33:56.039 for Unreal runtime to automatically call this one 529 00:33:56.039 --> 00:33:59.559 void, and call 530 00:33:59.559 --> 00:34:02.719 Let me implement this function 531 00:34:02.719 --> 00:34:05.440 Great, OnRep Yaw. RotYaw 532 00:34:05.440 --> 00:34:08.719 and I'll implement this one right under the tick function 533 00:34:08.719 --> 00:34:13.880 Under here 534 00:34:13.880 --> 00:34:14.730 Good 535 00:34:14.730 --> 00:34:19.440 What we got from the server will be here, not here 536 00:34:19.440 --> 00:34:22.840 If it's not the server, this doesn't need to be managed 537 00:34:22.840 --> 00:34:26.000 Because if the rotYaw is changed 538 00:34:26.000 --> 00:34:28.880 OnRep RotYaw is automatically called 539 00:34:28.880 --> 00:34:30.960 Let's build 540 00:34:30.960 --> 00:34:34.880 On tick, if the server, the value will be changed 541 00:34:34.880 --> 00:34:36.640 and if client 542 00:34:36.640 --> 00:34:40.200 the OnRep RotYaw function will be called 543 00:34:40.200 --> 00:34:43.679 and this will be done automatically 544 00:34:43.679 --> 00:34:47.460 Let's play it 545 00:34:47.460 --> 00:34:52.080 and also a client 546 00:34:52.080 --> 00:34:56.659 Then you can see that it rotates on the client as well 547 00:34:58.579 --> 00:35:03.239 And the ones here registered on the property replication 548 00:35:03.239 --> 00:35:08.559 How often will they be updated? 549 00:35:08.559 --> 00:35:12.760 That's in here as a default option 550 00:35:12.760 --> 00:35:18.320 On NetActor, you see this class default 551 00:35:18.320 --> 00:35:22.840 Search net update here 552 00:35:22.840 --> 00:35:24.780 and you'll see net update frequency 553 00:35:27.200 --> 00:35:30.520 This is set as 100 554 00:35:30.521 --> 00:35:33.980 Actors will by default, NetUpdateFrequency 555 00:35:33.980 --> 00:35:37.919 will be called 100 times per second 556 00:35:37.919 --> 00:35:39.799 and updated, that's the setting 557 00:35:39.799 --> 00:35:41.599 Just because it's set as 100 558 00:35:41.599 --> 00:35:43.679 doesn't mean that it will always do that 559 00:35:43.679 --> 00:35:46.559 Depending on the network environment it could fall 560 00:35:46.559 --> 00:35:48.000 or become 1 561 00:35:48.000 --> 00:35:50.320 if it's very slow 562 00:35:50.320 --> 00:35:52.559 But the default actor 563 00:35:52.559 --> 00:35:57.919 is set to have the frequency of 100 times per second 564 00:35:57.919 --> 00:36:01.479 So we change the data 565 00:36:01.479 --> 00:36:03.479 it will be updated immediately 566 00:36:03.479 --> 00:36:07.080 if the 100 frame stands, right? 567 00:36:07.080 --> 00:36:09.320 But if, on network 568 00:36:09.320 --> 00:36:13.159 there's too much latency 569 00:36:13.159 --> 00:36:14.599 meaning that it lags 570 00:36:14.599 --> 00:36:16.960 Then, the NetUpdateFrequency of 571 00:36:16.960 --> 00:36:19.000 100 that's set here 572 00:36:19.000 --> 00:36:20.599 might not work properly 573 00:36:20.599 --> 00:36:23.280 Then it will have pauses 574 00:36:23.280 --> 00:36:28.840 For example, let me change this NetUpdateFrequency 575 00:36:28.840 --> 00:36:35.200 First close this, and on constructor, there's net duplicate 576 00:36:35.200 --> 00:36:40.400 I'll change the NetUpdateFrequency to 1.0 577 00:36:40.400 --> 00:36:43.880 and let's run it 578 00:36:43.880 --> 00:36:45.320 Then, on server 579 00:36:45.320 --> 00:36:48.919 I kept it to rotate at this speed 580 00:36:48.919 --> 00:36:51.080 But client might have a problem here 581 00:36:51.080 --> 00:36:55.640 That one's set to be updated only once a second 582 00:36:55.641 --> 00:36:59.260 so on the client, 583 00:36:59.260 --> 00:37:02.279 it will receive the changed event and be updated only once every second 584 00:37:04.799 --> 00:37:07.039 Let's see how that looks 585 00:37:07.039 --> 00:37:11.239 Let's play 586 00:37:11.239 --> 00:37:16.559 On the server, you can see that it's rotating smoothly 587 00:37:16.559 --> 00:37:18.399 Let's see from the client 588 00:37:19.599 --> 00:37:21.599 How does it look 589 00:37:21.599 --> 00:37:26.760 You can see that it's pausing, it's being updated just once every second 590 00:37:26.760 --> 00:37:28.800 so it's trying to catch up the server value 591 00:37:28.800 --> 00:37:32.120 It's being updated every second and pausing in between 592 00:37:34.040 --> 00:37:39.040 Like this, the NetUpdateFrequency is set as 100 593 00:37:39.040 --> 00:37:42.280 but that doesn't mean that all actors have the default of 100 594 00:37:42.280 --> 00:37:45.800 Why? There are instances where 1 is enough every second 595 00:37:45.800 --> 00:37:49.680 The game won't have much problem even if it's updated just once a second 596 00:37:49.680 --> 00:37:52.839 So on game state classes 597 00:37:52.839 --> 00:37:56.920 the net update is set to be just once 598 00:37:56.920 --> 00:38:01.119 Depending on objects 599 00:38:01.119 --> 00:38:03.479 the value might vary 600 00:38:03.479 --> 00:38:06.400 But the basic actors like Pawn 601 00:38:06.400 --> 00:38:08.750 and characters 602 00:38:08.750 --> 00:38:10.720 are set on 100 by default 603 00:38:12.880 --> 00:38:17.920 Next, let's sync the material and color 604 00:38:17.920 --> 00:38:19.680 On begin play, we'll use a timer 605 00:38:19.680 --> 00:38:23.520 to update it 606 00:38:23.520 --> 00:38:27.000 And every time it is updated 607 00:38:27.000 --> 00:38:30.000 the updated value will be received as event function 608 00:38:30.000 --> 00:38:32.439 and from then on the clients will also 609 00:38:32.439 --> 00:38:34.400 be synced 610 00:38:34.400 --> 00:38:36.040 Go back to header file 611 00:38:36.040 --> 00:38:41.680 and to sync the material color, make it public 612 00:38:41.680 --> 00:38:46.920 and put material, color 613 00:38:46.920 --> 00:38:49.280 First, UPROPERTY 614 00:38:49.281 --> 00:38:51.980 class MaterialInstance 615 00:38:51.980 --> 00:38:55.199 I'll put dynamic MaterialInstance 616 00:38:55.199 --> 00:39:02.879 I'll put UMaterialInstanceDynamic 617 00:39:04.119 --> 00:39:07.959 Then we'll name the variable mat 618 00:39:07.959 --> 00:39:13.439 and have the color of the material that will be synced as a variable 619 00:39:13.439 --> 00:39:20.959 This will be the property that we'll sync 620 00:39:20.959 --> 00:39:22.719 UPROPERTY 621 00:39:22.719 --> 00:39:26.439 and then I'll use ReplicatedUsing 622 00:39:26.439 --> 00:39:33.719 Let's say the function name will go OnRep_ 623 00:39:33.719 --> 00:39:38.560 and ChangeMatColor 624 00:39:38.560 --> 00:39:42.719 Then that means a function with this name will have to exist 625 00:39:42.719 --> 00:39:49.839 Put FLinearColor, MatColor 626 00:39:49.839 --> 00:39:54.479 Then we have to make the OnRep ChangeMatColor function 627 00:39:54.479 --> 00:39:57.800 Add a UFUNCTION macro 628 00:39:57.800 --> 00:40:01.420 and declare void here 629 00:40:03.800 --> 00:40:08.400 Here, the variable to by synced, the property will be MatColor 630 00:40:08.400 --> 00:40:12.719 and when this MatColor is changed, the function 631 00:40:12.719 --> 00:40:14.860 OnRep ChangeMatColor will be called 632 00:40:15.900 --> 00:40:18.520 Right? We'll add implementation on this one 633 00:40:20.660 --> 00:40:27.580 and I'll move this under BeginPlay 634 00:40:27.580 --> 00:40:30.460 to see if BeginPlay calls and it is synced properly 635 00:40:30.460 --> 00:40:33.300 I'll move it here to do that 636 00:40:34.420 --> 00:40:37.300 Great, now this option that on network 637 00:40:37.300 --> 00:40:42.340 it wlil be synced is declared that 638 00:40:42.340 --> 00:40:46.959 But we can't just declare this MatColor 639 00:40:46.960 --> 00:40:51.199 but we also have to add this one to the definition part On the very bottom of NetActor 640 00:40:51.199 --> 00:40:54.080 there's this function GetLifetimeReplicatedProps 641 00:40:54.080 --> 00:41:00.679 Here, like rotYaw, matColor needs to be registered 642 00:41:03.112 --> 00:41:06.412 Great, it must be registered 643 00:41:06.412 --> 00:41:09.679 for this to be synced automatically when value changes on network 644 00:41:13.920 --> 00:41:17.140 Good, now let's go to BeginPlay 645 00:41:19.439 --> 00:41:22.080 In the beginning 646 00:41:23.759 --> 00:41:28.359 to bring and put dynamic material instance, we'll put mat 647 00:41:28.359 --> 00:41:29.400 and this mat 648 00:41:31.240 --> 00:41:35.200 will have the 0th one of 649 00:41:35.200 --> 00:41:40.379 CreateDynamicMaterialInstance 650 00:41:40.379 --> 00:41:42.559 from meshComp on NetActor 651 00:41:46.180 --> 00:41:49.440 Then we'll put the code that 652 00:41:49.440 --> 00:41:55.059 works when the value is changed in this function 653 00:41:55.060 --> 00:41:59.620 if mat 654 00:41:59.620 --> 00:42:05.119 There will be setVectorParameterValue in mat 655 00:42:07.100 --> 00:42:09.340 We have to put the parameter name here 656 00:42:09.340 --> 00:42:12.679 How do we know this parameter is right here 657 00:42:14.839 --> 00:42:18.639 The material the our NetActor is using is right here 658 00:42:18.639 --> 00:42:21.539 Double click on this 659 00:42:24.620 --> 00:42:27.020 and the material instance shows up here 660 00:42:27.021 --> 00:42:31.580 The thing we want to change is this FloorColor 661 00:42:31.580 --> 00:42:33.080 You see FloorColor here 662 00:42:33.080 --> 00:42:36.500 There's also GlowColor but I'll change FloorColor only 663 00:42:36.500 --> 00:42:40.940 I'll change the FloorColor which is grey right now 664 00:42:42.860 --> 00:42:46.740 Come to Visual Studio and on setVectorParameterValue 665 00:42:46.740 --> 00:42:51.779 The value we'll put in, the parameter will be text 666 00:42:51.800 --> 00:42:56.050 and here, FloorColor 667 00:42:56.050 --> 00:43:00.740 We're going to update this to matColor 668 00:43:02.900 --> 00:43:05.450 Update to matColor 669 00:43:05.450 --> 00:43:08.120 This function, onWrapChangeMatColor 670 00:43:08.120 --> 00:43:10.960 is called when matColor is updated 671 00:43:10.960 --> 00:43:15.660 This will change to the updated material color 672 00:43:15.660 --> 00:43:18.420 Then we'll need a code that updates this 673 00:43:19.960 --> 00:43:25.360 We'll make one using a timer on BeginPlay 674 00:43:25.360 --> 00:43:28.210 The action of making the data that changes value 675 00:43:28.210 --> 00:43:29.579 must be done where? 676 00:43:29.580 --> 00:43:31.480 On the server 677 00:43:31.480 --> 00:43:37.800 Action of making data, changing 678 00:43:39.180 --> 00:43:43.899 It must be done in the server 679 00:43:43.899 --> 00:43:49.039 Then we'll check if server, has authority 680 00:43:49.039 --> 00:43:53.039 and we'll put the timer on 681 00:43:53.039 --> 00:43:58.160 FTimerHandle. Handle 682 00:43:58.161 --> 00:44:03.020 and GetWorldTimerManager, SetTimer 683 00:44:03.020 --> 00:44:06.680 Put a handle here and FTimerDelegate 684 00:44:09.780 --> 00:44:14.000 create Lambda, we'll use Lambda 685 00:44:14.000 --> 00:44:23.119 Capture, annotate, and we'll do this 686 00:44:23.119 --> 00:44:27.499 We'll put the needed values here 687 00:44:29.279 --> 00:44:37.300 First, the matColor. We'll have to put values in 688 00:44:37.301 --> 00:44:39.440 FLinearColor one by one 689 00:44:39.440 --> 00:44:44.699 We'll have RandRange on FMath 690 00:44:48.300 --> 00:44:52.240 and make it have a value between 0.0 and 0.3 691 00:44:53.700 --> 00:44:56.679 We'll put RGB on X, Y, Z 692 00:44:56.679 --> 00:45:00.180 We're going to copy this part and keep them the same 693 00:45:03.079 --> 00:45:08.200 We'll make them three 694 00:45:08.200 --> 00:45:11.860 And the last value will be 1, the alpha value 695 00:45:14.920 --> 00:45:19.400 Then comma, 1 696 00:45:19.400 --> 00:45:24.800 and we'll put true at the end 697 00:45:28.040 --> 00:45:31.759 We're making it repeat the process 698 00:45:31.759 --> 00:45:35.200 and this means to repeat every 1 second 699 00:45:35.201 --> 00:45:40.080 Great, what we know from this is that every second 700 00:45:40.080 --> 00:45:45.720 matColor will be updated repeatedly 701 00:45:45.721 --> 00:45:50.660 If the matColor is updated, OnRep ChanheMatColor is called 702 00:45:50.660 --> 00:45:55.160 and the clients will be synced to this value 703 00:45:55.160 --> 00:45:58.019 Let's build and see 704 00:45:59.460 --> 00:46:01.900 On the server, it's not updated 705 00:46:01.900 --> 00:46:03.550 But on the client 706 00:46:03.550 --> 00:46:07.160 you can see that it's being updated 707 00:46:07.160 --> 00:46:09.560 The color changes only for the client 708 00:46:09.560 --> 00:46:10.760 The reason is? 709 00:46:12.620 --> 00:46:15.440 The server only changes the data 710 00:46:15.441 --> 00:46:17.160 Right? It's not implementing it 711 00:46:17.160 --> 00:46:21.200 OnRep event function only updates it 712 00:46:21.201 --> 00:46:26.380 But on C++, how does this OnRep event function work? 713 00:46:26.380 --> 00:46:28.030 It's called only on the clients 714 00:46:28.030 --> 00:46:30.160 So only the clients' colors change 715 00:46:30.161 --> 00:46:33.420 It's not calledo n the server so it doesn't change 716 00:46:33.420 --> 00:46:37.239 So what do we do, how do we sync the server? 717 00:46:37.240 --> 00:46:40.019 We'll have to call this function 718 00:46:40.020 --> 00:46:44.759 so on the timer, we'll change matColor and 719 00:46:44.759 --> 00:46:46.680 call it here 720 00:46:48.160 --> 00:46:51.400 Let's build again 721 00:46:53.799 --> 00:46:57.499 Now on the server as well, it's changing properly 722 00:46:57.499 --> 00:46:59.199 On the client as well 723 00:47:01.139 --> 00:47:01.939 How does it look? 724 00:47:01.939 --> 00:47:05.760 You can see that they are synced and changing 725 00:47:07.320 --> 00:47:10.792 This was property replication 726 00:47:10.792 --> 00:47:13.272 RPC 727 00:47:14.839 --> 00:47:18.080 Now we'll learn about RPC 728 00:47:18.080 --> 00:47:21.359 RPC is the abbreviation of remote procedure call 729 00:47:21.359 --> 00:47:22.909 and RPC is used 730 00:47:22.909 --> 00:47:26.899 when you want to run a function on a remote 731 00:47:26.900 --> 00:47:28.279 someone else's computer 732 00:47:28.279 --> 00:47:32.679 This RPC is the only way for the client to express their opinion 733 00:47:32.679 --> 00:47:36.299 Requests like asking the server to run the logic of 734 00:47:36.300 --> 00:47:39.359 shooting a gun can be done with this RPC 735 00:47:39.359 --> 00:47:41.209 Then to use RPC 736 00:47:41.209 --> 00:47:45.119 let's talk about more detailed operation structure 737 00:47:45.120 --> 00:47:48.519 RPC works in 3 ways 738 00:47:48.519 --> 00:47:52.000 Server, client, and NetMulticast 739 00:47:52.000 --> 00:47:57.399 First, the server is used to call a function in the server from the client 740 00:47:57.399 --> 00:48:02.479 and the client is used to call a function in the client from the server 741 00:48:02.479 --> 00:48:04.879 This applies to only one client 742 00:48:05.959 --> 00:48:10.399 Lastly, NetMulticast, unlike client option I just mentioned 743 00:48:10.399 --> 00:48:14.160 is used to call function in all clients from the server 744 00:48:14.161 --> 00:48:15.660 For example, on chat 745 00:48:15.660 --> 00:48:20.600 you can send a message you typed using server option to the server 746 00:48:20.601 --> 00:48:22.340 and the server can again 747 00:48:22.340 --> 00:48:26.359 send that to client option or NetMulticast option 748 00:48:26.359 --> 00:48:29.320 To send it to just one client 749 00:48:29.321 --> 00:48:31.161 use client option 750 00:48:31.161 --> 00:48:33.640 and to send it to all users 751 00:48:33.640 --> 00:48:36.239 you can use NetMulticast option 752 00:48:36.239 --> 00:48:38.139 Looking at a diagram 753 00:48:38.139 --> 00:48:41.839 you can understand how RPC works better 754 00:48:41.839 --> 00:48:43.489 First, from the client 755 00:48:43.489 --> 00:48:48.000 user sends a message to the server using server RPC option 756 00:48:48.000 --> 00:48:51.559 This works by calling a function in the server 757 00:48:51.559 --> 00:48:54.559 And when that function is called in the server 758 00:48:54.559 --> 00:48:56.760 server processes the game's logic 759 00:48:56.761 --> 00:49:00.060 and send the result to clients 760 00:49:00.060 --> 00:49:04.520 using client RPC option or NetMulticast RPC option 761 00:49:04.520 --> 00:49:09.080 This also works by calling each clients' functions 762 00:49:09.081 --> 00:49:12.180 When the client function is called, the client 763 00:49:12.180 --> 00:49:15.840 syncs to the data the the server sent 764 00:49:15.840 --> 00:49:20.080 or updates the effect on the screen or UI 765 00:49:20.081 --> 00:49:23.160 Unreal Engine uses this RPC 766 00:49:23.160 --> 00:49:28.760 When a client receives an input 767 00:49:28.760 --> 00:49:35.000 then it requests to the server 768 00:49:35.001 --> 00:49:37.700 It sends a request 769 00:49:37.700 --> 00:49:40.080 to the server 770 00:49:40.080 --> 00:49:43.139 Then on the server, it processes a game logic 771 00:49:43.140 --> 00:49:45.479 How will it request then 772 00:49:45.480 --> 00:49:48.359 It uses RPC to request 773 00:49:49.179 --> 00:49:50.929 It requests with RPC 774 00:49:50.929 --> 00:49:54.540 and the server runs the logic and the result 775 00:49:54.540 --> 00:49:59.590 is sent back to the client using property replication 776 00:49:59.590 --> 00:50:01.840 or another RPC 777 00:50:01.840 --> 00:50:04.779 to call a function in the client 778 00:50:06.520 --> 00:50:11.760 RPC works in several ways 779 00:50:11.761 --> 00:50:14.900 As you saw on the screen 780 00:50:14.900 --> 00:50:20.100 there's server RPC where client sends to server 781 00:50:22.800 --> 00:50:27.560 and there's one that server 782 00:50:27.560 --> 00:50:31.320 sends to client, this was client to server 783 00:50:32.980 --> 00:50:37.300 and this one is server to client 784 00:50:37.300 --> 00:50:39.460 Here, there are two types 785 00:50:40.740 --> 00:50:45.280 One is client RPC 786 00:50:45.280 --> 00:50:50.119 and the other is NetMulticast 787 00:50:51.540 --> 00:50:55.920 NetMulticast, this one 788 00:50:57.540 --> 00:51:00.679 sends to just one client 789 00:51:00.679 --> 00:51:02.379 But NetMulticast under here 790 00:51:02.379 --> 00:51:04.979 sends to all clients 791 00:51:06.599 --> 00:51:09.999 So this time, NetMulticast 792 00:51:09.999 --> 00:51:15.119 client, and server RPC Using this RPC 793 00:51:15.119 --> 00:51:18.260 we'll change the color value 794 00:51:21.840 --> 00:51:26.040 Go to Visual Studio 795 00:51:27.760 --> 00:51:32.300 and go to NetActor.h 796 00:51:32.300 --> 00:51:37.100 Here, when matColor changes 797 00:51:37.100 --> 00:51:39.239 this function is called automatically 798 00:51:39.240 --> 00:51:43.239 We'll change this part using RPC 799 00:51:43.239 --> 00:51:46.559 RPC will be here separately 800 00:51:46.560 --> 00:51:50.139 UFUNCTION 801 00:51:50.139 --> 00:51:54.039 To use RPC, put UFUNCTION and 802 00:51:54.039 --> 00:52:01.489 have the option of serve, client, or NetMulticast 803 00:52:01.489 --> 00:52:08.744 First, we make the server RPC 804 00:52:08.744 --> 00:52:13.599 The server will request a client to change the color 805 00:52:13.600 --> 00:52:16.079 Then the server will receive that and 806 00:52:16.079 --> 00:52:19.180 send to all clients to change the color 807 00:52:19.960 --> 00:52:23.960 Server, and there's another option 808 00:52:23.960 --> 00:52:28.910 Here, reliable or unreliable 809 00:52:28.910 --> 00:52:30.719 There are these two options 810 00:52:30.720 --> 00:52:35.759 Reliable means trusting the data 811 00:52:35.759 --> 00:52:41.350 The function I'm calling might be omitted on the network 812 00:52:41.350 --> 00:52:47.320 But if it's reliable, it means that it will be ensured not to be omitted 813 00:52:47.320 --> 00:52:50.620 Here, to make sure to change the color 814 00:52:50.620 --> 00:52:53.679 we'll put reliable 815 00:52:53.680 --> 00:52:59.279 void server, we use this like a promise 816 00:52:59.279 --> 00:53:02.359 It could be used in different forms for different developers 817 00:53:02.359 --> 00:53:05.009 but to let you know that it's an RPC function 818 00:53:05.009 --> 00:53:09.840 it will be good to mention server RPC 819 00:53:09.840 --> 00:53:15.180 We'll put ServerRPC_ChangeColor 820 00:53:15.180 --> 00:53:17.380 const f linear 821 00:53:18.840 --> 00:53:24.919 Color, renew color 822 00:53:24.919 --> 00:53:29.000 Then let's work on this value 823 00:53:31.479 --> 00:53:36.159 if mat, we'll 824 00:53:36.160 --> 00:53:41.119 like OnRep ChangeMatColor 825 00:53:41.120 --> 00:53:45.539 update to newColor 826 00:53:45.539 --> 00:53:47.639 But there's something weird here right 827 00:53:47.639 --> 00:53:52.979 We gave the function the name ServerRPC ChangeColor from the header 828 00:53:52.979 --> 00:53:58.319 but on the cpp there's this _implimentaion thing 829 00:53:58.320 --> 00:54:02.899 This is here because I used auto completion and why did this happen? 830 00:54:02.899 --> 00:54:07.200 The function ServerRPC ChangeColor here on the original one 831 00:54:07.200 --> 00:54:11.700 is saved in here generated h 832 00:54:11.700 --> 00:54:13.480 And 833 00:54:13.480 --> 00:54:14.730 it's implemented there 834 00:54:14.730 --> 00:54:16.440 We are going to 835 00:54:16.440 --> 00:54:19.159 internally make this function be called using this 836 00:54:19.159 --> 00:54:22.039 _implementation 837 00:54:22.040 --> 00:54:24.119 so to call the implementation of this function 838 00:54:24.119 --> 00:54:25.980 this part is needed 839 00:54:27.400 --> 00:54:28.439 Good? 840 00:54:31.120 --> 00:54:36.640 So to make the server RPC function be called 841 00:54:36.640 --> 00:54:38.520 Let's do that 842 00:54:38.520 --> 00:54:43.360 Go up and as the timer on BeginPlay is called 843 00:54:43.361 --> 00:54:46.301 the value will change and automatically call this 844 00:54:46.302 --> 00:54:50.181 We'll make it call server RPC function here 845 00:54:50.181 --> 00:54:56.500 So annotate this and ServerRPC_ChangeColor 846 00:54:56.501 --> 00:54:58.301 You can also call the implementation function 847 00:54:58.301 --> 00:55:00.960 but then it will only be called in the server 848 00:55:00.960 --> 00:55:04.560 For the client to call the server 849 00:55:04.560 --> 00:55:06.540 this will be better 850 00:55:06.540 --> 00:55:09.919 And then I'll put matColor 851 00:55:09.920 --> 00:55:15.339 This one is also syncing right here 852 00:55:15.339 --> 00:55:18.000 on the header file 853 00:55:18.001 --> 00:55:21.260 So to not change this value 854 00:55:21.260 --> 00:55:28.720 I'll put FLinear color so that they're different 855 00:55:28.721 --> 00:55:32.300 I'll make a separate local variable 856 00:55:32.300 --> 00:55:36.660 Then the matColor in the property and this loval variable will be different 857 00:55:38.640 --> 00:55:43.000 Great, then this function in the server will be called 858 00:55:46.300 --> 00:55:51.560 Then ServerRPC ChangeColor function is called and then 859 00:55:51.560 --> 00:55:53.600 sent to the server 860 00:55:53.600 --> 00:55:58.460 After that this function will be automatically called 861 00:55:58.460 --> 00:56:00.420 and this code will be run 862 00:56:03.280 --> 00:56:06.120 Let's build 863 00:56:08.520 --> 00:56:10.500 Let's see, play 864 00:56:12.040 --> 00:56:14.919 You can see that it's changing properly 865 00:56:14.920 --> 00:56:16.920 Let's play 866 00:56:16.920 --> 00:56:18.459 with a client added 867 00:56:18.459 --> 00:56:23.239 How does it look from the client 868 00:56:23.240 --> 00:56:25.459 Is it changing properly 869 00:56:25.460 --> 00:56:29.099 Nothing's changing, only the server is, why? 870 00:56:29.099 --> 00:56:32.180 Because we're using server RPC 871 00:56:34.480 --> 00:56:37.560 This is run only in the server 872 00:56:37.560 --> 00:56:41.439 Server RPC means client requesting the server 873 00:56:42.360 --> 00:56:45.540 So this code only runs in the server 874 00:56:45.540 --> 00:56:49.559 Then we should make it be updated on the client 875 00:56:49.559 --> 00:56:53.399 With a diagram, this is how it must work 876 00:56:55.320 --> 00:57:00.379 Looking at this part here, client requested the server 877 00:57:00.379 --> 00:57:04.579 Change the color, so the server changed the color 878 00:57:05.540 --> 00:57:07.220 From server RPC 879 00:57:07.220 --> 00:57:09.980 Then what should server RPC do? 880 00:57:09.980 --> 00:57:14.020 I changed the color, update it 881 00:57:14.020 --> 00:57:17.260 It should send that to the client and only then 882 00:57:17.260 --> 00:57:20.020 the client can update it 883 00:57:21.180 --> 00:57:24.600 So we shouldn't do this on the server 884 00:57:24.600 --> 00:57:28.460 but on the client so that the clients can work on that separately 885 00:57:28.460 --> 00:57:31.300 so we'll add client RPC 886 00:57:33.479 --> 00:57:35.700 Here on the very bottom 887 00:57:38.300 --> 00:57:43.560 we'll have UFUNCTION client 888 00:57:43.560 --> 00:57:46.119 Let's say unreliable 889 00:57:46.120 --> 00:57:49.199 This means that it can get omitted and not that it is omitted often or always 890 00:57:49.199 --> 00:57:53.680 Omission doesn't happen often in the network 891 00:57:53.680 --> 00:57:56.999 void ClientRPC, we'll put the name 892 00:57:57.000 --> 00:58:00.959 _ChangeColor 893 00:58:00.959 --> 00:58:04.759 Then const FlinearColor 894 00:58:04.759 --> 00:58:08.520 newColor 895 00:58:08.520 --> 00:58:11.019 Great, let's add implementation 896 00:58:13.080 --> 00:58:17.020 We'll add implementation on netactor.cpp 897 00:58:17.020 --> 00:58:19.719 That's this part on the server 898 00:58:19.719 --> 00:58:22.860 This means that we'll make the client 899 00:58:22.860 --> 00:58:26.520 change colors instead of the server 900 00:58:26.520 --> 00:58:30.820 Then the server can call ClientRPC 901 00:58:30.820 --> 00:58:31.839 Let's do that 902 00:58:31.839 --> 00:58:36.439 ClientRPC, ChangeColor newColor 903 00:58:36.439 --> 00:58:40.599 Then it will be communicated on network 904 00:58:40.600 --> 00:58:41.850 How? 905 00:58:41.850 --> 00:58:45.019 Client requests server RPC to server 906 00:58:45.019 --> 00:58:48.400 Then the server again 907 00:58:48.401 --> 00:58:49.451 runs a logic 908 00:58:49.451 --> 00:58:52.200 which sends a client RPC back 909 00:58:52.200 --> 00:58:56.239 Then the remote, client's 910 00:58:56.239 --> 00:58:59.840 client RPC change color function will be called 911 00:58:59.840 --> 00:59:02.700 Now let's build 912 00:59:03.560 --> 00:59:06.900 Let's play it here 913 00:59:06.900 --> 00:59:11.280 It's being called properly on the server 914 00:59:11.280 --> 00:59:13.530 Right? We can see it 915 00:59:13.530 --> 00:59:16.199 But run a client 916 00:59:18.119 --> 00:59:20.869 and let's see 917 00:59:20.869 --> 00:59:23.959 Does it work properly on the client? 918 00:59:25.940 --> 00:59:28.380 No right? It is on the server 919 00:59:28.380 --> 00:59:29.330 but on the client, it's not changing 920 00:59:29.330 --> 00:59:31.820 But see what I'm going to do 921 00:59:31.820 --> 00:59:34.600 I'll go in here into the boudary 922 00:59:34.600 --> 00:59:36.660 and there's a owner now 923 00:59:38.040 --> 00:59:42.559 The client has owner now 924 00:59:44.079 --> 00:59:45.729 Here the OwnerName 925 00:59:45.729 --> 00:59:49.079 shows BPThirdPersonCharacter in owner 926 00:59:49.080 --> 00:59:51.599 Here, right? 927 00:59:51.599 --> 00:59:55.399 On the NetActor, owner is here 928 00:59:55.399 --> 00:59:57.079 because it's in here 929 00:59:57.080 --> 00:59:59.599 The moment it enters here 930 00:59:59.599 --> 01:00:01.999 they can network communicate 931 01:00:01.999 --> 01:00:04.060 Then let's look and the server 932 01:00:04.060 --> 01:00:07.820 Server's value isn't being updated 933 01:00:09.280 --> 01:00:10.680 Right? 934 01:00:12.100 --> 01:00:14.000 Now I'll go out 935 01:00:14.000 --> 01:00:16.900 Now the client isn't updating and only the server is 936 01:00:16.901 --> 01:00:22.320 The reason is, when there's no owner, look 937 01:00:22.321 --> 01:00:24.500 There's no owner 938 01:00:24.500 --> 01:00:29.160 then there can't be communication 939 01:00:29.161 --> 01:00:32.011 Client asks the server to send something 940 01:00:32.011 --> 01:00:33.720 and uses client RPC 941 01:00:33.721 --> 01:00:37.320 Then the server, on client RPC 942 01:00:37.320 --> 01:00:40.359 'I'll send that data to that client' 943 01:00:40.360 --> 01:00:42.779 so this client RPC function was called 944 01:00:42.780 --> 01:00:46.299 But then why isn't that working on the server? 945 01:00:46.299 --> 01:00:48.700 This is a characteristic of this 946 01:00:49.780 --> 01:00:52.620 client RPC option 947 01:00:52.621 --> 01:00:56.580 It only sends to on client 948 01:00:56.581 --> 01:00:58.720 so the server has a client 949 01:00:58.720 --> 01:01:01.500 and the client also has its own client 950 01:01:01.501 --> 01:01:03.360 But to only who from the server? 951 01:01:03.361 --> 01:01:08.300 Just to that client so it only has this right now 952 01:01:08.300 --> 01:01:11.960 Because this owner is the only one that can communicate 953 01:01:13.180 --> 01:01:15.180 NetActor is now the owner 954 01:01:15.181 --> 01:01:16.900 This is the only one that communicates 955 01:01:16.900 --> 01:01:21.680 Then what should we do if we want all clients to update this data 956 01:01:21.681 --> 01:01:25.260 We can use NetMulticast RPC instead of this 957 01:01:25.260 --> 01:01:29.260 We'll use NetMulticast 958 01:01:31.900 --> 01:01:35.600 Let's build and play again 959 01:01:35.601 --> 01:01:39.060 It's changing properly on the server, and what about the client? 960 01:01:39.060 --> 01:01:43.340 They're both changing properly 961 01:01:44.460 --> 01:01:48.980 That wraps up until NetMulticast 962 01:01:48.980 --> 01:01:53.419 and RPC 963 01:01:53.419 --> 01:01:56.259 Let me summarize what we've learned on this unit 964 01:01:56.920 --> 01:01:57.921 Property replication 965 01:01:57.921 --> 01:01:59.161 Actor replication Method for Unreal network's sync 966 01:01:59.161 --> 01:02:00.401 Member variable data syncing on property replication 967 01:02:00.401 --> 01:02:01.661 Must use UPROPERTY (Replicated) Must register on GetLifetimeReplicatedProps function 968 01:02:01.661 --> 01:02:03.927 Property value aimed to sync Can receive event from network when synced The event callback function must have OnRep_ in front 969 01:02:03.927 --> 01:02:06.800 RPC What is RPC? Abbreviation of Remote Procedure Call Calling a remote function 970 01:02:06.800 --> 01:02:08.420 Server RPC Used to send message from client to server 971 01:02:08.420 --> 01:02:10.121 Client RPC Used to send message from server to client 972 01:02:10.121 --> 01:02:11.741 NetMulticaste RPC Used to send message from server to all clients 973 01:02:11.741 --> 01:02:12.741 The End