Upgrades to Model Streaming

Will the legacy mode ever be deprecated/eventually removed? I rely on the fact Non-Atomic models initially replicate the empty parent model to the client for referencing reasons.

Incase anyone is curious I take advantage of this fact to have a unified module script table for both the server/client that includes a direct reference to the Model along with other information. This is a really easy solution to solve ether by using a separate module script or just dynamically adding the reference on the server only but i’m lazy :smiley:

I do imagine some people have situations where its non-trivial to replace this functionality which is why I’m curious if it will ever be removed.

11 Likes

Thank you so much for this update! This hasn’t solved all of our problems with streaming enabled and memory usage from it but it’s definitely a welcome improvement.

9 Likes

I appreciate the constant improvements to streaming and the benefits it provides. I would love to utilize streaming but find it impossible to until locally created parts are simulated outside the streaming radius, which they are currently not even while in a persistent model.

Since streaming correlates to loading and unloading parts on the client, locally created parts, especially while in a persistent model, should always run physics.

10 Likes

Why can’t we just have a ReplicationService where we can manually toggle replication on individual objects, including terrain? I know exactly what I want to stream in/out and exactly what I don’t want to bother wasting bandwidth on. Streaming isn’t a toggleable ‘upgrade’, there are networking costs that come with it due to having to send large amounts of parts and voxels to potentially hundreds of players. This network impact is rarely discussed and instead streaming seems to be treated as this perfect ideal package.

21 Likes

Sounds great. FWIW, the principles of less models being sent improving join times is also why I created a custom replication system for my own experience. ReplicatedStorage has the absolute bare minimum and we manually replicate instances the client wants soon after they join. I am able to achieve 1-second join times with a codebase of 5.4K+ ModuleScripts, StreamingEnabled, Deferred SignalBehavior and a bare minimum amount of replication during the initial snapshot.

What is the behaviour of streaming out, a destruction or a nil parent? I’d like to know what the proper way to check for parts streamed out is so I can know when to cleanup lifetime objects that need to observe part descendants of the workspace. Probably the best way to check is a nil parent after AncestryChanged, though other methods like Destroy also fire it, no?

As more and more optimisation features visit developers’ gift boxes that have to do with contextual parenting by the engine, it would also be helpful to start thinking about methods to differentiate between destruction and nil parenting. This is already a pain point with our own systems and it will grow as features like this become more widely used.

Also deferred parenting sounds especially great for characters. To avoid daisy chaining waits I take advantage of replication also being reliably ordered to essentially “snapshot” an instance tree at a moment of replication. It’s unnecessary boilerplate though, and character loading events are a wick of evil old engine code that was intended to be fixed but encountered technical blockers. Deferred literally solves 99% of most deep tree access issues (hence the fancy display name). Hopefully this works even without StreamingEnabled or with Deferred SignalBehavior at the very least.

9 Likes

We recently added a clarification to streaming out in the documentation:

“When an instance streams out, it is parented to nil so that any existing Luau state will reconnect if the instance streams back in. As a result, removal signals such as ChildRemoved or DescendantRemoving fire on its parent or ancestor, but the instance itself is not destroyed in the same sense as an Instance:Destroy() call.”

Signals related to destruction do not fire on stream out.

13 Likes

I doubt Roblox will remove it, but just take that with a grain of salt since it’s likely they will unfortunatly.

5 Likes

Hoping soon we see an update that makes parts be always streamed in by default, except for the parts that we mark as safe to stream out. So essentially the opposite of what we have now. Unfortunately this is a very limiting factor for us, so we have to rely on a custom implementation for streaming.

5 Likes

Does this decrease load times for games with lets say 50 zombies in a current game? I want to increase the amount of zombies in my game while also decreasing load times/lag for lower end devices by streaming them out.

I currently use Streaming in my game that relies heavily on mesh but I can’t really test that parts/models are streamed out. Is there a way for me to test that without buying a potato? Even with min radius of 128 it still seems to load everything when I join?

Game in question if anyone can help: Valor FPS 🎃 ZOMBIES EVENT - Roblox

5 Likes

The reason why they are not streaming in and persisting is because players are having their devices crash and they are unable to play Roblox if Roblox is unable to stream out.

4 Likes

Wouldn’t it make sense to have those parts streamed out by default and only stream them in when possible?

It’s basically what we already have but without having to go through every part in the workspace and selecting persistent to get the illusion of exclusivity

3 Likes

This means that once a subtree arrives there is less need for localscripts to use WaitForChild to ensure that instances have arrived

Good!

4 Likes

Hi
So basically this new way of streaming is atomic, but without all parts of the model being loaded atomically?

