View difference between Paste ID: 4xf2G5AJ and QVNCR5Af
SHOW: | | - or go back to the newest paste.
1
--[[
2
	SaveInstance V3 - Swift
3
	
4
	THIS IS A SAVEINSTANCE CORE NOT A SAVEINSTANCE SCRIPT. THINK OF THIS AS A MOCK OF THE BUILT IN FUNCTION. ALL THIS DOES IT MAKE THE FUNCTION
5
	YOU NEED A COPIER SCRIPT THAT CALLS _G.SInstance(Instance, Name) FOR THIS TO WORK.
6
	
7
	You have three options of saveinstance that you can change by setting "saveMethod".
8
	1 - Using the "writefile" function if you support it
9
	2 - Using a webhost like v2
10
	3 - Using the new create model method
11
	
12
	NEW: If you just want to save the place right away, go to the "SAVE PLACE UI OPTIONS" and enable it.
13
		 You also need to get one of your place's id and set "savePlaceId" to it. This is where your place will be exported to.
14
	
15
	Made by Pi and sad Moon :c
16
--]]
17
18
-- ========== MAIN SETTINGS ==========
19
local saveMethod = 3 -- 1 = writefile, 2 = host, 3 = createmodel
20
local debugMessages = true -- Debug messages
21
local APIOverride = [==[]==] -- The JSON Api of Roblox if you have no TrustCheck
22
23
-- ========== FOR HOST OPTION ==========
24
-- You need your host with the php set up on it for this to work. Make sure read/write permissions are enabled for php.
25
-- You don't need it if you have a writefile function. Actually no setup if you have writefile ahaha.
26
27
local host = "http://slowcomplicatedafmethod.com/Master.php" -- Your php file
28
local splitSize = 800000 -- If your host supports bigger post size then change this (1mb default)
29
30
-- ========== SAVE PLACE UI OPTIONS ==========
31-
local savePlaceId = 0 -- Put the PlaceID of ONE OF THE PLACES THAT YOU OWN here from https://www.roblox.com/develop which will be updated by this script.
31+
local savePlaceId = 724225093 -- Put the PlaceID of ONE OF THE PLACES THAT YOU OWN here from https://www.roblox.com/develop which will be updated by this script.
32
local savePlaceExtra = true -- Nil Instances, PlayerGui, etc
33
local savePlaceScripts = true -- If you have decompiler
34
local savePlaceTerrain = true -- Opens Terrain Chunk Selector
35
local savePlaceTerrainShowChunks = true -- Shows the selection boxes which are your selected chunks
36
local savePlaceNilInstances = true -- Nil Instances
37
local savePlaceUseWriteFile = false -- Writes the place file to your disk instead if you have a writefile function
38
39
-- ========== DO NOT MODIFY BELOW ==========
40
41
if saveMethod == 1 and not writefile then print("no writefile ending") return end
42
43
local http = game:GetService("HttpService")
44
local API = {}
45
local APIJson
46
local LPlayer = game:GetService("Players").LocalPlayer
47
local selectingTerrain = false
48
local terrainChunks = {}
49
local terrainChunksTemp = {}
50
local terrainBeen = {}
51
local placeMode = false
52
53
local instanceCount = 0
54
local saveString = ""
55
local totalInstances = 1
56
57
local savedProps = {}
58
local instanceRefs = {}
59
local storedInstances = {}
60
local splits = 0
61
62
local globalName = ""
63
local extraFolder = Instance.new("Folder")
64
extraFolder.Name = "_IMPORTANT_AND_EXTRA_INSTANCES_"
65
66
local terrainLoader = Instance.new("Script",extraFolder)
67
terrainLoader.Name = "LoadTerrain"
68
local terrainData = Instance.new("ModuleScript",terrainLoader)
69
terrainData.Name = "Data"
70
71
local consoleFunc = printconsole or writeconsole
72
73
local success,err = ypcall(function()
74
	if APIOverride and APIOverride ~= "" then
75
		APIJson = APIOverride
76
	else
77
		APIJson = game:HttpGetAsync("http://anaminus.github.io/rbx/json/api/latest.json")
78
	end
79
end)
80
81
if err then
82
	if script:FindFirstChild("API") then
83
		APIJson = require(script.API)
84
	end
85
end
86
87
APIJson = http:JSONDecode(APIJson)
88
89
for i,v in pairs(APIJson) do
90
	if v.type == "Class" then
91
		API[v.Name] = v
92
		API[v.Name].Properties = {}
93
	elseif v.type == "Property" then
94
		local dontuse = false
95
		for i2,v2 in pairs(v.tags) do
96
			if v2 == "deprecated" or v2 == "hidden" or v2 == "readonly" then
97
				dontuse = true
98
			end
99
		end
100
		if not dontuse then
101
			table.insert(API[v.Class].Properties,v)
102
		end
103
	end
104
end
105
106
local function getProperties(obj)
107
	if savedProps[obj.ClassName] then return savedProps[obj.ClassName] end
108
	
109
	local tempProps = {}
110
	local currentClass = obj.ClassName
111
	
112
	while currentClass do
113
		for i,v in pairs(API[currentClass].Properties) do
114
			table.insert(tempProps,v)
115
		end
116
		currentClass = API[currentClass].Superclass
117
	end
118
	
