Any ways to improve my map-loading system (rudimentary)?

I put this in code-review because my code technically works.

So basically, the improvement I’m looking to implement is to be able to load in maps part by part, without disrupting parent-child relationships However, the issue with using descendants is that it basically removes all nested children and puts all the parts into the generated part. This is an issue if, say, my map has a part with a ParticleEmitter in it, and when the map is made, the particle emitter is no longer a child of that part.

While the current system (loading by children) works if there are no groups with a lot of parts, if there’s a group with a lot of parts, then I’m worried about lag spikes in clients because of the sheer loading.

And I can’t un-group them because then it would look very cluttered.

Module Script: (In SSS)

local MapSpawn = {}
local ss = game:GetService("ServerStorage")
local rs = game:GetService("ReplicatedStorage")
local contProv = game:GetService("ContentProvider")

local remote = rs:WaitForChild("ChunkLoading")
local DefaultSpawn = game:FindFirstChild("DefaultSpawn",true)

function MapSpawn.spawnMap(mapName,mapPosition,mapScale,LoadingChunk,loadingText) --Spawning Maps
	if (ss:FindFirstChild(mapName)) then  --Runs if the map name was found in Server Storage
		if (LoadingChunk) then --If true, then all players are teleported to a failsafe (in case the current map was deleted for whatever reason) and shown a loading screen with a custom message, which vanishes after the map fully loads in
			remote:FireAllClients("loadingBegin",nil,loadingText) --Enables loading screen
			remote:FireAllClients("Failsafe") --Sends players to the DefaultSpawn, but without disabling the loading screen
		end
		local Map = ss:FindFirstChild(mapName) --The map in question
		Map:ScaleTo(mapScale) --Scales the map to the desired scale
		local part = Instance.new("Part") --The part which holds the map
		part.CFrame = mapPosition
		Map:PivotTo(part.CFrame)
		part.Anchored = true
		part.Transparency = 1
		part.CanCollide = false
		part.CanTouch = false
		part.CanQuery = false
		part.Name = mapName
		part.Parent = game.Workspace
		for i,v in pairs(Map:GetChildren()) do --Clones all children in the map into the part
			local clone = v:Clone()
			clone.Parent = part
		end
		task.wait(1)
		local spawnPad = part:FindFirstChild("SpawnPad") --The spawnpad to teleport players to when the map is done loading (if there is one)
		local spawnFolder = part:FindFirstChild("Spawn") --The spawnpad to teleport players to when the map is done loading (if there are multiple)
		if (spawnPad and spawnPad:IsA("BasePart")) then 
			remote:FireAllClients("Teleport",spawnPad.CFrame)  --If the spawnpad is a part and the remote is done loading, teleport all players to the spawnpad
		elseif (spawnFolder) then
			local list = spawnFolder:GetChildren()
			local pad = list[math.random(1,#list)]
			if (pad:IsA("BasePart")) then remote:FireAllClients("Teleport",pad.CFrame) end --Same thing, but a random spawnpad is picked
		end
	else
		print("That map dosen't exist, or hasn't been loaded in yet.")  --If the map dosen't exist, it will state that the map didn't exist and teleport all clients to the default spawn (failsafe).
		remote:FireAllClients("MapDidntExist") --Client teleport.
	end
end

function MapSpawn.deleteMap(mapName,transition) --Deleting Maps
	if (transition) then remote:FireAllClients("Teleport",DefaultSpawn.CFrame) end --Teleports all players to the default spawn
	if (workspace:FindFirstChild(mapName) == nil) then print("That map dosen't exist.")  --If the map dosen't exist, it will state that the map didn't exist
	else workspace:FindFirstChild(mapName):Destroy() end
end --(Transition distinguishes teleports from simple chunk unloads)

return MapSpawn

Client-sided script in StarterPlayerScripts for handling player teleportation:

local rs = game:GetService("ReplicatedStorage")

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local remote = rs:WaitForChild("ChunkLoading")
local playerGUI = player:WaitForChild("PlayerGui")
local loading = playerGUI:WaitForChild("Loading")
local initialMap = game.Workspace:WaitForChild("Failsafe")
local defaultSpawn = initialMap:WaitForChild("SpawnLocation")
local text = loading:WaitForChild("TextLabel")

remote.OnClientEvent:Connect(function(result,SpawnPadCFrame,loadingText) --Map loading (and teleport)
	if (result == "MapDidntExist") then
		loading.Enabled = false
		character:PivotTo(defaultSpawn.CFrame * CFrame.new(0,3,0))
	elseif (result == "Teleport") then 
		character:PivotTo(SpawnPadCFrame * CFrame.new(0,3,0))
		loading.Enabled = false
	elseif (result == "Failsafe") then character:PivotTo(defaultSpawn.CFrame * CFrame.new(0,3,0))
	elseif (result == "loadingBegin") then
		text.Text = loadingText
		loading.Enabled = true 
	end
end)

The functions are called this way

module.spawnMap("Map",CFrame.new(0,0,0),1,false,"") --mapName,mapPosition,mapScale,LoadingChunk,loadingText
module.deleteMap("Map",false) --mapName,transition

An image of “model with a lot of parts” that would be very painful to just un-group
Screenshot 2025-02-18 172818

you can use task.wait() if you don’t want it to lag ( it will load slower but dosen’t lag)

The issue with this is if I’m loading in chunks and I want it to load fast.
I could just write an if loop to exclude chunks, but then I would be having the same issue with chunks: lag because if a chunk has a lot of models, which each contain a lot of parts, loading the models instantly would create lag.

Since my game has both maps and chunks in it.

Oh and plus, if there were an extreme amount of parts, loading slower would be even more detrimental, I know for sure nobody likes to wait 40 seconds for a map to load.