Updates to Streaming Enabled

Your code relies on polling and weird magic numbers, here’s a version I’ve used for a long time for my own game:

local function WaitForDescendant(Parent: Instance, Child: string, TimeOut: number?)
    local AlreadyFound = Parent:FindFirstChild(Child, true)
    if AlreadyFound then
        return AlreadyFound
    end

    local Connection
    local TimeOutThread

    local Thread = coroutine.running()

    Connection = Parent.DescendantAdded:Connect(function(Descendant)
        if Descendant.Name == Child then
            Connection:Disconnect()
            if TimeOutThread and coroutine.status(TimeOutThread) == "suspended" then
                task.cancel(TimeOutThread)
            end

            task.spawn(Thread, Descendant)
        end
    end)

    if TimeOut then
        TimeOutThread = task.delay(TimeOut, function()
            if Connection.Connected then
                Connection:Disconnect()
                task.spawn(Thread)
            end
        end)
    end

    return coroutine.yield(Thread)
end
8 Likes

I wonder if any of this solves the consistent replication problems I have been having.

I needed to play an animation when a part spawned, what I was doing before was firing a remotevent with the part as the argument, then animating it. With streaming enabled, even with the parts being marked to always be persistent, the parts were “slow” replicating - They were taking the Streaming process despite being persistent, and therefore came after the remote event fired, not before.

I got around that problem by giving them a unique ID tag so that if this happens, I can use the collection service to figure out what the part is still (probably a weird way to do it, but I had no other options)

Unfortunately this lead to a further consistent bug that I can’t even tell if is in my code or roblox’s - Everything fires correctly, but the things never animated. I think at the time of checking, the properties were seemingly changed correctly but were just… wrong. Like because of how I did it, it just wasn’t applying my changes or something very unusual. I’d print, it’d say it’s made the brick do what I want, but then would still just… not have an effect. Literally could not track this one down because it’s embedded into a lot of unusual code, so it’s hard to tell how far the rabbit hole goes here!

why am I so good at finding ridiculous bugs?

4 Likes

So, here is a major streaming issue, and this is the sole reason why I do not use streaming on any of my places.

Let’s say I have a place focused on trains, which happens to be all of mine quite frankly. If I have a train which is, say, 20 cars long, everything is fine. However, if I have a train that is 40-50 cars long, the rear end of the train un-streams because it is farther away and the whole thing freezes and breaks. This is because there is no way to adjust the way object physics streams. The railcars on the train are connected via constraints, usually rods or ropes.

For this reason, my places will never use streaming because trains of that length are commonplace for us. As a replacement, I use a client-sided chunk loader for scenery objects, which isn’t as efficient as streaming would be but using streaming is physically impossible in our places.

9 Likes

I’m not exactly sure what the problem is - Streaming enabled somewhat recently has given the option to make things persistent. You can set the train cars, at least the base/primary parts of them and such, to be permanently streamed in. You can also set the entire train to Atomic, which would mean the train only is either loaded in, or loaded out, with no inbetween.

If the train is being physically controlled by the server, I don’t see how this would cause issue. Can you describe the problem more in-depth, as well as telling me some of the steps you’ve already tried to fix it with? There might be some solutions yet to the issue, rather than it being a problem with streaming enabled.

9 Likes

sorry if this sounds ignorant but how is the train breaking if it’s being physically simulated on the server?

4 Likes

I agree with this. Render performance out of the box should get better.

Right now, achieving a high framerate on these large worlds is 100% possible, but needs (arguably considerable) manual intervention, by running systems such as custom distance culling (that also takes into account the importance of the object - so, stuff like pebbles should only be rendered while close), and LODs. I’d say Roblox’s largest rendering performance draw right now is the fact there is no occlusion culling.

Edit: I mean these systems can and have been made in Luau, which is able to run them with good performance, if optimized well.

9 Likes

While i’d like to give them the benefit of the doubt, I’d reckon they might be giving an individual player network ownership in this situation. That sounds like the quickest way to make a train stop functioning - second the player with physics ownership steps away from part of the train, the entire train stops functioning.

6 Likes

Yup it sounds like the networkownership is on a client for sure.

3 Likes

This however forces Roblox to go through the entire workspace hierarchy (until it finds the desired instance) every heartbeat which is wildly wasteful and inefficient, this may not cause problems in a very small game but in games with a lot of instances it will have to go through this can definitely impact performance.

4 Likes

I’m hopeful for the addition of the streaming exclusion feature. Being able to exclude certain models from being streamed to specific players is the last missing feature for StreamingEnabled in my opinion.

5 Likes

A important need for some would be to toggle how select objects are streamed, or a similar method, for railway based games, if you attempt to run a long train, streaming will “shut down” on the cars farthest from the player, making for a frustrating experience for the player, who will derail or get stuck.

3 Likes