119
	savedProps[obj.ClassName] = tempProps
120
	return tempProps
121
end
122
123
local function appendToHost()
124
	game:HttpPostAsync(host,table.concat(storedInstances)) --http:PostAsync(host,http:JSONEncode({Option = "Append",Name = globalName,Data = table.concat(storedInstances)}))
125
	splits = splits + 1
126
	if debugMessages then
127
		if consoleFunc then -- Stealth option is always better af
128
			consoleFunc("SaveAmounts: "..tostring(splits).." Progress = "..tostring(instanceCount/totalInstances*100).."%")
129
		else
130
			print("SaveAmounts: "..tostring(splits),"Progress = "..tostring(instanceCount/totalInstances*100).."%")
131
		end
132
	end
133
end
134
135
local function submitSave()
136
	game:HttpPostAsync(host,http:JSONEncode({Option = "Submit",Name = globalName}))
137
end
138
139
local function clearAll()
140
	game:HttpPostAsync(host,http:JSONEncode({Option = "Clear"}))
141
end
142
143
local function checkRef(obj)
144
	local check = instanceRefs[obj]
145
	if check then
146
		return tostring(check)
147
	end
148
	instanceRefs[obj] = instanceCount
149
	return tostring(instanceCount)
150
end
151
152
local function setRef(obj)
153
	if obj == nil then return "null" end
154
	local check = instanceRefs[obj]
155
	if check then
156
		return "RBX"..tostring(check)
157
	end
158
	instanceCount = instanceCount + 1
159
	instanceRefs[obj] = instanceCount
160
	return "RBX"..tostring(instanceCount)
161
end
162
163
local function cleanUglyAf(str)
164
	if #str == 0 then return "" end
165
	
166
	local firstChar = str:sub(1,1)
167
	local firstByte = string.byte(firstChar)
168
	
169
	if firstByte >= 32 and firstByte <= 126 then
170
		return firstChar..cleanUglyAf(str:sub(2))
171
	elseif firstByte == 9 or firstByte == 10 then
172
		return firstChar..cleanUglyAf(str:sub(2))
173
	else
174
		return cleanUglyAf(str:sub(2))
175
	end
176
end
177
178
function CreateInstance(cls,props)
179
	local inst = Instance.new(cls)
180
	for i,v in pairs(props) do
181
		inst[i] = v
182
	end
183
	return inst
184
end
185
186
local function createTerrainGui()
187
	local TerrainGui = CreateInstance("Frame",{Style=0,Active=false,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(0.10980392992496,0.16470588743687,0.22352942824364),BackgroundTransparency=0,BorderColor3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=1,ClipsDescendants=false,Draggable=false,Position=UDim2.new(0,0,0.5,0),Rotation=0,Selectable=false,Size=UDim2.new(0,150,0,150),SizeConstraint=0,Visible=false,ZIndex=1,Name="Main",})
188
	local TerrainGui2 = CreateInstance("TextLabel",{Font=4,FontSize=5,Text="Terrain Chunk Selection",TextColor3=Color3.new(1,1,1),TextScaled=false,TextSize=14,TextStrokeColor3=Color3.new(0,0,0),TextStrokeTransparency=1,TextTransparency=0,TextWrapped=false,TextXAlignment=2,TextYAlignment=1,Active=false,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderColor3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=1,ClipsDescendants=false,Draggable=false,Position=UDim2.new(0,0,0,0),Rotation=0,Selectable=false,Size=UDim2.new(1,0,0,20),SizeConstraint=0,Visible=true,ZIndex=1,Name="Title",Parent = TerrainGui})
189
	local TerrainGui3 = CreateInstance("TextLabel",{Font=3,FontSize=5,Text="Use your mouse to click on all the terrain to save. When you are finished, press done.",TextColor3=Color3.new(1,1,1),TextScaled=false,TextSize=14,TextStrokeColor3=Color3.new(0,0,0),TextStrokeTransparency=1,TextTransparency=0,TextWrapped=true,TextXAlignment=2,TextYAlignment=1,Active=false,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderColor3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=1,ClipsDescendants=false,Draggable=false,Position=UDim2.new(0,0,0,25),Rotation=0,Selectable=false,Size=UDim2.new(1,0,0,50),SizeConstraint=0,Visible=true,ZIndex=1,Name="Desc",Parent = TerrainGui})
190
	local TerrainGui4 = CreateInstance("TextLabel",{Font=4,FontSize=5,Text="Chunks: 0",TextColor3=Color3.new(1,1,1),TextScaled=false,TextSize=14,TextStrokeColor3=Color3.new(0,0,0),TextStrokeTransparency=1,TextTransparency=0,TextWrapped=true,TextXAlignment=2,TextYAlignment=1,Active=false,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderColor3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=1,ClipsDescendants=false,Draggable=false,Position=UDim2.new(0,0,0,80),Rotation=0,Selectable=false,Size=UDim2.new(1,0,0,20),SizeConstraint=0,Visible=true,ZIndex=1,Name="Chunks",Parent = TerrainGui})
