-- Script to prevent players from spawning inside each other
-- Especially useful for MilitaryRP/Helix where many players spawn simultaneously

local UNSTUCK_TIMEOUT = 5 -- How many seconds we consider for unstuck logic
local UNSTUCK_SEARCH_RADIUS = 300 -- Max search radius

local function IsPosEmpty(pos, filter)
    local trace = util.TraceHull({
        start = pos + Vector(0,0,10),
        endpos = pos + Vector(0,0,10),
        mins = Vector(-16, -16, 0),
        maxs = Vector(16, 16, 71),
        filter = filter
    })
    
    if trace.Hit then return false end

    -- Also check for other players explicitly (TraceHull filter might skip them if they are within each other)
    local entsNear = ents.FindInBox(pos + Vector(-16, -16, 0), pos + Vector(16, 16, 72))
    for _, v in pairs(entsNear) do
        if v:IsPlayer() and v:Alive() and v ~= filter then
            return false
        end
    end

    return true
end

local function FindSafePos(startPos, ply)
    if IsPosEmpty(startPos, ply) then return startPos end

    -- Spiral search
    for r = 32, UNSTUCK_SEARCH_RADIUS, 32 do
        local steps = math.floor(r / 4)
        for i = 0, steps do
            local ang = (i / steps) * 360
            local offset = Angle(0, ang, 0):Forward() * r
            local tryPos = startPos + offset
            
            if IsPosEmpty(tryPos, ply) then 
                -- Ensure there is ground below
                local groundTrace = util.TraceLine({
                    start = tryPos + Vector(0,0,50),
                    endpos = tryPos - Vector(0,0,100),
                    filter = ply
                })
                
                if groundTrace.Hit then
                    return groundTrace.HitPos
                end
            end
        end
    end
    
    return startPos
end

hook.Add("PlayerSpawn", "Helix_AntiStuckSpawn", function(ply)
    -- Wait a frame for Helix to finish its set-spawn-point logic
    timer.Simple(0, function()
        if not IsValid(ply) or not ply:Alive() then return end
        
        local currentPos = ply:GetPos()
        local safePos = FindSafePos(currentPos, ply)
        
        if safePos ~= currentPos then
            ply:SetPos(safePos)
        end
        
        -- Temporary NO COLLISION with other players for 3 seconds to avoid "jittery" physics if slightly overlapping
        ply:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
        timer.Create("Unstuck_CD_" .. ply:SteamID64(), 3, 1, function()
            if IsValid(ply) then
                ply:SetCollisionGroup(COLLISION_GROUP_PLAYER)
            end
        end)
    end)
end)

print("[Anti-Stuck] Player spawn protection loaded")
