CollarHandler:
local events = game.ReplicatedStorage:WaitForChild("RemoteEvents")

local function GiveCollarGetAttachment(player)
	local char = player.Character

	local g = script.Collar:clone()
	g.Parent = char
	local C = g:GetChildren()
	for i=1, #C do
		if C[i]:IsA("BasePart") then
			local W = Instance.new("Weld")
			W.Part0 = g.Middle
			W.Part1 = C[i]
			local CJ = CFrame.new(g.Middle.Position)
			local C0 = g.Middle.CFrame:inverse() * CJ
			local C1 = C[i].CFrame:inverse() * CJ
			W.C0 = C0
			W.C1 = C1
			W.Parent = g.Middle
		end
		local Y = Instance.new("Weld")
		Y.Part0 = char.Head
		Y.Part1 = g.Middle
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0
	end

	local h = g:GetChildren()
	for i = 1, #h do
		if h[i]:IsA("BasePart") then
			h[i].Anchored = false
			h[i].CanCollide = false
		end
	end

	return g.AttachmentPart.Attachment
end

local function AddAttachmentToArm(player)
	local char = player.Character
	local newAttachment = Instance.new("Attachment")
	newAttachment.Position = Vector3.new(0, -1, 0)
	newAttachment.Parent = char["Right Arm"]

	return newAttachment
end

local function MakeLeash(Attachment0, Attachment1)
	local newRopeRenderer = script.RopeRenderer:Clone()
	newRopeRenderer.DrawLocalLine.Attachment0.Value = Attachment0
	newRopeRenderer.DrawLocalLine.Attachment1.Value = Attachment1
	newRopeRenderer.Parent = workspace
	newRopeRenderer.Enabled = true

	return newRopeRenderer
end

local function AddPlayerController(victim, owner)
	local newPlayerController = script.PlayerController:Clone()
	newPlayerController.Owner.Value = owner.Character
	newPlayerController.Parent = victim.PlayerGui
	newPlayerController.Enabled = true
end

local function AddCollarRemover(victim, owner)
	local newRemover = script.CollarRemover:Clone()
	newRemover.Victim.Value = victim
	newRemover.Owner.Value = owner
	newRemover.Parent = workspace
	newRemover.Enabled = true
end

local function MakeCollar(owner, victim)
	local attachment0 = GiveCollarGetAttachment(victim)
	local attachment1 = AddAttachmentToArm(owner)
	local newRope = MakeLeash(attachment0, attachment1)

	AddPlayerController(victim, owner)
	AddCollarRemover(victim, owner)
end

events.SendCollarRequest.OnServerEvent:Connect(function(player, target)
	events.ActivateLocalCollarUI:FireClient(target, player.Name)
end)

events.CollarPlayer.OnServerEvent:Connect(function(victim, owner)
	MakeCollar(owner, victim)
	events.CreateCollarObjectEvent:FireClient(victim, owner.Name)
	events.CreateCollarObjectEvent:FireClient(owner, victim.Name)
end)



CollarRemover(parented to CollarHandler):
local victim = script.Victim.Value
local owner = script.Owner.Value

function RemoveCollar()
	print("Removing collar")
	game.ReplicatedStorage.RemoteEvents.RemoveCollar:FireClient(victim)
	game.ReplicatedStorage.RemoteEvents.RemoveCollar:FireClient(owner)
	if victim.Character then
		victim.Character.Collar:Destroy()
	end
	script:Destroy()
	game.ReplicatedStorage.RemoteEvents.DestroyCollarObjectEvent:FireClient(victim, owner.Name)
	game.ReplicatedStorage.RemoteEvents.DestroyCollarObjectEvent:FireClient(owner, victim.Name)
end

victim.Character.Humanoid.Died:Connect(RemoveCollar)
owner.Character.Humanoid.Died:Connect(RemoveCollar)

victim.CharacterRemoving:Connect(RemoveCollar)
owner.CharacterRemoving:Connect(RemoveCollar)

game.ReplicatedStorage.RemoteEvents.RemoveCollar.OnServerEvent:Connect(function(player, target)
	if (player == victim or player == owner) and (target == victim or target == owner) then
		RemoveCollar()
	end
end)

RopeRenderer(also parented to CollarHandler):
local replicatedScripts = {}
local JoinReplicateConnection

