local Classes; -- Author @Rerumu <3 local Props = {}; local Concat = table.concat; -- Concatenation is going to get reworked just a couple times maybe? local tostring = tostring; local Players = game:GetService('Players'); local Beat = game:GetService('RunService').Heartbeat; -- Changelog --[[ * Whatever version this is - Re-did Elysian callback stuff because it was slow - Added an Elysian fallback to LuaDec whenever needed -- Delays improved -- Changed how LocalPlayer and nil are handled --- Fixed Synapse support ]] local InNil; local Print; local WritesFl; local Decompile; local SaveList = { game:GetService('Workspace'); game:GetService('ReplicatedFirst'); game:GetService('ReplicatedStorage'); game:GetService('ServerStorage'); -- Internal stuff game:GetService('Lighting'); game:GetService('StarterGui'); game:GetService('StarterPack'); game:GetService('StarterPlayer'); game:GetService('Teams'); game:GetService('InsertService'); }; local IgnoredList = { 'CameraScript'; 'ControlScript'; 'ChatScript'; 'BubbleChat'; 'Camera'; } local NoNoProp = { Instance = { Archivable = true, DataCost = true, ClassName = true, RobloxLocked = true, Parent = true }; BasePart = { Position = true, Rotation = true }; }; for Idx = 1, 3 do local Ran, Err = ypcall(function() Classes = game:HttpGet('https://raw.githubusercontent.com/Anaminus/anaminus.github.io/master/rbx/json/api/latest.json', true); -- Classes = game:GetService('HttpService'):GetAsync('https://raw.githubusercontent.com/Anaminus/anaminus.github.io/master/rbx/json/api/latest.json'); end); if (not Ran) then if (Idx == 3) then error(Err, 0); else wait(1); end; else -- Setup stuff local Me = Players.LocalPlayer; for _, Player in next, Players:GetPlayers() do if (Player ~= Me) then table.insert(IgnoredList, tostring(Player)); -- Let's *not* end; end; local NumIg = #IgnoredList; Classes = game:GetService('HttpService'):JSONDecode(Classes); for Idx = 1, NumIg do IgnoredList[IgnoredList[Idx]] = true; IgnoredList[Idx] = nil; end; break; end; end; if elysianexecute then -- Scripts is handled async in Elysian because the decompiler is callback based local Sources = {}; InNil = getnilinstances; WritesFl = writefile; function Decompile(Script) -- Austin finna gonna make me die local Name = Script.Name; -- Remove if you don't want a cache local Scr = Sources[Name]; if (not Scr) then local Timeout = tick() + 8; local Ran, Err = decompile(Script, 'unluac', newcclosure(function(Res, Err) -- Fix or something on newcclosure if Res then Scr = Res:gsub('\r+', ''); -- Austin-proof newline machine else Scr = '--[[\n' .. tostring(Err) .. '\n--]]'; end; end)); if (not Ran) then Scr = '--[[\n' .. tostring(Err) .. '\n--]]'; else Print('Decompiling ' .. Script:GetFullName()); Beat:wait(); end; while (not Scr) do if (tick() > Timeout) then Print('Script timeout ' .. Script:GetFullName()); Scr = '-- Unluac timed out, falling back to LuaDec\n'; Beat:wait(); Beat:wait(); Ran, Err = decompile(Script); if Ran then Print('LuaDec fallback succeeded'); Scr = Scr .. Ran; else Scr = Scr .. '--[[\n' .. tostring(Err) .. '\n--]]'; end; break; else Beat:wait(); -- Shouldn't cause an issue Beat:wait(); end; end; Sources[Name] = Scr; end; return Scr; end; function Print(String) printconsole(String, 100, 200, 180); end; Print('ReruSavePlace detected Elysian, functions loaded'); elseif syn then -- Oh my god 3ds why couldn't you just use '.' syntax function InNil() return getnilinstances(); end; function WritesFl(Location, Data) return writefile(Location, Data); end; function Decompile(Script) return decompile(Script); end; Print = warn; Print('ReruSavePlace detected Synapse, functions loaded'); else error('This exploit may not be supported by RSP, please contact me'); end; do local Temp = {}; for Idx, Val in next, Classes do if (Val.type == 'Class') then Temp[Val.Name] = Val; Temp[Val.Name].Properties = {}; elseif (Val.type == 'Property') then local Ignore; for _, Tag in next, Val.tags do if (Tag == 'deprecated') or (Tag == 'readonly') then Ignore = true; break; end; end; if (not Ignore) then local Ignored = NoNoProp[Val.Class]; if Ignored and Ignored[Val.Name] then Ignore = true; end; if (not Ignore) then local Props = Temp[Val.Class].Properties; Props[#Props + 1] = Val; end; end; end; end; Classes = Temp; end; local function PropsOf(Obj) if Props[Obj.ClassName] then return Props[Obj.ClassName]; end; local Prop = {}; local Class = Obj.ClassName; while Class do local Curr = Classes[Class]; for Index, Value in next, Curr.Properties do Prop[#Prop + 1] = Value; end; Class = Curr.Superclass; end; table.sort(Prop, function(A, B) return A.Name < B.Name; end); Props[Obj.ClassName] = Prop; return Prop; end; local function SetParent(Obj, Parent) local Cloned; if Obj.Archivable then Cloned = Obj:Clone(); end; if (not Cloned) then local pcall = pcall; Cloned = Instance.new'Folder' for Index, Child in next, Obj:GetChildren() do pcall(SetParent, Child, Cloned); end; Cloned.Name = Obj.Name .. ':' .. Obj.ClassName; end; Cloned.Parent = Parent; end; local function SavePlaceAsync() local Count = 0; local Final = {}; local Timer = tick(); local Saved = setmetatable({}, {__index = function(This, Idx) local C = Count + 1; Count = C; This[Idx] = C; return C; end}); local pcall = pcall; -- Skid syndrome Final[1] = 'nullnil'; Print('Saving place...'); local function SaveInstance(Obj) if Classes[Obj.ClassName] and (not IgnoredList[Obj.Name]) then local Props = PropsOf(Obj); local Num = Saved[Obj]; local Conversions = { ['&'] = '&'; ['<'] = '<'; ['>'] = '>'; } Final[#Final + 1] = ''; if ((Num % 1080) == 0) then Beat:wait(); end; for _, Prop in next, Props do local Append; local Type = Prop.ValueType; local ObjProp = Prop.Name; local Objp_ok, Objp = pcall(function() return Obj[ObjProp] end); if not Objp_ok then Append = ''; elseif (typeof(Objp) == 'EnumItem') then Append = '' .. Objp.Value .. ''; else if (Type == 'bool') then Append = '' .. tostring(Objp) .. ''; elseif (Type == 'float') then Append = '' .. tostring(Objp) .. ''; elseif (Type == 'int') then Append = '' .. tostring(Objp) .. ''; elseif (Type == 'double') then Append = '' .. tostring(Objp) .. ''; elseif (Type == 'string') then local String = Objp:gsub("[&<>]", Conversions); -- Because I got C O M P L A I N T S Append = '' .. String .. ''; elseif (Type == 'BrickColor') then Append = '' .. Objp.Number .. ''; elseif (Type == 'Vector2') then Append = '' .. '' .. Objp.x .. '' .. '' .. Objp.y .. '' .. '' elseif (Type == 'Vector3') then Append = '' .. '' .. Objp.x .. '' .. '' .. Objp.y .. '' .. '' .. Objp.z .. '' .. '' elseif (Type == 'CoordinateFrame') then local X, Y, Z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = Objp:components() Append = '' .. '' .. X .. '' .. '' .. Y .. '' .. '' .. Z .. '' .. '' .. R00 .. '' .. '' .. R01 .. '' .. '' .. R02 .. '' .. '' .. R10 .. '' .. '' .. R11 .. '' .. '' .. R12 .. '' .. '' .. R20 .. '' .. '' .. R21 .. '' .. '' .. R22 .. '' .. '' elseif (Type == 'Content') then local String = Objp:gsub("[&<>]", Conversions); Append = '' .. String .. ''; elseif (Type == 'UDim2') then local Objp = Objp; Append = '' .. '' .. Objp.X.Scale .. '' .. '' .. Objp.X.Offset .. '' .. '' .. Objp.Y.Scale .. '' .. '' .. Objp.Y.Offset .. '' .. '' elseif (Type == 'Color3') then Append = '' .. '' .. Objp.r .. '' .. '' .. Objp.g .. '' .. '' .. Objp.b .. '' .. '' elseif (Type == 'NumberRange') then Append = '' .. tostring(Objp.Min) .. ' ' .. tostring(Objp.Max) .. '' elseif (Type == 'NumberSequence') then local Ob = {}; Ob[1] = '' for i, v in next, Objp.Keypoints do Ob[#Ob + 1] = tostring(v.Time) .. ' ' .. tostring(v.Value) .. ' ' .. tostring(v.Envelope) .. ' '; end Ob[#Ob + 1] = ''; Append = Concat(Ob); elseif (Type == 'ColorSequence') then local Ob = {}; Ob[1] = '' for i, v in next, Objp.Keypoints do Ob[#Ob + 1] = Concat{tostring(v.Time) .. ' ' .. tostring(v.Value.r) .. ' ' .. tostring(v.Value.g) .. ' ' .. tostring(v.Value.b), " 0 "}; end Ob[#Ob + 1] = ''; Append = Concat(Ob); elseif (Type == 'Rect2D') then Append = '' .. '' .. '' .. tostring(Objp.Min.X) .. '' .. '' .. tostring(Objp.Min.Y) .. '' .. '' .. '' .. '' .. tostring(Objp.Max.X) .. '' .. '' .. tostring(Objp.Max.Y) .. '' .. '' .. '' elseif (Type == 'ProtectedString') then local Src; if (ObjProp == 'Source') then if (Obj.ClassName ~= 'Script') then local Sc, Er = Decompile(Obj); if (not Sc) then Src = '--[[\n\t' .. Er .. '\n--]]'; else Src = Sc; end; else Src = '-- Server script not decompiled :('; end; else Src = ''; end; Append = ''; elseif (Type == 'Object') then if (not Objp) then Objp = 'null'; else Objp = 'RBX' .. Saved[Objp]; end; Append = '' .. Objp .. ''; elseif (Type == 'PhysicalProperties') then if Objp then Append = 'true' .. '' .. tostring(Objp.Density) .. '' .. '' .. tostring(Objp.Friction) .. '' .. '' .. tostring(Objp.Elasticity) .. '' .. '' .. tostring(Objp.FrictionWeight) .. '' .. '' .. tostring(Objp.ElasticityWeight) .. '' .. '' else Append = 'false'; end; end; end; if Append then Final[#Final + 1] = Append; end; end Final[#Final + 1] = ''; for _, Obj in next, Obj:GetChildren() do SaveInstance(Obj); end; Final[#Final + 1] = ''; end; end; do local Other = Instance.new'Folder'; local Real = Players.LocalPlayer; local Play = Instance.new'Folder'; Other.Name = 'Other'; Other.RobloxLocked = true; Other.Parent = game; Play.Parent = Other; Play.Name = 'LocalPlayer'; for _, Des in next, Real:GetChildren() do pcall(SetParent, Des, Play); end; if InNil then local Extr = Instance.new'Folder'; Extr.Parent = Other; Extr.Name = 'Nil_Instances'; for _, Nil in next, InNil() do pcall(SetParent, Nil, Extr); end; end; SaveList[#SaveList + 1] = Other; end; for _, Child in next, SaveList do SaveInstance(Child); end; Final[#Final + 1] = ''; local Place = game:GetService('MarketplaceService'):GetProductInfo(game.PlaceId); if Place.Name then local Illegal = {'/', '\\', ':', '?', '"', '\'', '<', '>', '|'}; for Idx = 1, #Illegal do Illegal[Illegal[Idx]] = ''; Illegal[Idx] = nil; end; Place = string.gsub(Place.Name, '.', Illegal); else Place = 'Unknown'; end; Final = Concat(Final); Print(string.format('Done serializing, saving (%d bytes)', #Final)); WritesFl(Place .. '.rbxl', Final); Print(string.format('Saving took %d second(s), please check your workspace folder', tick() - Timer)); end; SavePlaceAsync();