local Z={}Z.__index=Z function Z.new()local w=setmetatable({},Z)w.lastUpdate=tick()w.transparencyDirty=false w.enabled=false w.lastTransparency=nil w.descendantAddedConn,w.descendantRemovingConn=nil,nil w.toolDescendantAddedConns={}w.toolDescendantRemovingConns={}w.cachedParts={}return w end function Z.HasToolAncestor(w,Z)if Z.Parent==nil then return false end return Z.Parent:IsA("\084\111\111\108")or w:HasToolAncestor(Z.Parent)end function Z.IsValidPartToModify(w,Z)if Z:IsA("\066\097\115\101\080\097\114\116")or Z:IsA("\068\101\099\097\108")then return not w:HasToolAncestor(Z)end return false end function Z.CachePartsRecursive(w,Z)if Z then if w:IsValidPartToModify(Z)then w.cachedParts[Z]=true w.transparencyDirty=true end for Z,z in pairs(Z:GetChildren())do w:CachePartsRecursive(z)end end end function Z.TeardownTransparency(Z)for Z,w in pairs(Z.cachedParts)do Z.LocalTransparencyModifier=0 end Z.cachedParts={}Z.transparencyDirty=true Z.lastTransparency=nil if Z.descendantAddedConn then Z.descendantAddedConn:disconnect()Z.descendantAddedConn=nil end if Z.descendantRemovingConn then Z.descendantRemovingConn:disconnect()Z.descendantRemovingConn=nil end for w,z in pairs(Z.toolDescendantAddedConns)do z:Disconnect()Z.toolDescendantAddedConns[w]=nil end for w,z in pairs(Z.toolDescendantRemovingConns)do z:Disconnect()Z.toolDescendantRemovingConns[w]=nil end end function Z.SetupTransparency(w,Z)w:TeardownTransparency()if w.descendantAddedConn then w.descendantAddedConn:disconnect()end w.descendantAddedConn=Z.DescendantAdded:Connect(function(z)if w:IsValidPartToModify(z)then w.cachedParts[z]=true w.transparencyDirty=true elseif z:IsA("\084\111\111\108")then if w.toolDescendantAddedConns[z]then w.toolDescendantAddedConns[z]:Disconnect()end w.toolDescendantAddedConns[z]=z.DescendantAdded:Connect(function(Z)w.cachedParts[Z]=nil if Z:IsA("\066\097\115\101\080\097\114\116")or Z:IsA("\068\101\099\097\108")then Z.LocalTransparencyModifier=0 end end)if w.toolDescendantRemovingConns[z]then w.toolDescendantRemovingConns[z]:disconnect()end w.toolDescendantRemovingConns[z]=z.DescendantRemoving:Connect(function(z)wait()if Z and(z and z:IsDescendantOf(Z))then if w:IsValidPartToModify(z)then w.cachedParts[z]=true w.transparencyDirty=true end end end)end end)if w.descendantRemovingConn then w.descendantRemovingConn:disconnect()end w.descendantRemovingConn=Z.DescendantRemoving:connect(function(Z)if w.cachedParts[Z]then w.cachedParts[Z]=nil Z.LocalTransparencyModifier=0 end end)w:CachePartsRecursive(Z)end function Z.Enable(w,Z)if w.enabled~=Z then w.enabled=Z w:Update()end end function Z.SetSubject(w,Z)local z=nil if Z and Z:IsA("\072\117\109\097\110\111\105\100")then z=Z.Parent end if Z and(Z:IsA("\086\101\104\105\099\108\101\083\101\097\116")and Z.Occupant)then z=Z.Occupant.Parent end if z then w:SetupTransparency(z)else w:TeardownTransparency()end end function Z.Update(Z)local w=false local z=tick()local A=workspace.CurrentCamera if A then local M=0 if not Z.enabled then w=true else local S=(A.Focus.p-A.CoordinateFrame.p).magnitude M=S<2 and 1.0-(S-.5)/1.5 or 0 if M<.5 then M=0 end if Z.lastTransparency then local A=M-Z.lastTransparency if not w and(M<1 and Z.lastTransparency<.95)then local w=MAX_TWEEN_RATE*(z-Z.lastUpdate)A=Util.Clamp(-w,w,A)end M=Z.lastTransparency+A else Z.transparencyDirty=true end M=Util.Clamp(0,1,Util.Round(M,2))end if Z.transparencyDirty or Z.lastTransparency~=M then for Z,w in pairs(Z.cachedParts)do Z.LocalTransparencyModifier=M end Z.transparencyDirty=false Z.lastTransparency=M end end Z.lastUpdate=z end return Z
--[[ The Module ]]
--
local TransparencyController = {}
TransparencyController.__index = TransparencyController

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

	self.lastUpdate = tick()
	self.transparencyDirty = false
	self.enabled = false
	self.lastTransparency = nil

	self.descendantAddedConn, self.descendantRemovingConn = nil, nil
	self.toolDescendantAddedConns = {}
	self.toolDescendantRemovingConns = {}
	self.cachedParts = {}

	return self