function StartCurveReplication()
	JoinReplicateConnection = game.Players.PlayerAdded:Connect(function(player)
		coroutine.resume(coroutine.create(function()
			local replicatedCurve = script.DrawLocalLine:Clone()
			replicatedCurve.Parent = player.PlayerGui
			table.insert(replicatedScripts, replicatedCurve)
			replicatedCurve.Disabled = false
		end))
	end)

	for _, player in pairs(game.Players:GetPlayers()) do
		coroutine.resume(coroutine.create(function()
			local replicatedCurve = script.DrawLocalLine:Clone()
			replicatedCurve.Parent = player.PlayerGui
			table.insert(replicatedScripts, replicatedCurve)
			replicatedCurve.Disabled = false
		end))
	end
end

StartCurveReplication()

game.ReplicatedStorage.RemoteEvents.RemoveCollar.OnServerEvent:Connect(function(player)
	game.ReplicatedStorage.RemoteEvents.RemoveCollar:FireAllClients(player.Name)
end)

DrawLocalLine(parented to RopeRenderer):
local localPlayer = game.Players.LocalPlayer
local RemoveCollarEvent = game.ReplicatedStorage.RemoteEvents.RemoveCollar
local RopeModule = require(game.ReplicatedStorage:WaitForChild("RopeModule"))

local attachment0 = script:WaitForChild("Attachment0").Value
local attachment1 = script:WaitForChild("Attachment1").Value
local segments = 10
local pull = workspace.Gravity / (20.00611807 * 5)
local width = 0.1
local container = workspace

local currentRope = RopeModule.new(attachment0, attachment1, segments, pull, width, container)

RemoveCollarEvent.OnClientEvent:Connect(function(playerName)
	if localPlayer.Name == playerName and currentRope then
		currentRope:RemoveRope()
		currentRope = nil
	end
end)

RopeModule(in Replicated Storage):
local Rope = {}
Rope.__index = Rope

local RunService = game:GetService("RunService")

function Rope.new(attachment0, attachment1, segments, pull, width, container)
	local self = setmetatable({}, Rope)
	self.attachment0 = attachment0
	self.attachment1 = attachment1
	self.segments = segments
	self.pull = pull
	self.width = width
	self.lineSegments = {}
	self.firstLineDrawn = false
	self.container = container or workspace
	self.updateConnection = RunService.RenderStepped:Connect(function() self:DrawCatenary() end)
	return self
end

function Rope:DrawLineSegment(p1, p2, i)
	local distance = (p1 - p2).magnitude
	if self.firstLineDrawn then
		self.lineSegments[i].Size = Vector3.new(distance, self.width, self.width)
		self.lineSegments[i].CFrame = CFrame.new(p1, p2) * CFrame.new(0, 0, -distance / 2) * CFrame.Angles(0, math.rad(90), 0)
	else
		local line = Instance.new("Part")
		line.Name = "LineSegment"
		line.BrickColor = BrickColor.new("Really black")
		line.Material = "SmoothPlastic"
		line.Transparency = 0
		line.Anchored = true
		line.CanCollide = false
		line.Shape = Enum.PartType.Cylinder
		line.TopSurface = Enum.SurfaceType.Smooth
		line.BottomSurface = Enum.SurfaceType.Smooth
		line.Size = Vector3.new(distance, self.width, self.width)
		line.CFrame = CFrame.new(p1, p2) * CFrame.new(0, 0, -distance / 2) * CFrame.Angles(0, math.rad(90), 0)
		table.insert(self.lineSegments, line)
		line.Parent = self.container
	end
end

function Rope:DrawCatenary()
	if not self.attachment0 or not self.attachment1 then
		self:RemoveRope()
		return
	end

	local p1 = self.attachment0.WorldPosition
	local p2 = self.attachment1.WorldPosition
	for i = 1, self.segments do
		local x = (((i - 1) * 2) / self.segments) - 1
		local x2 = ((i * 2) / self.segments) - 1
		self:DrawLineSegment(
			p1 + ((p2 - p1) / self.segments * (i - 1)) + Vector3.new(0, (((math.cosh(x) - 1) / (math.cosh(1) - 1)) - 1) * self.pull, 0),
			p1 + ((p2 - p1) / self.segments * i) + Vector3.new(0, (((math.cosh(x2) - 1) / (math.cosh(1) - 1)) - 1) * self.pull, 0),
			i
		)
	end
	self.firstLineDrawn = true
end

function Rope:RemoveRope()
	if self.updateConnection then
		self.updateConnection:Disconnect()
	end
	for _, segment in ipairs(self.lineSegments) do
		segment:Destroy()
	end
	self.lineSegments = {}
end

return Rope


imagine Player1 and Player2. Player1 is collaring Player2 and he is the one collared by Player1. If any of them try and remove the collar, from their point of view, all leashes (LineSegment) parts get deleted. however, this isn't the case for other players, who only see the Player1 and Player2 leash deleted.