81 lines
2.6 KiB
Lua
81 lines
2.6 KiB
Lua
-- 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")
|