Quick actions

cmd+k|ctrl+k

Navigation

Languages

NihonSaveInstance

Snippet info

Language

Lua

Visibility

public

Author

legacy-v1-16166

Created

2023-07-31T22:06:31.327334Z

Updated

2023-07-31T22:06:31.327334Z

local function fetchAPI()
	local api
	local s,e = pcall(function()
		local version = game:HttpGet("http://setup.roblox.com/versionQTStudio",true)
		local rawApi = game:HttpGet("http://setup.roblox.com/"..version.."-API-Dump.json",true)
		api = game:GetService("HttpService"):JSONDecode(rawApi)
	end)
	if not s then warn("API Fail") return end
	local classes,enums = {},{}
	
	for _,class in pairs(api.Classes) do
		local newClass = {}
		newClass.Name = class.Name
		newClass.Superclass = class.Superclass
		newClass.Properties = {}
		newClass.Functions = {}
		newClass.Events = {}
		newClass.Callbacks = {}
		newClass.Tags = {}
		
		if class.Tags then for c,tag in pairs(class.Tags) do newClass.Tags[tag] = true end end
		for __,member in pairs(class.Members) do
			local mType = member.MemberType
			if mType == "Property" then
				local newProp = {}
				newProp.Name = member.Name
				newProp.Class = class.Name
				newProp.ValueType = member.ValueType.Name
				newProp.Category = member.Category
				newProp.Serialization = member.Serialization
				newProp.Tags = {}
				if member.Tags then for c,tag in pairs(member.Tags) do newProp.Tags[tag] = true end end
				table.insert(newClass.Properties,newProp)
			elseif mType == "Function" then
				local newFunc = {}
				newFunc.Name = member.Name
				newFunc.Class = class.Name
				newFunc.Parameters = {}
				newFunc.ReturnType = member.ReturnType.Name
				newFunc.Tags = {}
				for c,param in pairs(member.Parameters) do
					table.insert(newFunc.Parameters,{Name = param.Name, Type = param.Type.Name})
				end
				if member.Tags then for c,tag in pairs(member.Tags) do newFunc.Tags[tag] = true end end
				table.insert(newClass.Functions,newFunc)
			elseif mType == "Event" then
				local newEvent = {}
				newEvent.Name = member.Name
				newEvent.Class = class.Name
				newEvent.Parameters = {}
				newEvent.Tags = {}
				for c,param in pairs(member.Parameters) do
					table.insert(newEvent.Parameters,{Name = param.Name, Type = param.Type.Name})
				end
				if member.Tags then for c,tag in pairs(member.Tags) do newEvent.Tags[tag] = true end end
				table.insert(newClass.Events,newEvent)
			end
		end
		
		classes[class.Name] = newClass
	end
	
	for _,enum in pairs(api.Enums) do
		local newEnum = {}
		newEnum.Name = enum.Name
		newEnum.Items = {}
		newEnum.Tags = {}
		
		if enum.Tags then for c,tag in pairs(enum.Tags) do newEnum.Tags[tag] = true end end
		for __,item in pairs(enum.Items) do
			local newItem = {}
			newItem.Name = item.Name
			newItem.Value = item.Value
			table.insert(newEnum.Items,newItem)
		end
		
		enums[enum.Name] = newEnum
	end
	
	local function getMember(class,member)
		if not classes[class] or not classes[class][member] then return end
        local result = {}

        local currentClass = classes[class]
        while currentClass do
            for _,entry in pairs(currentClass[member]) do
                table.insert(result,entry)
            end
            currentClass = classes[currentClass.Superclass]
        end

        table.sort(result,function(a,b) return a.Name < b.Name end)
        return result
	end
	
	return {
		Classes = classes,
		Enums = enums,
		GetMember = getMember
	}
end