191
	local TerrainGui5 = CreateInstance("TextButton",{Font=4,FontSize=6,Text="Done",TextColor3=Color3.new(1,1,1),TextScaled=false,TextSize=18,TextStrokeColor3=Color3.new(0,0,0),TextStrokeTransparency=1,TextTransparency=0,TextWrapped=false,TextXAlignment=2,TextYAlignment=1,AutoButtonColor=true,Modal=false,Selected=false,Style=0,Active=true,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(0.17254902422428,0.22745099663734,0.28627452254295),BackgroundTransparency=0,BorderColor3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=1,ClipsDescendants=false,Draggable=false,Position=UDim2.new(0,5,1,-30),Rotation=0,Selectable=true,Size=UDim2.new(1,-10,0,25),SizeConstraint=0,Visible=true,ZIndex=1,Name="Done",Parent = TerrainGui})
192
	return TerrainGui
193
end
194
195
local terrainGui = createTerrainGui()
196
terrainGui.Parent = game:GetService("CoreGui").RobloxGui
197
198
local ignorePlaceClasses = {
199
	["CoreGui"] = true,
200
	["Players"] = true,
201
	["Chat"] = true,
202
	["StarterPlayerScripts"] = true,
203
	["StarterCharacterScripts"] = true
204
}
205
206
local function placeInstCheck(inst)
207
	return not ignorePlaceClasses[inst.ClassName] and not game:GetService("Players"):GetPlayerFromCharacter(inst) and inst ~= workspace.CurrentCamera
208
end
209
210
local propFunc = {
211
	["bool"] = function(inst,prop)
212
		saveString = saveString..'\n<bool name="'..prop..'">'..tostring(inst[prop])..'</bool>'
213
	end,
214
	["float"] = function(inst,prop)
215
		saveString = saveString..'\n<float name="'..prop..'">'..tostring(inst[prop])..'</float>'
216
	end,
217
	["int"] = function(inst,prop)
218
		saveString = saveString..'\n<int name="'..prop..'">'..tostring(inst[prop])..'</int>'
219
	end,
220
	["string"] = function(inst,prop)
221
		local cleanName = inst[prop]
222
		cleanName = string.gsub(cleanName,"&","&amp;")
223
		cleanName = string.gsub(cleanName,"<","&lt;")
224
		cleanName = string.gsub(cleanName,">","&gt;")
225
		saveString = saveString..'\n<string name="'..prop..'">'..cleanName..'</string>'
226
	end,
227
	["BrickColor"] = function(inst,prop)
228
		saveString = saveString..'\n<int name="'..prop..'">'..tostring(inst[prop].Number)..'</int>'
229
	end,
230
	["Vector2"] = function(inst,prop)
231
		saveString = saveString..'\n<Vector2 name="'..prop..'">'
232
		saveString = saveString..'\n<X>'..inst[prop].x..'</X>'
233
		saveString = saveString..'\n<Y>'..inst[prop].y..'</Y>'
234
		saveString = saveString..'\n</Vector2>'
235
	end,
236
	["Vector3"] = function(inst,prop)
237
		saveString = saveString..'\n<Vector3 name="'..prop..'">'
238
		saveString = saveString..'\n<X>'..inst[prop].x..'</X>'
239
		saveString = saveString..'\n<Y>'..inst[prop].y..'</Y>'
240
		saveString = saveString..'\n<Z>'..inst[prop].z..'</Z>'
241
		saveString = saveString..'\n</Vector3>'
242
	end,
243
	["CoordinateFrame"] = function(inst,prop)
244
		local X,Y,Z,R00,R01,R02,R10,R11,R12,R20,R21,R22 = inst[prop]:components()
245
		saveString = saveString..'\n<CoordinateFrame name="'..prop..'">'
246
		saveString = saveString..'\n<X>'..X..'</X>'
247
		saveString = saveString..'\n<Y>'..Y..'</Y>'
248
		saveString = saveString..'\n<Z>'..Z..'</Z>'
249
		saveString = saveString..'\n<R00>'..R00..'</R00>'
250
		saveString = saveString..'\n<R01>'..R01..'</R01>'
251
		saveString = saveString..'\n<R02>'..R02..'</R02>'
252
		saveString = saveString..'\n<R10>'..R10..'</R10>'
253
		saveString = saveString..'\n<R11>'..R11..'</R11>'
254
		saveString = saveString..'\n<R12>'..R12..'</R12>'
255
		saveString = saveString..'\n<R20>'..R20..'</R20>'
256
		saveString = saveString..'\n<R21>'..R21..'</R21>'
257
		saveString = saveString..'\n<R22>'..R22..'</R22>'
258
		saveString = saveString..'\n</CoordinateFrame>'
259
	end,
260
	["Content"] = function(inst,prop)
261
		local cleanName = tostring(inst[prop])
262
		cleanName = string.gsub(cleanName,"&","&amp;")
263
		cleanName = string.gsub(cleanName,"<","&lt;")
264
		cleanName = string.gsub(cleanName,">","&gt;")
265
		saveString = saveString..'\n<Content name="'..prop..'"><url>'..cleanName..'</url></Content>'
266
	end,
267
	["UDim2"] = function(inst,prop)
268
		saveString = saveString..'\n<UDim2 name="'..prop..'">'
269
		saveString = saveString..'\n<XS>'..inst[prop].X.Scale..'</XS>'
270
		saveString = saveString..'\n<XO>'..inst[prop].X.Offset..'</XO>'
271
		saveString = saveString..'\n<YS>'..inst[prop].Y.Scale..'</YS>'
272
		saveString = saveString..'\n<YO>'..inst[prop].Y.Offset..'</YO>'
273
		saveString = saveString..'\n</UDim2>'
274
	end,
275
	["Color3"] = function(inst,prop)
276
		saveString = saveString..'\n<Color3 name="'..prop..'">'
277
		saveString = saveString..'\n<R>'..inst[prop].r..'</R>'
278
		saveString = saveString..'\n<G>'..inst[prop].g..'</G>'
279
		saveString = saveString..'\n<B>'..inst[prop].b..'</B>'
280
		saveString = saveString..'\n</Color3>'
281
	end,
282
	["NumberRange"] = function(inst,prop)
283
		saveString = saveString..'\n<NumberRange name="'..prop..'">'..tostring(inst[prop].Min).." "..tostring(inst[prop].Max).." "..'</NumberRange>'
284
	end,
285
	["NumberSequence"] = function(inst,prop)
286
		saveString = saveString..'\n<NumberSequence name="'..prop..'">'
287
		for i,v in pairs(inst[prop].Keypoints) do
288
			saveString = saveString..tostring(v.Time).." "..tostring(v.Value).." "..tostring(v.Envelope).." "
289
		end
290
		saveString = saveString..'</NumberSequence>'
291
	end,
292
	["ColorSequence"] = function(inst,prop)
293
		saveString = saveString..'\n<ColorSequence name="'..prop..'">'
294
		for i,v in pairs(inst[prop].Keypoints) do
295
			saveString = saveString..tostring(v.Time).." "..tostring(v.Value.r).." "..tostring(v.Value.g).." "..tostring(v.Value.b).." 0 "
296
		end
297
		saveString = saveString..'</ColorSequence>'
298
	end,
299
	["Rect2D"] = function(inst,prop)
300
		saveString = saveString..'\n<Rect2D name="'..prop..'">'
301
		saveString = saveString..'\n<min>'
302
		saveString = saveString..'\n<X>'..tostring(inst[prop].Min.X)..'</X>'
303
		saveString = saveString..'\n<Y>'..tostring(inst[prop].Min.Y)..'</Y>'
304
		saveString = saveString..'\n</min>'
305
		saveString = saveString..'\n<max>'
306
		saveString = saveString..'\n<X>'..tostring(inst[prop].Max.X)..'</X>'
307
		saveString = saveString..'\n<Y>'..tostring(inst[prop].Max.Y)..'</Y>'
308
		saveString = saveString..'\n</max>'
309
		saveString = saveString..'\n</Rect2D>'
310
	end,
311
	["ProtectedString"] = function(inst,prop)
312
		local prostr = inst[prop]
313
		if placeMode and decompile and (inst:IsA("LocalScript") or inst:IsA("ModuleScript")) and savePlaceScripts and inst.Source == "" then prostr = decompile(inst) end
314
		if inst == terrainData then prostr = "return [==["..table.concat(terrainChunks,"|").."]==]" terrainChunks = {} end
315
		saveString = saveString..'\n<ProtectedString name="'..prop..'"><![CDATA['..prostr..']]></ProtectedString>'
316
	end,
317
	["Object"] = function(inst,prop)
318
		saveString = saveString..'\n<Ref name="'..prop..'">'..setRef(inst[prop])..'</Ref>'
319
	end
320
}
321
322
local ignorePropNames = {
323
	["Archivable"] = true,
324
	["DataCost"] = true,
325
	["ClassName"] = true,
326
	["RobloxLocked"] = true,
327
	["Parent"] = true
328
}
329
330
local function writeInstance(inst,altData)
331
	if API[inst.ClassName] and (placeMode and placeInstCheck(inst) or not placeMode) then
