Attempting to create a "Client-side InsertService"... is this idea sound?

Hey DevForumers;

I’m in the process of optimizing the memory usage for my game. The biggest pain-point right now is client-side memory usage via replicated instances. To combat this, I’ve done some research into effective ways to replicate instances selectively (in essence, a sort-of client-side InsertService.)

I have a list of requirements that I want this system to fulfill, some pseudocode, and a prototype. I’ve done some light testing with this prototype, but not enough to be confident that this system will fulfill all the requirements. (particularly with freeing the memory used by the replicated instances.) So I figure I’d ask about it here!

So my main question is: Does my design meet my requirements? Are there any pitfalls or concerns with this design? Is there any way I can improve it?

Pseudocode

Server
function Replicate(player, instance)
    -- Assuming that 'instance' is a descendant of ServerStorage.    

    -- Wrap instance in a ScreenGui with RemoveOnDeath set to false (for integrity)
    -- Parent the ScreenGui to the Player's PlayerGui
    -- Fire a RemoteEvent with the Instance as an argument
    -- Immediately re-parent the Instance to its original location, e.g ServerStorage
end

function OnServerEvent(player)
    -- Call Replicate() with the player and the server-side instance
end
Client

local remoteEvent: RemoteEvent
local replicatedInstance: Instance? = nil

function BeginReplication()
    -- Call task.defer(remoteEvent.FireServer())
        -- (ensures that the event is fired *after* we start waiting for the response)
    -- set 'replicatedInstance' to remoteEvent.Event:Wait() (this maintains our reference)
    -- call task.wait() to delay for a single replication step
        -- (This allows us to immediately manipulate the instance's parent without it being
        -- overwritten when the server re-parents the instance to ServerStorage)
end

function EndReplication()
    -- Set 'replicatedInstance' to nil to remove our reference to the instance.
end

Requirements

  • Instances are able to be replicated to individual players.
  • The integrity of replicated instances should be perfect (it should not be possible for instances to somehow be “half-replicated” or corrupted in some way)
  • Instances are replicated to players without the use of :Clone()
  • Instances should be able to be freed from memory if not in use
  • Should not be abusable or prone to exploits.
  • Should be performant and efficient.
  • Should be capable of replicating very large instance trees if needed (on the order of 30k+ instances) without a noticeable performance hit for other players.

Prototype

asset-replication-test.rbxl (7.1 KB)

1 Like

You’re trading static instance replication, which happens in the Roblox loading screen before the Player can actually play, to dynamic instance replication, while the player is playing, which can cause a large lag spike during “gameplay”, unless you have some kind of loading screen. Is this acceptable for your use-case?

Yes.

Our game is over 8 years old and is bloated with content-- We have over 1,500 character models, hundreds of purchasable gears, hundreds of items for our character creator, and hundreds more items for our building mode. Loading times & memory usage are very poor, and many players cannot even join due to the requirements. Frankly it’s a bit embarrassing that I haven’t looked into this sooner, haha

1 Like

I was looking to mitigate noticeable lag thru game design decisions:

  1. Loading screens, as you suggested
  2. Clearly telegraphing when assets will load (e.g when opening a system that requires these assets be loaded)
  3. Depending on the system in question, splitting giant assets into much smaller assets to be loaded more granularity.
1 Like