local B=2.8 local function i(B,i,e)return e>i and i or e<B and B or e end local e=math.floor local function u(B,i)local u=10^i return e(B*u+.5)/u end local function F()local e={}local F=tick()local k=false local j=false local g=nil local S,Y=nil,nil local D={}local Z={}local v={}local function h(B)if B.Parent==nil then return false end return B.Parent:IsA("\084\111\111\108")or h(B.Parent)end local function x(B)if B:IsA("\066\097\115\101\080\097\114\116")or B:IsA("\068\101\099\097\108")then return not h(B)end return false end local function q(B)if B then if x(B)then v[B]=true k=true end for B,i in pairs(B:GetChildren())do q(i)end end end local function O()for B,i in pairs(v)do B.LocalTransparencyModifier=0 end v={}k=true g=nil if S then S:disconnect()S=nil end if Y then Y:disconnect()Y=nil end for B,i in pairs(D)do i:disconnect()D[B]=nil end for B,i in pairs(Z)do i:disconnect()Z[B]=nil end end local function d(B)O()if S then S:disconnect()end S=B.DescendantAdded:connect(function(i)if x(i)then v[i]=true k=true elseif i:IsA("\084\111\111\108")then if D[i]then D[i]:disconnect()end D[i]=i.DescendantAdded:connect(function(B)v[B]=nil if B:IsA("\066\097\115\101\080\097\114\116")or B:IsA("\068\101\099\097\108")then B.LocalTransparencyModifier=0 end end)if Z[i]then Z[i]:disconnect()end Z[i]=i.DescendantRemoving:connect(function(i)task.wait()if B and(i and i:IsDescendantOf(B))then if x(i)then v[i]=true k=true end end end)end end)if Y then Y:disconnect()end Y=B.DescendantRemoving:connect(function(B)if v[B]then v[B]=nil B.LocalTransparencyModifier=0 end end)q(B)end function e.SetEnabled(i,B)if j~=B then j=B i:Update()end end function e.SetSubject(i,B)local e=nil if B and B:IsA("\072\117\109\097\110\111\105\100")then e=B.Parent end if B and(B:IsA("\086\101\104\105\099\108\101\083\101\097\116")and B.Occupant)then e=B.Occupant.Parent end if e then d(e)else O()end end function e.Update(e)local S=false local Y=tick()local D=workspace.CurrentCamera if D then local e=0 if not j then S=true else local j=(D.Focus.p-D.CoordinateFrame.p).magnitude e=(7-j)/5 if e<.5 then e=0 end if g then local u=e-g if not S and(e<1 and g<.95)then local e=B*(Y-F)u=i(-e,e,u)end e=g+u else k=true end e=i(0,1,u(e,2))end if k or g~=e then for B,i in pairs(v)do B.LocalTransparencyModifier=e end k=false g=e end end F=Y end return e end return F
-- SolarCrane

local MAX_TWEEN_RATE = 2.8 -- per second

local function clamp(low, high, num)
	return (num > high and high or num < low and low or num)
end

local math_floor = math.floor

local function Round(num, places)
	local decimalPivot = 10 ^ places
	return math_floor(num * decimalPivot + 0.5) / decimalPivot
end

