void AMyActor::ServerSetValue() //In Server Scope
{
Value = !Value;
}
void AMyActor::Test() //In Server Scope
{
for (int i=0;i<100;i++) ServerSetValue();
}
void AMyActor::NotifyTheClient() //In Client Scope
{
UE_LOG(LogTemp, Log, TEXT("%i"), Value);
}
In this case the client only receives 4 or 5 notifications (it has lost approximately 95% of the requests).
Ok, I know this is an extreme example… I know that the CPU is thousands of times faster than the Socket connection.
Can RepNotify be faster?
I think that if it is able to process 100 requests in one second, I can rest in peace.
I think it’s more than I need. But I think it’s better to have too much than not enough.
If it can’t be done quickly,… Can data be sent to the client in a queue?
I would feel better if I could make sure that the data is not lost (even if it arrives late).
Better late than never.
Does anyone know how to do this?
Thank you so much!!
Does this test really give you 4 or 5 notifications?
It should give you 0.
Flipping a boolean 100 times (an even number) will leave it in same state it started in, and as this is all happening in one frame, there should be nothing to replicate (nothing actually changed, frame to frame).
I’ve actually simplified the example a lot… my real code is much more complex. It probably lasts four or five frames.
Thanks for the explanation. I didn’t know it worked that way.
In any case, I would like not to lose information even if it happens in less than one frame.
There is AActor::ForceNetUpdate(), Looking around I saw some conflicting anecdotal evidence on whether it updates immediately or queues, a quick (not very thorough) look at the code suggests it queues, so this may not be sufficient.
If you absolutely must know about every change, reliable RPC may be the only way.
Yes, I also tried increasing the frequency, but it didn’t solve the problem. I increased it to 10000 and only got a few more executions on the client side.
I think I’ll have to change the design… I have multiple actors changing the value of this replicated variable. I thought it would be replicated instantly but since it does it once per frame it doesn’t work as expected.
If two actors change the variable in a single frame, only one of them receives the notification.
The server only checks relevance once per server tick. 30Hz server means once every 33.333ms.
Loops are confined to the frame it started in. Meaning if I start a loop in frame 100 it will run until its complete, then frame 101 can start.
Replication of a value (NetFlush, NetSend) happens on the start of the following tick in which the value was set. Meaning, A value set in Frame 100 will be sent frame 101 start.
for (int i=0;i<100;i++) ServerSetValue(); sets the value 100 times in the same frame. The last value change is what’s flushed on the next server tick.
All replication from the server happens at the start of tick. One shot for each client at server tick frequency.
Client → server updates including inputs & RPC’s are bundled and sent at a defined frequency and always at start of tick.
First, RepNotify is not a RPC event – it’s a code generation tool that says “when I detect on the client that this thing changes, call this callback.”
If you need each and every event on the server to be mirrored on the client, you should send a reliable RPC event, not try to use replication notify. Sending too many RPC events, and relying on them having very low latency, is still a recipe for a bad player experience, but it will be the closest to the semantic you seem to expect.
Second, if you require anything to be 100% accurate and reliable and fast in a networked simulation, you are doomed to failure. Networks are neither infinitely fast nor infinitely infallible. You should build your architecture around sending commands/inputs as events, and “co-simulate” the same actions on the client, and only use state replication as a mechanism to correct for cases where that fails for whatever reason.
Thank you very much for the explanation.
I was trying to make a pool of objects (of projectiles) and a NetworkManager. (To reduce network and CPU usage)
I thought I could use a single replicated variable for all objects. Obviously I was wrong.
Now i’m using “FFastArraySerializer” and “FFastArraySerializerItem” for replication.
This seems to work much better than my previous idea.
Basically I need replication to trigger sounds and particles on the client side. (“co-simulate”).
Sometimes I feel like an idiot. I’ve been using Unreal for over a year and I still didn’t know that calculations are updated every tick.
Well, this is like the umpteenth time I’ve broken all my code to improve it. The novice circle.
Obj Pools should never be networked. For projectile pools you want to use an Actor Component that manages them. Each client gets one with its own set of projectiles. The server proxies will share a single Server_ProjectilePool.
Decouple your shooting so that the client does its own thing and handles fx locally for its own shots. Server does its own shot (not replicated) and simply calls a multicast and passes the values needed for Sims to fire their own shot. Server would also multicast hit data.
I will do it as you say.
The truth is that the replication of the object pool has become a real headache.
Everything was much easier when i just spawned and destroyed it.
But the FPS drop was quite important.
Thank you very much for the explanation and the example code. Highly appreciated!!
@Rev0verDrive
Your method works great!!
I only had to make a few changes to my code!!
It even fixes a choppy projectile movement issue due to replication in the client side. (No replication no problem)
It was all advantages!!
Thank you so much!!