local B={}local i={}i.__index=i function i.__tostring(B)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",B.object.Name,B.object.ClassName)end function B.new(B)return setmetatable({},i)end function i.config(e,B,i)e.active=false e.deleted=false e.partMode=false e.debugMode=false e.points={}e.targetsHit={}e.endTime=0 e.OnHit=Signal:Create()e.OnUpdate=Signal:Create()e.raycastParams=RaycastParams.new()e.raycastParams.FilterType=Enum.RaycastFilterType.Blacklist e.raycastParams.FilterDescendantsInstances=i or{}e.object=B CollectionService:AddTag(e.object,"\082\097\121\099\097\115\116\077\111\100\117\108\101\077\097\110\097\103\101\100")end function i.SetPoints(u,B,i,e)if B and(B:IsA("\066\097\115\101\080\097\114\116")or B:IsA("\077\101\115\104\080\097\114\116")or B:IsA("\065\116\116\097\099\104\109\101\110\116"))then for i,F in ipairs(i)do if typeof(F)=="\086\101\099\116\111\114\051"then local i={IsAttachment=B:IsA("\065\116\116\097\099\104\109\101\110\116"),RelativePart=B;Attachment=F;LastPosition=nil,group=e,solver=CastVectorPoint}table.insert(u.points,i)end end end end function i.RemovePoints(e,B,i)if B then if B:IsA("\066\097\115\101\080\097\114\116")or B:IsA("\077\101\115\104\080\097\114\116")then for u=1,#e.points,1 do local F=e.points[u]for i,k in ipairs(i)do if typeof(F.Attachment)=="\086\101\099\116\111\114\051"and(F.Attachment==k and F.RelativePart==B)then e.points[u]=nil end end end end end end function i.LinkAttachments(e,B,i)if B:IsA("\065\116\116\097\099\104\109\101\110\116")and i:IsA("\065\116\116\097\099\104\109\101\110\116")then local u=B:FindFirstChild("\071\114\111\117\112")local F={RelativePart=nil,Attachment=B;Attachment0=i,LastPosition=nil;group=u and u.Value;solver=CastLinkAttach}table.insert(e.points,F)end end function i.UnlinkAttachments(i,B)for e,u in ipairs(i.points)do if u.Attachment and u.Attachment==B then table.remove(i.points,e)break end end end function i.seekAttachments(e,B,i)if#e.points<=0 then table.insert(e.raycastParams.FilterDescendantsInstances,workspace.Terrain)end for i,u in ipairs(e.object:GetDescendants())do if u:IsA("\065\116\116\097\099\104\109\101\110\116")and u.Name==B then local B=u:FindFirstChild("\071\114\111\117\112")local i={Attachment=u;RelativePart=nil;LastPosition=nil;group=B and B.Value,solver=CastAttachment}table.insert(e.points,i)end end if i then if#e.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",B,e.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",e.object.Name,#e.points))end end end function i.Destroy(B)if B.deleted then return end if B.OnHit then B.OnHit:Delete()end if B.OnUpdate then B.OnUpdate:Delete()end B.points=nil B.active=false B.deleted=true end function i.HitStart(i,B)i.active=true if B then assert(type(B)=="\110\117\109\098\101\114","\065\114\103\117\109\101\110\116 \035\049 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114\033")local e=.016666666666667 if B<=e or B==math.huge then B=e end i.endTime=clock()+B end end function i.HitStop(B)if B.deleted then return end B.active=false B.endTime=0 table.clear(B.targetsHit)end function i.PartMode(i,B)i.partMode=B end function i.DebugMode(i,B)i.debugMode=B end return B
--------
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.endTime = 0
	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") or object:IsA("Attachment")) then
		for _, vectors in ipairs(vectorPoints) do
			if typeof(vectors) == "Vector3" then
				local Point = {
					IsAttachment = object:IsA("Attachment"),
					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(seconds)
	self.active = true

	if seconds then
		assert(type(seconds) == "number", "Argument #1 must be a number!")

		local minSeconds = 1 / 60 --- Seconds cannot be under 1/60th

		if seconds <= minSeconds or seconds == math.huge then
			seconds = minSeconds
		end

		self.endTime = clock() + seconds
	end
end

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

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

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

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

return HitboxObject