332
		if saveMethod == 2 and string.len(table.concat(storedInstances)) >= splitSize then
333
            appendToHost()
334
            storedInstances = {}
335
        end
336
		instanceCount = instanceCount + 1
337
		local props = getProperties(inst)
338
		saveString = saveString..'\n<Item class="'..inst.ClassName..'" referent="RBX'..checkRef(inst)..'">'
339
		saveString = saveString.."\n<Properties>"
340
		for _,prop in pairs(props) do
341
			ypcall(function()
342
				if ignorePropNames[prop.Name] then return end
343
				local propF = propFunc[prop.ValueType]
344
				if propF then
345
					propF(inst,prop.Name)
346
				elseif inst[prop.Name].Value then
347
					saveString = saveString..'\n<token name="'..prop.Name..'">'..inst[prop.Name].Value..'</token>'
348
				end
349
				table.insert(storedInstances,saveString)
350
				saveString = ""
351
			end)
352
		end
353
		if inst:IsA("UnionOperation") and ypcall(function()local lolaf = inst.AssetId end) then -- Had to do this, "BinaryString" type values were not in the API dump.
354
			local cleanName = tostring(inst.AssetId)
355
			cleanName = string.gsub(cleanName,"&","&amp;")
356
			cleanName = string.gsub(cleanName,"<","&lt;")
357
			cleanName = string.gsub(cleanName,">","&gt;")
358
			saveString = saveString..'\n<Content name="AssetId"><url>'..cleanName..'</url></Content>'
359
			saveString = saveString..'\n<Vector3 name="InitialSize">'
