Download

Replicating large arrays.

Hello!

I have been fighting with this one a long time. Basically, I have a tool that allows players to draw into air by creating an Actor that has Instanced Static mesh component. When player is holding the trigger, new instances are added. This works great in single player game, but problems arise when I need to have this working in multiplayer.

There are approx, 100-1000 mesh instances in one drawing. If I replicate array normally, the clients will start lagging so much that playing is impossible until replication is finished. What I tried to do is putting all new instances to array and after 1 second, move all stuff from array to replicated array that is send to client, so the payload is much smaller for server, but I am having problems implementing that. Also, that system might have problems because game is Drop in / Drop out. So eventually, the replicated array has lot of stuff and newly joined players would try to replicate the whole array and we are back in square 1.

In Attachement is the code from the crucial parts.I explain them here:

Function BeginPlay:
We set the timer on. Timer runs functions SendJointBulkToReplicate and SendStrokeBulkToReplicate

Function Update:
Runs every tick. In this function, We are adding all the new strokes to NON-replicated array. If we are server, then we just draw them to world.

Function SendStrokeBulkToReplicate
We add all the stuff to replicated arrays and then clear the array so we can have new stuff in there.

Functions** OnRep_AddStroke** and OnRep_AddJoint
These are run after the** ReplicatedStrokeTransforms and ReplicatedJointTransforms **are updated. What I try to do there is to add instances that are yet to be added.

If I play this as a client, I can paint normally maybe 1-2 seconds and after that I get more and more lag. The more I draw, the more lag I starting to get. I thought that Array replication in Unreal is clever enough to replicate only new changes to array, not the whole array?

Any help how would I need to tackle the problem I have? I am even willing to pay for the help and guidance. Thanks!

I can’t see why it must be replicated.
You can use OnMouseUp() events to send data, quit using timers…

A client performing the draw action should request server a reliable Multicast RPC telling all clients to draw a stroke into their own local array, no replication.

Whenever new play joined you send them a copy of latest versions of strokes array, afterwards all new strokes are handled by rpc as well.

What you’re doing is sending a new copy of the entire array every timer tick, that is absurd waste of bandwidth.

Thanks! I totally rearranged everything. Absolutely nothing is replicated inside my PaintBrush class. In my character class, I check that painting is true and then locally draw brush and after that Server multicast that same brush. Everything seems to be working fine and there is no lag spikes. Thanks!

Now, how would you suggest I do next step: If player was not network relevant at the time, but later becomes relevant? I assume I need to send all the strokedata back to new client somehow. Any suggestions? I cannot simply send the data array because it causes massive lag spike if there are hundreds of items inside array.

Looks like all you need is to sync those behavior of cursor.

Hope my mind map of the streaming of real time behavior could help.

The new joined player can receive a copy of the array from an unreliable RPC. Maybe see a loading screen of some sort.
If that’s not possible then make all players relevant… If that’s not desired too try to make use of data compression like using *FVector_NetQuantize *to at least reduce the size of data to sync.

You may also want to increase the throughput the engine allows you for networking. By default it is limited to something like 10kb/s data roaming which is pretty narrow and obviously gonna take a while to replicate large quantities of data.

Hello. I created a quick mock-up project where player can draw instances around map. Network relevancy is about 50 meters from the brush. You can test it by moving near to other player and start painting by clicking and holding right mouse button. If you are within 50 meter radius, you should see something drawn to screen.
Next try go other side of the map and wait little but so the relevancy stops. Then walk again near the painting and it should have disappeared. This is the main problem now. I want that painting to be showed for the users that later becomes network relevant.

Thanks for the answers already, I try to examinate them.

Here is link for the project (4.22)
https://ksamk-my.sharepoint.com/:u:/…db9xA?e=fVWKc9

Inside FirstPersonCharacter is the painting logic. It’s very small logic and should be self explaning. C++ has the logic for drawing the strokes.

edit:
Just saw a minor bug. Please see attachement. Basically, change GetWorldTransform to GetWorldLocation when spawning the Brush. Otherwise, rotation of the brushes are wrong. Thanks!

That sounds like a candidate for going inside a GameState, something that is replicated at startup, and is always relevant.