local function q(q,w,M)repeat local Q,z=CastRay(q,w,M)if Q and(Q.Transparency>.95 or Q.CanCollide==false)then table.insert(M,Q)else return Q,z end until false end local function w(q,w,M)local Q,z=Camera.FieldOfView,Camera.CoordinateFrame local b=w.y/(2*math.tan(math.rad(Q)/2))local g=Vector3.new(q.x-w.x/2,w.y/2-q.y,-b)local J=(z:vectorToWorldSpace(g)).Unit local V=math.acos(math.min(1,J:Dot(z.lookVector)))local G=M/math.sin(math.pi/2-V)return z.p+J*G end local function M(q)if q=="\067\097\109\101\114\097\083\117\098\106\101\099\116"then VehicleParts={}local q=Camera.CameraSubject if q then PopperEnabled=false for w,M in pairs(VALID_SUBJECTS)do if q:IsA(M)then PopperEnabled=true break end end if q:IsA("\086\101\104\105\099\108\101\083\101\097\116")then VehicleParts=q:GetConnectedParts(true)end end end end local function Q(q,w)PlayerCharacters[q]=w end local function z(q)if q:IsA("\080\108\097\121\101\114")then q.CharacterAdded:connect(function(w)Q(q,w)end)if q.Character then Q(q,q.Character)end end end local function b(q)if q:IsA("\080\108\097\121\101\114")then PlayerCharacters[q]=nil end end local function g(q)if q=="\067\117\114\114\101\110\116\067\097\109\101\114\097"then local q=workspace.CurrentCamera if q then Camera=q if CameraChangeConn then CameraChangeConn:disconnect()end CameraChangeConn=Camera.Changed:connect(M)M("\067\097\109\101\114\097\083\117\098\106\101\099\116")end end end
-- Casts and recasts until it hits either: nothing, or something not transparent or collidable
local function PiercingCast(fromPoint, toPoint, ignoreList) --NOTE: Modifies ignoreList!
	repeat
		local hitPart, hitPoint = CastRay(fromPoint, toPoint, ignoreList)
		if hitPart and (hitPart.Transparency > 0.95 or hitPart.CanCollide == false) then
			table.insert(ignoreList, hitPart)
		else
			return hitPart, hitPoint
		end
	until false
end

local function ScreenToWorld(screenPoint, screenSize, pushDepth)
	local cameraFOV, cameraCFrame = Camera.FieldOfView, Camera.CoordinateFrame
	local imagePlaneDepth = screenSize.y / (2 * math.tan(math.rad(cameraFOV) / 2))
	local direction =
		Vector3.new(screenPoint.x - (screenSize.x / 2), (screenSize.y / 2) - screenPoint.y, -imagePlaneDepth)
	local worldDirection = (cameraCFrame:vectorToWorldSpace(direction)).Unit
	local theta = math.acos(math.min(1, worldDirection:Dot(cameraCFrame.lookVector)))
	local fixedPushDepth = pushDepth / math.sin((math.pi / 2) - theta)
	return cameraCFrame.p + worldDirection * fixedPushDepth
end

local function OnCameraChanged(property)
	if property == "CameraSubject" then
		VehicleParts = {}

		local newSubject = Camera.CameraSubject
		if newSubject then
			-- Determine if we should be popping at all
			PopperEnabled = false
			for _, subjectType in pairs(VALID_SUBJECTS) do
				if newSubject:IsA(subjectType) then
					PopperEnabled = true
					break
				end
			end

			-- Get all parts of the vehicle the player is controlling
			if newSubject:IsA("VehicleSeat") then
				VehicleParts = newSubject:GetConnectedParts(true)
			end
		end
	end
end

local function OnCharacterAdded(player, character)
	PlayerCharacters[player] = character
end

local function OnPlayersChildAdded(child)
	if child:IsA("Player") then
		child.CharacterAdded:connect(function(character)
			OnCharacterAdded(child, character)
		end)
		if child.Character then
			OnCharacterAdded(child, child.Character)
		end
	end
end

local function OnPlayersChildRemoved(child)
	if child:IsA("Player") then
		PlayerCharacters[child] = nil
	end
end

local function OnWorkspaceChanged(property)
	if property == "CurrentCamera" then
		local newCamera = workspace.CurrentCamera
		if newCamera then
			Camera = newCamera

			if CameraChangeConn then
				CameraChangeConn:disconnect()
			end
			CameraChangeConn = Camera.Changed:connect(OnCameraChanged)
			OnCameraChanged("CameraSubject")
		end
	end
end
