Files
PlaneBuilding/scripts/modules/MethodModule.lua
T

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