local function CreateTransparencyController()
	local module = {}

	local LastUpdate = tick()
	local TransparencyDirty = false
	local Enabled = false
	local LastTransparency = nil

	local DescendantAddedConn, DescendantRemovingConn = nil, nil
	local ToolDescendantAddedConns = {}
	local ToolDescendantRemovingConns = {}
	local CachedParts = {}

	local function HasToolAncestor(object)
		if object.Parent == nil then
			return false
		end
		return object.Parent:IsA("Tool") or HasToolAncestor(object.Parent)
	end

	local function IsValidPartToModify(part)
		if part:IsA("BasePart") or part:IsA("Decal") then
			return not HasToolAncestor(part)
		end
		return false
	end

	local function CachePartsRecursive(object)
		if object then
			if IsValidPartToModify(object) then
				CachedParts[object] = true
				TransparencyDirty = true
			end
			for _, child in pairs(object:GetChildren()) do
				CachePartsRecursive(child)
			end
		end
	end

	local function TeardownTransparency()
		for child, _ in pairs(CachedParts) do
			child.LocalTransparencyModifier = 0
		end
		CachedParts = {}
		TransparencyDirty = true
		LastTransparency = nil

		if DescendantAddedConn then
			DescendantAddedConn:disconnect()
			DescendantAddedConn = nil
		end
		if DescendantRemovingConn then
			DescendantRemovingConn:disconnect()
			DescendantRemovingConn = nil
		end
		for object, conn in pairs(ToolDescendantAddedConns) do
			conn:disconnect()
			ToolDescendantAddedConns[object] = nil
		end
		for object, conn in pairs(ToolDescendantRemovingConns) do
			conn:disconnect()
			ToolDescendantRemovingConns[object] = nil
		end
	end

	local function SetupTransparency(character)
		TeardownTransparency()

		if DescendantAddedConn then
			DescendantAddedConn:disconnect()
		end
		DescendantAddedConn = character.DescendantAdded:connect(function(object)
			-- This is a part we want to invisify
			if IsValidPartToModify(object) then
				CachedParts[object] = true
				TransparencyDirty = true
			-- There is now a tool under the character
			elseif object:IsA("Tool") then
				if ToolDescendantAddedConns[object] then
					ToolDescendantAddedConns[object]:disconnect()
				end
				ToolDescendantAddedConns[object] = object.DescendantAdded:connect(function(toolChild)
					CachedParts[toolChild] = nil
					if toolChild:IsA("BasePart") or toolChild:IsA("Decal") then
						-- Reset the transparency
						toolChild.LocalTransparencyModifier = 0
					end
				end)
				if ToolDescendantRemovingConns[object] then
					ToolDescendantRemovingConns[object]:disconnect()
				end
				ToolDescendantRemovingConns[object] = object.DescendantRemoving:connect(function(formerToolChild)
					task.wait() -- wait for new parent
					if character and formerToolChild and formerToolChild:IsDescendantOf(character) then
						if IsValidPartToModify(formerToolChild) then
							CachedParts[formerToolChild] = true
							TransparencyDirty = true
						end
					end
				end)
			end
		end)
		if DescendantRemovingConn then
			DescendantRemovingConn:disconnect()
		end
		DescendantRemovingConn = character.DescendantRemoving:connect(function(object)
			if CachedParts[object] then
				CachedParts[object] = nil
				-- Reset the transparency
				object.LocalTransparencyModifier = 0
			end
		end)
		CachePartsRecursive(character)
	end

	function module:SetEnabled(newState)
		if Enabled ~= newState then
			Enabled = newState
			self:Update()
		end
	end

	function module:SetSubject(subject)
		local character = nil
		if subject and subject:IsA("Humanoid") then
			character = subject.Parent
		end
		if subject and subject:IsA("VehicleSeat") and subject.Occupant then
			character = subject.Occupant.Parent
		end
		if character then
			SetupTransparency(character)
		else
			TeardownTransparency()
		end
	end

	function module:Update()
		local instant = false
		local now = tick()
		local currentCamera = workspace.CurrentCamera

		if currentCamera then
			local transparency = 0
			if not Enabled then
				instant = true
			else
				local distance = (currentCamera.Focus.p - currentCamera.CoordinateFrame.p).magnitude
				transparency = (7 - distance) / 5
				if transparency < 0.5 then
					transparency = 0
				end

				if LastTransparency then
					local deltaTransparency = transparency - LastTransparency
					-- Don't tween transparency if it is instant or your character was fully invisible last frame
					if not instant and transparency < 1 and LastTransparency < 0.95 then
						local maxDelta = MAX_TWEEN_RATE * (now - LastUpdate)
						deltaTransparency = clamp(-maxDelta, maxDelta, deltaTransparency)
					end
					transparency = LastTransparency + deltaTransparency
				else
					TransparencyDirty = true
				end

				transparency = clamp(0, 1, Round(transparency, 2))
			end

			if TransparencyDirty or LastTransparency ~= transparency then
				for child, _ in pairs(CachedParts) do
					child.LocalTransparencyModifier = transparency
				end
				TransparencyDirty = false
				LastTransparency = transparency
			end
		end
		LastUpdate = now
	end

	return module
end

return CreateTransparencyController
