local W={}local f=game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")local e=game:GetService("\080\104\121\115\105\099\115\083\101\114\118\105\099\101")function W.RaycastMouse(N,e,R,r)local o=f:GetMouseLocation()local n=game.Workspace.CurrentCamera local t=n:ViewportPointToRay(o.X,o.Y)return W:Raycast(n.CFrame.Position,t.Direction,e,R,r)end function W.Raycast(o,W,f,R,r,N)N=N or false f=f.Unit local n=game.Workspace:Raycast(W,f*R,r)if N then local N={}for W,f in pairs(e:GetRegisteredCollisionGroups())do local R=f.name if not e:CollisionGroupsAreCollidable("\068\101\102\097\117\108\116",R)then table.insert(N,R)end end for e,N in pairs(N)do local o=RaycastParams.new()o.CollisionGroup=N o.FilterDescendantsInstances=r and r.FilterDescendantsInstances or o.FilterDescendantsInstances o.FilterType=r and r.FilterType or o.FilterType o.IgnoreWater=r and r.IgnoreWater or o.IgnoreWater local t=game.Workspace:Raycast(W,f*R,o)local x=not n or t and n.Distance>t.Distance n=x and t or n end end return n end return W
---
---RaycastUtil
---
---@class RaycastUtil
---
local RaycastUtil = {}

--------------------------------------------------
-- Types
-- ...

--------------------------------------------------
-- Dependencies
local UserInputService = game:GetService("UserInputService") ---@type UserInputService
local PhysicsService = game:GetService("PhysicsService") ---@type PhysicsService

--------------------------------------------------
-- Constants
-- ...

--------------------------------------------------
-- Members

---
---Returns the RaycastResult of raycasting toward the position our mouse is at in the world.
---If `checkAllCollisionGroups` is true, will raycast in CollisionGroups that don't collide with the `Default` collision groups as well.
---@param distance number
---@param raycastParams RaycastParams
---@param checkAllCollisionGroups boolean
---@return RaycastResult
---
---@overload fun(distance:number):RaycastResult
---
function RaycastUtil:RaycastMouse(distance, raycastParams, checkAllCollisionGroups)
    -- Get Mouse Position on screen
    local mousePoint = UserInputService:GetMouseLocation()

    -- Get Ray
    local camera = game.Workspace.CurrentCamera
    local unitRay = camera:ViewportPointToRay(mousePoint.X, mousePoint.Y)

    -- Raycast
    return RaycastUtil:Raycast(camera.CFrame.Position, unitRay.Direction, distance, raycastParams, checkAllCollisionGroups)
end

---
---Returns the RaycastResult of this raycast.
---If `checkAllCollisionGroups` is true, will raycast in CollisionGroups that don't collide with the `Default` collision groups as well.
---@param origin Vector3
---@param direction Vector3
---@param distance number
---@param raycastParams RaycastParams
---@param checkAllCollisionGroups boolean
---@return RaycastResult
---
---@overload fun(distance:number):RaycastResult
---
function RaycastUtil:Raycast(origin, direction, distance, raycastParams, checkAllCollisionGroups)
    checkAllCollisionGroups = checkAllCollisionGroups or false
    direction = direction.Unit

    -- Raycast
    local raycastResult = game.Workspace:Raycast(origin, direction * distance, raycastParams)
    if checkAllCollisionGroups then
        -- Get groups that don't collide with default
        local groupNames = {}
        for _, groupInfo in pairs(PhysicsService:GetRegisteredCollisionGroups()) do
            local name = groupInfo.name
            if not PhysicsService:CollisionGroupsAreCollidable("Default", name) then
                table.insert(groupNames, name)
            end
        end

        -- Check if we get a closer raycastResult
        for _, groupName in pairs(groupNames) do
            local newRaycastParams = RaycastParams.new()
            newRaycastParams.CollisionGroup = groupName
            newRaycastParams.FilterDescendantsInstances = raycastParams and raycastParams.FilterDescendantsInstances
                or newRaycastParams.FilterDescendantsInstances
            newRaycastParams.FilterType = raycastParams and raycastParams.FilterType or newRaycastParams.FilterType
            newRaycastParams.IgnoreWater = raycastParams and raycastParams.IgnoreWater or newRaycastParams.IgnoreWater

            local newRaycastResult = game.Workspace:Raycast(origin, direction * distance, newRaycastParams)
            local thisIsABetterResult = not raycastResult or newRaycastResult and raycastResult.Distance > newRaycastResult.Distance
            raycastResult = thisIsABetterResult and newRaycastResult or raycastResult
        end
    end

    return raycastResult
end

return RaycastUtil