-- Dex Serializer Module
local function SerializerModule()
	-- Modules
	local Serializer,API
	
	-- Un-init
	local _writefile,_getnilinstances,oldIndex,classes,enums
	
	-- Rest
	local t_ins,t_concat = table.insert,table.concat
	local buffer = {}
	local refCount = 0
	local getChildren = Instance.new("Part").GetChildren
	local toDecompile = {}
	local saveFilter = {}
	local instDir = {}
	
	local elyFuncs = false
	
	local xmlReplace = {
		["'"] = "&apos;",
		["\""] = "&quot;",
		["<"] = "&lt;",
		[">"] = "&gt;",
		["&"] = "&amp;"
	}
	
	local propBypass = {
		["BasePart"] = {
			["Size"] = true,
			["Color"] = true,
		},
		["Part"] = {
			["Shape"] = true
		},
		["Fire"] = {
			["Heat"] = true,
			["Size"] = true,
		},
		["Smoke"] = {
			["Opacity"] = true,
			["RiseVelocity"] = true,
			["Size"] = true,
		},
		["DoubleConstrainedValue"] = {
			["Value"] = true
		},
		["IntConstrainedValue"] = {
			["Value"] = true
		},
		["TrussPart"] = {
			["Style"] = true
		}
	}
	
	local propFilter = {
		["BaseScript"] = {
			["LinkedSource"] = true
		},
		["ModuleScript"] = {
			["LinkedSource"] = true
		},
		["Players"] = {
			["CharacterAutoLoads"] = true
		}
	}
	
	local sProps = setmetatable({},{__index = function(self,class)
		local props = {}
		
		local apiProps = API.GetMember(class,"Properties") or {}
		for i,v in pairs(apiProps) do
			if (v.Serialization.CanSave and not v.Tags.NotScriptable) or (propBypass[v.Class] and propBypass[v.Class][v.Name]) then
				if not propFilter[v.Class] or not propFilter[v.Class][v.Name] then
					local s,e = pcall(function() local exist = instDir[class][v.Name] end)
					if s then table.insert(props,v) end
				end
			end
		end
		
		self[class] = props
		
		return props
	end})
	
	local testInsts = setmetatable({},{__index = function(self,class)
		local s,testInst = pcall(function() return Instance.new(class) end)
		local testInstTable = {}
		
		if testInst then
			for i,v in pairs(sProps[class]) do
				testInstTable[v.Name] = testInst[v.Name]
			end
		end
		
		self[class] = testInstTable
		
		return testInstTable
	end})
	
	local refMt = {__index = function(self,inst)
		if not inst then return "" end
		refCount = refCount + 1
		self[inst] = refCount
		return refCount
	end}
	local refs = setmetatable({},refMt)
	
	local valueHandlers = {
		["bool"] = function(name,val)
			t_ins(buffer,'\n<bool name="'..name..'">'..tostring(val)..'</bool>')
		end,
		["float"] = function(name,val)
			t_ins(buffer,'\n<float name="'..name..'">'..val..'</float>')
		end,
		["int"] = function(name,val)
			t_ins(buffer,'\n<int name="'..name..'">'..val..'</int>')
		end,
		["int64"] = function(name,val)
			t_ins(buffer,'\n<int64 name="'..name..'">'..val..'</int64>')
		end,
		["double"] = function(name,val)
			t_ins(buffer,'\n<double name="'..name..'">'..val..'</double>')
		end,
		["string"] = function(name,val)
			t_ins(buffer,'\n<string name="'..name..'">'..val:gsub("['\"<>&]",xmlReplace)..'</string>')
		end,
		["BrickColor"] = function(name,val)
			t_ins(buffer,'\n<int name="'..name..'">'..val.Number..'</int>')
		end,
		["Vector2"] = function(name,val)
			t_ins(buffer,'\n<Vector2 name="'..name..'">\
<X>'..val.X..'</X>\
<Y>'..val.Y..'</Y>\
</Vector2>')
		end,
		["Vector3"] = function(name,val)
			t_ins(buffer,'\n<Vector3 name="'..name..'">\
<X>'..val.X..'</X>\
<Y>'..val.Y..'</Y>\
<Z>'..val.Z..'</Z>\
</Vector3>')
		end,
		["CFrame"] = function(name,val)
			t_ins(buffer,('\n<CoordinateFrame name="'..name..[[">
<X>%f</X>
<Y>%f</Y>
<Z>%f</Z>
<R00>%f</R00>
<R01>%f</R01>
<R02>%f</R02>
<R10>%f</R10>
<R11>%f</R11>
<R12>%f</R12>
<R20>%f</R20>
<R21>%f</R21>
<R22>%f</R22>
</CoordinateFrame>]]):format(val:components()))
		end,
		["Content"] = function(name,val)
			t_ins(buffer,'\n<Content name="'..name..'"><url>'..val:gsub("['\"<>&]",xmlReplace)..'</url></Content>')
		end,
		["UDim"] = function(name,val)
			t_ins(buffer,'\n<UDim name="'..name..'">\
<S>'..val.Scale..'</S>\
<O>'..val.Offset..'</O>\
</UDim>')
		end,
		["UDim2"] = function(name,val)
			local x = val.X
			local y = val.Y
			t_ins(buffer,'\n<UDim2 name="'..name..'">\
<XS>'..x.Scale..'</XS>\
<XO>'..x.Offset..'</XO>\
<YS>'..y.Scale..'</YS>\
<YO>'..y.Offset..'</YO>\
</UDim2>')
		end,
		["Color3"] = function(name,val)
			t_ins(buffer,'\n<Color3 name="'..name..'">\
<R>'..val.r..'</R>\
<G>'..val.g..'</G>\
<B>'..val.b..'</B>\
</Color3>')
		end,
		["NumberRange"] = function(name,val)
			t_ins(buffer,'\n<NumberRange name="'..name..'">'..tostring(val)..'</NumberRange>')
		end,
		["NumberSequence"] = function(name,val)
			t_ins(buffer,'\n<NumberSequence name="'..name..'">'..tostring(val)..'</NumberSequence>')
		end,
		["ColorSequence"] = function(name,val)
			t_ins(buffer,'\n<ColorSequence name="'..name..'">'..tostring(val)..'</ColorSequence>')
		end,
		["Rect"] = function(name,val)
			local min,max = val.Min,val.Max
			t_ins(buffer,'\n<Rect2D name="'..name..'">\
<min>\
<X>'..min.X..'</X>\
<Y>'..min.Y..'</Y>\
</min>\
<max>\
<X>'..max.X..'</X>\
<Y>'..max.Y..'</Y>\
</max>\
</Rect2D>')
		end,
		["Object"] = function(name,val)
			t_ins(buffer,'\n<Ref name="'..name..'">RBX'..refs[val]..'</Ref>')
		end,
		["PhysicalProperties"] = function(name,val)
			if val then
			t_ins(buffer,'\n<PhysicalProperties name="'..name..'">\
<CustomPhysics>true</CustomPhysics>\
<Density>'..val.Density..'</Density>\
<Friction>'..val.Friction..'</Friction>\
<Elasticity>'..val.Elasticity..'</Elasticity>\
<FrictionWeight>'..val.FrictionWeight..'</FrictionWeight>\
<ElasticityWeight>'..val.ElasticityWeight..'</ElasticityWeight>\
</PhysicalProperties>')
			else
				t_ins(buffer,'\n<PhysicalProperties name="'..name..'">\n<CustomPhysics>false</CustomPhysics>\n</PhysicalProperties>')
			end
		end,
		["Faces"] = function(name,val)
			local faceInt = (val.Front and 32 or 0)
							+(val.Bottom and 16 or 0)
							+(val.Left and 8 or 0)
							+(val.Back and 4 or 0)
							+(val.Top and 2 or 0)
							+(val.Right and 1 or 0)
			t_ins(buffer,'\n<Faces name="'..name..'">\
<faces>'..faceInt..'</faces>\
</Faces>')
		end,
		["Axes"] = function(name,val)
			local axisInt = (val.Z and 4 or 0)
							+(val.Y and 2 or 0)
							+(val.X and 1 or 0)
			t_ins(buffer,'\n<Axes name="'..name..'">\
<axes>'..axisInt..'</axes>\
</Faces>')
		end,
		["Ray"] = function(name,val)
			local origin = val.Origin
			local direction = val.Direction
			t_ins(buffer,'\n<Ray name="'..name..'">\
<origin>\
<X>'..origin.X..'</X>\
<Y>'..origin.Y..'</Y>\
<Z>'..origin.Z..'</Z>\
</origin>\
<direction>\
<X>'..direction.X..'</X>\
<Y>'..direction.Y..'</Y>\
<Z>'..direction.Z..'</Z>\
</direction>\
</Ray>')
		end,
	}
	
	local function getNS(inst,name)
		rfl_setscriptable(inst,name,true)
		local propVal = oldIndex and oldIndex(inst,name) or inst[name]
		rfl_setscriptable(inst,name,false)
		return propVal
	end
	
	local function getBS(inst,name)
		local bs = getbspval(inst,name,true)
		if bs then
			return "<![CDATA["..bs.."]]>"
		else
			return ""
		end
	end
	
	local specialInst = {
		["UnionOperation"] = function(inst)
			if elyFuncs then -- Assume all ely funcs defined
				t_ins(buffer,'\n<Content name="AssetId"><url>'..getNS(inst,"AssetId"):gsub("['\"<>&]",xmlReplace)..'</url></Content>')
				local initialSize = getNS(inst,"InitialSize")
				t_ins(buffer,'\n<Vector3 name="InitialSize">\
<X>'..initialSize.X..'</X>\
<Y>'..initialSize.Y..'</Y>\
<Z>'..initialSize.Z..'</Z>\
</Vector3>')
				t_ins(buffer,'\n<BinaryString name="ChildData">'..getBS(inst,"ChildData")..'</BinaryString>')
				t_ins(buffer,'\n<BinaryString name="MeshData">'..getBS(inst,"MeshData")..'</BinaryString>')
				t_ins(buffer,'\n<BinaryString name="PhysicsData">'..getBS(inst,"PhysicsData")..'</BinaryString>')
			end
		end,
		["MeshPart"] = function(inst)
			if elyFuncs then -- Assume all ely funcs defined
				local initialSize = getNS(inst,"InitialSize")
				t_ins(buffer,'\n<Vector3 name="InitialSize">\
<X>'..initialSize.X..'</X>\
<Y>'..initialSize.Y..'</Y>\
<Z>'..initialSize.Z..'</Z>\
</Vector3>')
				t_ins(buffer,'\n<BinaryString name="PhysicsData">'..getBS(inst,"PhysicsData")..'</BinaryString>')
			end
		end,
		["Terrain"] = function(inst)
			if elyFuncs then
				t_ins(buffer,'\n<BinaryString name="MaterialColors">'..getBS(inst,"MaterialColors")..'</BinaryString>')
				t_ins(buffer,'\n<BinaryString name="SmoothGrid">'..getBS(inst,"SmoothGrid")..'</BinaryString>')
			end
		end,
		["TerrainRegion"] = function(inst)
			if elyFuncs then
				t_ins(buffer,'\n<BinaryString name="SmoothGrid">'..getBS(inst,"SmoothGrid")..'</BinaryString>')
			end
		end,
		["BinaryStringValue"] = function(inst)
			if elyFuncs then
				t_ins(buffer,'\n<BinaryString name="Value">'..getBS(inst,"Value")..'</BinaryString>')
			end
		end,
		["Workspace"] = function(inst)
			if elyFuncs then
				t_ins(buffer,'\n<token name="AutoJointsMode">'..getNS(inst,"AutoJointsMode").Value..'</token>')
			end
			t_ins(buffer,'\n<bool name="PGSPhysicsSolverEnabled">'..tostring(inst:PGSIsEnabled())..'</bool>')
			local groupTable = {}
			for i,v in pairs(game:GetService("PhysicsService"):GetCollisionGroups()) do
				t_ins(groupTable,v.name:gsub("['\"<>&]",xmlReplace).."^"..v.id.."^"..v.mask)
			end
			t_ins(buffer,'\n<string name="CollisionGroups">'..t_concat(groupTable,"\\")..'</string>')
		end,
		["Humanoid"] = function(inst)
			t_ins(buffer,'\n<float name="Health_XML">'..inst.Health..'</float>')
		end,
		["Sound"] = function(inst)
			t_ins(buffer,'\n<float name="xmlRead_MaxDistance_3">'..inst.MaxDistance..'</float>')
		end,
		["WeldConstraint"] = function(inst)
			if elyFuncs then
				valueHandlers["CFrame"]("CFrame0",getNS(inst,"CFrame0"))
				valueHandlers["CFrame"]("CFrame1",getNS(inst,"CFrame1"))
			end
			t_ins(buffer,'\n<Ref name="Part0Internal">RBX'..refs[inst.Part0]..'</Ref>')
			t_ins(buffer,'\n<Ref name="Part1Internal">RBX'..refs[inst.Part1]..'</Ref>')
		end,
		["LocalScript"] = function(inst)
			t_ins(buffer,'\n<ProtectedString name="Source">')
			local src = decompile(inst):gsub("['\"<>&]",xmlReplace)
			t_ins(buffer, src)
			t_ins(buffer,'</ProtectedString>')
			t_ins(toDecompile,{inst,#buffer-1})
		end,
		["ModuleScript"] = function(inst)
			t_ins(buffer,'\n<ProtectedString name="Source">')
			t_ins(buffer,"")
			t_ins(buffer,'</ProtectedString>')
			t_ins(toDecompile,{inst,#buffer-1})
		end,
	}

	local savePlaceBlacklist = {
		["CoreGui"] = true,
		["CorePackages"] = true
	}
	
	local function writeXML(inst)
		if saveFilter[inst] then return end
		
		local class = oldIndex and oldIndex(inst,"ClassName") or inst.ClassName	
		if not instDir[class] then instDir[class] = inst end
		local testInst = testInsts[class]
		
		t_ins(buffer,'\n<Item class="'..class..'" referent="RBX'..refs[inst]..'">\n<Properties>')
		
		for _,prop in pairs(sProps[class]) do
			local propName = prop.Name
			local propVal = oldIndex and oldIndex(inst,propName) or inst[propName]
			if testInst[propName] ~= propVal then
				local valueType = prop.ValueType
				if valueHandlers[valueType] then
					valueHandlers[valueType](propName,propVal)
				elseif enums[valueType] then
				--	t_ins(buffer,'\n<token name="'..propName..'">'..propVal.Value..'</token>')
				elseif classes[valueType] then
					valueHandlers["Object"](propName,propVal)
				end
			end
		end
		
		if specialInst[class] then
			specialInst[class](inst)
		end
		
		t_ins(buffer,"\n</Properties>")
		
		for i,v in pairs(getChildren(inst)) do
			writeXML(v)
		end
		
		t_ins(buffer,"\n</Item>")
	end
	
	local function resetState()
		buffer = {}
		refs = setmetatable({},refMt)
		refCount = 0
		toDecompile = {}
		saveFilter = {}
		instDir = {}
	end
	
	local defaultSettings = {
		DecompileMode = 0,
		NilInstances = false,
		RemovePlayers = true,
		SavePlayerDescendants = false,
		DecompileTimeout = 10,
		UnluacMaxThreads = 5,
		DecompileIgnore = {}
	}
	
	Serializer = {
		Init = function(data)
			API = data.API
			_writefile = data.WriteFile
			_getnilinstances = data.GetNilInstances
			oldIndex = data.OldIndex
			
			classes = API.Classes
			enums = API.Enums
			
			elyFuncs = getbspval and rfl_setscriptable
			
			Serializer.ResetSettings()
		end,
		
		Settings = {},
		
		ResetSettings = function()
			Serializer.Settings = {}
			for i,v in pairs(defaultSettings) do
				Serializer.Settings[i] = v
			end
		end,
		
		SaveInstance = function(inst,name,sets)
			Serializer.ResetSettings()
			
			for i,v in pairs(sets or {}) do
				Serializer.Settings[i] = v
			end
			
			resetState()
			
			if inst == game and Serializer.Settings.RemovePlayers then
				for i,v in pairs(game:GetService("Players"):GetPlayers()) do
					saveFilter[v.Character] = true
				end
			end
			
			t_ins(buffer,[==[<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<Meta name="ExplicitAutoJoints">true</Meta>
<External>null</External>
<External>nil</External>]==])
			
			if inst ~= game then
				if type(inst) == "table" then
					for i,v in pairs(inst) do
						writeXML(v)
					end
				else
					writeXML(inst)
				end
			else
				for i,v in pairs(game:GetChildren()) do
					if not savePlaceBlacklist[v.ClassName] then
						writeXML(v)
					end
				end
			end
			
			if inst == game and Serializer.Settings.NilInstances and _getnilinstances then
				t_ins(buffer,'\n<Item class="Folder" referent="RBX'..refs[Instance.new("Folder")]..'">\
<Properties>\
<string name="Name">Nil Instances</string>\
</Properties>')
				for i,v in pairs(_getnilinstances()) do
					if ((API.Classes[v.ClassName] and not API.Classes[v.ClassName].Tags.Service) or not API.Classes[v.ClassName]) and v ~= game then
						writeXML(v)
					end
				end
				t_ins(buffer,"\n</Item>")
			end
			
			if inst == game and Serializer.Settings.SavePlayerDescendants then
				t_ins(buffer,'\n<Item class="Folder" referent="RBX'..refs[Instance.new("Folder")]..'">\
<Properties>\
<string name="Name">Player Descendants</string>\
</Properties>')
				for i,v in pairs(game:GetService("Players").LocalPlayer:GetChildren()) do
					if v:IsA("PlayerGui") or v:IsA("PlayerScripts") or v:IsA("StarterGear") then
						t_ins(buffer,'\n<Item class="Folder" referent="RBX'..refs[Instance.new("Folder")]..'">\
<Properties>\
<string name="Name">'..v.ClassName..'</string>\
</Properties>')
						for _,c in pairs(v:GetChildren()) do
							writeXML(c)
						end
						t_ins(buffer,"\n</Item>")
					else
						writeXML(v)
					end
				end
				t_ins(buffer,"\n</Item>")
			end
			
			if inst == game then
				t_ins(buffer,'\n<Item class="Script" referent="RBX'..refs[Instance.new("Folder")]..'">\
<Properties>\
<string name="Name">Please Read</string>\
<ProtectedString name="Source">'..[==[--[[
If you cannot play the game, please try relocating any scripts in StarterPlayer elsewhere.
]]]==]..'</ProtectedString>\
</Properties>\
</Item>')
			end
			
			t_ins(buffer,"\n</roblox>")
			
			if Serializer.Settings.DecompileMode > 0 and decompile then
				if inst == game and #Serializer.Settings.DecompileIgnore > 0 then
					local ignoreServices = {}
					for i,v in pairs(Serializer.Settings.DecompileIgnore) do t_ins(ignoreServices,game:GetService(v)) end
					for i = #toDecompile,1,-1 do
						for _,serv in pairs(ignoreServices) do
							if toDecompile[i][1]:IsDescendantOf(serv) then
								table.remove(toDecompile,i)
								break
							end
						end
					end
				end
				
				if Serializer.Settings.DecompileMode == 1 then
					for i,v in pairs(toDecompile) do
						local decstr = "-- This could not decompile"
						pcall(function()
						    if (false) then
							decstr = tostring(v[1]):gsub("['\"<>&]",xmlReplace)
							else
							decstr = "" 
                            end
						end)
						buffer[v[2]] = decstr
					end
				elseif Serializer.Settings.DecompileMode == 2 then
					local left = #toDecompile
					local totalScripts = left
					
					local statusGui = Instance.new("ScreenGui")
					local statusText = Instance.new("TextLabel",statusGui)
					statusText.BackgroundTransparency = 1
					statusText.TextColor3 = Color3.new(1,1,1)
					statusText.Position = UDim2.new(0,0,0,0)
					statusText.Size = UDim2.new(1,0,0,36)
					statusText.TextSize = 32
					statusText.Font = Enum.Font.Code
					statusText.Text = left.."/"..totalScripts.." Scripts Left"
					statusGui.Parent = gethui()
				
					local function doDec(scr)
						local thread = coroutine.running()
						local decompiled = false
						
						tostring(scr,"unluac",function(scr,err)
							decompiled = true
							coroutine.resume(thread,scr,err)
						end)
						
						spawn(function()
							wait(Serializer.Settings.DecompileTimeout)
							if decompiled then return end
							coroutine.resume(thread,nil,"timeout")
						end)
						
						return coroutine.yield()
					end
				
					for i = 1,Serializer.Settings.UnluacMaxThreads do
						spawn(function()
							while #toDecompile > 0 do
								local nextScript = table.remove(toDecompile)
								local scr,err = doDec(nextScript[1])
								if scr then
									buffer[nextScript[2]] = scr:gsub("['\"<>&]",xmlReplace)
								else
									buffer[nextScript[2]] = "-- This could not decompile because "..(err or ""):gsub("['\"<>&]",xmlReplace)
								end
								left = left - 1
								statusText.Text = left.."/"..totalScripts.." Scripts Left"
							end
						end)
					end
					while left > 0 do game:GetService("RunService").RenderStepped:wait() end
					statusGui:Destroy()
				end
			end
			
			_writefile(name..(inst == game and ".rbxlx" or ".rbxmx"),(t_concat(buffer)))
			resetState()
		end
	}
	
	return Serializer
end

local initialized = false
local serializer = SerializerModule()

local function init()
	local startup = {
		API = fetchAPI(),
		WriteFile = writefile,
		GetNilInstances = nil,
		OldIndex = oldindex
	}
	serializer.Init(startup)
	initialized = true
end

if not initialized then
	init()
end

getgenv().saveinstance = function()
    serializer.SaveInstance(game, string.format("%i-PlaceSave", game["PlaceId"]), sets)
end
INFO