360
			saveString = saveString..'\n<X>'..inst.InitialSize.x..'</X>'
361
			saveString = saveString..'\n<Y>'..inst.InitialSize.y..'</Y>'
362
			saveString = saveString..'\n<Z>'..inst.InitialSize.z..'</Z>'
363
			saveString = saveString..'\n</Vector3>'
364
		elseif inst:IsA("MeshPart") and ypcall(function()local lolaf = inst.MeshID end) then
365
			local cleanName = tostring(inst.MeshID)
366
			cleanName = string.gsub(cleanName,"&","&amp;")
367
			cleanName = string.gsub(cleanName,"<","&lt;")
368
			cleanName = string.gsub(cleanName,">","&gt;")
369
			saveString = saveString..'\n<Content name="MeshID"><url>'..cleanName..'</url></Content>'
370
			saveString = saveString..'\n<Vector3 name="InitialSize">'
371
			saveString = saveString..'\n<X>'..inst.InitialSize.x..'</X>'
372
			saveString = saveString..'\n<Y>'..inst.InitialSize.y..'</Y>'
373
			saveString = saveString..'\n<Z>'..inst.InitialSize.z..'</Z>'
374
			saveString = saveString..'\n</Vector3>'
375
		end
376
		saveString = saveString.."\n</Properties>"
377
		if inst == extraFolder then
378
			if getnilinstances and savePlaceNilInstances then
379
				local nilFolder = Instance.new("Folder",extraFolder)
380
				nilFolder.Name = "Nil Instances"
381
				
382
				local nilledInstances = {}
383
				for i,v in pairs(getnilinstances()) do
384
					if v.Name ~= "_DexTrash_" and v ~= extraFolder then
385
						table.insert(nilledInstances,v)
386
					end
387
				end
388
				writeInstance(nilFolder,nilledInstances)
389
			end
390
			
391
			if savePlaceExtra then
392
				local playerFolder = Instance.new("Folder",extraFolder)
393
				playerFolder.Name = "Instances In Player"
394
				writeInstance(playerFolder,LPlayer:GetChildren())
395
			
396
				local playerGuiFolder = Instance.new("Folder",extraFolder)
397
				playerGuiFolder.Name = "Instances In PlayerGui"
398
				writeInstance(playerGuiFolder,LPlayer:FindFirstChildOfClass("PlayerGui"):GetChildren())
399
			
400
				local cameraFolder = Instance.new("Folder",extraFolder)
401
				cameraFolder.Name = "Instances In Camera"
402
				writeInstance(cameraFolder,workspace.CurrentCamera:GetChildren())
403
			
404
				local chatFolder = Instance.new("Folder",extraFolder)
405
				chatFolder.Name = "Instances In Chat"
406
				writeInstance(chatFolder,game:GetService("Chat"):GetChildren())
407
			
408
				local SPSFolder = Instance.new("Folder",extraFolder)
409
				SPSFolder.Name = "Instances In StarterPlayerScripts"
410
				writeInstance(SPSFolder,game:GetService("StarterPlayer"):FindFirstChildOfClass("StarterPlayerScripts"):GetChildren())
411
			
412
				local SCSFolder = Instance.new("Folder",extraFolder)
413
				SCSFolder.Name = "Instances In StarterCharacterScripts"
414
				writeInstance(SCSFolder,game:GetService("StarterPlayer"):FindFirstChildOfClass("StarterCharacterScripts"):GetChildren())
415
			end			
416
			
417
			local unionFixer = Instance.new("Script",extraFolder)
418
			unionFixer.Name = "Fix Union Collisions - READ"
419
			unionFixer.Source = '--[[\n	THIS GUIDE WILL HELP YOU FIX THE COLLISIONS WITH UNIONS AND MESHPARTS IN THE MAP.\n	\n	Run this script in the command bar to select all the Unions and MeshParts in the map.\n	\n	After that, go to the properties frame and set the CollisionFidelity property to "Hull"\n	\n	Then, set them back to "Default"\n	\n	You have fixed all union collisions.\n	\n	\n	- Credit to Jester for original instructions\n--]]\n\nlocal unions = {}\n\nfunction getUnions(root)\n	for i,v in pairs(root:GetChildren()) do\n		if v:IsA("UnionOperation") or v:IsA("MeshPart") then\n			table.insert(unions,v)\n		end\n		getUnions(v)\n	end\nend\n\ngetUnions(workspace)\n\ngame.Selection:Set(unions)'
420
			writeInstance(unionFixer)		
421
		elseif altData then
422
			for i,v in pairs(altData) do
423
				writeInstance(v)
424
			end
425
		else
426
			for i,v in pairs(inst:GetChildren()) do
427
				writeInstance(v)
428
			end
429
		end
430
		saveString = saveString.."\n</Item>"
431
		table.insert(storedInstances,saveString)
432
		saveString = ""
433
	end
434
end
435
436
local function removeExtension(str)
437
    if string.find(str,".rbxm") then
438
        return string.sub(str,1,string.find(str,".rbxm")-1)
439
    elseif string.find(str,".rbxmx") then
440
        return string.sub(str,1,string.find(str,".rbxmx")-1)
441
    else
442
        return str
443
    end
444
end
445
446
local function countTotal(obj)
447
	for i,v in pairs(obj:GetChildren()) do
