local function B(B)if B.Magnitude==0 then return Vector3.zero end return B.Unit end local function G(B,G,R,p)local r=p-B local c=r:Dot(G)c=math.clamp(c,-R,R)return B+G*c,c end local function R(B,G,R)local p=R-B local r=p:Dot(G)local c=R-r*G return c end local function p(p,r,c)local j=(r.Y<r.Z and r.Y or r.Z)*.5 local y=r.X*.5 local W,l=G(p.Position,p.RightVector,y,c)local a=p.Position+-p.RightVector*y local Y=p.Position+p.RightVector*y local f=-p.RightVector local H=p.RightVector local q=R(a,f,c)local N=R(Y,H,c)local function Z(G,R)local p=B(G-R)local r=(G-R).Magnitude return R+p*(r<j and r or j)end q=Z(q,a)N=Z(N,Y)local J=(W-c).Magnitude local S=B(c-W)local T=J<=j local i=W+S*j local g=(N-c).Magnitude local u=(q-c).Magnitude local t=(i-c).Magnitude local O=math.min(g,u,t)if l==y or O==g then local G=(B(c-N)):Dot(H)return G<0,N,H elseif l==-y or O==u then local G=(B(c-q)):Dot(f)return G<0,q,f end return T,i,S end return function(B,G,R,r)debug.profilebegin("\067\121\108\105\110\100\101\114 \084\101\115\116\105\110\103")local c,j,y=p(B,G,R)if c then return c,j,y end local W=(j-R).Magnitude c=W<r debug.profileend()return c,j,y end
--!native
local function SafeUnit(v3)
	if v3.Magnitude == 0 then
		return Vector3.zero
	end

	return v3.Unit
end

local function solve(p0, d0, len, p1)
	local v = p1 - p0
	local k = v:Dot(d0)
	k = math.clamp(k, -len, len)
	return p0 + d0 * k, k
end

local function ProjectOnPlane(pos, normal, point)
	local d = point - pos
	local v_dot = d:Dot(normal)
	local v = point - v_dot * normal

	return v
end

local function ClosestPointFunc(cframe, size, point)
	local radius = (size.Y < size.Z and size.Y or size.Z) * 0.5
	local length = size.X * 0.5
	local l0, k = solve(cframe.Position, cframe.RightVector, length, point)

	local endPlane = cframe.Position + -cframe.RightVector * length
	local topPlane = cframe.Position + cframe.RightVector * length

	local endPlaneN = -cframe.RightVector
	local topPlaneN = cframe.RightVector

	local projEnd = ProjectOnPlane(endPlane, endPlaneN, point)
	local projTop = ProjectOnPlane(topPlane, topPlaneN, point)

	local function GetFinalProj(proj, o)
		local projDir = SafeUnit(proj - o)
		local projDistance = (proj - o).Magnitude
		return o + projDir * (projDistance < radius and projDistance or radius)
	end

	projEnd = GetFinalProj(projEnd, endPlane)
	projTop = GetFinalProj(projTop, topPlane)

	local radiusDistance = (l0 - point).Magnitude
	local radiusNormal = SafeUnit(point - l0)
	local radiusInside = (radiusDistance <= radius)
	local radiusPosition = l0 + (radiusNormal * radius)

	local d0 = (projTop - point).Magnitude
	local d1 = (projEnd - point).Magnitude
	local d2 = (radiusPosition - point).Magnitude

	local d = math.min(d0, d1, d2)

	if k == length or d == d0 then
		local dot = SafeUnit(point - projTop):Dot(topPlaneN)
		return dot < 0, projTop, topPlaneN
	elseif k == -length or d == d1 then
		local dot = SafeUnit(point - projEnd):Dot(endPlaneN)
		return dot < 0, projEnd, endPlaneN
	end

	return radiusInside, radiusPosition, radiusNormal
end

return function(CylinderCFrame, CylinderSize, Point, Radius) -- IsInside, PushPosition, PushNormal
	debug.profilebegin("Cylinder Testing")
	local IsInside, PushPosition, PushNormal = ClosestPointFunc(CylinderCFrame, CylinderSize, Point)

	if IsInside then
		return IsInside, PushPosition, PushNormal
	end

	local PointDistance = (PushPosition - Point).Magnitude

	IsInside = PointDistance < Radius
	debug.profileend()
	return IsInside, PushPosition, PushNormal
end
