100 lines
2.1 KiB
Lua
100 lines
2.1 KiB
Lua
local function returnFilter(pl)
|
|
return function(e)
|
|
if e == pl then return false end
|
|
local cg = e:GetCollisionGroup()
|
|
|
|
return cg ~= 15 and cg ~= 11 and cg ~= 1 and cg ~= 2 and cg ~= 20
|
|
end
|
|
end
|
|
|
|
local function IsStuck(pl, fast, pos)
|
|
local t = {mask = MASK_PLAYERSOLID}
|
|
t.start = pos or pl:GetPos()
|
|
t.endpos = t.start
|
|
|
|
if fast then
|
|
t.filter = {pl}
|
|
else
|
|
t.filter = returnFilter(pl)
|
|
end
|
|
|
|
local output = util.TraceEntity(t, pl)
|
|
return output.StartSolid, output.Entity, output
|
|
end
|
|
|
|
local function FindPassableSpace(ply, dirs, n, direction, step)
|
|
local origin = dirs[n]
|
|
if not origin then
|
|
origin = ply:GetPos()
|
|
dirs[n] = origin
|
|
end
|
|
|
|
origin:Add(step * direction)
|
|
|
|
if not IsStuck(ply, false, origin) then
|
|
ply:SetPos(origin)
|
|
if not IsStuck(ply, false) then
|
|
ply.NewPos = ply:GetPos()
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local right = Vector(0, 1, 0)
|
|
local up = Vector(0, 0, 1)
|
|
|
|
local function UnstuckPlayer(ply)
|
|
ply.NewPos = ply:GetPos()
|
|
local OldPos = ply.NewPos
|
|
|
|
local dirs = {}
|
|
if IsStuck(ply) then
|
|
local SearchScale = 1
|
|
local ok
|
|
local forward = ply:GetAimVector()
|
|
forward.z = 0
|
|
forward:Normalize()
|
|
right = forward:Angle():Right()
|
|
|
|
for i = 1, 20 do
|
|
ok = true
|
|
if not FindPassableSpace(ply, dirs, 1, forward, SearchScale * i)
|
|
and not FindPassableSpace(ply, dirs, 2, right, SearchScale * i)
|
|
and not FindPassableSpace(ply, dirs, 3, right, -SearchScale * i)
|
|
and not FindPassableSpace(ply, dirs, 4, up, SearchScale * i)
|
|
and not FindPassableSpace(ply, dirs, 5, up, -SearchScale * i)
|
|
and not FindPassableSpace(ply, dirs, 6, forward, -SearchScale * i) then
|
|
ok = false
|
|
end
|
|
if ok then break end
|
|
end
|
|
|
|
if not ok then return false end
|
|
|
|
if OldPos == ply.NewPos then
|
|
ply:SetPos(ply.NewPos)
|
|
ply.NewPos = nil
|
|
return true
|
|
else
|
|
ply:SetPos(ply.NewPos)
|
|
ply.NewPos = nil
|
|
|
|
if SERVER and ply and ply:IsValid() and ply:GetPhysicsObject():IsValid() then
|
|
ply:SetVelocity(-ply:GetVelocity())
|
|
end
|
|
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
util.UnstuckPlayer = UnstuckPlayer
|
|
|
|
local Player = FindMetaTable("Player")
|
|
|
|
function Player:UnStuck()
|
|
return UnstuckPlayer(self)
|
|
end
|