448
		totalInstances = totalInstances + 1
449
		countTotal(v)
450
	end
451
end
452
453
local function createModel(name,data)
454
	local url = "https://data.roblox.com/Data/Upload.ashx?assetid=0&type=Model&name="..name.."&description=&genreTypeId=1&ispublic=False&allowComments=False"
455
	local id = game:HttpPostAsync(url,data)	
456
	if debugMessages then
457
		if consoleFunc then
458
			consoleFunc("Your "..name.." Instance was saved to the id: "..id)
459
		else
460
			print("Your "..name.." Instance was saved to the id: "..id)
461
		end
462
	end
463
end
464
465
function _G.SInstance(inst,name,terrainRegions)
466
	placeMode = false
467
	name = removeExtension(name)
468
	if saveMethod == 2 then
469
		clearAll()
470
	end
471
	instanceCount = 0
472
	totalInstances = 1
473
	countTotal(inst)
474
	instanceRefs = {}
475
	storedInstances = {}
476
	globalName = name
477
	splits = 0
478
	saveString = [[<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">
479
<External>null</External>
480
<External>nil</External>]]
481
	
482
	if debugMessages then
483
		if not ypcall(function()local lolaf = Instance.new("UnionOperation").AssetId end) then
484
			if consoleFunc then
485
				consoleFunc("RUNNING WITH NO UNSCRIPTABLE PATCH")
486
			else
487
				print("RUNNING WITH NO UNSCRIPTABLE PATCH")
488
			end
489
		else
490
			if consoleFunc then
491
				consoleFunc("RUNNING WITH UNSCRIPTABLE PATCH c:")
492
			else
493
				print("RUNNING WITH UNSCRIPTABLE PATCH c:")
494
			end
495
		end
496
	end
497
	
498
	writeInstance(inst)
499
	table.insert(storedInstances,"\n</roblox>")
500
	if saveMethod == 1 then
501
		writefile(name..".rbxmx",table.concat(storedInstances))
502
	elseif saveMethod == 2 then
503
		appendToHost()
504
		submitSave()
505
	elseif saveMethod == 3 then
506
		createModel(name,table.concat(storedInstances))
507
	end
508
	if debugMessages then
509
		if consoleFunc then
510
			consoleFunc("Saved with "..tostring(splits).." splits.")
511
		else
512
			print("Saved with "..tostring(splits).." splits.")
513
		end
514
	end
515
	storedInstances = {}
516
end
517
518
function DoSPlace()
519
	placeMode = true
520
	instanceCount = 0
521
	instanceRefs = {}
522
	storedInstances = {}
523
	
524
	saveString = [[<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">
525
<External>null</External>
526
<External>nil</External>]]
527
	for i,v in pairs(game:GetChildren()) do
528
		writeInstance(v)
529
	end
530
	writeInstance(extraFolder)
531
	if savePlaceTerrain then writeInstance(terrainLoader) end
532
	table.insert(storedInstances,"\n</roblox>")
533
	if savePlaceUseWriteFile then
534
		if writefile then
535
			local filterChars = {"/","\\",":","?","\"","<",">","|"}
536
			local gameName = game:GetService("MarketplaceService"):GetProductInfo(game.PlaceId).Name
537
			for i,v in pairs(filterChars) do
538
				gameName = string.gsub(gameName,v,"")
539
			end
540
			writefile(tostring(game.PlaceId).." - "..gameName..".rbxlx",table.concat(storedInstances))
541
			return true
542
		end
543
		return false
544
	else
545
		return game:HttpPostAsync("https://data.roblox.com/Data/Upload.ashx?assetid="..tostring(savePlaceId).."&type=Place",table.concat(storedInstances))
546
	end
547
end
548
549
function _G.SPlace()
550
	if debugMessages then
551
		if consoleFunc then
552
			consoleFunc("SaveInstance V3 - Swift: Now saving place "..tostring(game.PlaceId))
553
		else
554
			print("SaveInstance V3 - Swift: Now saving place "..tostring(game.PlaceId))
555
		end
556
	end
557
	if savePlaceTerrain then
