976 lines
28 KiB
Lua
976 lines
28 KiB
Lua
local module = {}
|
|
_G.Methods = module
|
|
|
|
local tags = _G.Tags
|
|
|
|
local saveToPartTranslator = {
|
|
Barrel = "$B",
|
|
Sheet = "$S",
|
|
Stick = "$s"
|
|
}
|
|
local partToSaveTranslator = {
|
|
|
|
}
|
|
|
|
local ids = require(_G.Modules.IdModule)
|
|
module.Ids = ids
|
|
local mouse = require(_G.Modules.MouseModule)
|
|
module.Mouse = mouse
|
|
|
|
local buildParts = {}
|
|
local idParts = {}
|
|
local idNodes = {}
|
|
local polyParts = {}
|
|
module.canLoad = false
|
|
module.polyParts = polyParts
|
|
module.buildParts = buildParts
|
|
module.idParts = idParts
|
|
task.spawn(function()
|
|
require(game.ReplicatedFirst.ReadyModule)("Parts")
|
|
_G.Storage:WaitForChild("Parts")
|
|
for _,object in pairs(_G.Storage.Parts:GetDescendants()) do
|
|
if object.Parent:IsA("Folder") then
|
|
local id = object:GetAttribute("PartId")
|
|
if not id then continue end
|
|
if not object:HasTag("ConnectorObject") then
|
|
buildParts[object.Name] = object
|
|
if saveToPartTranslator[object.Name] then buildParts[saveToPartTranslator[object.Name]] = object end
|
|
idParts[id] = object
|
|
else
|
|
if object:GetAttribute("Nodes") == 3 then
|
|
if not object:FindFirstChild("A") then
|
|
warn(tostring(object).." missing sub-wedge 'A'")
|
|
end
|
|
if not object:FindFirstChild("B") then
|
|
warn(tostring(object).." missing sub-wedge 'B'")
|
|
end
|
|
end
|
|
idParts[id] = object
|
|
polyParts[id] = object
|
|
polyParts[object.Name] = object
|
|
--[[if object:FindFirstChild("A") and object:FindFirstChild("B") then
|
|
polyParts[object.Name] = object
|
|
polyParts[id] = object
|
|
elseif object:FindFirstChild("1") and object:FindFirstChild("2") then
|
|
idParts[id] = object
|
|
else
|
|
polyParts[object.Name] = object
|
|
polyParts[id] = object
|
|
idParts[id] = object
|
|
end]]
|
|
end
|
|
end
|
|
end
|
|
-- To fix old compatibility issues
|
|
local polyCompat = {
|
|
Pane = 17,
|
|
Wedge = 6,
|
|
Stick = 5,
|
|
Paper = 20,
|
|
HeavySheet = 10,
|
|
Bar = 13,
|
|
LightSheet = 14,
|
|
Rod = 13,
|
|
Rope = 22
|
|
}
|
|
for index,item in pairs(polyCompat) do
|
|
--[[local part = idParts[item]:Clone()
|
|
part.Parent = idParts[item].Parent
|
|
if part:FindFirstChild("1") then part["1"].Name = "A" end
|
|
if part:FindFirstChild("2") then part["2"].Name = "B" end]]
|
|
polyParts[index] = polyParts[item]
|
|
end
|
|
module.canLoad = true
|
|
end)
|
|
for id,part in pairs(idParts) do
|
|
local nodeId = part:GetAttribute("NodeId")
|
|
if nodeId then
|
|
idNodes[id] = idParts[nodeId]
|
|
end
|
|
end
|
|
function module.getPartByName(name)
|
|
return buildParts[name]
|
|
end
|
|
function module.getPolyByName(name)
|
|
return polyParts[name]
|
|
end
|
|
function module.getPartById(id)
|
|
return idParts[id]
|
|
end
|
|
function module.getNodeById(id)
|
|
return idNodes[id]
|
|
end
|
|
|
|
function module.setItemCFrame(item,cframe)
|
|
if item:IsA("BasePart") then
|
|
item.CFrame = cframe
|
|
elseif item:IsA("Model") then
|
|
if item.PrimaryPart then
|
|
local mcframe,size = item:GetBoundingBox()
|
|
item:SetPrimaryPartCFrame(cframe-cframe.Position+cframe:PointToWorldSpace(mcframe:PointToObjectSpace(item.PrimaryPart.Position)))
|
|
end
|
|
end
|
|
return cframe
|
|
end
|
|
|
|
function module.getItemSize(item)
|
|
if item:IsA("BasePart") then
|
|
return item.Size
|
|
elseif item:IsA("Model") then
|
|
if item.PrimaryPart then
|
|
return item:GetExtentsSize()
|
|
end
|
|
end
|
|
end
|
|
|
|
function module.getItemCFrame(item)
|
|
if item:IsA("BasePart") then
|
|
return item.CFrame
|
|
elseif item:IsA("Model") then
|
|
return item:GetBoundingBox()
|
|
end
|
|
end
|
|
|
|
function module.colorPart(part,color)
|
|
if part:IsA("Model") then
|
|
for _,subpart in pairs(part:GetDescendants()) do
|
|
if subpart:IsA("BasePart") then
|
|
subpart.Color = color
|
|
end
|
|
end
|
|
else
|
|
part.Color = color
|
|
end
|
|
part:SetAttribute("Color",color)
|
|
end
|
|
|
|
function module.shapeTriangle(p1,p2,p3,r1,r2) -- simple function, might work?
|
|
local s = 0 --0.01
|
|
local bottom = {
|
|
b1 = nil,
|
|
b2 = nil,
|
|
dist = 0,
|
|
other = nil
|
|
}
|
|
local function check(point1,point2,other)
|
|
local dist = (point1 - point2).Magnitude
|
|
if dist > bottom.dist then
|
|
bottom.b1 = point1
|
|
bottom.b2 = point2
|
|
bottom.other = other
|
|
bottom.dist = dist
|
|
end
|
|
end
|
|
check(p1,p2,p3) -- check all of the different options for bottom and get the right one?
|
|
check(p1,p3,p2)
|
|
check(p2,p3,p1)
|
|
local view = CFrame.lookAt(bottom.b1,bottom.b2,(bottom.other-bottom.b1).Unit)
|
|
local object = view:PointToObjectSpace(bottom.other)
|
|
local length = object.Z
|
|
local height = object.Y
|
|
r1.Size = Vector3.new(r1.Size.X,height-s,-length-s)
|
|
r1.CFrame = (view * CFrame.Angles(0,math.rad(180),0)) * CFrame.new(0,height/2+s/2,-length/2+s/2)
|
|
r2.Size = Vector3.new(r2.Size.X,height-s,-(-bottom.dist-length)-s)
|
|
r2.CFrame = view * CFrame.new(0,height/2+s/2,-(bottom.dist-length)/2+s/2)
|
|
return r1,r2
|
|
end
|
|
|
|
function module.positionPart(part,nodes,s)
|
|
local d = (nodes[1].Position - nodes[2].Position).Magnitude -- distance
|
|
local a = nodes[1].Position -- first node
|
|
local b = nodes[2].Position -- second node
|
|
if #nodes == 2 then -- stick on Z (XY thick)
|
|
part.CFrame = CFrame.lookAt(a,b) * CFrame.Angles(0,math.pi*0.5,0)
|
|
part.CFrame = part.CFrame + part.CFrame.RightVector * d * 0.5
|
|
part.Size = Vector3.new(d,part.Size.Y,part.Size.Z)
|
|
end
|
|
if #nodes == 3 then -- triangle on YZ (X thick)
|
|
local c = nodes[3].Position -- third node
|
|
local p2 = part["B"]
|
|
local p1 = part["A"]
|
|
module.shapeTriangle(a,b,c,p1,p2)
|
|
end
|
|
end
|
|
|
|
function module.shiftPart(part,shift)
|
|
shift = shift - (part:GetAttribute("Shift") or 0)
|
|
for _,part in pairs(part:GetChildren()) do
|
|
if part:IsA("BasePart") then
|
|
part.Position = part.Position + part.CFrame.RightVector * shift
|
|
end
|
|
end
|
|
end
|
|
|
|
function module.getNodePositions(part)
|
|
|
|
end
|
|
|
|
function module.form_rod(pa,p1,p2)
|
|
local d = (p1 - p2).Magnitude -- distance
|
|
pa.CFrame = CFrame.lookAt(p1,p2) * CFrame.Angles(0,math.pi*0.5,0)
|
|
pa.CFrame = pa.CFrame + pa.CFrame.RightVector * d * 0.5
|
|
pa.Size = Vector3.new(d,pa.Size.Y,pa.Size.Z)
|
|
end
|
|
|
|
module.saves = require(script.Parent:WaitForChild("SerialisationModule"))
|
|
|
|
spawn(function()
|
|
require(game.ReplicatedFirst.ReadyModule)("MethodCommands")
|
|
if _G.IsClient then
|
|
local commands = require(_G.Modules.CommandsModule)
|
|
commands.new("save format (%d)","set save format <number:string>: Sets current save version. Use '4'",function(v)
|
|
_G.Events.Notification:Fire("Set Save Format","Set save format to: "..v)
|
|
_G.SaveFormat = v
|
|
end)
|
|
commands.new("save comp[^%s]- (.+)","set save compress <on:bool>: Enables or disables save compression for debugging. A bad idea.",function(v)
|
|
v = not not v:match("t")
|
|
_G.Events.Notification:Fire("Set Save Compress","Set save compress to: "..tostring(v))
|
|
_G.SaveCompression = v
|
|
end)
|
|
end
|
|
end)
|
|
|
|
function module.saves.modelToData(root)
|
|
if root then
|
|
if module.saves[_G.SaveFormat] then
|
|
local success,result = xpcall(module.saves[_G.SaveFormat].encode,function(err)
|
|
print("before")
|
|
_G.Error(string.format("Save V%s Error: %s",_G.SaveFormat,err))
|
|
end,root,{
|
|
compress = _G.SaveCompression
|
|
})
|
|
if not success then return nil end
|
|
if #result.errors > 0 then print(result.errors) end
|
|
return result.data
|
|
else
|
|
return _G.Methods.dataToString(_G.Methods.modelToTable(root))
|
|
end
|
|
else
|
|
error("Root passed is nil!",2)
|
|
end
|
|
end
|
|
|
|
function module.saves.dataToModel(raw,physics,mirror)
|
|
if _G.IsString(raw) then
|
|
local v,r = raw:match("v(%d)save(.+)")
|
|
if v then
|
|
local success,result = xpcall(module.saves[v].decode,function(err)
|
|
warn(debug.traceback(err))
|
|
end,r,{
|
|
physics = physics,
|
|
mirror = mirror,
|
|
})
|
|
if not success then return nil end
|
|
if #result.errors > 0 then print(result.errors) end
|
|
if result.model then result.model:SetAttribute("Version","V"..v) end
|
|
return result.model
|
|
else
|
|
local tabular = _G.Protected(module.universalConvertToTable,raw)
|
|
if not tabular or not tabular[1] then return nil end
|
|
local model = _G.Protected(module.convertToModel,tabular,physics)
|
|
if not model then return nil end
|
|
if not tabular[1]:match("V%dSAVE") then
|
|
tabular.Name = tabular[1]
|
|
--model:AddTag("Old")
|
|
end
|
|
model:AddTag("Old")
|
|
return model
|
|
end
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
function module.tableToModel(data,physics)
|
|
|
|
end
|
|
|
|
function module.stringToData(str)
|
|
if type(str) ~= "string" then error("Not a string",2) end
|
|
local insert = table.insert
|
|
if str:sub(1,1) ~= "{" then return end
|
|
local function parse(start)
|
|
local data = {}
|
|
local function register(str)
|
|
if #str < 1 then return end
|
|
local index,part = str:match("(.*)=(.*)")
|
|
if not index then
|
|
insert(data,str)
|
|
else
|
|
data[index] = str
|
|
end
|
|
end
|
|
while start do
|
|
local first,last = str:find("[{},]",start+1,false)
|
|
local c = str:sub(last,last)
|
|
if c == "{" then
|
|
local sub_data
|
|
local index = str:sub(start+1,last-2)
|
|
sub_data,start = parse(last)
|
|
if #index > 0 then
|
|
data[index] = sub_data
|
|
else
|
|
insert(data,sub_data)
|
|
end
|
|
elseif c == "}" then
|
|
register(str:sub(start+1,last-1))
|
|
return data,last
|
|
else
|
|
if c == "," then
|
|
register(str:sub(start+1,last-1))
|
|
end
|
|
start = last
|
|
end
|
|
end
|
|
wait()
|
|
end
|
|
return parse(1)
|
|
end
|
|
|
|
function module.can_destroy(part,player)
|
|
return part:HasTag("Combat") or part.Parent:HasTag("Combat")
|
|
end
|
|
|
|
local built = {BuiltWeldConstraint = true}
|
|
function module.break_part(part,player)
|
|
if part:IsA("Model") then
|
|
for _,item in pairs(part:GetDescendants()) do
|
|
if built[item.Name] then
|
|
item:Destroy()
|
|
end
|
|
end
|
|
elseif part:IsA("BasePart") then
|
|
part:BreakJoints()
|
|
end
|
|
end
|
|
|
|
function module.wash_part(part,colour,material)
|
|
if part:IsA("Model") then
|
|
for _,item in pairs(part:GetDescendants()) do
|
|
if part:IsA("BasePart") then
|
|
part.Color = colour
|
|
part.Material = material
|
|
end
|
|
end
|
|
elseif part:IsA("BasePart") then
|
|
part.Color = colour
|
|
part.Material = material
|
|
end
|
|
end
|
|
|
|
function module.fire(root,player)
|
|
if module.can_destroy(root,player) then
|
|
if root:HasTag("Engine") then
|
|
local fire = _G.Storage.Fire:Clone()
|
|
fire.Parent = root.PrimaryPart
|
|
end
|
|
module.wash_part(root,Color3.new(1, 0.831617, 0.298161),Enum.Material.Neon)
|
|
wait(math.random(1,10)*0.333)
|
|
module.break_part(root,player)
|
|
for _,part in pairs(root:GetTouchingParts()) do
|
|
module.fire(part,player)
|
|
end
|
|
wait(math.random(1,20)*0.333)
|
|
module.wash_part(root,Color3.new(0,0,0),Enum.Material.Sand)
|
|
end
|
|
end
|
|
|
|
function module.explode(root,player,power)
|
|
print("explode")
|
|
if root:HasTag("Exploded") then return end
|
|
root:AddTag("Exploded")
|
|
local debris = game:GetService("Debris")
|
|
if not power then power = 10 end
|
|
local explosion = _G.Sounds.Explosion:Clone()
|
|
explosion.Parent = root
|
|
explosion:Destroy()
|
|
local burn = _G.Storage.Burn:Clone()
|
|
burn.Parent = root
|
|
debris:AddItem(burn,1)
|
|
|
|
local params = OverlapParams.new()
|
|
params.MaxParts = 40
|
|
params.RespectCanCollide = true
|
|
params.FilterType = Enum.RaycastFilterType.Include
|
|
params.FilterDescendantsInstances = {game.Workspace.Objects}
|
|
local result = game.Workspace:GetPartBoundsInRadius(root.Position,10,params)
|
|
|
|
wait()
|
|
for _,hit in pairs(result) do
|
|
if module.can_destroy(hit,player) then
|
|
module.break_part(hit,player)
|
|
if math.random(1,3) == 1 then module.fire(hit,player) end
|
|
end
|
|
end
|
|
|
|
wait(0.1)
|
|
for _,hit in pairs(result) do
|
|
hit:ApplyImpulse((hit.Position-root.Position)*-100)
|
|
end
|
|
end
|
|
|
|
function module.playerOwnsPart(player,part) return part:HasTag("P_"..player.UserId) or part:HasTag("P_ublic") end
|
|
|
|
function module.dataToString(data)
|
|
local insert = table.insert
|
|
local isString = {["string"] = true}
|
|
local isNumber = {["number"] = true}
|
|
local isTable = {["table"] = true}
|
|
local function converts(t)
|
|
local result = {"{"}
|
|
local first = true
|
|
for index,item in pairs(t) do
|
|
if not first then insert(result,",") else first = false end
|
|
local value
|
|
if isTable[type(item)] then
|
|
value = converts(item)
|
|
else
|
|
value = tostring(item)
|
|
end
|
|
if isNumber[type(index)] then
|
|
insert(result,value)
|
|
elseif isString[type(index)] then
|
|
insert(result,index.."="..value)
|
|
end
|
|
end
|
|
insert(result,"}")
|
|
return table.concat(result)
|
|
end
|
|
return converts(data)
|
|
end
|
|
|
|
function module.convertToData(data)
|
|
if not data:match("{.*}") then return end
|
|
data = data:gsub("%s","")
|
|
local index = 2
|
|
local function parseTable(t)
|
|
local this = {} -- The table we're working with now
|
|
local idx -- Special named table index
|
|
local _,last
|
|
local char
|
|
local value
|
|
while true do
|
|
_,last = data:find("[{,=}]",index)
|
|
if not last then return end
|
|
char = data:sub(last,last) -- The next significant character
|
|
if index ~= last then value = data:sub(index,last-1) end -- Current value in table
|
|
index = last + 1
|
|
--print(t,value,char)
|
|
local function terminate()
|
|
if idx then this[idx] = value -- If there is an index, add it by index
|
|
else table.insert(this,value) end -- Otherwise just plainly insert it (by order)
|
|
end
|
|
if char == "=" then -- When finding an '=', take the existing piece and make it an index
|
|
idx = value
|
|
elseif char == "," then -- When finding a ',', the entry has terminated so add it
|
|
terminate()
|
|
elseif char == "{" then -- When finding a '{', there is a new table whose value needs to be computed
|
|
value = parseTable(t+1)
|
|
else-- char == "}" then -- When finding a '}', this table has terminated so return
|
|
terminate()
|
|
return this
|
|
end
|
|
end
|
|
end
|
|
return parseTable(1)
|
|
end
|
|
|
|
function module.universalConvertToTable(data)
|
|
if not (data:match("{V%dSAVE,objects=")) then return module.stringToData(data)
|
|
else return module.convertToData(data) end
|
|
end
|
|
|
|
function module.removeSpaces(data)
|
|
local new = ""
|
|
for index = 1, #data do
|
|
local char = string.sub(data,index,index)
|
|
if char ~= " " then new = new .. char end
|
|
end
|
|
return new
|
|
end
|
|
function module.round(number,decimals)
|
|
local pow = math.pow(10,decimals)
|
|
return math.round(number*pow)/pow
|
|
end
|
|
function module.makeSaveString(data)
|
|
local saveDataString = "{"..data.saveName..","
|
|
local saveObjectsString = "{"
|
|
for index,item in ipairs(data.saveObjects) do
|
|
local editString = ""
|
|
local cframeString = module.removeSpaces(tostring(item.CFrame))
|
|
if item.Edit then
|
|
for _,edit in pairs(item.Edit) do
|
|
editString = editString .. "{"..edit[1]..","..edit[2].."},"
|
|
end
|
|
end
|
|
if #editString ~= 0 then editString = "{"..editString.."}," end
|
|
saveObjectsString = saveObjectsString .. "{{"
|
|
.. cframeString
|
|
.. "}" .. ","
|
|
.. item.Name .. ","..editString.."},"
|
|
end
|
|
saveObjectsString = saveObjectsString .. "}"
|
|
saveDataString = saveDataString .. saveObjectsString .. ","
|
|
local saveWeldsString = "{"
|
|
for index,item in pairs(data.saveWelds) do
|
|
saveWeldsString = saveWeldsString .. "{{"
|
|
.. tostring(item.Part0[1])
|
|
if item.Part0[2] then
|
|
saveWeldsString = saveWeldsString .. "," .. item.Part0[2]
|
|
end
|
|
saveWeldsString = saveWeldsString .. "},{"
|
|
.. tostring(item.Part1[1])
|
|
if item.Part1[2] then
|
|
saveWeldsString = saveWeldsString .. "," .. item.Part1[2]
|
|
end
|
|
saveWeldsString = saveWeldsString .. "}},"
|
|
end
|
|
saveWeldsString = saveWeldsString .. "}"
|
|
saveDataString = saveDataString .. saveWeldsString
|
|
saveDataString = saveDataString .. "}"
|
|
--print(saveDataString)
|
|
return saveDataString
|
|
end
|
|
|
|
function module.convertValue(value) -- BRUH
|
|
if value == "true" then return true
|
|
elseif value == "false" then return false
|
|
elseif tonumber(value) then return tonumber(value)
|
|
else return value end
|
|
end
|
|
function module.tableToCFrame(c)
|
|
local n = tonumber
|
|
return CFrame.new(
|
|
n(c[1]),n(c[2]),n(c[3]),
|
|
n(c[4]),n(c[5]),n(c[6]),
|
|
n(c[7]),n(c[8]),n(c[9]),
|
|
n(c[10]),n(c[11]),n(c[12])
|
|
)
|
|
end
|
|
|
|
local function weld(part1,part2)
|
|
local weld = Instance.new("WeldConstraint")
|
|
weld.Name = "BuiltWeldConstraint"
|
|
weld.Parent = part1
|
|
weld.Part0 = part1
|
|
weld.Part1 = part2
|
|
return weld
|
|
end
|
|
local function weldNoPersist(part1,part2)
|
|
weld(part1,part2).Name = "WeldConstraint"
|
|
end
|
|
local CFrameNew = CFrame.new
|
|
local CFrameFromAxisAngle = CFrame.fromAxisAngle
|
|
local tableUnpack = table.unpack
|
|
local Vector3New = Vector3.new
|
|
local n = tonumber
|
|
function module.cframeToData(cframe)
|
|
local p = cframe.Position
|
|
local r,w = cframe:ToAxisAngle()
|
|
return {{cframe.Position},{r},w}
|
|
end
|
|
local tp = table.pack
|
|
function module.cframeToDataNoAxis(cframe)
|
|
return tp(cframe:GetComponents())
|
|
end
|
|
local nc = CFrame.new
|
|
local tu = table.unpack
|
|
function module.dataToCFrameNoAxis(data)
|
|
return nc(tu(data))
|
|
end
|
|
function module.dataToCFrame(data)
|
|
if not (data[1] and data[2] and data[3]) then return CFrame.new() end
|
|
local p1,p2,p3 = tableUnpack(data[1])
|
|
local r1,r2,r3 = tableUnpack(data[2])
|
|
local w = data[3]
|
|
return CFrameNew(n(p1),n(p2),n(p3))*CFrameFromAxisAngle(Vector3New(n(r1),n(r2),n(r3)),n(w))
|
|
end
|
|
|
|
local editCompress = {Color="C",HingeCFrame="HC",Size="S"}
|
|
local editDepress = {HC="HingeCFrame",C="Color",S="Size"}
|
|
function module.modelToTable(root)
|
|
local getItemCFrame = function(object) if object:IsA("BasePart") then return object.CFrame elseif object:IsA("Model") then return object.PrimaryPart.CFrame end end
|
|
local origin = getItemCFrame(root)
|
|
local insert = table.insert
|
|
local saveData = {"V3SAVE"}
|
|
saveData.objects = {}
|
|
saveData.welds = {}
|
|
local objects = {}
|
|
--[[Agreed object structure:
|
|
{
|
|
1: name
|
|
2: {node1,node2,node3} cframes (nodes included)
|
|
3: {colour={a,b,c},size={a,b,c},speed=120} edits (size included)
|
|
}
|
|
]]
|
|
local isBuiltWeld = {["BuiltWeldConstraint"] = true}
|
|
local index = 1
|
|
ids.forEachConnectedObject(root,function(object)
|
|
insert(objects,object)
|
|
objects[object] = index
|
|
index = index + 1
|
|
local cframes = {}
|
|
local edits = {}
|
|
local nodes = object:GetAttribute("Nodes")
|
|
if nodes then
|
|
for i=1,nodes do
|
|
insert(cframes,module.cframeToDataNoAxis(origin:ToObjectSpace(object[i].CFrame)))
|
|
end
|
|
else
|
|
insert(cframes,module.cframeToDataNoAxis(origin:ToObjectSpace(getItemCFrame(object))))
|
|
end
|
|
-- edits
|
|
for index,edit in pairs(object:GetChildren()) do
|
|
if tags:HasTag(edit,"Edit") and
|
|
(edit:GetAttribute("Default") ~= edit.Value)
|
|
then
|
|
edits[editCompress[edit.Name] or edit.Name] = tostring(edit.Value)
|
|
end
|
|
end
|
|
local id = object:GetAttribute("PartId") or object.Name
|
|
--local original = module.getPartById(id) or module.getPartByName(id)
|
|
-- psuedo edits
|
|
local color = object:GetAttribute("Color")
|
|
if color then edits[editCompress["Color"]] = {color.R,color.G,color.B} end
|
|
local hinge = object:FindFirstChild("Hinge")
|
|
if hinge then edits[editCompress["HingeCFrame"]] = module.cframeToDataNoAxis(origin:ToObjectSpace(hinge.CFrame)) end
|
|
local size = object:GetAttribute("Size")
|
|
if size then size = size * math.sqrt(0.333); edits[editCompress["Size"]] = {size.X,size.Y,size.Z} end
|
|
|
|
-- final object
|
|
local final = {id,cframes}
|
|
if next(edits) then insert(final,edits) end
|
|
insert(saveData.objects,final)
|
|
end)
|
|
|
|
for index,object in ipairs(objects) do
|
|
for _,weld in pairs(object:GetDescendants()) do
|
|
if isBuiltWeld[weld.Name] then
|
|
if not weld.Part0 or not weld.Part1 then continue end
|
|
local first = objects[weld.Part0]
|
|
if not first then first = {objects[weld.Part0.Parent],weld.Part0.Name}
|
|
else first = {first} end
|
|
local second = objects[weld.Part1]
|
|
if not second then second = {objects[weld.Part1.Parent],weld.Part1.Name}
|
|
else second = {second} end
|
|
insert(saveData.welds,{first,second})
|
|
end
|
|
end
|
|
end
|
|
|
|
return saveData
|
|
end
|
|
|
|
function module.convertToModel(data,physics)
|
|
if not data then return end
|
|
local v = data[1]:match("V(%d)SAVE")
|
|
if not v or not data.objects then return module.oldConvertToModel(data,physics) end
|
|
local insert = table.insert
|
|
local objects = {}
|
|
local model = Instance.new("Model")
|
|
local toCFrame = module.dataToCFrameNoAxis
|
|
local setCFrame = function(part,cframe) if part:IsA("BasePart") then part.CFrame = cframe else part:SetPrimaryPartCFrame(cframe) end end
|
|
model:SetAttribute("Version","V3")
|
|
if v == "2" then setCFrame = module.setItemCFrame toCFrame = module.dataToCFrame model:SetAttribute("Version","V2") end
|
|
local editActions = {
|
|
Color = function(edit,part)
|
|
module.colorPart(part,Color3.new(n(edit[1]),n(edit[2]),n(edit[3])))
|
|
end,
|
|
HingeCFrame = function(edit,part)
|
|
local hinge = part:FindFirstChild("Hinge")
|
|
if hinge then hinge.CFrame = toCFrame(edit) end
|
|
end,
|
|
MaterialAttribute = function()
|
|
|
|
end,
|
|
Size = function(edit,part)
|
|
local size = Vector3.new(n(edit[1]),n(edit[2]),n(edit[3]))
|
|
if part:IsA("Model") then
|
|
part:ScaleTo(size.Magnitude)
|
|
size = (size/math.sqrt(0.333)) -- For parity with the new stronger system
|
|
else
|
|
part.Size = size
|
|
end
|
|
part:SetAttribute("Size",size)
|
|
end,
|
|
}
|
|
repeat wait() until module.canLoad
|
|
for index,object in ipairs(data.objects) do
|
|
local name = object[1]
|
|
name = n(name) or name
|
|
local isPoly = #object[2] > 1
|
|
local part = idParts[name]
|
|
local node
|
|
if not part then
|
|
if isPoly then
|
|
part = module.getPolyByName(name)
|
|
if not part then print(name) end
|
|
node = part.Parent:FindFirstChild("Node") or idParts[-1]
|
|
else part = module.getPartByName(name) end
|
|
else
|
|
if isPoly then
|
|
node = idNodes[name] or part.Parent:FindFirstChild("Node") or idParts[-1]
|
|
end
|
|
end
|
|
if not part then warn(name,isPoly,idParts,buildParts,polyParts) end
|
|
part = part:Clone()
|
|
local isModel = not part:IsA("BasePart")
|
|
local primary = part
|
|
if isModel then primary = part.PrimaryPart end
|
|
if isPoly then
|
|
local nodes = {}
|
|
for index,cframe in pairs(object[2]) do
|
|
local newNode = node:Clone()
|
|
newNode.CFrame = toCFrame(cframe)
|
|
newNode.Parent = part
|
|
newNode.Name = tostring(index)
|
|
newNode.Transparency = 1
|
|
nodes[index] = newNode
|
|
end
|
|
module.positionPart(part,nodes)
|
|
for _,subpart in pairs(part:GetChildren()) do if subpart ~= primary and subpart:IsA("BasePart") then weldNoPersist(subpart,primary) end end
|
|
else
|
|
setCFrame(part,toCFrame(object[2][1]))
|
|
end
|
|
local cnv = module.convertValue
|
|
if object[3] then
|
|
for index,edit in pairs(object[3]) do
|
|
if editDepress[index] then index = editDepress[index] end
|
|
local value = part:FindFirstChild(index)
|
|
if not value then
|
|
if editActions[index] then
|
|
editActions[index](edit,part)
|
|
end
|
|
else
|
|
value.Value = cnv(edit)
|
|
end
|
|
end
|
|
end
|
|
if not physics then
|
|
if isModel then
|
|
for _,object in pairs(part:GetChildren()) do
|
|
if object:IsA("BasePart") then
|
|
object.Anchored = true
|
|
object.CanCollide = false
|
|
end
|
|
end
|
|
else
|
|
part.CanCollide = false
|
|
part.Anchored = true
|
|
end
|
|
end
|
|
if index == 1 then if part:IsA("Model") then model.PrimaryPart = part.PrimaryPart else model.PrimaryPart = part end end
|
|
if part.Name == "VehicleSeat" then model.PrimaryPart = part.PrimaryPart end
|
|
part.Parent = model
|
|
insert(objects,part)
|
|
end
|
|
if physics then
|
|
for index,weld in pairs(data.welds) do
|
|
local weld11 = n(weld[1][1])
|
|
local weld12 = weld[1][2]
|
|
local weld21 = n(weld[2][1])
|
|
local weld22 = weld[2][2]
|
|
local part1 = objects[weld11]
|
|
local part2 = objects[weld21]
|
|
if weld12 then part1 = part1:FindFirstChild(weld12) or part1 end
|
|
if weld22 then part2 = part2:FindFirstChild(weld22) or part2 end
|
|
if not (part1 and part2) then print("Weld Missing",objects[weld11],objects[weld21],weld21,weld22) continue end
|
|
local new = Instance.new("WeldConstraint")
|
|
if part1:IsA("Model") then part1 = part1.PrimaryPart end
|
|
if part2:IsA("Model") then part2 = part2.PrimaryPart end
|
|
new.Part0 = part1
|
|
new.Part1 = part2
|
|
new.Parent = part1
|
|
new.Name = "BuiltWeldConstraint"
|
|
end
|
|
end
|
|
return model
|
|
end
|
|
|
|
function module.oldConvertToModel(data,physics)
|
|
if not data[1] then return end
|
|
|
|
local parts = {}
|
|
local n = tonumber
|
|
|
|
local currentModel = Instance.new("Model")
|
|
currentModel:SetAttribute("Version","V1")
|
|
|
|
local internalSuccess = true
|
|
local internalValue = {}
|
|
local success,value = xpcall(function()
|
|
for index,part in pairs(data[2]) do
|
|
local success,value = pcall(function()
|
|
local isPoly = #part[1] == 0
|
|
local new = module.getPartByName(part[2])
|
|
if new then new = new:Clone() end
|
|
if isPoly then
|
|
new = module.getPolyByName(part[2])
|
|
if not new then warn("Missing Poly: "..part[2]) end
|
|
local old = new
|
|
new = new:Clone()
|
|
local realNodes = {}
|
|
local attach = new
|
|
if new:IsA("Model") then attach = new.PrimaryPart end
|
|
for _,edit in pairs(part[3]) do
|
|
if #edit[1] == 1 and tonumber(edit[1]) then
|
|
local realNode = (old.Parent:FindFirstChild("Node") or _G.Storage.Parts.DefaultNode):Clone()
|
|
realNode.CFrame = module.tableToCFrame(edit[2])
|
|
realNode.Name = edit[1]
|
|
realNode.Parent = new
|
|
realNode.Transparency = 1
|
|
table.insert(realNodes,realNode)
|
|
end
|
|
end
|
|
module.positionPart(new,realNodes)
|
|
for _,node in pairs(realNodes) do
|
|
weldNoPersist(node,attach)
|
|
end
|
|
for _,part in pairs(new:GetChildren()) do
|
|
if part:IsA("BasePart") and part ~= attach then weldNoPersist(part,attach) end
|
|
end
|
|
end
|
|
if new then
|
|
table.insert(parts,new)
|
|
new.Parent = currentModel
|
|
if index == 1 then
|
|
if new:IsA("Model") then
|
|
currentModel.PrimaryPart = new.PrimaryPart else currentModel.PrimaryPart = new
|
|
end
|
|
end
|
|
if part[3] then
|
|
local cnv = module.convertValue
|
|
if typeof(part[3]) == "string" then print(part[3]) end
|
|
for _,edit in pairs(part[3]) do
|
|
if #edit ~= 1 and not tonumber(edit[1]) and not (edit[1] == "C") and new:FindFirstChild(edit[1]) then
|
|
new[edit[1]].Value = module.convertValue(edit[2])
|
|
elseif (edit[1] == "C") then
|
|
module.colorPart(new,Color3.new(cnv(edit[2][1]),cnv(edit[2][2]),cnv(edit[2][3])))
|
|
end
|
|
end
|
|
end
|
|
if not physics then
|
|
if new:IsA("Model") then
|
|
new.PrimaryPart.Anchored = true
|
|
for _,part in pairs(new:GetDescendants()) do
|
|
if part:IsA("BasePart") then part.CanCollide = false part.CanTouch = false end
|
|
end
|
|
else
|
|
new.Anchored = true
|
|
new.CanCollide = false
|
|
new.CanTouch = false
|
|
end
|
|
end
|
|
if not isPoly then
|
|
module.setItemCFrame(new,module.tableToCFrame(part[1]))
|
|
end
|
|
end
|
|
end)
|
|
if not success then internalSuccess = false table.insert(internalValue,value) end
|
|
end
|
|
if not physics then return currentModel,data end
|
|
|
|
for index,weld in pairs(data[3]) do
|
|
local new = Instance.new("WeldConstraint")
|
|
local part0 = parts[n(weld[1][1])]
|
|
if not part0 then warn("Weld missing.") continue end
|
|
if weld[1][2] and part0:FindFirstChild(weld[1][2]) then part0 = part0[weld[1][2]] end
|
|
local part1 = parts[n(weld[2][1])]
|
|
if not part1 then continue end
|
|
if weld[2][2] and part1:FindFirstChild(weld[2][2]) then part1 = part1[weld[2][2]] end
|
|
if part0:IsA("Model") then part0 = part0.PrimaryPart end
|
|
if part1:IsA("Model") then part1 = part1.PrimaryPart end
|
|
new.Part0 = part0
|
|
new.Part1 = part1
|
|
new.Parent = part0
|
|
new.Name = "BuiltWeldConstraint"
|
|
end
|
|
end,print)
|
|
|
|
if not internalSuccess then data[1] = "CORRUPTED" for _,item in pairs(internalValue) do print(data) print(item) debug.traceback(item,2) end end
|
|
|
|
--print(data)
|
|
|
|
return currentModel,data
|
|
end
|
|
|
|
local function getConnectedParts(part)
|
|
local connected = part:GetConnectedParts(false)
|
|
for _,joint in pairs(part:GetJoints()) do
|
|
if joint:IsA("Constraint") then
|
|
if joint.Attachment0 and joint.Attachment1 then
|
|
if joint.Attachment0.Parent == part then
|
|
table.insert(connected,joint.Attachment1.Parent)
|
|
else
|
|
table.insert(connected,joint.Attachment0.Parent)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return connected
|
|
end
|
|
|
|
function module.forEachConnectedObject(start,callback,show,parent)
|
|
if not start then return end
|
|
if start:IsA("Model") then start = start.PrimaryPart end
|
|
|
|
if not parent then parent = game.Workspace.Objects end
|
|
|
|
local parts = {}
|
|
local objects = {}
|
|
|
|
local function checkPart(part)
|
|
local object
|
|
if part.Parent:IsA("Model") and part.Parent.Parent == parent then
|
|
object = part.Parent
|
|
elseif part.Parent == parent then
|
|
object = part
|
|
end
|
|
if not object or objects[object] then return end
|
|
objects[object] = object
|
|
if callback then callback(object) end
|
|
end
|
|
|
|
local function tryConnected(part)
|
|
if parts[part] then return else parts[part] = part checkPart(part) end
|
|
local connected = getConnectedParts(part)
|
|
for _,part in pairs(connected) do
|
|
tryConnected(part)
|
|
end
|
|
end
|
|
|
|
tryConnected(start)
|
|
|
|
return objects
|
|
end
|
|
|
|
function module.setNetworkOwner(part,player)
|
|
for _,part in pairs(part:GetConnectedParts(true)) do
|
|
if part.Anchored then
|
|
return
|
|
end
|
|
end
|
|
part:SetNetworkOwner(player)
|
|
end
|
|
|
|
function module.getOwnedOrNil(player,part)
|
|
if module.playerOwnsPart(player,part) then
|
|
return part
|
|
elseif module.playerOwnsPart(player,part.Parent) then
|
|
return part
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function module.getObjectFromPart(part)
|
|
if part:GetAttribute("PartId") then
|
|
return part
|
|
elseif part.Parent and part.Parent:GetAttribute("PartId") then
|
|
return part.Parent
|
|
end
|
|
end
|
|
|
|
module.getMouseHit = mouse.getMouseHit
|
|
|
|
return module
|