As a roblox developer, it is currently too hard to find balance between view distance and memory usage when StreamingEnabled is active. Especially for worlds that contain a mixture of open and enclosed spaces.
This is an issue especially in Car Crushers 2, where we have a large building that players get to destroy their cars in, and a larger open-world island for driving on the outside. The center building is enclosed with walls and relatively dense with content, while the exterior is large and open.
These areas have vastly different part densities within a radius of 750 studs:
This isn’t to say we haven’t optimized the interior of the building. It is just full of content, with 59 different crushers, lobby contents, physics assemblies and much more all in the same building. And at the same time, this is where players and vehicles spawn into the map and spend most of their time, which further increases the amount of instances in the region.
If roblox was able to introduce a scriptable StreamingTargetRadius per player, we would be able to significantly reduce the streaming radius for players who are close to or inside the building. While maintaining a longer radius for players on the outside. Allowing us to have good viewing distances and richer open worlds, with good mobile performance at the same time. Instead of choosing just one.
As an example, if we could set the target streaming radius to just 25% of the building’s radius in Car Crushers 2 (Which is currently more than 100%), we would get:
Up to 75% less parts, vehicles, characters and assemblies that have to be loaded at the same time
Clients wouldn’t even have to stream in every car that spawns, nor would the server have to replicate them being destroyed. Which massively saves on network throughput (Benefiting everyone and not just low memory players)
Crusher animations and other effects would only have to replicate if they are in close proximity to a player. Further improving performance on both the client and server
But unfortunately if we did this now, it would make the view distances far too short for an open driving game, and there would be a larger risk of cars pausing or falling off the map at high speeds, which is detrimental to a driving experience.
I agree, it would be nice if it was already a feature of the game engine, but you can do this now by simply using a “Low Memory” stream out behavior with a very short range and simple spherical geometry to get the same effect per player to help those with low end devices without punishing those with high end PCs that can handle everything just fine, etc. I do this myself in my game to allow those on a cheap Wal-mart device to be about to play at low range and others can load the entire map into memory for faster PCs, devices, etc. via configuration settings if they want.
No, even easier. With a really low streaming distance, you simply take points around the player (via your spherical calculations) and do a streaming request. In mine for example, I’m using 8 points, kind of like North, South, East, West, then Northwest, Northeast, etc. All spaced at the minimum streaming distance. So if the player wants “more” distance, I simply increase the amount of points to “expand” out from the player’s point of view. So the default is a very low “visual” range, which cheap devices can handle, but if the player increases the range, the server just streams more chunks of the level to them on the fly. Because I’m using the “Low Memory” streaming mode, the client will stream out parts of the map far away if it needs more memory. Mobile devices usually do this, PC devices with lots of RAM don’t need to usually.
Another benefit, no loading screen needed. Before, waiting for a big map to load means a loading screen is usually good for the player. Since this cuts down on the time so much, I got rid of it in mine because the moment they join, their “streaming area” is loaded within seconds, even on low end mobile devices.
Ah. That definitely sounds like a viable workaround for the LowMemory mode right now.
Unfortunately for games like Car Crushers 2, we need opportunistic streaming not just for memory usage but also to ensure too many objects aren’t loaded simultaneously on a large map. This can worsen the framerate especially for high-memory players after they’ve explored the whole map, as everything otherwise remains loaded even after they left the area. Trying to combat this with custom render optimizations can also increase the memory usage further.
With variable target radius for streaming we could even implement a setting to control this like in your example, which would improve render performance too. So I guess this feature is especially useful when it comes to large maps.
I have tried this with opportunistic streaming and found that it can over-ride it while active and for example, once the player moved away from whatever radius I was working with, it would take over and stream out those areas automatically for the player but at the time, I wanted to use Low Memory mode and didn’t put more time into testing what the limits of Opportunistic would handle. It’s been some years, but I remember Opportunistic has some decay time around 9 seconds I think. Don’t know if they have changed with engine updates or not, I might be curious to check again because I do the see the benefits of using one versus the other.
While this would be a neat feature to have in all honesty, I’d recommend requesting access to have occlusion culling toggled on for your experience & see how that goes.
I tried out a quick test using Opportunistic streaming and it still seems to work, not an optimized test since I had to hack my player streaming service to make it work. The decay times are a lot shorter now I noticed but in theory, something could be built to work around this. I was running my server CPU window to see if it was hammering the server to do this, but appeared to be unaffected.
Still, some Roblox per player native support would be much better for the Streaming Mode. If I can hack it via some simple math and scripts, I don’t see why Roblox couldn’t implement this per player instance (for either Low Memory or Opportunistic Mode)