558
		terrainLoader.Source = 'local regions = {}\n\nfor w in string.gmatch(require(game:FindFirstChild("LoadTerrain").Data),"[^|]+") do\n    table.insert(regions,game:GetService("HttpService"):JSONDecode(w))\nend\n\nlocal chunkSize = 64\n\nlocal function makeRegion(str)\n    local t = {}\n    for w in string.gmatch(str,"[^,]+") do\n        table.insert(t,tonumber(w))\n    end\n    local regionPos = Vector3.new(t[1],t[2],t[3])\n    local newRegion = Region3.new(regionPos + Vector3.new(-chunkSize/2,-chunkSize/2,-chunkSize/2), regionPos + Vector3.new(chunkSize/2,chunkSize/2,chunkSize/2))\n    return newRegion\nend\n\nlocal function makeTable(o)\n    local t = {}\n    for i = 1,chunkSize/4 do\n        t[i] = {}\n        for j = 1,chunkSize/4 do\n            t[i][j] = {}\n            for k = 1,chunkSize/4 do\n                if not o then\n                    t[i][j][k] = Enum.Material.Air\n                else\n                    t[i][j][k] = 0\n                end\n            end\n        end\n    end\n    return t\nend\n\nlocal function getPos(str)\n    local t = {}\n    for w in string.gmatch(str,"[^,]+") do\n        table.insert(t,tonumber(w))\n    end\n    return t[1],t[2],t[3]\nend\n\nlocal materialMap = {}\nmaterialMap[1] = Enum.Material.Plastic\nmaterialMap[2] = Enum.Material.Wood\nmaterialMap[3] = Enum.Material.Slate\nmaterialMap[4] = Enum.Material.Concrete\nmaterialMap[5] = Enum.Material.CorrodedMetal\nmaterialMap[6] = Enum.Material.DiamondPlate\nmaterialMap[7] = Enum.Material.Foil\nmaterialMap[8] = Enum.Material.Grass\nmaterialMap[9] = Enum.Material.Ice\nmaterialMap[10] = Enum.Material.Marble\nmaterialMap[11] = Enum.Material.Granite\nmaterialMap[12] = Enum.Material.Brick\nmaterialMap[13] = Enum.Material.Pebble\nmaterialMap[14] = Enum.Material.Sand\nmaterialMap[15] = Enum.Material.Fabric\nmaterialMap[16] = Enum.Material.SmoothPlastic\nmaterialMap[17] = Enum.Material.Metal\nmaterialMap[18] = Enum.Material.WoodPlanks\nmaterialMap[19] = Enum.Material.Cobblestone\nmaterialMap[20] = Enum.Material.Air\nmaterialMap[21] = Enum.Material.Water\nmaterialMap[22] = Enum.Material.Rock\nmaterialMap[23] = Enum.Material.Glacier\nmaterialMap[24] = Enum.Material.Snow\nmaterialMap[25] = Enum.Material.Sandstone\nmaterialMap[26] = Enum.Material.Mud\nmaterialMap[27] = Enum.Material.Basalt\nmaterialMap[28] = Enum.Material.Ground\nmaterialMap[29] = Enum.Material.CrackedLava\nmaterialMap[30] = Enum.Material.Neon\nmaterialMap[31] = Enum.Material.Asphalt\nmaterialMap[32] = Enum.Material.LeafyGrass\nmaterialMap[33] = Enum.Material.Salt\nmaterialMap[34] = Enum.Material.Limestone\nmaterialMap[35] = Enum.Material.Pavement\n\nlocal function toMaterial(num)\n    return materialMap[num]\nend\n\nprint("Loading Terrain")\n\nfor c,chunk in pairs(regions) do\n    for i,v in pairs(chunk) do\n        local region = makeRegion(i)\n\n        local m = makeTable()\n        local o = makeTable(true)\n\n        for i2,v2 in pairs(v) do		\n            local x,y,z = getPos(v2[1])\n            m[x][y][z] = toMaterial(v2[2])\n            o[x][y][z] = v2[3]\n        end\n\n        workspace.Terrain:WriteVoxels(region,4,m,o)\n    end\n    print("Terrain Chunk: "..tostring(c))\n    wait()\nend\n\nprint("Finished Loading Terrain - Save The Place")'
559
		selectingTerrain = true
560
		terrainGui.Chunks.Text = "Chunks: 0"
561
		terrainGui.Visible = true
562
		repeat wait() until not selectingTerrain
563
	end
564
	local stopwatch = tick()
565
	local id = DoSPlace()
566
	local message = "Courtney ;("
567
	if savePlaceUseWriteFile then
568
		message = (id and "The place has been saved to a file." or "Place didn't save :c no writefile or error")
569
	else
570
		message = (id and "The place has been saved. Open it from the develop page on Roblox." or "Place didn't save :c something went wrong tell me")
571
	end
572
	if debugMessages then
573
		if consoleFunc then
574
			consoleFunc(message)
575
			consoleFunc("Saving took "..tostring(tick()-stopwatch).."s.")
576
		else
577
			print(message)
578
			print("Saving took "..tostring(tick()-stopwatch).."s.")
579
		end
580
	end
581
	storedInstances = {}
582
end
583
584
-- Terrain Stuff
585
local mouse = LPlayer:GetMouse()
586
local chunkSize = 64
587
local chunks = 0
588
local materialConv = {}
589
materialConv[Enum.Material.Plastic] = 1
590
materialConv[Enum.Material.Wood] = 2
591
materialConv[Enum.Material.Slate] = 3
592
materialConv[Enum.Material.Concrete] = 4
593
materialConv[Enum.Material.CorrodedMetal] = 5
594
materialConv[Enum.Material.DiamondPlate] = 6
595
materialConv[Enum.Material.Foil] = 7
596
materialConv[Enum.Material.Grass] = 8
597
materialConv[Enum.Material.Ice] = 9
598
materialConv[Enum.Material.Marble] = 10
599
materialConv[Enum.Material.Granite] = 11
600
materialConv[Enum.Material.Brick] = 12
601
materialConv[Enum.Material.Pebble] = 13
602
materialConv[Enum.Material.Sand] = 14
603
materialConv[Enum.Material.Fabric] = 15
604
materialConv[Enum.Material.SmoothPlastic] = 16
605
materialConv[Enum.Material.Metal] = 17
606
materialConv[Enum.Material.WoodPlanks] = 18
607
materialConv[Enum.Material.Cobblestone] = 19
608
materialConv[Enum.Material.Air] = 20
609
materialConv[Enum.Material.Water] = 21
610
materialConv[Enum.Material.Rock] = 22
611
materialConv[Enum.Material.Glacier] = 23
612
materialConv[Enum.Material.Snow] = 24
613
materialConv[Enum.Material.Sandstone] = 25
614
materialConv[Enum.Material.Mud] = 26
615
materialConv[Enum.Material.Basalt] = 27
616
materialConv[Enum.Material.Ground] = 28
617
materialConv[Enum.Material.CrackedLava] = 29
618
materialConv[Enum.Material.Neon] = 30
619
materialConv[Enum.Material.Asphalt] = 31
620
materialConv[Enum.Material.LeafyGrass] = 32
621
materialConv[Enum.Material.Salt] = 33
622
materialConv[Enum.Material.Limestone] = 34
623
materialConv[Enum.Material.Pavement] = 35
624
625
local function createMarker(pos,ne)
626
	if savePlaceTerrainShowChunks then
