Improbable Icon

Efficiently displaying all player locations on a hud map


#1

I have been thinking about what the best way to efficiently get updates for all the players in the map world might be. Streaming queries seem to make sense, since the goal is to periodically get all updates on player locations. However streaming queries also involve checking out entities which puts load on to the workers which is not desirable. Certainly don’t want all workers checking out all players just because of a streaming query.

I did come up with one idea but I’m not so sure about it.The idea is to have one entity with a large streaming radius setup that has a component with a map structure of <entity id, positions>. All the players would then send their position values at maybe 1hz to the entity that could even be managed by its own individual worker by being placed correctly. Then if the client wished to get all the player positions to render them on a UI hud map it could pull the map data from the single entity’s component. That idea at least seems to separate worker’s processing but it causes lots of traffic and bandwidth to the single entity having to do all the updates so it might fail.

I was wondering what the best ideas are for showing many players on a large map in a hud view?


#4

Hi @awbrown90 and sorry to have kept you waiting for so long!

This is an interesting question and something that we have played around with but do not have one “correct” answer to.

When it comes to streaming queries, the big overhead is loading entity prefabs for Unity when checking entities out. So one workaround would be creating a player pawn entity that would have a tiny prefab and simply follow a player around. You could then set up streaming queries for the positions of these entities.

You could also try using a C# or a C++ worker for which checking out an entity costs nearly nothing. You could store a map state in this map worker, and create regular update events for player position changes that your Unity Clients would listen to.

Finally, you can implement a “master” map entity that all Clients would query. One potential problem with this approach is what you already mentioned - it is not scalable, so large worlds with many players would cause too much load for one entity. To avoid this problem, you can implement a hierarchy of “collector” entities that would send the location updates upward to the master node and then distribute the full map back downward at fixed intervals.

Let us know which approach you end up going with and do ask if you have any other questions!


#5

To add to @ieva’s great starting proposal I’m putting together an even more distributed approach in an example project. No precise timeline for it but I’m working on it when I can. Looking forward to share it as well with the community in a “How To” post.

Also obviously curious to hear more of your own thoughts @awbrown90 and whether you have achieved any intermediate results yourself in the meantime?

Duco


#7

Thank you @ieva for the great suggestions and @dvanamst that is very exciting to hear. As @ieva mentioned the big overhead with streaming queries is the complexity of the entity prefabs. I was thinking maybe a good way to solve this then is to use LOD, so that even if the game object is still being checked out, for the player whats being rendered could be very simplified or even culled at far distances. However it depends on whats still being loaded for the prefab, if the checkout still has to process the load of all the prefabs components then it doesn’t matter if LOD is helping to simplify the render for at least the player.

One thing that seems like it would be really nice to have built into spatialos is a type of LOD system for streaming entities based on distances, it could checkout different prefabs depending on how close the entity of interest was to the client player or reference. If you were really far away then spatialos could checkout just a very simple prefab with a single transform.

Maybe there actually is a way to get something of this effect by just modifying the streaming definition more in client worker bridge settings, I’m not sure. I saw in the documentation that there was a way to receive only certain component value updates, and even turn off Position and Rotation updates. It would be nice to tell bridge to be able to do the opposite and only receive Position and Rotation updates, but I guess that doesn’t stop the entity from still checking out the expensive game object. Really all you want is 6 floats for position and rotation, so even if that’s a large total moving entity count, say 100,000, that’s only 400kB. If those 100,000 entities positions/rotations are updated at 1 hz for the client view then that’s 400kB/sec which is quite manageable.

One thing that I have found when using streaming queries as well is that any entities close to the distant streaming queries also get checked out too. It looks like this effect is described in the documentation as well and maybe makes sense from the chunk perspective, I just found it a little surprising and it is something to be careful about if you are trying to limit the number of items being loaded.

If you really wanted the entirely to have a separate very low weight prefab following and representing the player would there be a way so the streaming query entity didn’t check out other entities close to it? Otherwise just having the simple prefab entity close to the player entity would checkout out the player prefab anyway and defeat the purpose.