local v=require((game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):WaitForChild("\078\101\118\101\114\109\111\114\101"))local E=game:GetService("\067\111\108\108\101\099\116\105\111\110\083\101\114\118\105\099\101")local F=game:GetService("\087\111\114\107\115\112\097\099\101")local N=v("\066\111\117\110\100\105\110\103\066\111\120")local Q=v("\067\104\097\114\097\099\116\101\114\085\116\105\108")local c={}c.__index=c c.ClassName="\080\097\114\116\084\111\117\099\104\105\110\103\067\097\108\099\117\108\097\116\111\114"function c.new()local v=setmetatable({},c)return v end function c.CheckIfTouchingHumanoid(F,v,E)assert(v)assert(E,"\077\117\115\116 \104\097\118\101 \112\097\114\116\115")local N={}for v,E in pairs(v.Parent:GetDescendants())do if E:IsA("\066\097\115\101\080\097\114\116")then table.insert(N,E)end end if#N==0 then warn("\091\080\097\114\116\084\111\117\099\104\105\110\103\067\097\108\099\117\108\097\116\111\114\046\067\104\101\099\107\073\102\084\111\117\099\104\105\110\103\072\117\109\097\110\111\105\100\093 - \035\104\117\109\097\110\111\105\100\080\097\114\116\115 \061\061 \048\033")return false end local Q=F:GetCollidingPartFromParts(N)local c={}local l={CanCollide=true;Anchored=false}local V={}for v,E in pairs(E)do c[E]={}for v,F in pairs(l)do c[E][v]=E[v]E[v]=F end V[E]=true end local m=Q:GetTouchingParts()Q:Destroy()local p=false for v,E in pairs(m)do if V[E]then p=true break end end for v,E in pairs(c)do for E,F in pairs(E)do v[E]=F end end return p end function c.GetCollidingPartFromParts(c,v,E,Q)E=E or CFrame.new()local l,V=N.GetPartsBoundingBox(v,E)if Q then l=l+Vector3.new(Q,Q,Q)end local m=Instance.new("\080\097\114\116")m.Name="\067\111\108\108\105\115\105\111\110\068\101\116\101\099\116\105\111\110"m.Size=l m.CFrame=E+E:vectorToWorldSpace(V)m.Anchored=false m.CanCollide=true m.Parent=F return m end function c.GetTouchingBoundingBox(N,v,E,F)local Q=N:GetCollidingPartFromParts(v,E,F)local c=Q:GetTouchingParts()Q:Destroy()return c end function c.GetTouchingHull(F,v,E)local N={}for v,Q in pairs(v)do for v,E in pairs(F:GetTouching(Q,E))do N[E]=true end end local Q={}for v,E in pairs(N)do table.insert(Q,v)end return Q end function c.GetTouching(Q,v,N)N=N or 2 local c if v:IsA("\084\114\117\115\115\080\097\114\116")then c=Instance.new("\080\097\114\116")else c=v:Clone()for v,F in pairs(E:GetTags(c))do E:RemoveTag(c,F)end c:ClearAllChildren()end c.Size=v.Size+Vector3.new(N,N,N)c.CFrame=v.CFrame c.Anchored=false c.CanCollide=true c.Transparency=.1 c.Material=Enum.Material.SmoothPlastic c.Parent=F local l=c:GetTouchingParts()c:Destroy()return l end function c.GetTouchingHumanoids(E,v)local F={}for v,E in pairs(v)do local N=E.Parent:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if N then if not F[N]then local v=Q.GetPlayerFromCharacter(N)F[N]={Humanoid=N;Character=v and v.Character;Player=v,Touching={E}}else table.insert(F[N].Touching,E)end end end local N={}for v,E in pairs(F)do table.insert(N,E)end return N end return c
--- Determines if parts are touching or not
-- @classmod PartTouchingCalculator

local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

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

local BoundingBox = require("BoundingBox")
local CharacterUtil = require("CharacterUtil")

local PartTouchingCalculator = {}
PartTouchingCalculator.__index = PartTouchingCalculator
PartTouchingCalculator.ClassName = "PartTouchingCalculator"

function PartTouchingCalculator.new()
	local self = setmetatable({}, PartTouchingCalculator)

	return self
end

