Attacher - Weld Models with Attachments

Attacher allows you to quickly and easily weld one model to another using attachments. It also allows the ability to track attached models via CollectionService, so that when either model is removed, the corresponding model will be cleaned up (weld removed). I originally created this for a game where a custom tool and wearable system is used.

RobloxStudioBeta_s6BECtACms

Making models compatible with this system is easy. Simply create an attachment somewhere on both models, name them whatever you want, and that’s it.

Example

local Attachment = Attacher:Attach(MainModel.PrimaryPart, MainModel.MeshPart.AttachPoint, Character.Head, Character.Head:WaitForChild("HatAttach"));
print(Attachment.Part1, Attachment.Part2, Attachment.MainWeld)
Attachment:Destroy();

  • The first parameter, TargetPart1, is the part in the first model which will take the weld. In this case, PrimaryPart would be MainModel.MeshPart
  • Parameter 2 is the first attachment.
  • Parameter 3 is the part that will be used for welds in the second model.
  • Parameter 4 is the attachment in the second model. In this case, I made a custom attachment in the
    head named “HatAttach”

Model 1 will now be welded to Model 2.
if TRACK_ATTACHMENTS is set to true, if Model 1 is destroyed, Model 2 will have anything created by Attacher destroyed, and vice versa. It is recommended to keep this enabled.

Attach returns a table with a Destroy method, and three properties. Part1, Part2, and MainWeld

Module

--[[
	Voidage
	
	Attacher allows easy welding between two models via attachments.
	
	Example (Attach MainModel, a hat, to the head):
		local Attachment = Attacher:Attach(MainModel.PrimaryPart, MainModel.MeshPart.AttachPoint, Character.Head, Character.Head:WaitForChild("HatAttach"));
		print(Attachment.Part1, Attachment.Part2, Attachment.MainWeld)
		Attachment:Destroy();
	
	--
	TRACK_ATTACHMENTS help
	true: models which have been attached to each other will be tracked with collectionservice.
	when either model is destroyed, associated parts/welds with the other model will be destroyed.
]]--
local TRACK_ATTACHMENTS = true;


local CollectionService = game:GetService("CollectionService");

local WeldPart = Instance.new("Part");
WeldPart.Name = "WELDPART";
WeldPart.CanQuery = false;
WeldPart.CanCollide = false;
WeldPart.CanTouch = false;
WeldPart.Anchored = false;
WeldPart.Massless = true;
WeldPart.Size = Vector3.new(0.25, 0.25, 0.25);
WeldPart.Transparency = 1;

local Attacher = {};
Attacher.Attachments = {};

function Attacher:Clear(Part: any)
	if Part:FindFirstChild("WELDPART") ~= nil then
		if Part.WELDPART.Brother.Value ~= nil then
			Part.WELDPART.Brother.Value:Destroy();
		end
		Part.WELDPART:Destroy();
	end
	local intable = Attacher.Attachments[Part];
	if intable ~= nil then
		if intable[1] ~= nil then
			intable[1]:Destroy();
		end
		Attacher.Attachments[Part] = nil;
	end
end

function Attacher:Attach(TargetPart1: BasePart, Attach1: Attachment, TargetPart2: BasePart, Attach2: Attachment)
	if TargetPart1:FindFirstChild("WELDPART") ~= nil then
		Attacher:Clear(TargetPart1);
	end;
	
	local WeldPart1 = WeldPart:Clone();
	local WeldPart2 = WeldPart:Clone();
	
	WeldPart1.CFrame = Attach1.WorldCFrame;
	WeldPart2.CFrame = Attach2.WorldCFrame;
	
	local weld1 = Instance.new("WeldConstraint");
	weld1.Part0 = WeldPart1;
	weld1.Part1 = TargetPart1;
	weld1.Parent = WeldPart1;
	
	local weld2 = Instance.new("WeldConstraint");
	weld2.Part0 = WeldPart2;
	weld2.Part1 = TargetPart2;
	weld2.Parent = WeldPart2;
	
	local Weld1Brother = Instance.new("ObjectValue");
	Weld1Brother.Name = "Brother";
	Weld1Brother.Value = WeldPart2;
	Weld1Brother.Parent = WeldPart1;
	
	local Weld2Brother = Instance.new("ObjectValue");
	Weld2Brother.Name = "Brother";
	Weld2Brother.Value = WeldPart1;
	Weld2Brother.Parent = WeldPart2;
	
	WeldPart1.Parent = TargetPart1;
	WeldPart2.Parent = TargetPart2;
	
	WeldPart1.CFrame = Attach2.WorldCFrame;
	
	local Weld = Instance.new("WeldConstraint");
	Weld.Part0 = WeldPart1;
	Weld.Part1 = WeldPart2;
	Weld.Parent = WeldPart1;
	
	if TRACK_ATTACHMENTS then
		CollectionService:AddTag(TargetPart1, "AttacherTracked");
		CollectionService:AddTag(TargetPart2, "AttacherTracked");
		Attacher.Attachments[TargetPart1] = {WeldPart2};
		Attacher.Attachments[TargetPart2] = {WeldPart1};
	end
	
	local AttachTable = {Part1 = TargetPart1, Part2 = TargetPart2, MainWeld = Weld};
	
	function AttachTable:Destroy()
		if WeldPart1 ~= nil then WeldPart1:Destroy() end;
		if WeldPart2 ~= nil then WeldPart2:Destroy() end;
		if TRACK_ATTACHMENTS then
			Attacher:Clear(TargetPart1);
			Attacher:Clear(TargetPart2);
		end
	end
	
	return AttachTable;
end

-- Detect when tracked attachers are removed
if TRACK_ATTACHMENTS then
	CollectionService:GetInstanceRemovedSignal("AttacherTracked"):Connect(function(Model)
		Attacher:Clear(Model);
	end)
end

return Attacher;

update 1: made tracking more reliable with “brother” objectvalues for weldparts to work with collectionservice as well

5 Likes

You might wanna rename it to describe the module more, such as model attach.

1 Like