You seem to be saying the exact same thing that @ Hachiroku did, which as far as I can tell doesn’t appear to be valid critique? If you could read through the replies just above, I’d love to know what the actual issue you’re having is, as Streaming Enabled seems to be 100% set up to handle what you and Hachiroku are saying here. Just sounds like you aren’t using it right.

The TL;DR is, we literally do have the ability to toggle how select objects are streamed. You just probably aren’t using them.

4 Likes

Yes please this is the one thing we need keeping us from using streaming.

3 Likes

Lovely! All my major wishlist items are on there :smiley:

2 Likes

I’d really like to see streaming based on occlusion in addition to distance. It’s a waste of resources to replicate instances that the player can’t see.

2 Likes

That Exclusion Mode sounds very nifty. It’ll let me safely host my scripts in Workspace without hackers being able to copy instances in workspace, since I can exclude the script objects from being streamed – which, in turn, prevents workspace copy scripts from reading them.

Doing so would actually be a very big step forward for Roblox, as it would allow people to place scripts in Workspace in a secure manner. In turn, this change allows people to delete entire chains of WaitForChild() or the various WaitForDescendent() implementations people have posted here. No more game.Workspace:FindFirstChild("Game Objects"):FindFirstChild("Tycoon Blocks"):FindFirstChild("Upgrader 1")... chains!

TL;DR: adding Exclusion Mode would allow people to return to an object-oriented programming style that Roblox was originally visioning in the first place, as well as giving me the ability to hide Workspace objects from clients, such as anti-cheat range checkers to prevent flying and speedhacks.

4 Likes

I don’t think you’re quite aware of how roblox scripts work. Roblox never has and never will send the bytecode of server scripts to clients so exploiters never could copy your scripts but they very much do and need to send the bytecode of local scripts which exclusion mode won’t really solve since for those local scripts to run the bytecode has to be sent to the client.

3 Likes

The bytecode of server scripts in Workspace can be replicated through a few exploits (though, admittedly, most of which rely on some things to be set up in a certain way – if there are any that can do it without a specific framework in place, I’m not aware of them.)

But my issue is moreso that I want to be able to hide objects from the client - not bytecode. If, say, an exploiter finds a script and a remotevent in the workspace, it wouldn’t be hard to guess that spamming or exploiting the remoteevent affects the script in question - ergo people ticker with stuff that shouldn’t be tinkered with. Yes, I could put it in ServerStorage, but now I have to deal with a dozen WaitForChild calls for objects inside a non-atomic hierarchy.

4 Likes

Recently a Roblox developer (staff) provided a rather unconvincing reason for why selective replication hasn’t happened yet. You can read the replies to see what people thought of it.

I have a few use cases for selective replication.

Provide information only to players who need it.

  • For example, we have an instance holding information about a players inventory. By default it is only replicated to the player whose inventory it represents. If two players are trading we can temporarily replicate each players inventory object to the other so that each player can see what the other owns.

Moving between different ‘rooms’ in the same server.

  • Let’s say we have many different areas you can go to. In the current replication / streaming model you would place these areas physically far apart from each other so that you don’t see the other areas and instances / network updates for the other areas are filtered out from being sent to you. You would still be able to physically fly across a void from your current area to another area, which may be undesireable.
  • In a selective replication model, only the area you are currently assigned to is selectively replicated to you. The areas may be physically next to each other from the server side view but the only thing the client ‘sees and receives’ is the area they are assigned to. In this example, the player characters, game objects, and map of an area are descendants of a Model, which is what gets selectively replicated.

Selective replication does get complicated when you start to think about Physics and Terrain however.

  • If you are separating your game into discrete areas, physics starts being a problem because server side physics has the full picture, and it will collide parts that belong in different ‘areas’. Something would have to be worked out so that you could separate the physics simulation into arbitrary groups of instances (Something with having multiple WorldRoots?).

  • As for Terrain, it currently exists as a single object, parts of which are streamed to you based on your ingame position. In a selective replication model, it would make sense if you could create and render multiple different Terrain instances at the same time, similar to a part. And just like a part, you could have multiple Terrain objects with different shapes and appearances, and they will be able to occupy the same space without ‘joining’. Of the Terrain instances that are currently replicated to a client, only the relevant voxels of those Terrain instances will be streamed to them.

  • Going down this route would also allow for future ‘terrain type instances’ to be added, such as a ‘heightmap terrain surface’ object or an ‘arbitrary vertex terrain surface’ object, with the terrain of today becoming known as a ‘voxel terrain’ object. This idea is so good that I think I’m going to make a feature request about it.

Also if a selective instance replication API is added, current replication rules that exist for instances such as PlayerGui, PlayerScripts, ServerStorage and ServerScriptStorage, should be implemented using the new API. Such that, if desired, we have the choice to enable replication of a PlayerGui to a player that it doesn’t belong to.

7 Likes

As others have said, this issue can be addressed by having the entire train under a single model with the model streaming mode set to atomic, so that the entire train exists at once, rather than being partially available.

4 Likes