local f={}local S={}S.__index=S function S.__tostring(f)return string.format("\072\105\116\098\111\120 \102\111\114 \105\110\115\116\097\110\099\101 \037\115 \091\037\115\093",f.object.Name,f.object.ClassName)end function f.new(f)return setmetatable({},S)end function S.config(m,f,S)m.active=false m.deleted=false m.partMode=false m.debugMode=false m.points={}m.targetsHit={}m.OnHit=Signal:Create()m.OnUpdate=Signal:Create()m.raycastParams=RaycastParams.new()m.raycastParams.FilterType=Enum.RaycastFilterType.Blacklist m.raycastParams.FilterDescendantsInstances=S or{}m.object=f CollectionService:AddTag(m.object,"\082\097\121\099\097\115\116\077\111\100\117\108\101\077\097\110\097\103\101\100")end function S.SetPoints(x,f,S,m)if f and(f:IsA("\066\097\115\101\080\097\114\116")or f:IsA("\077\101\115\104\080\097\114\116"))then for S,s in ipairs(S)do if typeof(s)=="\086\101\099\116\111\114\051"then local S={RelativePart=f,Attachment=s;LastPosition=nil;group=m,solver=CastVectorPoint}table.insert(x.points,S)end end end end function S.RemovePoints(m,f,S)if f then if f:IsA("\066\097\115\101\080\097\114\116")or f:IsA("\077\101\115\104\080\097\114\116")then for x=1,#m.points,1 do local s=m.points[x]for S,H in ipairs(S)do if typeof(s.Attachment)=="\086\101\099\116\111\114\051"and(s.Attachment==H and s.RelativePart==f)then m.points[x]=nil end end end end end end function S.LinkAttachments(m,f,S)if f:IsA("\065\116\116\097\099\104\109\101\110\116")and S:IsA("\065\116\116\097\099\104\109\101\110\116")then local x=f:FindFirstChild("\071\114\111\117\112")local s={RelativePart=nil;Attachment=f;Attachment0=S,LastPosition=nil;group=x and x.Value,solver=CastLinkAttach}table.insert(m.points,s)end end function S.UnlinkAttachments(S,f)for m,x in ipairs(S.points)do if x.Attachment and x.Attachment==f then table.remove(S.points,m)break end end end function S.seekAttachments(m,f,S)if#m.points<=0 then table.insert(m.raycastParams.FilterDescendantsInstances,workspace.Terrain)end for S,x in ipairs(m.object:GetDescendants())do if x:IsA("\065\116\116\097\099\104\109\101\110\116")and x.Name==f then local f=x:FindFirstChild("\071\114\111\117\112")local S={Attachment=x,RelativePart=nil,LastPosition=nil,group=f and f.Value,solver=CastAttachment}table.insert(m.points,S)end end if S then if#m.points<=0 then warn(string.format("\n\091\091\082\065\089\067\065\083\084 \087\065\082\078\073\078\071\093\093\n\078\111 \097\116\116\097\099\104\109\101\110\116\115 \119\105\116\104 \116\104\101 \110\097\109\101 \'\037\115\' \119\101\114\101 \102\111\117\110\100 \105\110 \037\115\046 \078\111 \114\097\121\099\097\115\116\115 \119\105\108\108 \098\101 \100\114\097\119\110\046 \067\097\110 \098\101 \105\103\110\111\114\101\100 \105\102 \121\111\117 \097\114\101 \117\115\105\110\103 \083\101\116\080\111\105\110\116\115\046",f,m.object.Name))else print(string.format("\n\091\091\082\065\089\067\065\083\084 \077\069\083\083\065\071\069\093\093\n\n\067\114\101\097\116\101\100 \072\105\116\098\111\120 \102\111\114 \037\115 - \065\116\116\097\099\104\109\101\110\116\115 \102\111\117\110\100\058 \037\115",m.object.Name,#m.points))end end end function S.Destroy(f)if f.deleted then return end if f.OnHit then f.OnHit:Delete()end if f.OnUpdate then f.OnUpdate:Delete()end f.points=nil f.active=false f.deleted=true end function S.HitStart(f)f.active=true end function S.HitStop(f)if f.deleted then return end f.active=false table.clear(f.targetsHit)end function S.PartMode(S,f)S.partMode=f end function S.DebugMode(S,f)S.debugMode=f end return f
--------
local HitboxObject = {}
local Hitbox = {}
Hitbox.__index = Hitbox