627
		local mark = Instance.new("Part",workspace.CurrentCamera)
628
		mark.Name = "TerTop"
629
		mark.Anchored = true
630
		mark.Transparency = 1
631
		mark.CanCollide = false
632
		mark.Size = Vector3.new(chunkSize,chunkSize,chunkSize)
633
		mark.CFrame = CFrame.new(pos)
634
	
635
		local box = Instance.new("SelectionBox",mark)
636
		box.Adornee = mark
637
	end
638
	
639
	terrainChunksTemp[tostring(pos)] = ne
640
	terrainBeen[tostring(pos)] = true
641
	chunks = chunks + 1
642
	if chunks % 10 == 0 then
643
		table.insert(terrainChunks,game:GetService("HttpService"):JSONEncode(terrainChunksTemp))
644
		terrainChunksTemp = {}
645
	end
646
	terrainGui.Chunks.Text = "Chunks: "..tostring(chunks)
647
end
648
649
local function fillTerrain(start)
650
	if terrainBeen[tostring(start)] or not selectingTerrain then return end
651
	local checkRegion = Region3.new(start + Vector3.new(-chunkSize/2,-chunkSize/2,-chunkSize/2), start + Vector3.new(chunkSize/2,chunkSize/2,chunkSize/2))
652
	checkRegion:ExpandToGrid(4)
653
	local m,o = workspace.Terrain:ReadVoxels(checkRegion,4)
654
	local nonempty = {}	
655
	
656
	local size = m.Size
657
	local airCount = 0
658
	for x = 1,size.X do
659
		for y = 1,size.Y do
660
			for z = 1,size.Z do
661
				if m[x][y][z] == Enum.Material.Air then
662
					airCount = airCount + 1
663
				else
664
					table.insert(nonempty,{tostring(x)..","..tostring(y)..","..tostring(z),materialConv[m[x][y][z]],o[x][y][z]})
665
				end
666
			end
667
		end
668
	end
669
	
670
	if airCount == chunkSize^3/64 then return end
671
	
672
	createMarker(start,nonempty)
673
	spawn(function()fillTerrain(start + Vector3.new(chunkSize,0,0))end)
674
	spawn(function()fillTerrain(start + Vector3.new(-chunkSize,0,0))end)
675
	spawn(function()fillTerrain(start + Vector3.new(0,chunkSize,0))end)
676
	spawn(function()fillTerrain(start + Vector3.new(0,-chunkSize,0))end)
677
	spawn(function()fillTerrain(start + Vector3.new(0,0,chunkSize))end)
678
	spawn(function()fillTerrain(start + Vector3.new(0,0,-chunkSize))end)
679
end
680
681
local function makeRegion(str)
682
	local t = {}
683
	for w in string.gmatch(str,"[^,]+") do
684
		table.insert(t,tonumber(w))
685
	end
686
	local regionPos = Vector3.new(t[1],t[2],t[3])
687
	local newRegion = Region3.new(regionPos + Vector3.new(-chunkSize/2,-chunkSize/2,-chunkSize/2), regionPos + Vector3.new(chunkSize/2,chunkSize/2,chunkSize/2))
688
	return newRegion
689
end
690
691
mouse.Button1Down:connect(function()
692
	if selectingTerrain then
693
		local initPos = mouse.Hit.p
694
	
695
		local gridX = math.floor(initPos.X/chunkSize)*chunkSize
696
		local gridY = math.floor(initPos.Y/chunkSize)*chunkSize
697
		local gridZ = math.floor(initPos.Z/chunkSize)*chunkSize
698
	
699
		fillTerrain(Vector3.new(gridX,gridY,gridZ))
700
	end
701
end)
702
703
terrainGui.Done.MouseButton1Click:connect(function()
704
	if savePlaceTerrainShowChunks then
705
		for i,v in pairs(workspace.CurrentCamera:GetChildren()) do
706
			if v.Name == "TerTop" then v:Destroy() end
707
		end
708
	end
709
	selectingTerrain = false
710
	terrainGui.Visible = false
711
	table.insert(terrainChunks,game:GetService("HttpService"):JSONEncode(terrainChunksTemp))
712
	terrainChunksTemp = {}
713
	terrainBeen = {}
714
	chunks = 0
715
end)