Run it
Copy the script and paste it into your executor.
_ok, _err = (()
Players = :()
UserInputService = :()
RunService = :()
CoreGui = :()
ReplicatedStorage = :()
InsertService = :()
plr = Players.LocalPlayer
mouse = plr:()
C = {
bg = .(, , ),
panel = .(, , ),
card = .(, , ),
cardHi = .(, , ),
border = .(, , ),
accent = .(, , ),
accentD = .(, , ),
success = .(, , ),
danger = .(, , ),
= .(, , ),
text = .(, , ),
textDim = .(, , ),
}
propMap = {
[]=,[]=,[]=,
[]=,[]=,
}
(parent, targetName)
result =
(()
_, child (parent:())
child:() child.Name == targetName
result = child
isContainer =
(()
child:() child:() child:()
isContainer =
)
isContainer result
result = (child, targetName)
result
)
result
logLines = {}
LogTextBox =
(msg, col)
text = (msg)
.(logLines, text)
#logLines > .(logLines, )
(() ( .. text) )
LogTextBox LogTextBox.Parent
(()
LogTextBox.Text = .(logLines, )
LogTextBox.CursorPosition = #LogTextBox.Text +
)
loadedModel =
loadedModelPivot =
origPartData = {}
ghostModel =
ghostConn =
placingMode =
ghostRotation = .()
building =
cancelBuild =
buildSpeed =
partType =
convertMeshes =
meshVoxelSize =
meshMaxParts =
meshSurfaceCache = {}
(parent, r)
c = .()
c.CornerRadius = .(, r )
c.Parent = parent
c
(parent, col, thick)
s = .()
s.Color = col C.border
s.Thickness = thick
s.Parent = parent
s
gui = .()
gui.Name =
gui.ResetOnSpawn =
gui.ZIndexBehavior = .ZIndexBehavior.Sibling
gui.DisplayOrder =
gui.IgnoreGuiInset =
(() gui.Parent = CoreGui )
gui.Parent gui.Parent = plr:()
panel = .()
panel.Size = .(, , , )
panel.Position = .(, , , -)
panel.BackgroundColor3 = C.bg
panel.BorderSizePixel =
panel.Parent = gui
(panel, )
(panel, C.accentD, )
header = .()
header.Size = .(, , , )
header.BackgroundColor3 = C.panel
header.BorderSizePixel =
header.Parent = panel
(header, )
title = .()
title.Size = .(, -, , )
title.Position = .(, , , )
title.BackgroundTransparency =
title.Text =
title.TextColor3 = C.accent
title.Font = .Font.GothamBold
title.TextSize =
title.TextXAlignment = .TextXAlignment.Left
title.Parent = header
closeBtn = .()
closeBtn.Size = .(, , , )
closeBtn.Position = .(, -, , )
closeBtn.BackgroundColor3 = C.danger
closeBtn.Text =
closeBtn.TextColor3 = .(, , )
closeBtn.Font = .Font.GothamBold
closeBtn.TextSize =
closeBtn.Parent = header
(closeBtn, )
closeBtn.MouseButton1Click:(()
ghostConn ghostConn:()
ghostModel ghostModel:()
loadedModel loadedModel:()
gui:()
)
dragging, dragStart, startPos
header.InputBegan:((input)
input.UserInputType == .UserInputType.MouseButton1 input.UserInputType == .UserInputType.Touch
dragging =
dragStart = input.Position
startPos = panel.Position
)
UserInputService.InputChanged:((input)
dragging (input.UserInputType == .UserInputType.MouseMovement input.UserInputType == .UserInputType.Touch)
delta = input.Position - dragStart
panel.Position = .(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
)
UserInputService.InputEnded:((input)
input.UserInputType == .UserInputType.MouseButton1 input.UserInputType == .UserInputType.Touch
dragging =
)
content = .()
content.Size = .(, -, , -)
content.Position = .(, , , )
content.BackgroundTransparency =
content.Parent = panel
layout = .()
layout.Padding = .(, )
layout.Parent = content
(text)
lbl = .()
lbl.Size = .(, , , )
lbl.BackgroundTransparency =
lbl.Text = text
lbl.TextColor3 = C.accent
lbl.Font = .Font.GothamBold
lbl.TextSize =
lbl.TextXAlignment = .TextXAlignment.Left
lbl.Parent = content
lbl
(parent, placeholder)
t = .()
t.Size = .(, , , )
t.BackgroundColor3 = C.card
t.TextColor3 = C.text
t.PlaceholderText = placeholder
t.PlaceholderColor3 = C.textDim
t.Text =
t.Font = .Font.Gotham
t.TextSize =
t.ClearTextOnFocus =
t.Parent = parent
(t, )
(t, C.border, )
t
(parent, text, bgColor, textColor, height)
b = .()
b.Size = .(, , , height )
b.BackgroundColor3 = bgColor C.card
b.Text = text
b.TextColor3 = textColor C.text
b.Font = .Font.GothamBold
b.TextSize =
b.Parent = parent
(b, )
b
()
idBox = (content, )
loadBtnRow = .()
loadBtnRow.Size = .(, , , )
loadBtnRow.BackgroundTransparency =
loadBtnRow.Parent = content
loadBtnRowLay = .()
loadBtnRowLay.FillDirection = .FillDirection.Horizontal
loadBtnRowLay.Padding = .(, )
loadBtnRowLay.Parent = loadBtnRow
loadBtn = (loadBtnRow, , C.accent, C.bg, )
loadBtn.Size = .(, -, , )
loadBtn.TextSize =
forceLoadBtn = (loadBtnRow, , C.warn, C.bg, )
forceLoadBtn.Size = .(, -, , )
forceLoadBtn.TextSize =
loadStatus = .()
loadStatus.Size = .(, , , )
loadStatus.BackgroundTransparency =
loadStatus.Text =
loadStatus.TextColor3 = C.textDim
loadStatus.Font = .Font.Gotham
loadStatus.TextSize =
loadStatus.TextXAlignment = .TextXAlignment.Left
loadStatus.Parent = content
()
partTypes = {
, , , , , ,
, , , ,
, , ,
, , ,
}
ptButtons = {}
ptRow = .()
ptRow.Size = .(, , , )
ptRow.BackgroundTransparency =
ptRow.Parent = content
ptLbl = .()
ptLbl.Size = .(, , , )
ptLbl.BackgroundTransparency =
ptLbl.Text =
ptLbl.TextColor3 = C.text
ptLbl.Font = .Font.Gotham
ptLbl.TextSize =
ptLbl.TextXAlignment = .TextXAlignment.Left
ptLbl.Parent = ptRow
ptDdBtn = .()
ptDdBtn.Size = .(, -, , )
ptDdBtn.Position = .(, , , )
ptDdBtn.BackgroundColor3 = C.card
ptDdBtn.Text = partType
ptDdBtn.TextColor3 = C.text
ptDdBtn.Font = .Font.GothamBold
ptDdBtn.TextSize =
ptDdBtn.TextXAlignment = .TextXAlignment.Left
ptDdBtn.Parent = ptRow
(ptDdBtn, )
(ptDdBtn, C.border, )
ptDdList = .()
ptDdList.Size = .(, -, , )
ptDdList.Position = .(, , , )
ptDdList.BackgroundColor3 = C.card
ptDdList.BorderSizePixel =
ptDdList.Visible =
ptDdList.ZIndex =
ptDdList.ScrollBarThickness =
ptDdList.Parent = ptRow
(ptDdList, )
(ptDdList, C.accentD, )
ptDdLay = .()
ptDdLay.Padding = .(, )
ptDdLay.Parent = ptDdList
ptDropdownOpen =
()
_, ch (ptDdList:())
ch:() ch:()
_, t (partTypes)
b = .()
b.Size = .(, , , )
b.BackgroundColor3 = (t == partType) C.cardHi C.card
b.Text = t
b.TextColor3 = (t == partType) C.accent C.text
b.Font = .Font.Gotham
b.TextSize =
b.TextXAlignment = .TextXAlignment.Left
b.ZIndex =
b.Parent = ptDdList
b.MouseButton1Click:(()
partType = t
ptDdBtn.Text = t
ptDropdownOpen =
ptDdList.Visible =
()
( .. t, C.accent)
)
ptDdList.CanvasSize = .(, , , #partTypes * )
ptDdBtn.MouseButton1Click:(()
ptDropdownOpen = ptDropdownOpen
ptDdList.Visible = ptDropdownOpen
ptDropdownOpen
ptDdList.Size = .(, -, , .(#partTypes * , ))
)
()
speedRow = .()
speedRow.Size = .(, , , )
speedRow.BackgroundTransparency =
speedRow.Parent = content
speedLbl = .()
speedLbl.Size = .(, , , )
speedLbl.BackgroundTransparency =
speedLbl.Text =
speedLbl.TextColor3 = C.text
speedLbl.Font = .Font.Gotham
speedLbl.TextSize =
speedLbl.TextXAlignment = .TextXAlignment.Left
speedLbl.Parent = speedRow
speedValLbl = .()
speedValLbl.Size = .(, -, , )
speedValLbl.Position = .(, , , )
speedValLbl.BackgroundTransparency =
speedValLbl.Text = .(, buildSpeed)
speedValLbl.TextColor3 = C.accent
speedValLbl.Font = .Font.GothamBold
speedValLbl.TextSize =
speedValLbl.TextXAlignment = .TextXAlignment.Left
speedValLbl.Parent = speedRow
()
colorToggleBtn = (content, , C.accent, C.bg, )
applyColors =
colorToggleBtn.MouseButton1Click:(()
applyColors = applyColors
applyColors
colorToggleBtn.Text =
colorToggleBtn.BackgroundColor3 = C.accent
colorToggleBtn.TextColor3 = C.bg
colorToggleBtn.Text =
colorToggleBtn.BackgroundColor3 = C.card
colorToggleBtn.TextColor3 = C.textDim
)
materialToggleBtn = (content, , C.accent, C.bg, )
applyMaterials =
materialToggleBtn.MouseButton1Click:(()
applyMaterials = applyMaterials
applyMaterials
materialToggleBtn.Text =
materialToggleBtn.BackgroundColor3 = C.accent
materialToggleBtn.TextColor3 = C.bg
materialToggleBtn.Text =
materialToggleBtn.BackgroundColor3 = C.card
materialToggleBtn.TextColor3 = C.textDim
)
()
placeBtn = (content, , C.warn, C.bg, )
placeBtn.TextSize =
buildBtn = (content, , C.success, C.bg, )
buildBtn.TextSize =
(buildBtn, C.success, )
cancelBtn = (content, , C.danger, .(,,), )
cancelBtn.TextSize =
progressLbl = .()
progressLbl.Size = .(, , , )
progressLbl.BackgroundTransparency =
progressLbl.Text =
progressLbl.TextColor3 = C.textDim
progressLbl.Font = .Font.Gotham
progressLbl.TextSize =
progressLbl.TextXAlignment = .TextXAlignment.Left
progressLbl.Parent = content
progressBg = .()
progressBg.Size = .(, , , )
progressBg.BackgroundColor3 = C.card
progressBg.Parent = content
(progressBg, )
progressFill = .()
progressFill.Size = .(, , , )
progressFill.BackgroundColor3 = C.accent
progressFill.Parent = progressBg
(progressFill, )
(pct, text)
progressFill.Size = .(pct, , , )
text progressLbl.Text = text
()
LogTextBox = .()
LogTextBox.Size = .(, , , )
LogTextBox.BackgroundColor3 = C.card
LogTextBox.TextColor3 = C.text
LogTextBox.Text =
LogTextBox.Font = .Font.RobotoMono
LogTextBox.TextSize =
LogTextBox.TextWrapped =
LogTextBox.TextXAlignment = .TextXAlignment.Left
LogTextBox.TextYAlignment = .TextYAlignment.Top
LogTextBox.MultiLine =
LogTextBox.ClearTextOnFocus =
LogTextBox.TextEditable =
LogTextBox.Active =
LogTextBox.Parent = content
(LogTextBox, )
(LogTextBox, C.border, )
()
ghostConn ghostConn:() ghostConn =
ghostModel ghostModel:() ghostModel =
placingMode =
placeBtn.Text =
placeBtn.BackgroundColor3 = C.warn
placeBtn.TextColor3 = C.bg
()
loadedModel
(, C.danger)
()
ghostRotation = .()
ghostModel = loadedModel:()
_, p (ghostModel:())
p:()
p.Transparency =
p.Material = .Material.Neon
p.CanCollide =
p.CanQuery =
p.CanTouch =
p.Anchored =
ghostModel.Parent =
placingMode =
placeBtn.Text =
placeBtn.BackgroundColor3 = C.accent
placeBtn.TextColor3 = C.bg
ghostConn = RunService.RenderStepped:(()
ghostModel ghostModel.Parent
()
mousePos = mouse.Hit.Position
ghostModel:(.(mousePos) * ghostRotation)
)
(, C.accent)
placeBtn.MouseButton1Click:(()
building
(, C.warn)
placingMode
()
(, C.warn)
()
)
UserInputService.InputBegan:((input, gameProcessed)
input.KeyCode == .KeyCode.R
UserInputService:()
placingMode
ghostRotation = ghostRotation * .(, .(), )
(, C.accent)
input.UserInputType ~= .UserInputType.MouseButton1 input.UserInputType ~= .UserInputType.Touch
placingMode
building
placeCFrame = ghostModel:()
()
( .. (placeCFrame.Position), C.success)
(placeCFrame)
)
(meshPart, pivot)
convertMeshes meshPart:()
data = origPartData[meshPart]
data
step = .(, meshVoxelSize)
maxParts = .(, meshMaxParts)
size = meshPart.Size
half = size *
margin = .(, step * )
params = RaycastParams.()
params.FilterType = .RaycastFilterType.Include
params.FilterDescendantsInstances = {meshPart}
params.IgnoreWater =
samples = {}
seen = {}
NORMAL_TOLERANCE =
MAX_MERGE_LENGTH =
(position, normal)
normal = normal.Unit
reference = .yAxis
.(normal:(reference)) >
reference = .xAxis
right = reference:(normal)
right.Magnitude <
reference = .zAxis
right = reference:(normal)
right = right.Unit
forward = right:(normal).Unit
.(
position,
right,
normal,
forward
)
(hit)
hit
localPos =
meshPart.CFrame:(hit.Position)
qx = .(localPos.X / step + )
qy = .(localPos.Y / step + )
qz = .(localPos.Z / step + )
key =
qx .. ..
qy .. ..
qz
seen[key]
seen[key] =
.(samples, {
position = hit.Position,
normal = hit.Normal.Unit,
localPos = localPos,
x = qx,
y = qy,
z = qz,
})
(a, b)
wa = meshPart.CFrame:(a)
wb = meshPart.CFrame:(b)
hit = :(
wa,
wb - wa,
params
)
(hit)
xCount =
.(, .(size.X / step))
yCount =
.(, .(size.Y / step))
zCount =
.(, .(size.Z / step))
xi = , xCount
x =
-half.X +
size.X * xi / xCount
zi = , zCount
z =
-half.Z +
size.Z * zi / zCount
(
.(
x,
half.Y + margin,
z
),
.(
x,
-half.Y - margin,
z
)
)
(
.(
x,
-half.Y - margin,
z
),
.(
x,
half.Y + margin,
z
)
)
yi = , yCount
y =
-half.Y +
size.Y * yi / yCount
zi = , zCount
z =
-half.Z +
size.Z * zi / zCount
(
.(
half.X + margin,
y,
z
),
.(
-half.X - margin,
y,
z
)
)
(
.(
-half.X - margin,
y,
z
),
.(
half.X + margin,
y,
z
)
)
xi = , xCount
x =
-half.X +
size.X * xi / xCount
yi = , yCount
y =
-half.Y +
size.Y * yi / yCount
(
.(
x,
y,
half.Z + margin
),
.(
x,
y,
-half.Z - margin
)
)
(
.(
x,
y,
-half.Z - margin
),
.(
x,
y,
half.Z + margin
)
)
#samples ==
{}
grid = {}
(x, y, z)
x .. .. y .. .. z
_, sample (samples)
grid[
(
sample.x,
sample.y,
sample.z
)
] = sample
used = {}
result = {}
(a, b)
a:(b) >= NORMAL_TOLERANCE
(tileSamples)
#result >= maxParts
#tileSamples ==
center = .zero
normal = .zero
_, sample (tileSamples)
center += sample.position
normal += sample.normal
center /= #tileSamples
normal = normal.Unit
surfaceCFrame =
(center, normal)
minX = .huge
maxX = -.huge
minZ = .huge
maxZ = -.huge
_, sample (tileSamples)
relative =
surfaceCFrame:(
sample.position
)
minX = .(minX, relative.X)
maxX = .(maxX, relative.X)
minZ = .(minZ, relative.Z)
maxZ = .(maxZ, relative.Z)
tileX =
.(step, maxX - minX + step)
tileZ =
.(step, maxZ - minZ + step)
thickness =
.(, step * )
.(result, {
part = meshPart,
relCFrame =
pivot:(
surfaceCFrame
),
size = .(
tileX,
thickness,
tileZ
),
color = data.color,
material = data.material,
transparency = data.transparency,
reflectance = data.reflectance,
name = data.name .. ,
className = ,
obbyType = ,
effects = {},
spinProps = ,
})
_, base (samples)
#result >= maxParts
baseKey =
(
base.x,
base.y,
base.z
)
used[baseKey]
group = {}
minX = base.x
maxX = base.x
minY = base.y
maxY = base.y
minZ = base.z
maxZ = base.z
.(group, base)
used[baseKey] =
direction = ,
sign =
direction == -
distance = , MAX_MERGE_LENGTH
nx =
base.x +
sign * distance
candidate =
grid[
(
nx,
base.y,
base.z
)
]
candidate
candidateKey =
(
candidate.x,
candidate.y,
candidate.z
)
used[candidateKey]
(
base.normal,
candidate.normal
)
.(
group,
candidate
)
used[candidateKey] =
minX =
.(
minX,
candidate.x
)
maxX =
.(
maxX,
candidate.x
)
direction = ,
sign =
direction == -
distance = , MAX_MERGE_LENGTH
nz =
base.z +
sign * distance
candidate =
grid[
(
base.x,
base.y,
nz
)
]
candidate
candidateKey =
(
candidate.x,
candidate.y,
candidate.z
)
used[candidateKey]
(
base.normal,
candidate.normal
)
.(
group,
candidate
)
used[candidateKey] =
minZ =
.(
minZ,
candidate.z
)
maxZ =
.(
maxZ,
candidate.z
)
(group)
result
(model, pivot)
meshSurfaceCache = {}
convertMeshes
meshCount =
generatedCount =
meshObjects = {}
model:()
.(meshObjects, model)
_, d (model:())
d:()
.(meshObjects, d)
_, p (meshObjects)
meshCount = meshCount +
ok, result = (()
(p, pivot)
)
ok result #result >
meshSurfaceCache[p] = result
generatedCount = generatedCount + #result
( .. p.Name .. .. #result .. , C.success)
meshSurfaceCache[p] = {}
( .. p.Name .. , C.warn)
meshCount >
( .. meshCount .. ..
generatedCount .. , C.accent)
()
loadedModel {}
bricks = {}
pivot = loadedModelPivot loadedModel:()
skipped =
totalParts =
(p, data)
p:()
p:()
p:()
p:()
data.shape == .PartType.Ball
data.shape == .PartType.Cylinder
p:() p:()
_, child (p:())
child:()
mt = child.MeshType
mt == .MeshType.Sphere
mt == .MeshType.Cylinder
mt == .MeshType.FileMesh
collectParts = {}
loadedModel:()
.(collectParts, loadedModel)
_, d (loadedModel:())
d:()
.(collectParts, d)
_, p (collectParts)
p:()
totalParts = totalParts +
data = origPartData[p]
data
data = {
transparency = p.Transparency,
canCollide = p.CanCollide,
size = p.Size,
color = p.Color,
material = p.Material,
reflectance = p.Reflectance,
cframe = p.CFrame,
name = p.Name,
className = p.ClassName,
shape = p:() p.Shape ,
}
meshSurface = meshSurfaceCache[p]
convertMeshes p:() meshSurface
_, meshBrick (meshSurface)
.(bricks, meshBrick)
obbyType = (p, data)
effects = {}
_, child (p:())
child:()
.(effects, {
= ,
props = {
{, child.Heat},
{, child.Size},
{, child.Color},
{, child.SecondaryColor},
},
})
child:()
.(effects, {
= ,
props = {
{, (child.Face.Name)},
{, child.Brightness},
{, child.Range},
{, child.Color},
{, child.Angle},
},
})
child:()
texId = child.Texture
numId = texId:()
.(effects, {
= ,
props = {
{, (child.Face.Name)},
{, numId texId},
{, child.StudsPerTileU},
{, child.StudsPerTileV},
{, child.Transparency},
},
})
child:()
texId = child.Texture
numId = texId:()
.(effects, {
= ,
props = {
{, (child.Face.Name)},
{, numId texId},
{, child.Transparency},
},
})
child:()
pTexId = child.Texture
pNumId = pTexId (pTexId):()
.(effects, {
= ,
props = {
{, pNumId (pTexId)},
{, child.Transparency},
{, child.Speed},
{, child.SpreadAngle},
{, child.Rate},
{, child.Lifetime},
{, child.Size},
{, child.LightEmission},
{, child.LightInfluence},
{, child.Squash},
{, child.Acceleration},
{, child.Rotation},
{, child.RotSpeed},
{, (child.EmissionDirection.Name)},
{, child.Color},
},
})
child:()
.(effects, {
= ,
props = {
{, child.Color},
{, child.Range},
{, child.Brightness},
{, child.Shadows},
},
})
child:()
.(effects, {
= ,
props = {
{, child.Opacity},
{, child.RiseVelocity},
{, child.Size},
{, child.Color},
},
})
child:()
.(effects, {
= ,
props = {
{, child.SparkleColor},
},
})
ancestor = p.Parent
ancestor ancestor ~=
_, child (ancestor:())
child:()
.(effects, {
= ,
props = {
{, child.FillColor},
{, },
},
})
#effects > effects[#effects].type ==
ancestor = ancestor.Parent
_, child (p:())
child:()
.(effects, {
= ,
props = {
{, child.FillColor},
{, },
},
})
spinProps =
hasSpinAttr = p:() p:()
p:() p:()
spinTimeVal = (p, ) (p, )
spinOffsetVal = (p, ) (p, )
spinDistVal = (p, ) (p, )
hasSpinAttr spinTimeVal spinOffsetVal
spinProps = {
sO = (spinOffsetVal spinOffsetVal.Value) p:() p:() ,
sT = (spinTimeVal spinTimeVal.Value) p:() p:() ,
sd = (spinDistVal spinDistVal.Value) p:() p:() ,
sA = p:() p:() ,
A = p:() p:() ,
E = p:() p:() ,
Ed = p:() p:() ,
mR = p:() p:() ,
}
particleEffects = {}
textureEffects = {}
otherEffects = {}
_, e (effects)
e.type ==
.(particleEffects, e)
e.type ==
.(textureEffects, e)
.(otherEffects, e)
(effectsList)
.(bricks, {
part = p,
relCFrame = pivot:(data.cframe),
size = data.size,
color = data.color,
material = data.material,
transparency = data.transparency,
reflectance = data.reflectance,
name = data.name,
className = data.className,
obbyType = obbyType,
effects = effectsList,
spinProps = spinProps,
})
needClone = #particleEffects > #textureEffects >
needClone
(effects)
firstEffects = {}
_, e (otherEffects)
.(firstEffects, e)
#textureEffects >
.(firstEffects, textureEffects[])
#particleEffects >
.(firstEffects, particleEffects[])
(firstEffects)
i = , #textureEffects
({textureEffects[i]})
i = , #particleEffects
({particleEffects[i]})
cloneReason =
#textureEffects > cloneReason = cloneReason .. #textureEffects ..
#particleEffects > cloneReason = cloneReason .. #particleEffects ..
( .. (p.Name ) .. .. cloneReason ..
.. ( + .(, #textureEffects - ) + .(, #particleEffects - )) .. , C.warn)
typeCounts = {}
_, b (bricks)
typeCounts[b.obbyType] = (typeCounts[b.obbyType] ) +
breakdown = {}
t, c (typeCounts)
.(breakdown, t .. .. c)
.(breakdown)
( .. totalParts .. .. skipped .. .. #bricks .. , C.accent)
( .. .(breakdown, ), C.text)
effectCount =
effectTypes = {}
_, b (bricks)
b.effects
_, e (b.effects)
effectCount = effectCount +
effectTypes[e.type] = (effectTypes[e.type] ) +
effectCount >
eBreakdown = {}
t, c (effectTypes) .(eBreakdown, t .. .. c)
.(eBreakdown)
( .. effectCount .. .. .(eBreakdown, ) .. , C.success)
(, C.textDim)
bricks
(part, color)
evts = ReplicatedStorage:()
evts
(()
(()
evts:()
evts.PaintObject:({part}, , color)
evts:()
evts.BehaviourObject:({part}, , color)
)
)
(part, material)
evts = ReplicatedStorage:()
evts
matName = material.Name
(()
(()
evts:()
evts.BehaviourObject:({part}, , matName)
evts.BehaviourObject:({part}, , matName)
evts.BehaviourObject:({part}, , matName)
evts.BehaviourObject:({part}, , material)
evts.BehaviourObject:({part}, , material)
)
)
(()
(()
evts:()
evts.PaintObject:({part}, , matName)
evts.PaintObject:({part}, , material)
)
)
(()
(()
matValObj = (part, )
matValObj
matValObj:()
matValObj.Value = matName
matValObj:() matValObj:()
matValObj.Value = material.Value
mtlValObj = (part, )
mtlValObj
mtlValObj:()
mtlValObj.Value = matName
mtlValObj:() mtlValObj:()
mtlValObj.Value = material.Value
)
)
(part, reflectance)
evts = ReplicatedStorage:()
evts
(()
(()
evts:()
evts.BehaviourObject:({part}, , reflectance)
evts.BehaviourObject:({part}, , reflectance)
)
)
(()
(()
evts:()
evts.PaintObject:({part}, , reflectance)
)
)
(()
(()
valObj = (part, ) (part, )
valObj (valObj:() valObj:() valObj:())
valObj.Value = reflectance
)
)
(part, transparency)
evts = ReplicatedStorage:()
evts
(()
(()
evts:()
evts.BehaviourObject:({part}, , transparency)
evts.BehaviourObject:({part}, , transparency)
)
)
(()
(()
evts:()
evts.PaintObject:({part}, , transparency)
)
)
(()
(()
valObj = (part, ) (part, )
valObj (valObj:() valObj:() valObj:())
valObj.Value = transparency
)
)
(originCFrame)
building
bricks = ()
#bricks ==
(, C.danger)
building =
cancelBuild =
buildBtn.Text =
buildBtn.BackgroundColor3 = C.cardHi
( .. #bricks .. , C.accent)
(()
evts = ReplicatedStorage:()
evts
(, C.danger)
building =
buildBtn.Text =
buildBtn.BackgroundColor3 = C.success
(, C.warn)
(, .. #bricks)
placedParts = {}
()
obby = :()
obby
obby = obby:(plr.Name)
obby
obby:()
obby.Items:()
i, brick (bricks)
cancelBuild
(, C.danger)
building =
buildBtn.Text =
buildBtn.BackgroundColor3 = C.success
worldCFrame = originCFrame:(brick.relCFrame)
partsFolder = ()
partsFolder
(, C.danger)
building =
buildBtn.Text =
buildBtn.BackgroundColor3 = C.success
return
end
-- ===== SNAPSHOT existing parts BEFORE AddObject =====
-- This lets us reliably find the NEW part after AddObject fires.
local existingParts = {}
for _, ch in ipairs(partsFolder:GetChildren()) do
existingParts[ch] = true
end
-- Set up ChildAdded listener BEFORE AddObject so we don't miss the event
local newPartFound = nil
local childAddedConn = partsFolder.ChildAdded:Connect(function(child)
if not existingParts[child] then
newPartFound = child
end
end)
-- 1) AddObject — create the part using the AUTO-DETECTED type for this brick
local useType = brick.obbyType or partType -- fallback to global if detection failed
local ok, err = pcall(function()
evts.AddObject:InvokeServer(useType, worldCFrame)
end)
if not ok then
log("AddObject failed: " .. tostring(err), C.danger)
end
-- 2) Find the NEW part — check snapshot first, then wait for ChildAdded
local newPart = nil
-- Check snapshot immediately
for _, ch in ipairs(partsFolder:GetChildren()) do
if not existingParts[ch] then
newPart = ch
break
end
end
-- If not found immediately, wait for ChildAdded (up to 3 seconds)
if not newPart then
local waited = 0
while not newPartFound and not newPart and waited < 3 do
-- Also re-check snapshot in case we missed it
for _, ch in ipairs(partsFolder:GetChildren()) do
if not existingParts[ch] then
newPart = ch
break
end
end
if not newPart and not newPartFound then
wait(0.05)
waited = waited + 0.05
end
end
-- Use ChildAdded result if snapshot didn't find it
if not newPart and newPartFound then
newPart = newPartFound
end
end
childAddedConn:Disconnect()
if newPart then
-- 3) MoveObject — set size + CFrame (preserves rotation)
pcall(function()
evts.MoveObject:InvokeServer({
{
[1] = newPart,
[2] = worldCFrame,
[3] = brick.size,
}
})
end)
table.insert(placedParts, {brick = brick, part = newPart})
log("Placed " .. i .. "/" .. #bricks .. ": " .. (newPart.Name or "?") .. " [" .. useType .. "]", C.text)
else
log("Could not find new part after AddObject (brick " .. i .. ")", C.danger)
end
setProgress(i / #bricks * 0.25, "Phase 1/4: Placing " .. i .. "/" .. #bricks)
wait(buildSpeed)
end
log("Phase 1 done: " .. #placedParts .. " parts placed", C.success)
-- ===== PHASE 2: APPLY COLORS + TRANSPARENCY =====
if applyColors then
log("Phase 2: Applying colors + transparency...", C.warn)
for i, entry in ipairs(placedParts) do
if cancelBuild then
log("Build cancelled during coloring", C.danger)
building = false
buildBtn.Text = "BUILD MODEL"
buildBtn.BackgroundColor3 = C.success
return
end
if entry.part and entry.part.Parent then
applyColorToPart(entry.part, entry.brick.color)
-- ALWAYS apply transparency (even if 0, to reset any default)
applyTransparencyToPart(entry.part, entry.brick.transparency)
log("Color " .. i .. "/" .. #placedParts .. ": " .. (entry.brick.name or "?") ..
" -> " .. tostring(entry.brick.color) .. " (transparency=" .. entry.brick.transparency .. ")", C.text)
end
setProgress(0.25 + i / #placedParts * 0.25, "Phase 2/4: Coloring " .. i .. "/" .. #placedParts)
wait(buildSpeed)
end
log("Phase 2 done: colors + transparency applied", C.success)
else
log("Phase 2 skipped (Colors toggle OFF)", C.textDim)
end
-- ===== PHASE 3: APPLY MATERIALS + REFLECTANCE =====
if applyMaterials then
log("Phase 3: Applying materials + reflectance...", C.warn)
for i, entry in ipairs(placedParts) do
if cancelBuild then
log("Build cancelled during materials", C.danger)
building = false
buildBtn.Text = "BUILD MODEL"
buildBtn.BackgroundColor3 = C.success
return
end
if entry.part and entry.part.Parent then
applyMaterialToPart(entry.part, entry.brick.material)
-- ALWAYS apply reflectance (even if 0, to reset any default)
applyReflectanceToPart(entry.part, entry.brick.reflectance)
log("Material " .. i .. "/" .. #placedParts .. ": " .. (entry.brick.name or "?") ..
" -> " .. entry.brick.material.Name .. " (reflectance=" .. entry.brick.reflectance .. ")", C.text)
end
setProgress(0.50 + i / #placedParts * 0.25, "Phase 3/4: Material " .. i .. "/" .. #placedParts)
wait(buildSpeed)
end
log("Phase 3 done: materials + reflectance applied", C.success)
else
log("Phase 3 skipped (Materials toggle OFF)", C.textDim)
end
-- ===== PHASE 4: APPLY EFFECTS (Fire, SurfaceLight, Texture, Decal) =====
local totalEffects = 0
for _, entry in ipairs(placedParts) do
if entry.brick.effects then
totalEffects = totalEffects + #entry.brick.effects
end
end
if totalEffects > 0 then
log("Phase 4: Applying " .. totalEffects .. " effects...", C.warn)
local effectIdx = 0
for i, entry in ipairs(placedParts) do
if cancelBuild then
log("Build cancelled during effects", C.danger)
building = false
buildBtn.Text = "BUILD MODEL"
buildBtn.BackgroundColor3 = C.success
return
end
if entry.part and entry.part.Parent and entry.brick.effects then
for _, effect in ipairs(entry.brick.effects) do
-- 1) Add the effect: EffectObject:InvokeServer({part}, type, "Default")
local addOk, addErr = pcall(function()
evts.EffectObject:InvokeServer({entry.part}, effect.type, "Default")
end)
if not addOk then
log(" Effect add FAILED: " .. tostring(addErr), C.danger)
end
wait(0.5) -- wait longer for server to create the effect
-- 2) Set each property: EffectObject:InvokeServer({part}, type, property, value)
for _, propData in ipairs(effect.props) do
local propName, propValue = propData[1], propData[2]
local propOk, propErr = pcall(function()
evts.EffectObject:InvokeServer({entry.part}, effect.type, propName, propValue)
end)
if not propOk then
log(" Property '" .. propName .. "' FAILED: " .. tostring(propErr), C.danger)
end
wait(0.1) -- small delay between each property
end
effectIdx = effectIdx + 1
-- Build a property summary for the log
local propSummary = {}
for _, pd in ipairs(effect.props) do
table.insert(propSummary, pd[1] .. "=" .. tostring(pd[2]))
end
log("Effect " .. effectIdx .. "/" .. totalEffects .. ": " ..
(entry.brick.name or "?") .. " + " .. effect.type ..
" (" .. table.concat(propSummary, ", ") .. ")", C.text)
end
end
setProgress(0.75 + i / #placedParts * 0.25, "Phase 4/5: Effects " .. i .. "/" .. #placedParts)
wait(buildSpeed)
end
log("Phase 4 done: " .. totalEffects .. " effects applied", C.success)
else
log("Phase 4: No effects found in model, skipping", C.textDim)
end
-- ===== PHASE 5: CONVERT SPIN PARTS =====
-- For any part that had spin properties detected, we create a "Spin Part"
-- at the same position, transfer all properties, then delete the original.
local spinCount = 0
for _, entry in ipairs(placedParts) do
if entry.brick.spinProps then spinCount = spinCount + 1 end
end
if spinCount > 0 then
log("Phase 5: Converting " .. spinCount .. " spin parts...", C.warn)
local spinIdx = 0
for i, entry in ipairs(placedParts) do
if cancelBuild then
log("Build cancelled during spin conversion", C.danger)
building = false
buildBtn.Text = "BUILD MODEL"
buildBtn.BackgroundColor3 = C.success
return
end
if entry.part and entry.part.Parent and entry.brick.spinProps then
local sp = entry.brick.spinProps
local origPart = entry.part
local origCFrame = origPart.CFrame
local origSize = origPart.Size
local origColor = origPart.Color
local origMaterial = origPart.Material
local origTransparency = origPart.Transparency
local origReflectance = origPart.Reflectance
-- Get the Spin Parts folder BEFORE creating
local obby = workspace:FindFirstChild("Obbies")
if obby then obby = obby:FindFirstChild(plr.Name) end
local spinFolder = obby and obby:FindFirstChild("Items") and obby.Items:FindFirstChild("Spin Parts")
if not spinFolder then
log("Could not find Spin Parts folder! Creating spin part anyway...", C.warn)
end
-- SNAPSHOT existing spin parts BEFORE AddObject
local existingSpinParts = {}
if spinFolder then
for _, ch in ipairs(spinFolder:GetChildren()) do
existingSpinParts[ch] = true
end
end
-- 1) Create the Spin Part
log("Creating Spin Part at " .. tostring(origCFrame.Position), C.accent)
local addOk, addErr = pcall(function()
evts.AddObject:InvokeServer("Spin Part", origCFrame)
end)
if not addOk then
log("Spin Part AddObject FAILED: " .. tostring(addErr), C.danger)
end
wait(0.5)
-- 2) Find the NEW Spin Part (the one not in our snapshot)
local newSpin = nil
if spinFolder then
local waited = 0
while not newSpin and waited < 3 do
for _, ch in ipairs(spinFolder:GetChildren()) do
if not existingSpinParts[ch] then
newSpin = ch
break
end
end
if not newSpin then
wait(0.1)
waited = waited + 0.1
end
end
end
if not newSpin then
log("Could not find new Spin Part! Skipping.", C.danger)
else
log("Found new Spin Part: " .. (newSpin.Name or "?"), C.accent)
-- 3) Set size + position via MoveObject
pcall(function()
evts.MoveObject:InvokeServer({
{
[1] = newSpin,
[2] = origCFrame,
[3] = origSize,
}
})
end)
wait(0.1)
-- 4) Apply color + material to the spin part
if applyColors then
applyColorToPart(newSpin, origColor)
applyTransparencyToPart(newSpin, origTransparency)
end
if applyMaterials then
applyMaterialToPart(newSpin, origMaterial)
applyReflectanceToPart(newSpin, origReflectance)
end
-- 5) Apply spin properties via BehaviourObject
local bhvr = evts:FindFirstChild("BehaviourObject")
if bhvr then
pcall(function() bhvr:InvokeServer({newSpin}, "sO", sp.sO) end)
pcall(function() bhvr:InvokeServer({newSpin}, "sT", sp.sT) end)
pcall(function() bhvr:InvokeServer({newSpin}, "sd", sp.sd) end)
pcall(function() bhvr:InvokeServer({newSpin}, "sA", sp.sA) end)
pcall(function() bhvr:InvokeServer({newSpin}, "A", sp.A) end)
pcall(function() bhvr:InvokeServer({newSpin}, "mR", sp.mR) end)
pcall(function() bhvr:InvokeServer({newSpin}, "Ed", sp.Ed) end)
-- NEVER send "Line" as easing style — crashes the server
if sp.E ~= "Line" then
pcall(function() bhvr:InvokeServer({newSpin}, "E", sp.E) end)
else
pcall(function() bhvr:InvokeServer({newSpin}, "E", "Sine") end)
end
end
-- 6) Delete the original part
pcall(function()
evts.DeleteObject:InvokeServer({origPart})
end)
spinIdx = spinIdx + 1
log("Spin " .. spinIdx .. "/" .. spinCount .. ": " .. (entry.brick.name or "?") ..
" (axis=" .. sp.A .. ", time=" .. sp.sT .. ", offset=" .. sp.sO .. ")", C.text)
end
end
setProgress(0.80 + i / #placedParts * 0.20, "Phase 5/5: Spin Parts " .. i .. "/" .. #placedParts)
wait(buildSpeed)
end
log("Phase 5 done: " .. spinCount .. " spin parts converted", C.success)
else
log("Phase 5: No spin parts found, skipping", C.textDim)
end
setProgress(1, "Build complete! " .. #placedParts .. " bricks")
log("=== BUILD COMPLETE ===", C.success)
building = false
buildBtn.Text = "BUILD MODEL"
buildBtn.BackgroundColor3 = C.success
end)
end
buildBtn.MouseButton1Click:Connect(function()
if building then
log("Already building — cancel first", C.warn)
return
end
if not loadedModel then
log("Load a model first!", C.danger)
return
end
if not placingMode and not ghostModel then
-- Auto-start ghost mode
startGhost()
log("Click in world to place, then build starts", C.accent)
return
end
end)
cancelBtn.MouseButton1Click:Connect(function()
if building then
cancelBuild = true
log("Cancelling...", C.warn)
else
clearGhost()
log("Nothing to cancel", C.textDim)
end
end)
-- ============================================================
-- LOAD MODEL
-- ============================================================
-- ===== LOAD MODEL FUNCTION (shared by LOAD and FORCE LOAD buttons) =====
local function loadModel(id, forceMode)
loadStatus.Text = "Loading model " .. id .. (forceMode and " (FORCE)..." or "...")
loadStatus.TextColor3 = C.warn
log("Loading model ID " .. id .. (forceMode and " (FORCE MODE)" or ""), C.accent)
-- Clean up previous model
if loadedModel then loadedModel:Destroy() end
clearGhost()
spawn(function()
local model = nil
local loadErr = nil
-- Timeout helper: runs a function and returns nil if it takes too long
local function loadWithTimeout(func, timeoutSec)
local result = nil
local done = false
local co = coroutine.create(function()
local ok, res = pcall(func)
result = {ok = ok, res = res}
done = true
end)
coroutine.resume(co)
local waited = 0
while not done and waited < timeoutSec do
wait(0.1)
waited = waited + 0.1
end
if not done then
log("Load method timed out after " .. timeoutSec .. "s", C.warn)
return nil, "timeout"
end
if not result.ok then
return nil, tostring(result.res)
end
return result.res, nil
end
-- Method 1: game:GetObjects (executor function — preferred) — 10s timeout
local result, err = loadWithTimeout(function()
return game:GetObjects("rbxassetid://" .. id)
end, 10)
if result then
if type(result) == "table" then
if #result > 0 then
model = result[1]
log("Loaded via game:GetObjects (table)", C.success)
else
loadErr = "game:GetObjects returned empty"
log(loadErr, C.warn)
end
elseif typeof(result) == "Instance" then
model = result
log("Loaded via game:GetObjects (instance)", C.success)
else
loadErr = "game:GetObjects returned: " .. typeof(result)
log(loadErr, C.warn)
end
else
loadErr = err or "unknown error"
log("game:GetObjects failed: " .. loadErr, C.warn)
end
-- Method 2: InsertService fallback — 10s timeout
if not model then
result, err = loadWithTimeout(function()
return InsertService:LoadAsset(id)
end, 10)
if result then
model = result
if model:IsA("Model") then
local inner = model:FindFirstChildOfClass("Model")
if inner then model = inner end
end
log("Loaded via InsertService", C.success)
else
loadErr = err or "unknown error"
end
end
-- Method 3 (FORCE MODE only): try alternatives with timeouts
if not model and forceMode then
log("FORCE MODE: trying alternative load methods...", C.warn)
-- Try without rbxassetid prefix — 10s timeout
result, err = loadWithTimeout(function()
return game:GetObjects(id)
end, 10)
if result then
if type(result) == "table" and #result > 0 then
model = result[1]
log("Loaded via game:GetObjects (raw ID)", C.success)
elseif typeof(result) == "Instance" then
model = result
log("Loaded via game:GetObjects (raw ID, instance)", C.success)
end
end
-- Try with https URL — 10s timeout
if not model then
result, err = loadWithTimeout(function()
return game:GetObjects("https://www.roblox.com/item?id=" .. id)
end, 10)
if result then
if type(result) == "table" and #result > 0 then
model = result[1]
log("Loaded via game:GetObjects (https URL)", C.success)
elseif typeof(result) == "Instance" then
model = result
log("Loaded via game:GetObjects (https URL, instance)", C.success)
end
end
end
-- Try LoadAsset one more time — 10s timeout
if not model then
result, err = loadWithTimeout(function()
return InsertService:LoadAsset(id)
end, 10)
if result then
model = result
if model:IsA("Model") then
local inner = model:FindFirstChildOfClass("Model")
if inner then model = inner end
end
log("Loaded via InsertService (retry)", C.success)
else
loadErr = err or "unknown error"
end
end
end
if not model then
loadStatus.Text = "Failed to load"
loadStatus.TextColor3 = C.danger
log("Failed to load model: " .. tostring(loadErr), C.danger)
if not forceMode then
log("Try FORCE LOAD button — it tries alternative methods.", C.warn)
else
log("All load methods failed. This model may be a package or copylocked.", C.warn)
end
return
end
-- ===== FIND THE RICHEST MODEL (most BaseParts) =====
local function countBaseParts(obj)
local count = 0
if obj:IsA("BasePart") then count = 1 end
for _, d in ipairs(obj:GetDescendants()) do
if d:IsA("BasePart") then count = count + 1 end
end
return count
end
local bestModel = model
local bestCount = countBaseParts(model)
log("Initial object: " .. model.ClassName .. " '" .. (model.Name or "?") .. "' with " .. bestCount .. " BaseParts", C.text)
for _, d in ipairs(model:GetDescendants()) do
if d:IsA("Model") or d:IsA("Folder") or d:IsA("Tool") or d:IsA("Accoutrement") then
local c = countBaseParts(d)
if c > bestCount then
bestCount = c
bestModel = d
log("Found richer model: " .. d.ClassName .. " '" .. (d.Name or "?") .. "' with " .. c .. " BaseParts", C.text)
end
end
end
model = bestModel
local brickCount = bestCount
if brickCount == 0 then
loadStatus.Text = "No parts in model"
loadStatus.TextColor3 = C.danger
log("Model has no BaseParts", C.danger)
return
end
-- Log model structure breakdown
local meshParts = 0
local regularParts = 0
local unions = 0
local other = 0
local breakdownParts = {}
if model:IsA("BasePart") then
table.insert(breakdownParts, model)
end
for _, d in ipairs(model:GetDescendants()) do
if d:IsA("BasePart") then
table.insert(breakdownParts, d)
end
end
for _, d in ipairs(breakdownParts) do
if d:IsA("MeshPart") then
meshParts = meshParts + 1
elseif d:IsA("UnionOperation") then
unions = unions + 1
elseif d:IsA("Part") then
regularParts = regularParts + 1
else
other = other + 1
end
end
log("Breakdown: " .. regularParts .. " Parts, " .. meshParts .. " MeshParts, " .. unions .. " Unions, " .. other .. " other", C.accent)
-- Store the model (hide it — make all parts invisible + move far below)
loadedModel = model
-- Capture the ORIGINAL pivot BEFORE moving
loadedModelPivot = model:GetPivot()
-- ===== CAPTURE ORIGINAL PART DATA BEFORE HIDING =====
-- collectBricks will use this snapshot instead of reading from the
-- (now-modified) live parts. This prevents the "511 filtered, 0 to build" bug.
origPartData = {}
local snapshotParts = {}
-- include the root if the loaded object itself is a BasePart
if model:IsA("BasePart") then
table.insert(snapshotParts, model)
end
-- include any BaseParts inside the model
for _, d in ipairs(model:GetDescendants()) do
if d:IsA("BasePart") then
table.insert(snapshotParts, d)
end
end
for _, p in ipairs(snapshotParts) do
origPartData[p] = {
transparency = p.Transparency,
canCollide = p.CanCollide,
size = p.Size,
color = p.Color,
material = p.Material,
reflectance = p.Reflectance,
cframe = p.CFrame,
name = p.Name,
className = p.ClassName,
shape = p:IsA("Part") and p.Shape or nil,
}
end
log("Captured " .. #model:GetDescendants() .. " descendants (" .. brickCount .. " BaseParts) before hiding", C.text)
-- Scan meshes while they are still queryable at their original positions.
model.Parent = workspace
buildMeshCache(model, loadedModelPivot)
model:PivotTo(CFrame.new(0, -1000, 0))
for _, p in ipairs(model:GetDescendants()) do
if p:IsA("BasePart") then
p.Transparency = 1
p.CanCollide = false
p.CanQuery = false
p.CanTouch = false
end
end
loadStatus.Text = "Loaded: " .. brickCount .. " bricks"
loadStatus.TextColor3 = C.success
log("Model loaded: " .. brickCount .. " bricks. Click PLACE to start.", C.success)
end)
end
loadBtn.MouseButton1Click:Connect(function()
local idText = idBox.Text
local id = tonumber(idText:match("%d+"))
if not id then
loadStatus.Text = "Invalid ID"
loadStatus.TextColor3 = C.danger
log("Invalid model ID: " .. idText, C.danger)
return
end
loadModel(id, false)
end)
forceLoadBtn.MouseButton1Click:Connect(function()
local idText = idBox.Text
local id = tonumber(idText:match("%d+"))
if not id then
loadStatus.Text = "Invalid ID"
loadStatus.TextColor3 = C.danger
log("Invalid model ID: " .. idText, C.danger)
return
end
loadModel(id, true)
end)
-- ============================================================
-- INIT
-- ============================================================
log("=== Model Importer ===", C.accent)
log("1. Enter model ID -> click LOAD", C.text)
log("2. Click PLACE -> ghost follows mouse", C.text)
log("3. Click in world -> build starts", C.text)
log("Phases: place all -> color all -> material all", C.text)
log("Mesh conversion: " .. (convertMeshes and "ON" or "OFF") ..
" | voxel size=" .. tostring(meshVoxelSize) ..
" | max/mesh=" .. tostring(meshMaxParts), C.text)
end, function(err)
local msg = tostring(err) .. "\n" .. debug.traceback()
pcall(function() warn("[IMPORTER ERROR] " .. msg) end)
pcall(function()
local sg = Instance.new("ScreenGui")
sg.Name = "ImporterError"
sg.Parent = game:GetService("CoreGui")
local tf = Instance.new("TextLabel")
tf.Size = UDim2.new(0.6, 0, 0.6, 0)
tf.Position = UDim2.new(0.2, 0, 0.2, 0)
tf.BackgroundColor3 = Color3.fromRGB(20, 0, 0)
tf.TextColor3 = Color3.new(1, 1, 1)
tf.Text = "[IMPORTER ERROR]\n" .. msg
tf.Font = Enum.Font.Gotham
tf.TextSize = 12
tf.TextWrapped = true
tf.TextXAlignment = Enum.TextXAlignment.Left
tf.TextYAlignment = Enum.TextYAlignment.Top
tf.Parent = sg
end)
return msg
end)
if not _ok then
pcall(function() print("[IMPORTER] Script failed: " .. tostring(_err)) end)
endUSES INSERTSERVICE TO PLACE PARTS SO 100% GUARRENTED TO WORK ALSO WORKS WITH MESHES KINDA BUT VERY GOOD IT DOES MATERIAL COLOR AND SHAPE AND ONLY WORKS WITH 3D ASSETS FROM ROBLOX