-- 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
		local newSubject = Camera.CameraSubject
		if newSubject and newSubject:IsA('VehicleSeat') then
			VehicleParts = newSubject:GetConnectedParts(true)
		else
			VehicleParts = {}
		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)
		end
	end
end
