Smooth map loading?

I’m looking for a method of loading maps that doesn’t effectively halt all network transactions between client/server while the map is loading. When I load maps, I can’t sent chat messages or make purchases, etc, and it just contributes to an unsmooth experience. I’ve tried both of these map loading methods, neither seems to work.

do
	function maploader:LoadMap2(mapName)
		local loadStart = tick()
		if game.Workspace:FindFirstChild("ActiveMap") then
			game.Workspace.ActiveMap:Destroy()
		end
		local MapInstance = game.ServerStorage.Maps[mapName]:Clone()
		MapInstance.Parent = game.Workspace
		MapInstance.Name = "ActiveMap"
		workspace.Terrain:Clear()
		workspace.Terrain:PasteRegion(game.ServerStorage.Terrain[mapName], workspace.Terrain.MaxExtents.Min, true)
		local loadEnd = tick()
		print("OML: Load Time on "..mapName.. " - "..loadEnd - loadStart.."s")
	end
	
	function maploader:LoadMap(mapName)
		local loadStart = tick()
		if game.Workspace:FindFirstChild("ActiveMap") then
			game.Workspace.ActiveMap:Destroy()
		end
		workspace.Terrain:Clear()
		local ActiveMap = Instance.new("Model")
		ActiveMap.Name = "ActiveMap"
		ActiveMap.Parent = game.Workspace
		
		for iteration, child in ipairs(game.ServerStorage.Maps[mapName]:GetChildren()) do
			child:Clone().Parent = ActiveMap
		end
		workspace.Terrain:PasteRegion(game.ServerStorage.Terrain[mapName], workspace.Terrain.MaxExtents.Min, true)
		local loadEnd = tick()
		print("NML: Load Time on "..mapName.. " - "..loadEnd - loadStart.."s")
	end
end

So, as a preface to my reply, I think what you would want to do with your map loader is to yield when portions of your map asset are loaded so that other scripts have time to process what’s going on elsewhere, like chat and client-server communication.

I think the easiest way to yield while loading the map is just by adding a wait for each child. Say you used method 2:

-- other stuff
for i, child in ipairs(map:GetChildren()) do
	child:Clone().Parent = ActiveMap
end
-- other stuff

You could add a wait or RunService.Heartbeat:Wait() in between children:

for i, child in ipairs(map:GetChildren()) do
	child:Clone().Parent = ActiveMap
	wait() -- yields after loading a child
end

You can also use a counter to only wait every couple parentings instead of every single one:

local count = 0
for i, child in ipairs(map:GetChildren()) do
	child:Clone().Parent = ActiveMap
	count = (count + 1)%3 -- yields after loading 3 children
	if count == 0 then
		wait()
	end
end

I have no idea how you would throttle terrain loading except by pasting smaller regions, which might be a bit challenging? Who knows.
If it’s still lagging, just use longer waits, like wait(0.2) or something like that. You could maybe also count the number of descendants under the child and use that as an estimate for how long you should wait:

for i, child in ipairs(map:GetChildren()) do
	child:Clone().Parent = ActiveMap
	local length = #child:GetDescendants()
	wait(length/30) -- wait 1/30 second for each descendant
end
1 Like

Copying a map child-by-child to the Workspace is a little too much. That is far more expensive and improper than using clone on the map itself (to which all parts are synchronously cloned and replicated) and parenting it accordingly. You put more work on the engine overtime than to get it done in one go.

As for terrain, try pasting chunk by chunk instead. Pasting a whole region of terrain has been known to cause severe lag up to crashing. This is primarily due to the fact that you give the rendering engine an entire amount of terrain to render.

Chunk-by-chunk for terrain, but everything for a map.

How would I go about loading it chunk by chunk? Changing extends size or something?