local function B(B)if B.Magnitude==0 then return Vector3.zero end return B.Unit end local function G(G,R,p)local r=G:pointToObjectSpace(p)local c,j,y=R.x,R.y,R.z local W,l,a=r.x,r.y,r.z local Y=math.clamp(W,-c*.5,c*.5)local f=math.clamp(l,-j*.5,j*.5)local H=math.clamp(a,-y*.5,y*.5)if not(Y==W and(f==l and H==a))then local R=G*Vector3.new(Y,f,H)local r=B(p-R)return false,R,r end local q=W-c*.5 local N=l-j*.5 local Z=a-y*.5 local J=-W-c*.5 local S=-l-j*.5 local T=-a-y*.5 local i=math.max(q,N,Z,J,S,T)if i==q then local B=G*Vector3.new(c*.5,l,a)return true,B,G.XVector elseif i==N then local B=G*Vector3.new(W,j*.5,a)return true,B,G.YVector elseif i==Z then local B=G*Vector3.new(W,l,y*.5)return true,B,G.ZVector elseif i==J then local B=G*Vector3.new(-c*.5,l,a)return true,B,-G.XVector elseif i==S then local B=G*Vector3.new(W,-j*.5,a)return true,B,-G.YVector elseif i==T then local B=G*Vector3.new(W,l,-y*.5)return true,B,-G.ZVector end warn("\067\076\079\083\069\083\084 \080\079\073\078\084 \079\078 \066\079\088 \070\065\073\076")return false,G.Position,Vector3.zero end return function(B,R,p,r)debug.profilebegin("\066\111\120 \084\101\115\116\105\110\103")local c,j,y=G(B,R,p)if c then return c,j,y end local W=(j-p).Magnitude c=W<r debug.profileend()return c,j,y end
local function SafeUnit(v3)
	if v3.Magnitude == 0 then
		return Vector3.zero
	end

	return v3.Unit
end

local function ClosestPointFunc(cframe, size, point)
	local rel = cframe:pointToObjectSpace(point)
	local sx, sy, sz = size.x, size.y, size.z
	local rx, ry, rz = rel.x, rel.y, rel.z

	-- constrain to within the box
	local cx = math.clamp(rx, -sx * 0.5, sx * 0.5)
	local cy = math.clamp(ry, -sy * 0.5, sy * 0.5)
	local cz = math.clamp(rz, -sz * 0.5, sz * 0.5)

	if not (cx == rx and cy == ry and cz == rz) then
		local closestPoint = cframe * Vector3.new(cx, cy, cz)
		local normal = SafeUnit(point - closestPoint)
		return false, closestPoint, normal
	end

	-- else, they are intersecting, find the surface the point is closest to

	local posX = rx - sx * 0.5
	local posY = ry - sy * 0.5
	local posZ = rz - sz * 0.5
	local negX = -rx - sx * 0.5
	local negY = -ry - sy * 0.5
	local negZ = -rz - sz * 0.5

	local max = math.max(posX, posY, posZ, negX, negY, negZ)
	if max == posX then
		local closestPoint = cframe * Vector3.new(sx * 0.5, ry, rz)
		return true, closestPoint, cframe.XVector
	elseif max == posY then
		local closestPoint = cframe * Vector3.new(rx, sy * 0.5, rz)
		return true, closestPoint, cframe.YVector
	elseif max == posZ then
		local closestPoint = cframe * Vector3.new(rx, ry, sz * 0.5)
		return true, closestPoint, cframe.ZVector
	elseif max == negX then
		local closestPoint = cframe * Vector3.new(-sx * 0.5, ry, rz)
		return true, closestPoint, -cframe.XVector
	elseif max == negY then
		local closestPoint = cframe * Vector3.new(rx, -sy * 0.5, rz)
		return true, closestPoint, -cframe.YVector
	elseif max == negZ then
		local closestPoint = cframe * Vector3.new(rx, ry, -sz * 0.5)
		return true, closestPoint, -cframe.ZVector
	end

	-- Shouldnt reach
	warn("CLOSEST POINT ON BOX FAIL")
	return false, cframe.Position, Vector3.zero
end

return function(BoxCFrame, BoxSize, Point, Radius) -- Sphere vs Box
	debug.profilebegin("Box Testing")
	local IsInside, ClosestPoint, Normal = ClosestPointFunc(BoxCFrame, BoxSize, Point)

	if IsInside then
		return IsInside, ClosestPoint, Normal
	end

	local DistanceToCp = (ClosestPoint - Point).Magnitude

	IsInside = (DistanceToCp < Radius)
	debug.profileend()
	return IsInside, ClosestPoint, Normal
end