function PartTouchingCalculator:CheckIfTouchingHumanoid(humanoid, parts)
	assert(humanoid)
	assert(parts, "Must have parts")

	local humanoidParts = {}
	for _, item in pairs(humanoid.Parent:GetDescendants()) do
		if item:IsA("BasePart") then
			table.insert(humanoidParts, item)
		end
	end

	if #humanoidParts == 0 then
		warn("[PartTouchingCalculator.CheckIfTouchingHumanoid] - #humanoidParts == 0!")
		return false
	end

	local dummyPart = self:GetCollidingPartFromParts(humanoidParts)

	local previousProperties = {}
	local toSet = {
		CanCollide = true;
		Anchored = false;
	}
	local partSet = {}
	for _, part in pairs(parts) do
		previousProperties[part] = {}
		for name, value in pairs(toSet) do
			previousProperties[part][name] = part[name]
			part[name] = value
		end
		partSet[part] = true
	end

	local touching = dummyPart:GetTouchingParts()
	dummyPart:Destroy()

	local returnValue = false

	for _, part in pairs(touching) do
		if partSet[part] then
			returnValue = true
			break
		end
	end

	for part, properties in pairs(previousProperties) do
		for name, value in pairs(properties) do
			part[name] = value
		end
	end

	return returnValue
end

function PartTouchingCalculator:GetCollidingPartFromParts(parts, relativeTo, padding)
	relativeTo = relativeTo or CFrame.new()

	local size, position = BoundingBox.GetPartsBoundingBox(parts, relativeTo)

	if padding then
		size = size + Vector3.new(padding, padding, padding)
	end

	local dummyPart = Instance.new("Part")
	dummyPart.Name = "CollisionDetection"
	dummyPart.Size = size
	dummyPart.CFrame = relativeTo + relativeTo:vectorToWorldSpace(position)
	dummyPart.Anchored = false
	dummyPart.CanCollide = true
	dummyPart.Parent = Workspace

	return dummyPart
end

function PartTouchingCalculator:GetTouchingBoundingBox(parts, relativeTo, padding)
	local dummy = self:GetCollidingPartFromParts(parts, relativeTo, padding)
	local touching = dummy:GetTouchingParts()
	dummy:Destroy()

	return touching
end

--- Expensive hull check on a list of parts (aggregating each parts touching list)
function PartTouchingCalculator:GetTouchingHull(parts, padding)
	local hitParts = {}

	for _, part in pairs(parts) do
		for _, TouchingPart in pairs(self:GetTouching(part, padding)) do
			hitParts[TouchingPart] = true
		end
	end

	local touching = {}
	for part, _ in pairs(hitParts) do
		table.insert(touching, part)
	end

	return touching
end

--- Retrieves parts touching a base part
-- @param basePart item to identify touching. Geometry matters
-- @param padding studs of padding around the part
function PartTouchingCalculator:GetTouching(basePart, padding)
	padding = padding or 2
	local part

	if basePart:IsA("TrussPart") then
		-- Truss parts can't be resized
		part = Instance.new("Part")
	else
		-- Clone part
		part = basePart:Clone()

		-- Remove all tags
		for _, tag in pairs(CollectionService:GetTags(part)) do
			CollectionService:RemoveTag(part, tag)
		end

		part:ClearAllChildren()
	end

	part.Size = basePart.Size + Vector3.new(padding, padding, padding)
	part.CFrame = basePart.CFrame
	part.Anchored = false
	part.CanCollide = true
	part.Transparency = 0.1
	part.Material = Enum.Material.SmoothPlastic
	part.Parent = Workspace

	local touching = part:GetTouchingParts()
	part:Destroy()

	return touching
end

function PartTouchingCalculator:GetTouchingHumanoids(touchingList)
	local touchingHumanoids = {}

	for _, part in pairs(touchingList) do
		local humanoid = part.Parent:FindFirstChildOfClass("Humanoid")
		if humanoid then
			if not touchingHumanoids[humanoid] then
				local player = CharacterUtil.GetPlayerFromCharacter(humanoid)
				touchingHumanoids[humanoid] = {
					Humanoid = humanoid;
					Character = player and player.Character; -- May be nil
					Player = player; -- May be nil
					Touching = { part };
				}
			else
				table.insert(touchingHumanoids[humanoid].Touching, part)
			end
		end
	end

	local list = {}
	for _, data in pairs(touchingHumanoids) do
		table.insert(list, data)
	end

	return list
end

return PartTouchingCalculator