SteamingEnabled is Completely and Utterly Useless

When I have SteamingEnabled on Player.Character doesn’t replicate immediately and causes a lot of issues

I’m sending Player.Character to the player via a RemoteEvent immediately after Character.Parent has been set to workspace, however on the client the parameter for Character is nil

I even have these set

	character.ModelStreamingMode = Enum.ModelStreamingMode.PersistentPerPlayer
	character:AddPersistentPlayer(player)

This is not okay, it makes game development a lot more complex and complicated . I should not have to deal with this and go through the trouble because of a poorly designed and lacking feature

At least give us a way to tell when something has been Replicated, seriously this would improve and fix a lot of our problems with Replication and SteamingEnabled in general

I do not understand why we do not have an API for telling if an Instance has been Replicated to a specific client or not and events to detect when they are

I think it is great that Roblox wants StreamingEnabled to be enabled easily and forget but unfortunately that’s not how the feature is right now and it would be infinitely better to give us Developers granular control over Streaming / Replication in general because firsts of all we know our games best, Roblox does not and Roblox can not slap on a one size fits all feature for every game that’s not practical nor possible

10 Likes

One workaround can be using ChildAdded and then doing the GetPlayerFromCharacter function on the child (if its a model) or just doing game.Players:FindFirstChild(Child.Name). If true, that means this should be the player’s character. You can also use DescendantAdded to check for EVERYTHING that has replicated to Workspace

I already have a workaround, I disabled StreamingEnabled


Yes, I understand I can create a workaround however your method wouldn’t work properly for my use case or at least would require a lot of work which shouldn’t be necessary in the first place

	local function teleportCharacter(character: Model, cframe: CFrame)
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		if humanoid then
			character:SetAttribute("LastTeleportLocation", cframe.Position)
			character:PivotTo(cframe + Vector3.new(0, humanoid.hipHeight, 0))
			character.HumanoidRootPart.Velocity = Vector3.new(0, 0, 0)
		end
	end
       
       RemoteEvent.OnClientEvent:Connect(teleportCharacter)

why am I doing this?

Since the Player has networkownership over their own Character doing a teleport on client makes a lot of sense + when setting CFrame on the Server it can cause visual artifacts due to Replication trying to tween the character so it would appear as if the Character is moving to the CFrame location rather than a teleport and it also has additional safeguards so the player doesn’t sink into the floor, velocity is removed and there’s a fallback CFrame Location just in case the player falls off the map or goes out of bounds for whatever reason

1 Like

I see. If I’m not mistaken, you can try adding an empty modulescript/script under the character you’re teleporting to. Models with scripts under it should be always replicated, but I’m unsure if this has changed. I’ve read that a looong time ago.

Eitherway, you can try setting the CFrame on the server and keeping the event. This should teleport the player there. Also, I don’t think models can be transmitted over events? So you may need to use local string = character:GetFullName() and then on the client: game[string] but I really recommend using a WaitForChild() with a timeout (or inside a task.spawn()) since we’re still waiting for the character to replicate, it won’t just replicate the instant that the player recieves the model.

Orr you can make the server send the client the CFrame to teleport to

1 Like

That’s not true, since Players do have Scripts inside of them by default “Animate”, “Sound” and “Health”

additionally it doesn’t make sense for scripts to Stream in and out because they don’t have a CFrame


I already have a solution to my problem, the purpose of this OP is to make Roblox aware of the issues and pain points of using StreamingEnabled as something like this shouldn’t even be necessary and as a result wasting precious game dev time for solving problems created by bad design choices

Solution

I have a custom GUID tag system that works flawlessly with Replication and supports Clones, what that means is the GUID is in sync between Server and Client and whenever something is Cloned it will get a new GUID

With that system I could easily create a function to wait for something to replicate with the same GUID by using CollectionService:GetInstanceAddedSignal that would make it the most efficient and elegant

I just can’t / won’t to do that right now because I need to meet deadlines

3 Likes

Ahaa, okay then. The replies will be helpful for others who need to think of workarounds, so all’s good.

I do agree that StreamingEnabled quite makes too much trouble specially that it is now enabled by default, and some popular games sadly do not really implement proper ways to deal with instances that are being streamed in or out. There should be some sort of warning in the documentation at least

I can agree with that, but I disagree that it’s “utterly useless”. I’ve had my fair share of issues with it but fixed most things by making Models either Persistent or Atomic. Maybe Persistent instead of Persistent per player would work better?

For NPCs, main collectibles, the player character, and anything I need to constantly access (like spawn points) are Persistent in my game.

It’s not ideal, but would a repeat until that has a pcall (success, errorMsg) in it work here? That way code doesn’t continue until whatever is on the client.

4 Likes

Roblox replication is quite lacking, and it’s built so mobile devices won’t explode (hence the 20Hz network update rate)

What I’d suggest is if you aren’t planning to add mobile support to your game, make your own replication system (It’s what I’m currently working in aswell, I got really fed up, just like you tbh)

Use workspace.Camera in the serverside as an instance container for you to manually replicate as frequently as you want. Making your own replicator gives a lot more control over the network traffic, and can potentially even increase performance in the long run.

StreamingEnabled is like, 85% there but the key missing replication features make it an instant-disable every time. Constant issues with streaming networked contraptions, zero control over what doesn’t get streamed, lots of network clogging when streaming terrain voxels. It would’ve been better if they just made a ReplicationService and then released StreamingEnabled as a module for it.

3 Likes

oh, shocker, my request for better streamingenabled features made 2 years ago arises yet again from the dead >____>

image

honestly you’re better off writing your own streaming/rendering system, the only tradeoff is an expensive .parent call when the client enters the load zone, which is a no brainer considering that streaming enabled for some godforsaken reason is server sided and still after how many years has no instance-specific control over what gets offloaded

3 Likes

In that thread, you say in a post

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

Why does it seem more resource intensive? I use instance tags and streamingenabled, and it works really well. Not resource intensive in the slightest, even though I have tons of tags. I don’t see how objectstreamed in would be any less resource intensive because it’s really the exact same thing, except that you’d be setting up a signal for every object instead of a signal for a group of objects.

And we do have instance-specific control over what gets offloaded. Persistent and PersistentPerPlayer for example.

Collection service is a good workaround I found. Tag the instance on the server, with a unique name that no other instance has, send that tag to the client (or have the client be able to calculate it, such as "CharacterReplication_"..Player.UserId for the character), and then use CollectionService:GetTagged(), CollectionService:GetInstanceAddedSignal() and CollectionService:GetInstanceRemovedSignal() to detect when it is streamed in and out

3 Likes