function Hitbox:__tostring()
	return string.format("Hitbox for instance %s [%s]", self.object.Name, self.object.ClassName)
end

function HitboxObject:new()
	return setmetatable({}, Hitbox)
end

function Hitbox:config(object, ignoreList)
	self.active = false
	self.deleted = false
	self.partMode = false
	self.debugMode = false
	self.points = {}
	self.targetsHit = {}
	self.OnHit = Signal:Create()
	self.OnUpdate = Signal:Create()
	self.raycastParams = RaycastParams.new()
	self.raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	self.raycastParams.FilterDescendantsInstances = ignoreList or {}

	self.object = object
	CollectionService:AddTag(self.object, "RaycastModuleManaged")
end

function Hitbox:SetPoints(object, vectorPoints, groupName)
	if object and (object:IsA("BasePart") or object:IsA("MeshPart")) then
		for _, vectors in ipairs(vectorPoints) do
			if typeof(vectors) == "Vector3" then
				local Point = {
					RelativePart = object,
					Attachment = vectors,
					LastPosition = nil,
					group = groupName,
					solver = CastVectorPoint,
				}
				table.insert(self.points, Point)
			end
		end
	end
end

function Hitbox:RemovePoints(object, vectorPoints)
	if object then
		if object:IsA("BasePart") or object:IsA("MeshPart") then --- for some reason it doesn't recognize meshparts unless I add it in
			for i = 1, #self.points do
				local Point = self.points[i]
				for _, vectors in ipairs(vectorPoints) do
					if
						typeof(Point.Attachment) == "Vector3"
						and Point.Attachment == vectors
						and Point.RelativePart == object
					then
						self.points[i] = nil
					end
				end
			end
		end
	end
end

function Hitbox:LinkAttachments(primaryAttachment, secondaryAttachment)
	if primaryAttachment:IsA("Attachment") and secondaryAttachment:IsA("Attachment") then
		local group = primaryAttachment:FindFirstChild("Group")
		local Point = {
			RelativePart = nil,
			Attachment = primaryAttachment,
			Attachment0 = secondaryAttachment,
			LastPosition = nil,
			group = group and group.Value,
			solver = CastLinkAttach,
		}
		table.insert(self.points, Point)
	end
end

function Hitbox:UnlinkAttachments(primaryAttachment)
	for i, Point in ipairs(self.points) do
		if Point.Attachment and Point.Attachment == primaryAttachment then
			table.remove(self.points, i)
			break
		end
	end
end

function Hitbox:seekAttachments(attachmentName, canWarn)
	if #self.points <= 0 then
		table.insert(self.raycastParams.FilterDescendantsInstances, workspace.Terrain)
	end
	for _, attachment in ipairs(self.object:GetDescendants()) do
		if attachment:IsA("Attachment") and attachment.Name == attachmentName then
			local group = attachment:FindFirstChild("Group")
			local Point = {
				Attachment = attachment,
				RelativePart = nil,
				LastPosition = nil,
				group = group and group.Value,
				solver = CastAttachment,
			}
			table.insert(self.points, Point)
		end
	end

	if canWarn then
		if #self.points <= 0 then
			warn(
				string.format(
					"\n[[RAYCAST WARNING]]\nNo attachments with the name '%s' were found in %s. No raycasts will be drawn. Can be ignored if you are using SetPoints.",
					attachmentName,
					self.object.Name
				)
			)
		else
			print(
				string.format(
					"\n[[RAYCAST MESSAGE]]\n\nCreated Hitbox for %s - Attachments found: %s",
					self.object.Name,
					#self.points
				)
			)
		end
	end
end

function Hitbox:Destroy()
	if self.deleted then
		return
	end
	if self.OnHit then
		self.OnHit:Delete()
	end
	if self.OnUpdate then
		self.OnUpdate:Delete()
	end

	self.points = nil
	self.active = false
	self.deleted = true
end

function Hitbox:HitStart()
	self.active = true
end

function Hitbox:HitStop()
	if self.deleted then
		return
	end

	self.active = false
	table.clear(self.targetsHit)
end

function Hitbox:PartMode(bool)
	self.partMode = bool
end

function Hitbox:DebugMode(bool)
	self.debugMode = bool
end

return HitboxObject
