I’m actually doing something similar to this, and I thought I would share some of the things I learned.
Custom Streaming is Hard. And usually unnecessary.
The problem with implementing custom streaming in Roblox is that there exists no easy way to replicate instances to only a select group of clients. With standard Roblox replication, if the instance exists in a replicatable location, it will be replicated to all clients. This means that every single instance in your workspace in a non-streaming enabled workspace will be replicated, along with any changes to any of those instances.
I’ve been building a custom voxel terrain engine using this principle, and what I’ve learned is that doing something like this is very difficult. This is because standard Roblox instance replication is actually incredibly optimized. Roblox instance replication is not wrapped with lua; it runs as a part of the actual Roblox application. In addition to the performance boost of being executed in compiled code, Roblox instance replication also has lower-level optimizations because it can infer certain things that can’t be inferred with a more flexible RemoteEvent system. In short, Roblox pays network engineers hundreds of thousands of dollars annually to create really good infrastructure, and unless you REALLY need it, it’s likely not going to net you an acceptable performance benefit given its other costs.
If rendering is the bottleneck, streaming will not save you.
Roblox already does quite a bit to optimize rendering. I’m pretty certain Roblox implements, among other things, occlusion culling. Occlusion culling is a technique where complex mathematics is used to simply not render geometry that lies outside of the camera’s viewport. For more reading, see here.
With this in mind, custom streaming will likely not do you any favors in terms of rendering performance improvements unless you would be using several hundred thousand instances to represent a level otherwise.
If you want to do this, be prepared to reinvent the wheel hundreds of times.
Roblox gives us a lot of goodies that you will quickly take for granted. For example, when building a custom streaming system, you need to represent all of your level data in memory. Want to use raycasting in a part of your level that is not loaded? Well, because some of your level is not loaded on the server, you either have to forget about using raycasting in these areas or build your own raycasting solution. I opted for the latter, but it has taken quite a bit of time.
Among other things, you will have to build your own replication system that deals with your custom non-instance data structures. This is difficult and has a lot of problems surrounding how Roblox’s high-level APIs almost always do not give you the low-level control you actually need to do certain things.
Conclusion: If you want to do it, do it for science!
…just understand that unless your game lies in a very specific case, you won’t get much of a performance benefit at all.
If you really want to do something like this “just because,” do not let what I said stop you from doing it. Custom streaming in Roblox is an awesome engineering challenge, and I’ve learned a lot more about Roblox’s API while doing it.
If you have any more questions, don’t hesitate to reach out!