local B={}B.__index=B function B.new()local r=setmetatable({},B)r.lastUpdate=tick()r.transparencyDirty=false r.enabled=false r.lastTransparency=nil r.descendantAddedConn,r.descendantRemovingConn=nil,nil r.toolDescendantAddedConns={}r.toolDescendantRemovingConns={}r.cachedParts={}return r end function B.HasToolAncestor(r,B)if B.Parent==nil then return false end return false end function B.IsValidPartToModify(r,B)if B:IsA("\066\097\115\101\080\097\114\116")or B:IsA("\068\101\099\097\108")then return not r:HasToolAncestor(B)end return false end function B.CachePartsRecursive(r,B)if B then if r:IsValidPartToModify(B)then r.cachedParts[B]=true r.transparencyDirty=true end for B,z in pairs(B:GetChildren())do r:CachePartsRecursive(z)end end end function B.TeardownTransparency(B)for B,r in pairs(B.cachedParts)do B.LocalTransparencyModifier=0 end B.cachedParts={}B.transparencyDirty=true B.lastTransparency=nil if B.descendantAddedConn then B.descendantAddedConn:disconnect()B.descendantAddedConn=nil end if B.descendantRemovingConn then B.descendantRemovingConn:disconnect()B.descendantRemovingConn=nil end for r,z in pairs(B.toolDescendantAddedConns)do z:Disconnect()B.toolDescendantAddedConns[r]=nil end for r,z in pairs(B.toolDescendantRemovingConns)do z:Disconnect()B.toolDescendantRemovingConns[r]=nil end end function B.SetupTransparency(r,B)r:TeardownTransparency()if r.descendantAddedConn then r.descendantAddedConn:disconnect()end r.descendantAddedConn=B.DescendantAdded:Connect(function(B)if r:IsValidPartToModify(B)then r.cachedParts[B]=true r.transparencyDirty=true end end)if r.descendantRemovingConn then r.descendantRemovingConn:disconnect()end r.descendantRemovingConn=B.DescendantRemoving:connect(function(B)if r.cachedParts[B]then r.cachedParts[B]=nil B.LocalTransparencyModifier=0 end end)r:CachePartsRecursive(B)end function B.Enable(r,B)if r.enabled~=B then r.enabled=B r:Update()end end function B.SetSubject(r,B)local z=nil if B and B:IsA("\072\117\109\097\110\111\105\100")then z=B.Parent end if B and(B:IsA("\086\101\104\105\099\108\101\083\101\097\116")and B.Occupant)then z=B.Occupant.Parent end if z then r:SetupTransparency(z)else r:TeardownTransparency()end end function B.Update(B)local r=false local z=tick()local n=workspace.CurrentCamera if n then local t=0 if not B.enabled then r=true else local J=(n.Focus.p-n.CoordinateFrame.p).magnitude t=J<2 and 1.0-(J-.5)/1.5 or 0 if t<.5 then t=0 end if B.lastTransparency then local n=t-B.lastTransparency if not r and(t<1 and B.lastTransparency<.95)then local r=MAX_TWEEN_RATE*(z-B.lastUpdate)n=math.clamp(n,-r,r)end t=B.lastTransparency+n else B.transparencyDirty=true end t=math.clamp(Util.Round(t,2),0,1)end if B.transparencyDirty or B.lastTransparency~=t then for B,r in pairs(B.cachedParts)do B.LocalTransparencyModifier=t end B.transparencyDirty=false B.lastTransparency=t end end B.lastUpdate=z end return B
--
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 false
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
		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 = math.clamp(deltaTransparency, -maxDelta, maxDelta)
				end
				transparency = self.lastTransparency + deltaTransparency
			else
				self.transparencyDirty = true
			end

			transparency = math.clamp(Util.Round(transparency, 2), 0, 1)
		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
