Sorry I don't know anything about this but maybe looking through this source code from a plugin can help( i didn't make this):
local plugin = PluginManager():CreatePlugin()
local button = plugin:CreateToolbar("GeomTools"):CreateButton("Transform","Freezes attachments for transformations","rbxassetid://606821411")
local mouse = plugin:GetMouse()
local function partMoved(p)
wait()
local part = p.Part
local originCFrame = p.OriginCFrame
local originSize = p.OriginSize
local newCFrame = part.CFrame
for _, a in pairs(p.Attachments) do
local attachment = a.Attachment
local attachmentOriginCFrame = CFrame.new(a.OriginalPosition) * CFrame.Angles(math.rad(a.OriginalRotation.X), math.rad(a.OriginalRotation.Y), math.rad(a.OriginalRotation.Z))
local correctedCFrame = newCFrame:toObjectSpace(originCFrame) * attachmentOriginCFrame
attachment.Position = correctedCFrame.p
local x, y, z = correctedCFrame:toEulerAnglesXYZ()
attachment.Rotation = Vector3.new(math.deg(x), math.deg(y), math.deg(z))
end
end
local parts = {}
local function tableContains(list, instance)
for _, v in pairs(list) do
if v == instance then
return true
end
end
return false
end
local function getAttachments(part)
local attachments = {}
for _, v in pairs(part:GetChildren()) do
if v:IsA("Attachment") then
table.insert(attachments, {Attachment = v, OriginalPosition = v.Position, OriginalRotation = v.Rotation})
end
end
return attachments
end
local function getParts(instanceList, partList, gottenParts)
partList = partList or {}
gottenParts = gottenParts or {}
for _, v in pairs(instanceList) do
if v:IsA("BasePart") and not tableContains(gottenParts, v) then
table.insert(gottenParts, v)
local part = {Part = v, OriginCFrame = v.CFrame, OriginSize = v.Size, Attachments = getAttachments(v)}
if #part.Attachments > 0 then
part.UpdateConnection = v.Changed:connect(function() partMoved(part) end)
table.insert(partList, part)
end
end
getParts(v:GetChildren(), partList, gottenParts)
end
return partList
end
local function disconnectUpdates()
for _, part in pairs(parts) do
part.UpdateConnection:disconnect()
end
parts = {}
end
local function updateSelection()
if active then
disconnectUpdates()
parts = getParts(game.Selection:Get())
end
end
game.Selection.SelectionChanged:connect(updateSelection)
mouse.KeyDown:connect(function(key)
if not active then
return
end
key = string.byte(string.lower(key))
if key == 27 then
active = false
button:SetActive(false)
end
end)
plugin.Deactivation:connect(function()
end)
button.Click:connect(function()
active = not active
local active2 = active
plugin:Activate(active)
active = active2
button:SetActive(active)
if active then
updateSelection()
warn("Freeze attachments plugin active. Transforming and resizing parts will not affect the absolute positions of their attachments.")
else
disconnectUpdates()
warn("Freeze attachments plugin disabled.")
end
end)