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