Took me a while to figure out all the empty models that had default streaming were causing lag. I’m happy this is now the behavior so others won’t have to run into it.

My fix was to just put almost everything as atomic (99% of models are small, tightly packed parts).

2 Likes

It would be cool if we were able to load in interiors via script, when we want to.

Will this be a thing any time soon?

3 Likes

Why has model uploading become so slow?
I waited 5 minutes behind the map for my entire city to unload
I have opportunistic
and I’ve tried legacy and improved.

2 Likes

Once again i have to ask for manual systems for streaming. I have nothing against the fact that roblox is offering their own automatic and very simple to use streaming solution for games. I believe these can greatly help beginner developers into quickly and efficiently optimizing their own experiences… HOWEVER, my problem is the fact that the automatic solutions are the ONLY ONES that roblox trully supports and allows while anything else that the deverloper’s can make are solutions simply by default way less efficient systems. The lack of support for manual systems in order for us to make our own potentially more performant streaming systems is and will always be a very bad thing regardless of how many improvements and updates the singular automatic one gets. I believe it is delusional to believe that its possible to make a “one size fits all” streaming solution. Every game has its own design, systems and other various things that simply all require different approaches to the same problem of streaming.

Also on a side note, i don’t think its worth sacrificing tons of server resources for a system that normally should be done ONLY on the client.

8 Likes

Hi. Player.ChararacterRegionId : Vector3 is spelt wrong- and has two ra’s.
That’s all

I’m not sure if this change is intentional as per deferred parenting but;

  • A remote function is invoked on the server. The server creates a new model with a part in it.
  • The model is returned from the remote function so that the client that invoked the function has a reference of it. (The client in question is within the radius of the model)

In Legacy model streaming, the model would actually be returned to the client, but with Improved model streaming, the remote function returns nil.

Here’s a code snipped of what I mean

func.OnServerInvoke = function(plr)

  local mdl = Instance.new("Model", workspace)
  local p = Instance.new("Part", mdl)
  p.CFrame = plr.Character.HumanoidRootPart.CFrame
  
  return mdl

end

In Legacy mode, this returns the model to the player, but in Improved mode, it returns nil on the player (I’m guessing the model hasn’t been loaded yet on the client to actually return anything from the server)

Love to see improvements to streaming, it makes a tremendous difference in memory usage.


Can we see more improvements in the direction of streaming LODs? I understand that Roblox prefers to do solutions that affect 99% of the userbase instead of more niche advanced developer features, but these advanced features are what turn Roblox into a professional engine rather than a toy for users looking to push the envelope. I would like to be able to provide my own LODs for roblox to swap out when models stream out. There is a CPU cost to doing this myself in software, and Roblox can likely do this much faster engine-side. I would love a suite of LOD related tooling that enables us to do authored LODs at varying levels that can either persist when streamed out, or cull entirely at distance.

I was previously using streamingmeshes for my biggest foliage models so I could show the overview of a large alien forest from large distances, and I wish I could continue to use them, but it turns out these models are excessively high poly and poorly representative of the original model compared to manually authored LODs (also, they look like pudding in comparison to my sharp poly art style). In an open world with content in every direction, including downwards (into flora-filled caves), since Roblox does not do occlusion culling or distance culling on streamingmodels, they are not good enough to improve performance in my game. IIRC there was mention of occlusion culling at RDC, but I’m not optimistic for this since the majority of my world does not have huge solid occluders, but rather many partially occluding pieces of foliage, it would exclusively help with underground assets only.

Instead of using streamingmodels, I recently set up software distance culling and LODs with MCR’s vis tools and this reduced my scene polycount from a staggering 3 million worst case to barely over 700k, and reduced my drawcalls by half. If I had a high fidelity game, streamingmodels might be very acceptable, but I do not. Due to the low-poly artstyle I already use, and the severe excess of overdraw I have in presenting a vast open world, I need to manually author my LODs for the best visual and performance result, and explicitly hide them when they’re out of reasonable range. In doing this I have to take the trade-off of not using streamingmeshes, so you can’t see the forest overview when it’s all streamed out, which is indicative of the current solution simply not being good enough.

5 Likes

This observation is correct. With legacy mode if you create a part via a remote function then it will not exist on the client when the function returns, and in fact may never exist on the client. This is the reason for the function returning nil. With improved model streaming this behavior is also extended to models, for a similar reason. The model that was just created may be sent later to the client, or never be sent.

While this behavior is by design we do realize this makes some programming use cases more difficult to handle. We are discussing options for simplifying this longer term, but I don’t expect this behavior to change in the near future.

4 Likes