end

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

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

function TransparencyController:CachePartsRecursive(object)
	if object then
		if self:IsValidPartToModify(object) then
			self.cachedParts[object] = true
			self.transparencyDirty = true
		end
		for _, child in pairs(object:GetChildren()) do
			self:CachePartsRecursive(child)
		end
	end
end

function TransparencyController:TeardownTransparency()
	for child, _ in pairs(self.cachedParts) do
		child.LocalTransparencyModifier = 0
	end
	self.cachedParts = {}
	self.transparencyDirty = true
	self.lastTransparency = nil

	if self.descendantAddedConn then
		self.descendantAddedConn:disconnect()
		self.descendantAddedConn = nil
	end
	if self.descendantRemovingConn then
		self.descendantRemovingConn:disconnect()
		self.descendantRemovingConn = nil
	end
	for object, conn in pairs(self.toolDescendantAddedConns) do
		conn:Disconnect()
		self.toolDescendantAddedConns[object] = nil
	end
	for object, conn in pairs(self.toolDescendantRemovingConns) do
		conn:Disconnect()
		self.toolDescendantRemovingConns[object] = nil
	end
end

function TransparencyController:SetupTransparency(character)
	self:TeardownTransparency()

	if self.descendantAddedConn then
		self.descendantAddedConn:disconnect()
	end
	self.descendantAddedConn = character.DescendantAdded:Connect(function(object)
		-- This is a part we want to invisify
		if self:IsValidPartToModify(object) then
			self.cachedParts[object] = true
			self.transparencyDirty = true
		-- There is now a tool under the character
		elseif object:IsA("Tool") then
			if self.toolDescendantAddedConns[object] then
				self.toolDescendantAddedConns[object]:Disconnect()
			end
			self.toolDescendantAddedConns[object] = object.DescendantAdded:Connect(function(toolChild)
				self.cachedParts[toolChild] = nil
				if toolChild:IsA("BasePart") or toolChild:IsA("Decal") then
					-- Reset the transparency
					toolChild.LocalTransparencyModifier = 0
				end
			end)
			if self.toolDescendantRemovingConns[object] then
				self.toolDescendantRemovingConns[object]:disconnect()
			end
			self.toolDescendantRemovingConns[object] = object.DescendantRemoving:Connect(function(formerToolChild)
				wait() -- wait for new parent
				if character and formerToolChild and formerToolChild:IsDescendantOf(character) then
					if self:IsValidPartToModify(formerToolChild) then
						self.cachedParts[formerToolChild] = true
						self.transparencyDirty = true
					end
				end
			end)
		end
	end)
	if self.descendantRemovingConn then
		self.descendantRemovingConn:disconnect()
	end
	self.descendantRemovingConn = character.DescendantRemoving:connect(function(object)
		if self.cachedParts[object] then
			self.cachedParts[object] = nil
			-- Reset the transparency
			object.LocalTransparencyModifier = 0
		end
	end)
	self:CachePartsRecursive(character)
end

function TransparencyController:Enable(enable)
	if self.enabled ~= enable then
		self.enabled = enable
		self:Update()
	end
end

function TransparencyController: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
		self:SetupTransparency(character)
	else
		self:TeardownTransparency()
	end
end

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

	if currentCamera then
		local transparency = 0
		if not self.enabled then
			instant = true
		else
			local distance = (currentCamera.Focus.p - currentCamera.CoordinateFrame.p).magnitude
			transparency = (distance < 2) and (1.0 - (distance - 0.5) / 1.5) or 0 --(7 - distance) / 5
			if transparency < 0.5 then
				transparency = 0
			end

			if self.lastTransparency then
				local deltaTransparency = transparency - self.lastTransparency

				-- Don't tween transparency if it is instant or your character was fully invisible last frame
				if not instant and transparency < 1 and self.lastTransparency < 0.95 then
					local maxDelta = MAX_TWEEN_RATE * (now - self.lastUpdate)
					deltaTransparency = Util.Clamp(-maxDelta, maxDelta, deltaTransparency)
				end
				transparency = self.lastTransparency + deltaTransparency
			else
				self.transparencyDirty = true
			end

			transparency = Util.Clamp(0, 1, Util.Round(transparency, 2))
		end

		if self.transparencyDirty or self.lastTransparency ~= transparency then
			for child, _ in pairs(self.cachedParts) do
				child.LocalTransparencyModifier = transparency
			end
			self.transparencyDirty = false
			self.lastTransparency = transparency
		end
	end
	self.lastUpdate = now
end

return TransparencyController
