I can drop an item from my inventory and it spawns/replicates on the server, every player receives an update that it spawned and can interact with it.
The Net Cull Distance is around 50 meters (25000000uu) and works fine for items dropped by other players, but items dropped (and owned) by the player seem to always stay relevant. Even when moving over 500 meters away and zooming in I can still see the items I dropped.
Item dropped is a replicated static mesh actor with replicate movement enabled.
Only Relevant to Owner = off
Always Relevant = off
Net Use Owner Relevancy = off
Player A and B join game
Player B drops an item
Player A moves outside the net cull distance of Player B’s item
Player B’s item gets culled according to the cull distance
Player C and D join game
Player C and D drop an item on the same location
Player C moves outside the net cull distance of both items
Only the item Player D dropped gets culled, the item Player C (owner) dropped stays visible
I’ve tried spawning the actor without an owner and setting the owner to none after spawning, but the results are the same.
Also setting any possible combination of relevancy switches on the component itself had no effect (all set on the server). I read that owned objects are always considered relevant regardless of distance, but I can’t seem to change it with Blueprints.
I’m already familiar with eXi’s Network Compendium and the Actor Relevancy and Priority flow and haven’t found any other good leads besides AActor::IsNetRelevantFor() in C++.
Network cull distance has zero to do with the visibility of an actor. It only effects the relevancy of the actor in regards to network replication.
Once an actor has been replicated to you (made the client aware of its existence) it will remain in the client world proxy. Until, something network relevant changes with the actor. Like destroyed, moved or modified in a way that the client should be updated with the change. Yet, only when inside the cull distance radius will you be updated with those changes.
Ownership has no bearing as well. Technically anything dropped by the player should be owned by the server. When held or in inventory, the player owns it. On drop the server should then be given ownership. Or simply destroy the players dropped actor and have the server spawn a replicated actor in its place.
Relevancy helps reduce bandwidth usage and network saturation.
What you need to do is setup Render Culling. Actor → static mesh → Details: Rendering → LOD → min/max Draw Distance
Settings of 0 & 5000 will work.
Personally I’d increase the network cull distance for lootable items to around 75-100m and have the render culling at 50m. This should/will reduce the case instances of where multiple players in range aren’t seeing the same things.
e.g. Player A (low stable ping) gets the update and sees the items. Player B (higher, jittery connection) does not. yet a few frames later they appear.
Overall net cull distance should be balanced in regards to number of players in game and the density of lootable items. Multiple small updates are better than bulk updates. Less fragmentation and loss.
If the server spawns an actor and replicates it to you, then your client spawns a proxy. When you walk out of net cull distance the client doesn’t destroy it, then respawn it when you get back in range. It remains in your local proxy world until the server modifies or destroys it. Both would require a replication update (server → client).
Anything disappearing outside net cull distance is tied to either render culling, occlusion or level streaming distance. If you’re using world composition, then assets on the streamed level (tile) are typically bound to the levels streaming distance… as far as I recall. If it’s culled assets bound to it are culled as well.
Also with world comp you have to look at origin rebasing. If the offset gets screwed up then the world position is incorrect. That can lead to disappearing characters/actors.
Understood. It wasn’t a case of the actor being destroyed / re-created. it was like it wasn’t being updated and so effectively hidden iirc. The quick dirty solution was just force ‘always relevant’ on for the Character (level-streaming / culling-occlusion / wc origin-rebasing didn’t apply). Can’t rule out the possibility that always tick anim / bones wasn’t connected to this tho.
I think once you got in range the server updated the new location and seeing as the distance to the new location was too large to interpolate over a few frames it was teleported in 1 frame. I see this all the time in multiplayer games like Battlefield 4 & 1, Destiny 2 and PubG. Players with high pings (350+) and terrible jitter/loss warp around quite a bit.
In PubG (UE4 w/world comp) we get players being warped 500m+ on occasion. When you drive into a new area of the larger maps (8x8) and get slammed with updates there’s a chance of catching a player doing this. If memory serves their character net cull is just under 1Km…980m or so. Driving into an area at 120Km/h+ you get hammered with updates. 100’s of loot items and potentially 20+ players.
Thanks for the detailed replies! I was already trying to balance net cull distances in regards to items dropped by players, which is why I ran into the issue I mentioned. I’ll try to tweak the item mesh LOD distance based on the net cull distance from now on.
Take into consideration movement speeds and pings as well. Ping wise you need to set a high ping limit for design. A good standard is 120-130ms. Most popular multiplayer games have player with pings well over 250ms. The majority will be 80ms or less, but there are still a large chunk that grossly exceed that.
Use this High ping (HP) as your upper boundary when calculating net cull to render buffers.
Visualize your net and render cull distances as spheres. You want some level of buffer distance between net and render. A significant gap that allows for network resends and client processing to occur before reaching the render distance.
How fast your players can bridge the gap between net and render has an impact when you consider ping.
Using a 125ms HP as the limit average gives you a 63ms update travel time (UTT = ping/2). Which is roughly 40cm of movement distance @ 600cm/s speed ( 4 frames at 60Hz, 63 / 16.667). Then there’s a min of 1 frame processing time (16.667ms, 10cm movement). 3 times that if there’s loss… 205.667ms * 0.6cm/ms = 123.4002cm movement distance.
A good starter buffer algo would be 2.5 * ((HP Limit ms / 2) * (1000ms / max speed cm/s)).
Net cull would be Render cull + Buffer.
If you have vehicles then use the vehicle’s top speed instead of player’s.
I know this is old but I’m pretty sure when you walk out of net cull distance the client destroys the actor and it respawns again when you walk back in, this is of course when the actor is spawned by the server.
Thanks and also Kaidoom15 thanks.
I’ll try probably today.
What I’m seeing from my tests is that the actors are spawned when I ‘use network relevancy’
but with no mesh applied (meaning it is spawning with the actors initial mesh, not the one I want). both Actor replicated and Static Mesh Component replication are ticked.
I managed to test here in my end.
I’m changing the mesh in the class constructor in cpp and spawning that the first time in game mode, dedicated server. Both replicates and component replicates are true in the constructor.
Then clients enter the game, but they only see the updated mesh if I mark the actor as always relevant. If I try to use network relevancy they can collide with the actors, but it has no mesh. Hence, invisible. The mesh is not updated in this case.
I cannot understand why the mesh is not replicated, since it is defined in the actor class constructor , that is called before Begin Play.
Thank you very much, this was being a pain in the ■■■ to fix.
Do you know whether there is an Event that is called on the Server when an actor becomes relevant to another?
Say, Player A and Player B are together.
Player A moves out of NetCullDistanceSquared and disappears
Player A then comes back into NetCullDistanceSquared and becomes relevant again to Player B, is there any server event called at this point? I check PostNetInit() but that seems to be Client-Side only, unless I messed something up.