Copy salient and essential scripts and models from Plane Building Roblox
This commit is contained in:
@@ -0,0 +1,409 @@
|
||||
local partStateModule = require(script.Parent.PartStateModule)
|
||||
local saves = {}
|
||||
local id_parts = {}
|
||||
local parts_loaded
|
||||
spawn(function()
|
||||
game.ReplicatedStorage:WaitForChild("Parts")
|
||||
local function added(object)
|
||||
if object.Parent:IsA("Folder") then
|
||||
local id = object:GetAttribute("PartId")
|
||||
if id then id_parts[id] = object end
|
||||
end
|
||||
end
|
||||
for _,object in pairs(_G.Storage.Parts:GetDescendants()) do
|
||||
added(object)
|
||||
end
|
||||
_G.Storage.Parts.DescendantAdded:Connect(added)
|
||||
wait(1)
|
||||
parts_loaded = true
|
||||
end)
|
||||
do
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local isa = Instance.new("Part").IsA
|
||||
local no_cframe = {}
|
||||
local cframe_of = function(object)
|
||||
if isa(object,"BasePart") then
|
||||
return object.CFrame
|
||||
elseif isa(object,"Model") then
|
||||
return (object.PrimaryPart or no_cframe)["CFrame"]
|
||||
end
|
||||
end
|
||||
local cframe_set = function(object,cframe)
|
||||
if isa(object,"Model") then
|
||||
object:SetPrimaryPartCFrame(cframe)
|
||||
elseif isa(object,"BasePart") then
|
||||
object.CFrame = cframe
|
||||
end
|
||||
end
|
||||
local weld_is_build = {["BuiltWeldConstraint"] = true}
|
||||
local insert = table.insert
|
||||
local typeof = typeof
|
||||
local is_table = {["table"]=true}
|
||||
local id_module = _G.Methods.Ids
|
||||
local colorPart = _G.Methods.colorPart
|
||||
local ts = tostring
|
||||
local tn = tonumber
|
||||
local format = string.format
|
||||
local concat = table.concat
|
||||
local cframe_new = CFrame.new
|
||||
local vector3_new = Vector3.new
|
||||
local table_create = table.create
|
||||
local form_triangle = partStateModule.form_triangle
|
||||
local get_nodes = partStateModule.get_nodes
|
||||
local apply_nodes = partStateModule.apply_nodes
|
||||
local apply_shift = partStateModule.apply_shift
|
||||
local apply_size = partStateModule.apply_size
|
||||
local apply_material = partStateModule.apply_material
|
||||
local apply_internal_welds = partStateModule.apply_internal_welds
|
||||
local hexxie = require(script.Parent.HexxieModule)
|
||||
local hd = hexxie.decode
|
||||
local he = hexxie.encode
|
||||
local hexxie_cframe_match = string.rep("(...........)",12)
|
||||
local hexxie_position_match = string.rep("(...........)",3)
|
||||
local default_cframe_format = string.rep("%s,",10).."%s"
|
||||
local id_attach = {}
|
||||
local compress_cframe_decode = function(s)
|
||||
if not s then return nil end
|
||||
local a,b,c,d,e,f,g,h,i,j,k,l = s:match(hexxie_cframe_match)
|
||||
return cframe_new(hd(a),hd(b),hd(c),hd(d),hd(e),hd(f),hd(g),hd(h),hd(i),hd(j),hd(k),hd(l))
|
||||
end
|
||||
local compress_cframe_encode = function(c)
|
||||
local a,b,c,d,e,f,g,h,i,j,k,l = c:GetComponents()
|
||||
return concat({he(a),he(b),he(c),he(d),he(e),he(f),he(g),he(h),he(i),he(j),he(k),he(l)})
|
||||
end
|
||||
local compress_position_decode = function(s)
|
||||
local a,b,c = s:match(hexxie_position_match)
|
||||
return vector3_new(hd(a),hd(b),hd(c))
|
||||
end
|
||||
local compress_position_encode = function(v)
|
||||
return concat({he(v.X),he(v.Y),he(v.Z)})
|
||||
end
|
||||
local position
|
||||
local http = game:GetService("HttpService")
|
||||
local http_json_encode = http.JSONEncode
|
||||
local http_json_decode = http.JSONDecode
|
||||
local json_decode = function(value)
|
||||
return http_json_decode(http,value)
|
||||
end
|
||||
local json_encode = function(value)
|
||||
return http_json_encode(http,value)
|
||||
end
|
||||
local ID_INDEX = 1
|
||||
local CFRAMES_INDEX = 2
|
||||
local EDIT_INDEX = 3
|
||||
saves["4"] = {
|
||||
decode = function(raw,options)
|
||||
--print(raw)
|
||||
repeat wait() until parts_loaded
|
||||
local final = {errors = {}}
|
||||
local function err(text)
|
||||
warn(text)
|
||||
table.insert(final.errors,text)
|
||||
end
|
||||
options = options or {}
|
||||
local _compress_cframe_decode = compress_cframe_decode
|
||||
local _compress_position_decode = compress_position_decode
|
||||
if options.mirror then
|
||||
_compress_cframe_decode = function(str)
|
||||
local cf = compress_cframe_decode(str)
|
||||
local x,y,z = cf:ToEulerAnglesYXZ()
|
||||
return CFrame.fromEulerAnglesYXZ(x,-y,-z)+Vector3.new(cf.X,-cf.Y,cf.Z)
|
||||
end
|
||||
_compress_position_decode = function(str)
|
||||
local pos = compress_position_decode(str)
|
||||
return vector3_new(-pos.X,pos.Y,pos.Z)
|
||||
end
|
||||
end
|
||||
local compressed = raw:match("\"compress\"%:true")
|
||||
if compressed then raw = hexxie.rle_decode(raw) end
|
||||
local data = _G.Http:JSONDecode(raw)
|
||||
_G.Union(options,data.options or {})
|
||||
local physics = options.physics
|
||||
local template_cframe = Instance.new("CFrameValue")
|
||||
local weld_template = Instance.new("WeldConstraint")
|
||||
local built_weld_template = weld_template:Clone()
|
||||
built_weld_template.Name = "BuiltWeldConstraint"
|
||||
local model = Instance.new("Model")
|
||||
final.model = model
|
||||
local parts = {}
|
||||
local editActions = {
|
||||
c = function(edit,part)
|
||||
local color = Color3.new(unpack(edit))
|
||||
colorPart(part,color)
|
||||
end,
|
||||
h = function(edit,part)
|
||||
local hinge = part:FindFirstChild("Hinge")
|
||||
if hinge then hinge.CFrame = compress_cframe_decode(edit) end
|
||||
end,
|
||||
r = function(edit,part)
|
||||
local slider = part:FindFirstChild("Slider")
|
||||
if slider then slider.CFrame = compress_cframe_decode(edit) end
|
||||
end,
|
||||
m = function(edit,part)
|
||||
if edit then apply_material(part,Enum.Material[edit]) end
|
||||
end,
|
||||
s = function(edit,part)
|
||||
apply_size(part,Vector3.new(unpack(edit)))
|
||||
end,
|
||||
S = function(edit,part)
|
||||
apply_shift(part,edit)
|
||||
end,
|
||||
}
|
||||
local poly_to_internally_weld = {}
|
||||
local data_cframes = data.cframes
|
||||
local data_edits = data.edits
|
||||
for id,object in pairs(data.objects) do
|
||||
local template = id_parts[object[ID_INDEX]]
|
||||
if not template then err("Missing part with id "..tostring(id)) continue end
|
||||
local instance = template:Clone()
|
||||
instance.Parent = model
|
||||
parts[id] = instance
|
||||
|
||||
local nodes = {}
|
||||
local transform_ids = object[CFRAMES_INDEX]
|
||||
-- BEGIN PARITY 4.1 (CAN BE REMOVED LATER)
|
||||
if typeof(transform_ids) ~= "table" then transform_ids = {transform_ids} end
|
||||
-- END PARITY 4.1
|
||||
if #transform_ids == 1 then
|
||||
insert(nodes,compress_cframe_decode(data_cframes[transform_ids[1]]))
|
||||
elseif #transform_ids == 2 then
|
||||
insert(nodes,compress_cframe_decode(data_cframes[transform_ids[1]]))
|
||||
insert(nodes,hd(data_cframes[transform_ids[2]]))
|
||||
else
|
||||
for _,id in ipairs(transform_ids) do
|
||||
insert(nodes,compress_position_decode(data_cframes[id]))
|
||||
end
|
||||
insert(poly_to_internally_weld,instance)
|
||||
end
|
||||
apply_nodes(instance,nodes)
|
||||
-- Edit part
|
||||
if object[EDIT_INDEX] then
|
||||
for _,edit_id in pairs(object[EDIT_INDEX]) do
|
||||
local key,value = unpack(data_edits[edit_id]);
|
||||
(editActions[key] or function(value,instance)
|
||||
local edit = instance:FindFirstChild(key)
|
||||
if not edit then
|
||||
err(string.format("No key %s for %s",key,instance:GetFullName()))
|
||||
else
|
||||
if typeof(value) == "table" then value = _G.Http:JSONEncode(value) end
|
||||
edit.Value = value
|
||||
end
|
||||
end)(value,instance)
|
||||
end
|
||||
end
|
||||
-- Change anchoring
|
||||
if not options.physics then
|
||||
if instance:IsA("Model") then
|
||||
instance.PrimaryPart.Anchored = true
|
||||
else
|
||||
instance.Anchored = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if options.physics then
|
||||
for _,weld in pairs(data.welds) do
|
||||
local w = built_weld_template:Clone()
|
||||
local at,bt = unpack(weld)
|
||||
local ap = parts[at[1]]
|
||||
local bp = parts[bt[1]]
|
||||
w.Parent = ap
|
||||
if ap:IsA("Model") then
|
||||
if at[2] then
|
||||
ap = ap:FindFirstChild(at[2]) or ap.PrimaryPart
|
||||
else
|
||||
ap = ap.PrimaryPart
|
||||
err("Missing subpart reference for weld on model A")
|
||||
end
|
||||
end
|
||||
if bp:IsA("Model") then
|
||||
if bt[2] then
|
||||
bp = bp:FindFirstChild(bt[2]) or bp.PrimaryPart
|
||||
else
|
||||
bp = bp.PrimaryPart
|
||||
err("Missing subpart reference for weld on model B")
|
||||
end
|
||||
end
|
||||
w.Part0 = ap
|
||||
w.Part1 = bp
|
||||
end
|
||||
for _,poly in ipairs(poly_to_internally_weld) do
|
||||
apply_internal_welds(poly)
|
||||
end
|
||||
else
|
||||
for _,part in pairs(model:GetDescendants()) do
|
||||
if part:IsA("BasePart") then part.CanCollide = false part.Anchored = true end
|
||||
end
|
||||
end
|
||||
local root = parts[1]
|
||||
if not root then error("Fatal: Missing root part; implying #parts = 0") end
|
||||
if root:IsA("Model") then root = root.PrimaryPart end
|
||||
model.PrimaryPart = root
|
||||
final.model = model
|
||||
return final
|
||||
end,
|
||||
encode = function(root,options)
|
||||
repeat wait() until parts_loaded
|
||||
local final = {errors = {}}
|
||||
local function err(text)
|
||||
warn(text)
|
||||
table.insert(final.errors,text)
|
||||
end
|
||||
id_module.forEachConnectedObject(root,function(object)
|
||||
if object:IsA("VehicleSeat") then root = object end
|
||||
end)
|
||||
final.root = root
|
||||
|
||||
if not options then options = {} end
|
||||
|
||||
local origin = cframe_of(root)
|
||||
if not origin then err("Root CFrame could not be encoded, it is probably broken") return final end
|
||||
|
||||
local ids = {}
|
||||
|
||||
local cframes = {}
|
||||
local edits = {}
|
||||
local welds = {}
|
||||
local objects = {}
|
||||
local data = {
|
||||
options = options,
|
||||
objects = objects,
|
||||
cframes = cframes,
|
||||
edits = edits,
|
||||
welds = welds
|
||||
}
|
||||
|
||||
local should_optimise_cframe = not not options.optimise_cframe
|
||||
local cframe_epsilon = options.cframe_epsilon or 0.1
|
||||
local optimise_edit = {}
|
||||
local optimise_cframe = {}
|
||||
|
||||
local function cframe_id(c)
|
||||
local existing = optimise_cframe[c]
|
||||
if not existing then
|
||||
insert(cframes,c)
|
||||
local len = #cframes
|
||||
optimise_cframe[c] = len
|
||||
return len
|
||||
else
|
||||
return existing
|
||||
end
|
||||
end
|
||||
|
||||
local function edit_id(key,value)
|
||||
local str
|
||||
if type(value) == "table" then
|
||||
str = json_encode(value)
|
||||
elseif type(value) ~="string" then
|
||||
str = tostring(value)
|
||||
else
|
||||
str = value
|
||||
end
|
||||
local tab = optimise_edit[key]
|
||||
if not tab then tab = {} optimise_edit[key] = tab end
|
||||
if tab[str] then
|
||||
return tab[str]
|
||||
else
|
||||
insert(edits,{key,value})
|
||||
tab[str] = #edits
|
||||
return #edits
|
||||
end
|
||||
end
|
||||
|
||||
local errors = {}
|
||||
|
||||
local index = 0
|
||||
id_module.forEachConnectedObject(root,function(object)
|
||||
index = index + 1
|
||||
ids[object] = index
|
||||
|
||||
local id = object:GetAttribute("PartId") or object.Name
|
||||
if not id then insert(errors,string.format("Part without an ID! %s",ts(object))) end
|
||||
|
||||
-- ENCODE TRANSFORM
|
||||
local transform = get_nodes(object)
|
||||
if #transform >= 3 then
|
||||
for index,position in pairs(transform) do
|
||||
transform[index] = cframe_id(compress_position_encode(origin:PointToObjectSpace(position)))
|
||||
end
|
||||
elseif #transform == 2 then
|
||||
transform[1] = cframe_id(compress_cframe_encode(origin:ToObjectSpace(transform[1])))
|
||||
transform[2] = cframe_id(he(transform[2]))
|
||||
elseif #transform == 1 then
|
||||
transform[1] = cframe_id(compress_cframe_encode(origin:ToObjectSpace(transform[1])))
|
||||
end
|
||||
|
||||
-- ENCODE EDITS
|
||||
local edits = {}
|
||||
for index,edit in pairs(object:GetChildren()) do
|
||||
if edit:HasTag("Edit") or edit:HasTag("EditHidden") then
|
||||
if edit:HasTag("JSON") then
|
||||
insert(edits,edit_id(edit.Name,json_decode(edit.Value)))
|
||||
else
|
||||
local value = edit.Value
|
||||
if (edit:GetAttribute("Default") ~= value) then
|
||||
insert(edits,edit_id(edit.Name,value))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ENCODE CANDID DISPLACEMENT
|
||||
local hinge = object:FindFirstChild("Hinge")
|
||||
if hinge then insert(edits,edit_id("h",compress_cframe_encode(origin:ToObjectSpace(hinge.CFrame)))) end
|
||||
local slider = object:FindFirstChild("Slider")
|
||||
if slider then insert(edits,edit_id("r",compress_cframe_encode(origin:ToObjectSpace(slider.CFrame)))) end
|
||||
|
||||
-- ENCODE PROPERTIES
|
||||
local color = object:GetAttribute("Color") -- TODO HEXXIE OPTIMISE COLOUR AND SIZE
|
||||
if color then insert(edits,edit_id("c",{color.R,color.G,color.B})) end
|
||||
local material = object:GetAttribute("Material")
|
||||
if material then insert(edits,edit_id("m",material)) end
|
||||
local size = object:GetAttribute("Size")
|
||||
if size then insert(edits,edit_id("s",{size.X,size.Y,size.Z})) end
|
||||
local shift = object:GetAttribute("Shift")
|
||||
if shift then insert(edits,edit_id("S",shift)) end
|
||||
|
||||
-- INSERT OBJECT
|
||||
local data = {id,transform}
|
||||
if #edits > 0 then insert(data,edits) end
|
||||
|
||||
insert(objects,data)
|
||||
end)
|
||||
|
||||
-- ENCODE WELDS
|
||||
for object,id in pairs(ids) do
|
||||
for _,weld in pairs(object:GetDescendants()) do
|
||||
if weld_is_build[weld.Name] then
|
||||
if weld.Part0 and weld.Part1 then
|
||||
local first = {ids[weld.Part0]}
|
||||
if not first[1] then
|
||||
first[1] = ids[weld.Part0.Parent]
|
||||
first[2] = weld.Part0.Name
|
||||
if not first[1] then err("There was a stray first weld! "..tostring(weld:GetFullName())) continue end
|
||||
end
|
||||
local second = {ids[weld.Part1]}
|
||||
if not second[1] then
|
||||
second[1] = ids[weld.Part1.Parent]
|
||||
second[2] = weld.Part1.Name
|
||||
if not second[1] then err("There was a stray second weld! "..tostring(weld:GetFullName())) continue end
|
||||
end
|
||||
insert(data.welds,{first,second})
|
||||
else
|
||||
err("There was a dead weld!"..tostring(weld:GetFullName()))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local json = _G.Http:JSONEncode(data)
|
||||
local result = json
|
||||
if options.compress then result=hexxie.rle_encode(json) end
|
||||
local check = hexxie.rle_decode(result)
|
||||
result = "v4save"..result
|
||||
final.data = result
|
||||
return final
|
||||
end,
|
||||
}
|
||||
end
|
||||
return saves
|
||||
Reference in New Issue
Block a user