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