Added customization features to StreamingEnabled

As a Roblox developer, it is currently too hard to structure my experience for lower-spec devices using StreamingEnabled. Outside of the streaming radius properties, StreamingEnabled has zero customization and using this feature will risk the occurrence of race conditions and there’s no real guarantee that important instances (i.e. bosses, shops, npc’s, landmarks) will be rendered outside of the streaming radius.

Possible use cases include:

  • Rendering or offloading regions of a map or many maps, shops, etc.
    – Impractically positioning a shop or “world” at Vector3(100000, 0, 100000) to avoid other players from seeing it is a common practice among many experiences that have multiple maps
  • Allowance to write a custom LOD/object occlusion system
    – Control over Model LOD/visibility
    – Guaranteeing visibility of important instances/objects, such as important npc’s and landmarks
  • Events that fire when an instance is loaded/offloaded
    – No more need to spam WaitForChild() and hope that it doesn’t throw an infinite yield error

If Roblox is able to address this issue, it would improve my development experience because it would allow the scope of many experiences to be playable on low-spec devices without the risk or worry of race conditions and impractical workarounds to control who-sees-what.

37 Likes

Our documentation on streaming discusses using the collection service with tags to detect when instances are loaded/unloaded:
https://create.roblox.com/docs/optimization/content-streaming#detecting-instance-streaming

Would that be useable for your request to detect load/unload?

5 Likes

Using CollectionService seems rather patchy IMO; it seems more resource and memory-intensive than something such as ObjectStreamedIn/ObjectStreamedOut events.

Assuming that this wouldn’t require the upending of the entire StreamingEnabled system, maybe having WorldRoot/workspace events/functions would be a better alternative? I’m unsure how StreamingEnabled works under the hood but it seems like the aforementioned events would work more efficiently rather than using (lots of) resources to assign collection tags to every instance that will ever be streamed to the client.

-- a prettier event name probably exists
workspace.ObjectStreamingStateChanged:Connect(function(Thing : Instance)
	if Thing.Parent ~= nil then
		print("Streamed in object"..Thing.Name)
	else
		print("Streamed out object"..Thing.Name)
	end
end)
8 Likes

Does StreamingEnabled stream in an entire model if at least one part is streamed in, the documentation is unnecessarily vague on this.

I have an object handler script that uses CollectionService to initialise and destroy object structs, however if it doesn’t stream in the entire model, I might get weird behaviour.

Using CollectionService definitely feels like a bandaid fix when we could have a more granular event

5 Likes

And on the other hand, I’d want my map to have a folder or model to itself so it doesn’t clutter the explorer and I definitely don’t need it streaming in all at once. I feel we need an option to specify how something is streamed in (or handle folders differently from models)

2 Likes

I wouldn’t mind a property on models and folders having an Enum controlling how descendants are streamed.

Something like Model.StreamingBehavior = "StreamAllDescendants" or "Default" etc

It would be better as a per child basis so

Model:
  - has stream all, so every child is streamed
  ChildModel:
    - has default, so uses default streaming behavior
3 Likes

We are working on new controls for how models are streaming, we will share more details in the next few months. Currently models are not sent atomically.

9 Likes

I noticed you said “models are not sent atomically.” Does this mean other instances, specifically ones with no BaseParts, are sent atomically?

For example, say I have a Folder instance which contains a NumberValue. This Folder is sitting in ServerStorage.

The server moves this folder from ServerStorage into ReplicatedStorage, causing it to be replicated to clients.

Is it guaranteed for the client that the NumberValue inside the folder will exist as soon as the Folder exists? Or does the Folder appear first, then at an unknown later interval the NumberValue appears?

I tried testing this myself and in every condition I tested, the NumberValue was available at the same time as it’s parent Folder. But before I write code depending on this behavior and put it into a game, I’d like to know for sure. Thanks!

No, they are not guaranteed to arrive together. Particularly when there is high network traffic and lots of content to send to clients they may arrive separately. You should not rely on that behavior.

1 Like