Loading/Unloading System Theory?

I’m making a system for my friend that unloads a certain area and loads a different area when the player reaches an in-between location to prevent lag. (This is all happening on the client)

My current idea was to simply wait a fraction of a second every 10 or so instances that were loaded/destroy.

Is there a better way that I should know before scripting the entire thing?

3 Likes

You can do something that Grand Piece Online it groups up the islands so that each island is its own group and whenever a player gets close to it it loads it in so it is originally unloaded and loads and stays loaded when the player reaches the island obviously u can unload it when it gets far away enough what u can do but will take some time is group up parts of the map like “Chunks” in minecraft.

1 Like

You can’t technically really unload anything on the client, but it could lower your gpu because its not rendering it.


In my render system it works like this:


Preset a bunch of chunks into a table, each chunk has an origin which is used to decide how far the player is from the chunk.

Upon start, it looks through all the parts in the chunk, checks if its a BasePart or decal/texture, then enters it into a table for that chunk. If it’s a texture, it also stores the textures original transparency so it can set it back to that when being loaded.

Every x amount of seconds, the script loops through each table and checks the players distrance from the chunk origin. If the player is close enough and the chunk isnt already loaded, then load everything in that chunk. If the player is too far away and the chunk isnt already unloaded, unload everything in that chunk.

How I load/unload stuff is just by changing its LocalTransparencyModifier to 1, and for textures/decals changing its transparency to 1.


DO NOT check the players distance from every single basepart as it’s just unneeded, do what I said with checking from the chunks preset origin.

2 Likes

If you’re not making anything really big then it wouldn’t make a substantial difference I find.

How exactly do you transfer the values in the table to defined parts when loading. Are the values in the table object values, string values, or something else?

This takes stress off the client just as well as moving it to replicated storage correct?

Your input is helpful and I’d appreciate it a lot if you would answer my questions

Well, for me this is how I set up my system:

image

image

Inside the “render space 1”, you can see all the parts that are being rendered/unrendered (folder called “Parts”). The origin part is the position in which it decides the players distance from.


Upon start, the client gets all the render spaces, and stores each one as a table.
For each render space it stores the parts origin, then I use :GetDescendants on the “Parts” folder, check to make sure each piece is a basepart, then insert it into a table.

local runService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local renderFolder = workspace._Render
local renderTable = {}
local step = 0

for _,v in pairs(renderFolder:GetChildren()) do -- v is the render space
	local originPos = v.Origin.Position
	local renderDistance = v.Origin:GetAttribute("RenderDistance") or 250 -- each origin has an attribute for its render distance, if not found then make it 250
	local parts = {} -- where we will store all the parts for that render space
	for _,part in pairs(v.Parts:GetDescendants()) do
		if part:IsA("BasePart") then
			table.insert(parts,part) -- put it into the table "parts"
		end
	end
	table.insert(renderTable,{
		originPos;
		renderDistance;
		parts;
		true; -- this is used to decide if its rendered or not
	}) -- insert this into the main table, this contains all the data for this render space.
end

Then, I loop through every render space, and check the cameras distance from the render space’s origin, and see if its close enough to render it. If close enough, then render the parts (if not already rendered), else unrender the parts (if not already unrendered).

runService.Heartbeat:Connect(function()

	--- 
	step += 1
	if step < 8 then
		return
	end
	step = 0 
    --- this is so everything below only goes off every 8 heartbeats

	local cameraPosition = camera.CFrame.Position -- camera position

	for _,list in pairs(renderTable) do -- gets all render spaces
		local distance = (cameraPosition - list[1]).Magnitude -- finds cameras distance from render space's origin
		if distance <= list[2] then -- if distance is less than the render spaces render distance then
			if list[4] == false then --if not already rendered then
				for _,part in pairs(list[3]) do -- gets all parts from render space
					part.LocalTransparencyModifier = 0 -- set local transparency modifier to zero, so now it is render
				end
			end
			list[4] = true -- seen as how it is now render, update the list to say this
		elseif distance > list[2] then -- if distance is FARTHER than the render spaces render distance then
			if list[4] == true then -- make sure its not already unrendered
				for _,part in pairs(list[3]) do -- get all render spaces part
					part.LocalTransparencyModifier = 1 -- make part invisible/unrender it
				end
			end
			list[4] = false -- update table to say that now this render space is unrendered
		end
	end
end)

Here’s my full script:

task.wait(1)

if not game.Loaded then
	game.Loaded:Wait()
end

local runService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local renderFolder = workspace._Render
local renderTable = {}
local step = 0


for _,v in pairs(renderFolder:GetChildren()) do
	local originPos = v.Origin.Position
	local renderDistance = v.Origin:GetAttribute("RenderDistance") or 250
	local parts = {}
	for _,part in pairs(v.Parts:GetDescendants()) do
		if part:IsA("BasePart") then
			table.insert(parts,part)
		end
	end
	table.insert(renderTable,{
		originPos;
		renderDistance;
		parts;
		true; -- is rendered on start
	})
end


runService.Heartbeat:Connect(function()
	
	step += 1
	if step < 8 then
		return
	end
	step = 0

	local cameraPosition = camera.CFrame.Position
	for _,list in pairs(renderTable) do
		local distance = (cameraPosition - list[1]).Magnitude
		if distance <= list[2] then
			if list[4] == false then
				for _,part in pairs(list[3]) do
					part.LocalTransparencyModifier = 0
				end
			end
			list[4] = true
		else
			if list[4] == true then
				for _,part in pairs(list[3]) do
					part.LocalTransparencyModifier = 1
				end
			end
			list[4] = false
		end
	end
end)

I hope this helps! My script is not perfect so I only advise you to take reference from it. This also does not unrender textures/decals, just baseparts.

Extra Tips:

  • Another way you could get all the render spaces is collection service
  • I suggest trying to keep the amount of render spaces limited
  • if you want to have it update less, change the 8 to a higher number. Lower it to have it update faster (but this makes it less performant)
    image

If you’re wondering why I use LocalTransparencyModifier instead of transparency, is because its kind of like an override to normal transparency. Here’s more about it: BasePart.LocalTransparencyModifier

4 Likes

Thanks a ton! This was already the sort of thing I had in mind but reading your explanation will help me to create it in a more organized and simple way.

1 Like