Hi! The situation is: I have a “Energy” variable which grows with every frame on the server and on the client. This is like smoothly energy regeneration. I can’t replicate this variable every changing, because it is very expensive. But I will need to do some synchronization when i losing energy, meaning to cast spells etc…
A simplified version of the code looks like this:
.h
UENUM()
enum EHeroReplicationMask
{
/** For Energy replication control. */
EnergyReplicationActive = 0x01,
};
UCLASS()
class ARENA_API AHero : public ACharacter, public ICasterBase
{
/** In OnRepEnergySync I do some sync with UMG. */
UPROPERTY(ReplicatedUsing = OnRepEnergySync)
float Energy;
/** Contains replication mask. Required for replications optimization. */
UPROPERTY()
uint8 ReplicationMask;
};
.cpp
void AHero::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
/** COND_SimulatedOnly for example. */
DOREPLIFETIME_CONDITION(AHero, Energy, COND_SimulatedOnly);
}
void AHero::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker)
{
DOREPLIFETIME_ACTIVE_OVERRIDE(AHero, Energy, ReplicationMask & EnergyReplicationActive);
/** Removing flag, because we need replication once. */
EnergyReplicationActive &= ~EnergyReplicationActive;
}
/** Calling on the client and on the server. */
void AHero::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
/** For example our DeltaTime always ticking by 0.1f on the server. */
Energy += DeltaTime * 10.f;
}
/** Calling only on the server. */
void AHero::ModifyEnergy(float AddEnergy)
{
/** simplify */
Energy = FMath::Clamp<float>(Energy - 80.f, 0.f, 1000.f);
/** Add flag. Without this there will be no replication. */
ReplicationMask |= EnergyReplicationActive;
}
So, we starting the game and suppose we spent the energy (60 of 1000 remain). Now we call ModifyEnergy() and our sequence of calls will be looks like this:
ModifyEnergy() → Tick() → PreReplication() → Checking the variable change and send replication to client if it was…
Where:
Energy = 0.0 after ModifyEnergy() ->
Energy = 1.0 after Tick() ->
We replication (Energy = 1.f) to client.
Next step we waiting some time and our Energy was regenerated to 30.f (on the client and server). We do the same move: calling AHero::ModifyEnergy() again, where:
Energy = 0.0 after ModifyEnergy() ->
Energy = 1.0 after Tick() ->
And here the problem. The last replication to client was 1.f too. Engine not see the change of variable and will no replication. By the end we get desync. Where:
On the client Energy = 30.0
On the server Energy = 0.0
I can’t use RPC due to lack of flexibility (means maybe i want to sync Energy only for SimulatedProxy, how i can do this with RPC?)
I am tried to use DOREPLIFETIME_CONDITION_NOTIFY with REPNOTIFY_Always, but it still was worked a same.
Ok, like idea I can initializing “Energy” variable like a uint32 and do some manipulating of bits. I mean using 31 bits for Energy value and reserving last bit for switching to provoke replication. But is there really no solution for easier? Or maybe I missing something?
Hope you understand what I was mean. Thanks!