UE4 | Inventory for Multiplayer # 1 | Data Store on DataAsset
UE4 | Inventory for Multiplayer # 2 | Connect Blueprint to C ++
UE4 | Inventory for Multiplayer # 3 | Interaction structure
UE4 | Inventory for Multiplayer # 4 | Creating and connecting a container
UE4 | Inventory for multiplayer # 5 | Information transfer between Server and Client
In this article we will look at the data transfer between the Server and Client in the Unreal Engine 4 implemented in C ++ . At the very beginning, for a person who does not have a profile education, this seems to be something incomprehensibly difficult. Despite the large number of examples and analyzes, I personally found it very difficult to put together a complete picture of this process. But, when the critical amount of information obtained from reading and tests made was reached, it came to an understanding of how this all works.
First of all, you need to clearly understand that all objects in the game (with rare exceptions) may have several copies. The original object is located on the server. The original is always there. Copies can exist on Clients, but not necessarily, i.e. they may not be. All significant events occur on the Server, and it is he who decides who needs to know about it, and who does not.
Everything that happens on the Client is not known to anyone except the Client. |
We start the game with two clients. On stage cube. The original of this cube is located on the server. He is the most important. The first copy will be on the first Client, and the second - on the second Client. If we do something with a copy of the object on any of their clients, the original will not suffer . The change will be strictly local, only for this Client. If you change the original, then there are 2 main scenarios:
Now that the basic rules of the game are clear, we can consider which options for transferring information between the Server and the Client are available to us. I know 3 ways, but we will consider only the first two, because the third allows you to transfer anything at all and anywhere, and applies only if you have rested against the limitations of the first two.
The first thing is to unconditionally accept:
Replication is a one-way road, and works only from Server to Client. |
Only objects or class variables can be replicated. |
Replication occurs only when a change has occurred on the server. |
First consider the replication of objects.
In the constructor we write:
bReplicates = true;
If you want to replicate the movement:
bReplicateMovement = true;
If you need to replicate the connected component:
Component->SetReplicates(true);
A full description can be found here .
With variable replication, things are a little more interesting.
Let's start with the header file .h .
You can simply replicate the variable:
UPROPERTY(Replicated) bool bMyReplicatedVariable;
And you can run any function on the side of the Client, if the variable has been replicated. It doesn't matter what kind of value the variable took. What is important is the fact of its change.
UPROPERTY(ReplicatedUsing = OnRep_MySomeFunction) TArray<float> MyReplicatedArray; UFUNCTION() void OnRep_MySomeFunction();
The launch of the function is nothing more than one of the ways to send commands from the Server. It is very important to know that the replication of arrays does not occur entirely, but only the changed part. Thus, using just one variable, you can transfer multiple commands from the server, parsing the array into elements, and elements into bits.
We now turn to .cpp
We register replication conditions:
void AMySuperActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AMySuperActor, bMyReplicatedVariable); DOREPLIFETIME_CONDITION(AMySuperActor, MyReplicatedArray, COND_OwnerOnly); }
The first bMyReplicatedVariable variable was replicated without any condition to all Clients at once, whereas the second, MyReplicatedArray , was updated only for the Client of the owner of the AMySuperActor object, if, of course, it was announced.
A full list of possible conditions can be found here .
This method of data transfer, in contrast to replication, works both ways, but is more expensive. To use it, you just need to include #include "UnrealNetwork.h" .
An important feature is that the RPC method can transfer variables. |
So, to send our parcel from the Client to the Server, you need to register three functions:
UFUNCTION(Reliable, Server, WithValidation) void ServerTestFunction(float MyVariable); void ServerTestFunction_Implementation(float MyVariable); bool ServerTestFunction_Validate(float MyVariable);
Reliable - parcel with confirmation of receipt.
Server - sending from Client to Server.
WithValidation - the parcel is opened by the recipient only under the conditions described in the bool ServerTestFunction_Validate (float MyVariable) function . That is, if the function returns true . This parameter is required only for functions that run on the Server.
ServerTestFunction (float MyVariable) - this function is called by the client, if it wants, to send something to the server. In general, it is not even required to describe it in .cpp .
ServerTestFunction_Implementation (float MyVariable) - this function will be called directly on the Server only if ...
ServerTestFunction_Validate (float MyVariable) - this function is executed on the Server, and if true is returned, ServerTestFunction_Implementation (float MyVariable) will be called.
To send a parcel from the Server to the Client, if we are absolutely not satisfied with the use of replication, in fact only the Server changes to the Client :
UFUNCTION(Reliable, Client, WithValidation)
Names of functions, in principle, can be any, but usually they should reflect exactly where the package is going. For our convenience.
UFUNCTION(Reliable, Client, WithValidation) void ClientTestFunction(float MyVariable); void ClientTestFunction_Implementation(float MyVariable); bool ClientTestFunction_Validate(float MyVariable);
Otherwise, it works in the same way as in the previous example, taking into account the fact that this time the package goes from the Server to the Client.
There is another option to send from the Server, when the package goes to all clients at once.
UFUNCTION(Reliable, NetMulticast, WithValidation) void NetMulticastTestFunction(); void NetMulticastTestFunction_Implementation(); bool NetMulticastTestFunction_Validate();
Do not abuse this option. Think, perhaps you will manage replication.
For Client and NetMulticast, validation is optional |
/* , */ void ADreampaxActor::DoSomethingWithOtherActor(ADreampaxOtherActor * SomeOtherActor) { /* , */ if (Role < ROLE_Authority) { /* , , */ ServerDoSomethingWithOtherActor(SomeOtherActor); /* , */ return; } /* */ SomeOtherActor->Destroy(true); } /* , ServerDoSomethingWithOtherActor(SomeOtherActor) */ void ADreampaxCharacter::ServerDoSomethingWithOtherActor_Implementation(ADreampaxOtherActor * SomeOtherActor) { /* , */ DoSomethingWithOtherActor(SomeOtherActor); } /* , ServerDoSomethingWithOtherActor_Implementation(ADreampaxOtherActor * SomeOtherActor) */ bool ADreampaxCharacter::ServerDoSomethingWithOtherActor_Validate(ADreampaxOtherActor * SomeOtherActor) { /* true, , - fasle. */ return true; }
And finally, a link to the manual, which must be read.
'Unreal Engine 4' Network Compendium
That's all you need to know about communication between the Server and the Client in order to proceed to the next section, where we will register the replication of the inventory and consider how to make changes to it correctly.
PS If you notice any inaccuracies or errors, please write in the comments.
Source: https://habr.com/ru/post/420233/
All Articles