local function G(G,M,t,m)local D=M:Cross(m)local n=t.x-G.x local E=t.y-G.y local P=t.z-G.z local q=Det3x3(M.x,-m.x,D.x,M.y,-m.y,D.y,M.z,-m.z,D.z)if q==0 then return ZERO_VECTOR3 end local c=Det3x3(n,-m.x,D.x,E,-m.y,D.y,P,-m.z,D.z)/q local x=Det3x3(M.x,n,D.x,M.y,E,D.y,M.z,P,D.z)/q local F=G+c*M local o=t+x*m local b=F+.5*(o-F)if(o-F).Magnitude<.25 then return b else return ZERO_VECTOR3 end end local function M(M)local t=TorsoPart.CFrame.upVector.unit local m=TorsoPart.CFrame.rightVector.unit M[#M+1]=TorsoPart.CFrame.p M[#M+1]=TorsoPart.CFrame.p+t M[#M+1]=TorsoPart.CFrame.p-t M[#M+1]=TorsoPart.CFrame.p+m M[#M+1]=TorsoPart.CFrame.p-m if HeadPart then M[#M+1]=HeadPart.CFrame.p end local D=Camera.CFrame-Camera.CFrame.p local n=Vector3_new(0,.5,0)+(TorsoPart and TorsoPart.Position or HumanoidRootPart.Position)local E=2.5 for t=1,SMART_CIRCLE_CASTS,1 do local m=SMART_CIRCLE_INCREMENT*t-.5*math.pi local P=E*Vector3_new(math_cos(m),math_sin(m),0)local q=n+D*P local c=q-Camera.CFrame.p local x=Ray.new(n,q-n)local F,o,b=game.Workspace:FindPartOnRayWithIgnoreList(x,{Character},false,false)local h=q if F then local M=o+.1*b.unit local t=M-n local m=t.magnitude local D=(t:Cross(c)).unit local E=(D:Cross(b)).unit local P=(M-Camera.CFrame.p).unit if t.unit:Dot(-E)<t.unit:Dot(P)then h=G(M,E,q,c)if h.Magnitude>0 then local G=Ray.new(M,h-M)local t,m,D=game.Workspace:FindPartOnRayWithIgnoreList(G,{Character},false,false)if t then local G=m+.1*D.unit h=G end else h=M end else h=M end local x=Ray.new(n,h-n)local F,L,W=game.Workspace:FindPartOnRayWithIgnoreList(x,{Character},false,false)if F then local G=L-.1*(h-n).unit h=G end end M[#M+1]=h end end local function t()if Character then TorsoPart=Character:FindFirstChild("\084\111\114\115\111")if not TorsoPart then TorsoPart=Character:FindFirstChild("\085\112\112\101\114\084\111\114\115\111")if not TorsoPart then TorsoPart=Character:FindFirstChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")end end HeadPart=Character:FindFirstChild("\072\101\097\100")end end local function m(G)if childAddedConn then childAddedConn:disconnect()childAddedConn=nil end if childRemovedConn then childRemovedConn:disconnect()childRemovedConn=nil end Character=G TrackedLimbs={}local function M(G)if G:IsA("\066\097\115\101\080\097\114\116")then if LIMB_TRACKING_SET[G.Name]then TrackedLimbs[G]=true end if G.Name=="\084\111\114\115\111"or G.Name=="\085\112\112\101\114\084\111\114\115\111"then TorsoPart=G end if G.Name=="\072\101\097\100"then HeadPart=G end end end local function m(G)TrackedLimbs[G]=nil t()end childAddedConn=G.ChildAdded:connect(M)childRemovedConn=G.ChildRemoved:connect(m)for G,t in pairs(Character:GetChildren())do M(t)end end local function D()local G=workspace.CurrentCamera if G then Camera=G end end
-- Smart Circle mode needs the intersection of 2 rays that are known to be in the same plane
-- because they are generated from cross products with a common vector. This function is computing
-- that intersection, but it's actually the general solution for the point halfway between where
-- two skew lines come nearest to each other, which is more forgiving.
local function RayIntersection(p0, v0, p1, v1)
	local v2 = v0:Cross(v1)
	local d1 = p1.x - p0.x
	local d2 = p1.y - p0.y
	local d3 = p1.z - p0.z
	local denom = Det3x3(v0.x, -v1.x, v2.x, v0.y, -v1.y, v2.y, v0.z, -v1.z, v2.z)

	if denom == 0 then
		return ZERO_VECTOR3 -- No solution (rays are parallel)
	end

	local t0 = Det3x3(d1, -v1.x, v2.x, d2, -v1.y, v2.y, d3, -v1.z, v2.z) / denom
	local t1 = Det3x3(v0.x, d1, v2.x, v0.y, d2, v2.y, v0.z, d3, v2.z) / denom
	local s0 = p0 + t0 * v0
	local s1 = p1 + t1 * v1
	local s = s0 + 0.5 * (s1 - s0)

	-- 0.25 studs is a threshold for deciding if the rays are
	-- close enough to be considered intersecting, found through testing
	if (s1 - s0).Magnitude < 0.25 then
		return s
	else
		return ZERO_VECTOR3
	end
end

local function SmartCircleBehavior(castPoints)
	local torsoUp = TorsoPart.CFrame.upVector.unit
	local torsoRight = TorsoPart.CFrame.rightVector.unit

	-- SMART_CIRCLE mode includes rays to head and 5 to the torso.
	-- Hands, arms, legs and feet are not included since they
	-- are not canCollide and can therefore go inside of parts
	castPoints[#castPoints + 1] = TorsoPart.CFrame.p
	castPoints[#castPoints + 1] = TorsoPart.CFrame.p + torsoUp
	castPoints[#castPoints + 1] = TorsoPart.CFrame.p - torsoUp
	castPoints[#castPoints + 1] = TorsoPart.CFrame.p + torsoRight
	castPoints[#castPoints + 1] = TorsoPart.CFrame.p - torsoRight
	if HeadPart then
		castPoints[#castPoints + 1] = HeadPart.CFrame.p
	end

	local cameraOrientation = Camera.CFrame - Camera.CFrame.p
	local torsoPoint = Vector3_new(0, 0.5, 0) + (TorsoPart and TorsoPart.Position or HumanoidRootPart.Position)
	local radius = 2.5

	-- This loop first calculates points in a circle of radius 2.5 around the torso of the character, in the
	-- plane orthogonal to the camera's lookVector. Each point is then raycast to, to determine if it is within
	-- the free space surrounding the player (not inside anything). Two iterations are done to adjust points that
	-- are inside parts, to try to move them to valid locations that are still on their camera ray, so that the
	-- circle remains circular from the camera's perspective, but does not cast rays into walls or parts that are
	-- behind, below or beside the character and not really obstructing view of the character. This minimizes
	-- the undesirable situation where the character walks up to an exterior wall and it is made invisible even
	-- though it is behind the character.
	for i = 1, SMART_CIRCLE_CASTS do
		local angle = SMART_CIRCLE_INCREMENT * i - 0.5 * math.pi
		local offset = radius * Vector3_new(math_cos(angle), math_sin(angle), 0)
		local circlePoint = torsoPoint + cameraOrientation * offset

		-- Vector from camera to point on the circle being tested
		local vp = circlePoint - Camera.CFrame.p

		local ray = Ray.new(torsoPoint, circlePoint - torsoPoint)
		local hit, hp, hitNormal = game.Workspace:FindPartOnRayWithIgnoreList(ray, { Character }, false, false)
		local castPoint = circlePoint

		if hit then
			local hprime = hp + 0.1 * hitNormal.unit -- Slightly offset hit point from the hit surface
			local v0 = hprime - torsoPoint -- Vector from torso to offset hit point
			local d0 = v0.magnitude

			local perp = (v0:Cross(vp)).unit

			-- Vector from the offset hit point, along the hit surface
			local v1 = (perp:Cross(hitNormal)).unit

			-- Vector from camera to offset hit
			local vprime = (hprime - Camera.CFrame.p).unit

			-- This dot product checks to see if the vector along the hit surface would hit the correct
			-- side of the invisicam cone, or if it would cross the camera look vector and hit the wrong side
			if v0.unit:Dot(-v1) < v0.unit:Dot(vprime) then
				castPoint = RayIntersection(hprime, v1, circlePoint, vp)

				if castPoint.Magnitude > 0 then
					local ray = Ray.new(hprime, castPoint - hprime)
					local hit, hitPoint, hitNormal =
						game.Workspace:FindPartOnRayWithIgnoreList(ray, { Character }, false, false)

					if hit then
						local hprime2 = hitPoint + 0.1 * hitNormal.unit
						castPoint = hprime2
					end
				else
					castPoint = hprime
				end
			else
				castPoint = hprime
			end

			local ray = Ray.new(torsoPoint, (castPoint - torsoPoint))
			local hit, hitPoint, hitNormal =
				game.Workspace:FindPartOnRayWithIgnoreList(ray, { Character }, false, false)

			if hit then
				local castPoint2 = hitPoint - 0.1 * (castPoint - torsoPoint).unit
				castPoint = castPoint2
			end
		end

		castPoints[#castPoints + 1] = castPoint
	end
end

local function CheckTorsoReference()
	if Character then
		TorsoPart = Character:FindFirstChild("Torso")
		if not TorsoPart then
			TorsoPart = Character:FindFirstChild("UpperTorso")
			if not TorsoPart then
				TorsoPart = Character:FindFirstChild("HumanoidRootPart")
			end
		end

		HeadPart = Character:FindFirstChild("Head")
	end
end

local function OnCharacterAdded(character)
	if childAddedConn then
		childAddedConn:disconnect()
		childAddedConn = nil
	end
	if childRemovedConn then
		childRemovedConn:disconnect()
		childRemovedConn = nil
	end

	Character = character

	TrackedLimbs = {}
	local function childAdded(child)
		if child:IsA("BasePart") then
			if LIMB_TRACKING_SET[child.Name] then
				TrackedLimbs[child] = true
			end

			if child.Name == "Torso" or child.Name == "UpperTorso" then
				TorsoPart = child
			end

			if child.Name == "Head" then
				HeadPart = child
			end
		end
	end

	local function childRemoved(child)
		TrackedLimbs[child] = nil

		-- If removed/replaced part is 'Torso' or 'UpperTorso' double check that we still have a TorsoPart to use
		CheckTorsoReference()
	end

	childAddedConn = character.ChildAdded:connect(childAdded)
	childRemovedConn = character.ChildRemoved:connect(childRemoved)

	for _, child in pairs(Character:GetChildren()) do
		childAdded(child)
	end
end

local function OnCurrentCameraChanged()
	local newCamera = workspace.CurrentCamera
	if newCamera then
		Camera = newCamera
	end
end
