add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -0,0 +1,161 @@
local TAG = "SitAny_"
local PLUGIN = PLUGIN
CreateClientConVar("sitting_use_walk", "1.00", true, true, "Требовать шаг для сидения", 0, 1)
CreateClientConVar("sitting_force_left_alt", "0", true, true, "Использовать левый Alt как шаг для сидения", 0, 1)
CreateClientConVar("sitting_allow_on_me", "1.00", true, true, "Разрешить другим садиться на вас", 0, 1)
local useAlt = GetConVar("sitting_use_walk")
local forceBinds = GetConVar("sitting_force_left_alt")
local function ShouldSit(ply)
return hook.Run("ShouldSit", ply)
end
local arrow, drawScale, traceDist = Material("widgets/arrow.png"), 0.1, 20
local traceScaled = traceDist / drawScale
local function StartSit(trace)
local wantedAng = nil
local cancelled = false
local start = CurTime()
local ply = LocalPlayer()
hook.Add("PostDrawOpaqueRenderables", TAG .. "PostDrawOpaqueRenderables", function(depth, skybox)
if CurTime() - start <= 0.25 then return end
if trace.StartPos:Distance(ply:EyePos()) > 10 then
cancelled, wantedAng = true, nil
hook.Remove("PostDrawOpaqueRenderables", TAG .. "PostDrawOpaqueRenderables")
return
end
local vec = util.IntersectRayWithPlane(ply:EyePos(), ply:EyeAngles():Forward(), trace.HitPos, Vector(0, 0, 1))
if not vec then return end
local posOnPlane = WorldToLocal(vec, Angle(0, 90, 0), trace.HitPos, Angle(0, 0, 0))
local testVec = posOnPlane:GetNormal() * traceScaled
local currentAng = (trace.HitPos - vec):Angle()
wantedAng = currentAng
if posOnPlane:Length() < 2 then
wantedAng = nil
return
end
if wantedAng then
local goodSit = SitAnywhere.CheckValidAngForSit(trace.HitPos, trace.HitNormal:Angle(), wantedAng.y)
if not goodSit then wantedAng = nil end
cam.Start3D2D(trace.HitPos + Vector(0, 0, 1), Angle(0, 0, 0), drawScale)
surface.SetDrawColor(goodSit and Color(255, 255, 255, 255) or Color(255, 0, 0, 255))
surface.SetMaterial(arrow)
surface.DrawTexturedRectRotated(testVec.x * 0.5, testVec.y * -0.5, 2 / drawScale, traceScaled, currentAng.y + 90)
cam.End3D2D()
end
end)
return function()
hook.Remove("PostDrawOpaqueRenderables", TAG .. "PostDrawOpaqueRenderables")
if cancelled then return end
if CurTime() - start < 0.25 then
RunConsoleCommand("sit")
return
end
if wantedAng then
net.Start("SitAnywhere")
net.WriteInt(SitAnywhere.NET.SitWantedAng, 4)
net.WriteFloat(wantedAng.y)
net.WriteVector(trace.StartPos)
net.WriteVector(trace.Normal)
net.SendToServer()
wantedAng = nil
end
end
end
local function DoSit(trace)
if not trace.Hit then return end
local surfaceAng = trace.HitNormal:Angle() + Angle(-270, 0, 0)
local playerTrace = not trace.HitWorld and IsValid(trace.Entity) and trace.Entity:IsPlayer()
local goodSit = SitAnywhere.GetAreaProfile(trace.HitPos + Vector(0, 0, 0.1), 24, true)
if math.abs(surfaceAng.pitch) >= 15 or not goodSit or playerTrace then
RunConsoleCommand("sit")
return
end
local valid = SitAnywhere.ValidSitTrace(LocalPlayer(), trace)
if not valid then return end
return StartSit(trace)
end
local currSit
concommand.Add("+sit", function(ply, cmd, args)
if currSit then return end
if not IsValid(ply) or not ply.GetEyeTrace then return end
currSit = DoSit(ply:GetEyeTrace())
end)
concommand.Add("-sit", function(ply, cmd, args)
if currSit then
currSit()
currSit = nil
end
end)
function PLUGIN:KeyPress(ply, key)
if not IsFirstTimePredicted() and not game.SinglePlayer() then return end
if currSit then return end
if key ~= IN_USE then return end
local good = not useAlt:GetBool()
local alwaysSit = ShouldSit(ply)
if forceBinds:GetBool() then
if useAlt:GetBool() and input.IsKeyDown(KEY_LALT) then
good = true
end
else
if useAlt:GetBool() and ply:KeyDown(IN_WALK) then
good = true
end
end
if ix.config.Get("sitForceNoWalk", false) then
good = true
end
if alwaysSit == true then
good = true
elseif alwaysSit == false then
good = false
end
if not good then return end
local trace = LocalPlayer():GetEyeTrace()
if trace.Hit then
currSit = DoSit(trace)
hook.Add("KeyRelease", TAG .. "KeyRelease", function(releasePly, releaseKey)
if not IsFirstTimePredicted() and not game.SinglePlayer() then return end
if ply ~= releasePly or releaseKey ~= IN_USE then return end
hook.Remove("KeyRelease", TAG .. "KeyRelease")
if not currSit then return end
currSit()
currSit = nil
end)
end
end
hook.Add("ShouldDrawLocalPlayer", "SitAnywhere_DrawLocalPlayer", function(ply)
if not IsValid(ply) then return end
local veh = ply:GetVehicle()
if IsValid(veh) and veh:GetClass() == "prop_vehicle_prisoner_pod" and veh:GetNWBool("playerdynseat", false) then
return true
end
end)

View File

@@ -0,0 +1,209 @@
SitAnywhere = SitAnywhere or {}
SitAnywhere.NET = {
["SitWantedAng"] = 0,
["SitRequestExit"] = 1,
}
SitAnywhere.ClassBlacklist = {
["gmod_wire_keyboard"] = true,
["prop_combine_ball"] = true
}
SitAnywhere.DoNotParent = {
["yava_chunk"] = true
}
SitAnywhere.ModelBlacklist = {}
local EMETA = FindMetaTable("Entity")
function SitAnywhere.GetAreaProfile(pos, resolution, simple)
local filter = player.GetAll()
local dists = {}
local distsang = {}
local ang_smallest_hori = nil
local smallest_hori = 90000
local angPerIt = (360 / resolution)
for I = 0, 360, angPerIt do
local rad = math.rad(I)
local dir = Vector(math.cos(rad), math.sin(rad), 0)
local trace = util.QuickTrace(pos + dir * 20 + Vector(0,0,5), Vector(0,0,-15000), filter)
trace.HorizontalTrace = util.QuickTrace(pos + Vector(0,0,5), dir * 1000, filter)
trace.Distance = trace.StartPos:Distance(trace.HitPos)
trace.Distance2 = trace.HorizontalTrace.StartPos:Distance(trace.HorizontalTrace.HitPos)
trace.ang = I
if (not trace.Hit or trace.Distance > 14) and (not trace.HorizontalTrace.Hit or trace.Distance2 > 20) then
if simple then return true end
table.insert(dists, trace)
end
if trace.Distance2 < smallest_hori and (not trace.HorizontalTrace.Hit or trace.Distance2 > 3) then
smallest_hori = trace.Distance2
ang_smallest_hori = I
end
distsang[I] = trace
end
if simple then return false end
return dists, distsang, ang_smallest_hori, smallest_hori
end
function SitAnywhere.CheckValidAngForSit(pos, surfaceAng, ang)
local rad = math.rad(ang)
local dir = Vector(math.cos(rad), math.sin(rad), 0)
local trace2 = util.TraceLine({
start = pos - dir * (20 - .5) + surfaceAng:Forward() * 5,
endpos = pos - dir * (20 - .5) + surfaceAng:Forward() * -160,
filter = player.GetAll()
})
local hor_trace = util.TraceLine({
start = pos + Vector(0, 0, 5),
endpos = pos + Vector(0, 0, 5) - dir * 1600,
filter = player.GetAll()
})
return hor_trace.StartPos:Distance(hor_trace.HitPos) > 20 and trace2.StartPos:Distance(trace2.HitPos) > 14
end
-- Настройки через ix.config
if SERVER then
ix.config.Add("sitEntMode", 3, "Режим сидения на объектах: 0=нет, 1=только мировые, 2=свои+мировые, 3=любые", nil, {
data = {min = 0, max = 3},
category = "Sit Anywhere"
})
end
local function GetSitOnEntsMode()
if SERVER then
return ix.config.Get("sitEntMode", 3)
end
return 3
end
local blacklist = SitAnywhere.ClassBlacklist
local model_blacklist = SitAnywhere.ModelBlacklist
function SitAnywhere.ValidSitTrace(ply, EyeTrace)
if not EyeTrace.Hit then return false end
if EyeTrace.HitPos:Distance(EyeTrace.StartPos) > 100 then return false end
local t = hook.Run("CheckValidSit", ply, EyeTrace)
if t == false or t == true then
return t
end
local mode = GetSitOnEntsMode()
if not EyeTrace.HitWorld and mode == 0 then return false end
if not EyeTrace.HitWorld and blacklist[string.lower(EyeTrace.Entity:GetClass())] then return false end
if not EyeTrace.HitWorld and EyeTrace.Entity:GetModel() and model_blacklist[string.lower(EyeTrace.Entity:GetModel())] then return false end
if EMETA.CPPIGetOwner and mode >= 1 then
if mode == 1 then
if not EyeTrace.HitWorld then
local owner = EyeTrace.Entity:CPPIGetOwner()
if type(owner) == "Player" and owner ~= nil and owner:IsValid() and owner:IsPlayer() then
return false
end
end
elseif mode == 2 then
if not EyeTrace.HitWorld then
local owner = EyeTrace.Entity:CPPIGetOwner()
if type(owner) == "Player" and owner ~= nil and owner:IsValid() and owner:IsPlayer() and owner ~= ply then
return false
end
end
end
end
return true
end
local seatClass = "prop_vehicle_prisoner_pod"
local PMETA = FindMetaTable("Player")
function PMETA:GetSitters()
local seats, holders = {}, {}
local function processSeat(seat, depth)
depth = (depth or 0) + 1
if IsValid(seat:GetDriver()) and seat:GetDriver() ~= self then
table.insert(seats, seat)
end
for _, v in pairs(seat:GetChildren()) do
if IsValid(v) and v:GetClass() == seatClass and IsValid(v:GetDriver()) and #v:GetChildren() > 0 and depth <= 128 then
processSeat(v, depth)
end
end
end
local plyVehicle = self:GetVehicle()
if IsValid(plyVehicle) and plyVehicle:GetClass() == seatClass then
processSeat(plyVehicle)
end
for _, v in pairs(self:GetChildren()) do
if IsValid(v) and v:GetClass() == seatClass then
processSeat(v)
end
end
for _, v in pairs(ents.FindByClass("sit_holder")) do
if v.GetTargetPlayer and v:GetTargetPlayer() == self then
table.insert(holders, v)
if v.GetSeat and IsValid(v:GetSeat()) then
processSeat(v:GetSeat())
end
end
end
return seats, holders
end
function PMETA:IsPlayerSittingOn(ply)
local seats = ply:GetSitters()
for _,v in pairs(seats) do
if IsValid(v:GetDriver()) and v:GetDriver() == self then return true end
end
return false
end
function PMETA:GetSitting()
if not IsValid(self:GetVehicle()) then return false end
local veh = self:GetVehicle()
if veh:GetNWBool("playerdynseat", false) then
local parent = veh:GetParent()
if IsValid(parent) and parent:GetClass() == "sit_holder" then
return veh, parent
else
return veh
end
end
return false
end
function PMETA:ExitSit()
if CLIENT then
if self ~= LocalPlayer() then return end
net.Start("SitAnywhere")
net.WriteInt(SitAnywhere.NET.SitRequestExit, 4)
net.SendToServer()
else
local seat, holder = self:GetSitting()
SafeRemoveEntity(seat)
SafeRemoveEntity(holder)
if SitAnywhere.GroundSit and self:GetNWBool("SitGroundSitting", false) then
self:SetNWBool("SitGroundSitting", false)
end
end
end
function EMETA:IsSitAnywhereSeat()
if self:GetClass() ~= "prop_vehicle_prisoner_pod" then return false end
if SERVER and self.playerdynseat then return true end
return self:GetNWBool("playerdynseat", false)
end

View File

@@ -0,0 +1,9 @@
PLUGIN.name = "Sit Anywhere"
PLUGIN.author = "Xerasin / Ported by RefoselTeamWork"
PLUGIN.description = "Позволяет игрокам садиться везде с помощью клавиши использования."
ix.util.Include("sh_helpers.lua")
ix.util.Include("sv_plugin.lua", "server")
ix.util.Include("sv_unstuck.lua", "server")
ix.util.Include("cl_plugin.lua", "client")

View File

@@ -0,0 +1,605 @@
local TAG = "SitAny_"
local PLUGIN = PLUGIN
SitAnywhere = SitAnywhere or {}
local NextUse = setmetatable({}, {__mode = 'k', __index = function() return 0 end})
-- Конфигурация через ix.config
ix.config.Add("sitOnPlayers", true, "Разрешить сидеть на игроках в SitAnywhere", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitOnPlayerEntities", true, "Разрешить сидеть на сущностях игроков", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitPlayerDamage", false, "Разрешить урон сидящим игрокам", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAllowWeapons", false, "Разрешить использование оружия при сидении", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAdminOnly", false, "Только админы могут сидеть", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAntiPropSurf", true, "Запретить физган на объектах с сидящими игроками", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAntiToolAbuse", true, "Запретить тулган на объектах с сидящими игроками", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAllowTightPlaces", false, "Разрешить сидеть в тесных местах", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitForceNoWalk", false, "Отключить необходимость шага для сидения", nil, {
category = "Sit Anywhere"
})
local META = FindMetaTable("Player")
util.AddNetworkString("SitAnywhere")
net.Receive("SitAnywhere", function(len, ply)
local netID = net.ReadInt(4)
if netID == SitAnywhere.NET.SitWantedAng then
local wantedAng, traceStart, traceNormal = net.ReadFloat(), net.ReadVector(), net.ReadVector()
if traceStart:Distance(ply:EyePos()) > 10 then return end
local trace = util.TraceLine({
start = traceStart,
endpos = traceStart + traceNormal * 12000,
filter = player.GetAll()
})
ply:Sit(trace, nil, nil, nil, nil, nil, wantedAng)
elseif netID == SitAnywhere.NET.SitRequestExit then
ply:ExitSit()
end
end)
local function Sit(ply, pos, ang, parent, parentbone, func, exit)
if IsValid(ply:GetVehicle()) then
local veh = ply:GetVehicle()
if veh:GetClass() == "prop_vehicle_prisoner_pod" and IsValid(veh.holder) then
SafeRemoveEntity(veh.holder)
end
ply:ExitVehicle()
end
local vehicle = ents.Create("prop_vehicle_prisoner_pod")
local t = hook.Run("OnPlayerSit", ply, pos, ang, parent or NULL, parentbone, vehicle)
if t == false then
SafeRemoveEntity(vehicle)
return false
end
vehicle:SetAngles(ang)
pos = pos + vehicle:GetUp() * 18
vehicle:SetPos(pos)
vehicle.playerdynseat = true
vehicle:SetNWBool("playerdynseat", true)
vehicle.sittingPly = ply
vehicle.oldpos = vehicle:WorldToLocal(ply:GetPos())
vehicle.wasCrouching = ply:Crouching()
vehicle:SetModel("models/nova/airboat_seat.mdl")
vehicle:SetKeyValue("vehiclescript", "scripts/vehicles/prisoner_pod.txt")
vehicle:SetKeyValue("limitview", "0")
vehicle:Spawn()
vehicle:Activate()
if not IsValid(vehicle) or not IsValid(vehicle:GetPhysicsObject()) then
SafeRemoveEntity(vehicle)
return false
end
local phys = vehicle:GetPhysicsObject()
vehicle:SetMoveType(MOVETYPE_PUSH)
phys:Sleep()
vehicle:SetCollisionGroup(COLLISION_GROUP_WORLD)
vehicle:SetNotSolid(true)
phys:Sleep()
phys:EnableGravity(false)
phys:EnableMotion(false)
phys:EnableCollisions(false)
phys:SetMass(1)
vehicle:CollisionRulesChanged()
vehicle:DrawShadow(false)
vehicle:SetColor(Color(0,0,0,0))
vehicle:SetRenderMode(RENDERMODE_TRANSALPHA)
vehicle:SetNoDraw(true)
vehicle.VehicleName = "Airboat Seat"
vehicle.ClassOverride = "prop_vehicle_prisoner_pod"
vehicle.PhysgunDisabled = true
vehicle.m_tblToolsAllowed = {}
vehicle.customCheck = function() return false end
if IsValid(parent) then
local r = math.rad(ang.yaw + 90)
vehicle.plyposhack = vehicle:WorldToLocal(pos + Vector(math.cos(r) * 2, math.sin(r) * 2, 2))
vehicle:SetParent(parent)
vehicle.parent = parent
else
vehicle.OnWorld = true
end
local prev = ply:GetAllowWeaponsInVehicle()
if prev then
ply.sitting_allowswep = nil
elseif ix.config.Get("sitAllowWeapons", false) then
ply.sitting_allowswep = prev
ply:SetAllowWeaponsInVehicle(true)
end
ply:EnterVehicle(vehicle)
if ix.config.Get("sitPlayerDamage", false) then
ply:SetCollisionGroup(COLLISION_GROUP_WEAPON)
ply:CollisionRulesChanged()
end
if func then
func(ply)
end
ply.seatExit = exit
ply:SetEyeAngles(Angle(0,90,0))
return vehicle
end
local d = function(a,b) return math.abs(a-b) end
local SittingOnPlayerPoses = {
{
Pos = Vector(-33, 13, 7),
Ang = Angle(0, 90, 90),
FindAng = 90,
},
{
Pos = Vector(33, 13, 7),
Ang = Angle(0, 270, 90),
Func = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(0,90,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(0,90,0))
end,
OnExitFunc = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(0,0,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(0,0,0))
end,
FindAng = 270,
},
{
Pos = Vector(0, 16, -15),
Ang = Angle(0, 180, 0),
Func = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(45,0,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(-45,0,0))
end,
OnExitFunc = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(0,0,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(0,0,0))
end,
FindAng = 0,
},
{
Pos = Vector(0, 8, -18),
Ang = Angle(0, 0, 0),
FindAng = 180,
},
}
local lookup = {}
for k,v in pairs(SittingOnPlayerPoses) do
table.insert(lookup, {v.FindAng, v})
table.insert(lookup, {v.FindAng + 360, v})
table.insert(lookup, {v.FindAng - 360, v})
end
local function FindPose(this,me)
local avec = me:GetAimVector()
avec.z = 0
avec:Normalize()
local evec = this:GetRight()
evec.z = 0
evec:Normalize()
local derp = avec:Dot(evec)
local avec2 = me:GetAimVector()
avec2.z = 0
avec2:Normalize()
local evec2 = this:GetForward()
evec2.z = 0
evec2:Normalize()
local herp = avec2:Dot(evec2)
local v = Vector(derp,herp,0)
local a = v:Angle()
local ang = a.y
ang = ang + 90 + 180
ang = ang % 360
table.sort(lookup,function(aa,bb)
return d(ang,aa[1]) < d(ang,bb[1])
end)
return lookup[1][2]
end
function META.Sit(ply, EyeTrace, ang, parent, parentbone, func, exit, wantedAng)
if EyeTrace == nil then
EyeTrace = ply:GetEyeTrace()
elseif type(EyeTrace) == "Vector" then
return Sit(ply, EyeTrace, ang or Angle(0,0,0), parent, parentbone or 0, func, exit)
end
local valid, ent = SitAnywhere.ValidSitTrace(ply, EyeTrace)
if not valid then return end
local surfaceAng = EyeTrace.HitNormal:Angle() + Angle(-270, 0, 0)
ang = surfaceAng
if wantedAng and math.abs(surfaceAng.pitch) <= 15 then
ent = EyeTrace.Entity
if EyeTrace.HitWorld or not ent:IsPlayer() then
if SitAnywhere.CheckValidAngForSit(EyeTrace.HitPos, EyeTrace.HitNormal:Angle(), wantedAng) then
ang.yaw = wantedAng + 90
else
return
end
end
return Sit(ply, EyeTrace.HitPos - Vector(0, 0, 23), ang, ent, EyeTrace.PhysicsBone or 0)
end
if ix.config.Get("sitOnPlayers", true) then
local veh
if not EyeTrace.HitWorld and IsValid(EyeTrace.Entity) and EyeTrace.Entity:IsPlayer() and IsValid(EyeTrace.Entity:GetVehicle()) and EyeTrace.Entity:GetVehicle().playerdynseat then
local safe = 256
veh = EyeTrace.Entity:GetVehicle()
while IsValid(veh.SittingOnMe) and IsValid(veh.SittingOnMe:GetDriver()) and safe > 0 do
safe = safe - 1
veh = veh.SittingOnMe
end
else
for k, v in pairs(ents.FindInSphere(EyeTrace.HitPos, 12)) do
local safe = 256
veh = v
while IsValid(veh.SittingOnMe) and IsValid(veh.SittingOnMe:GetDriver()) and safe > 0 do
safe = safe - 1
veh = veh.SittingOnMe
end
end
end
if IsValid(veh) and veh:GetClass() == "prop_vehicle_prisoner_pod" and veh:GetModel() ~= "models/vehicles/prisoner_pod_inner.mdl" and veh:GetDriver() and veh:GetDriver():IsValid() and not veh.PlayerSitOnPlayer then
if IsValid(veh.holder) and veh.holder.GetTargetPlayer and veh.holder:GetTargetPlayer() == ply then return end
if veh:GetDriver():GetInfoNum("sitting_allow_on_me", 1) == 0 then
ply:ChatPrint(("%s отключил возможность сидеть на нём!"):format(veh:GetDriver():Name()))
return false
end
local pose = FindPose(veh, ply)
local pos = veh:GetDriver():GetPos()
if veh.plyposhack then
pos = veh:LocalToWorld(veh.plyposhack)
end
local vec, ang2 = LocalToWorld(pose.Pos, pose.Ang, pos, veh:GetAngles())
if veh:GetParent() == ply then return false end
ent = Sit(ply, vec, ang2, veh, 0, pose.Func, pose.OnExitFunc)
if ent and IsValid(ent) then
ent.PlayerOnPlayer = true
veh.SittingOnMe = ent
end
return true, ent
end
else
for k, v in pairs(ents.FindInSphere(EyeTrace.HitPos, 5)) do
if v.playerdynseat then
return false
end
end
end
local shouldSitOnPlayer = (ply.IsFlying and ply:IsFlying()) or EyeTrace.Entity == ply:GetGroundEntity() or ply:GetMoveType() == MOVETYPE_NOCLIP
if IsValid(EyeTrace.Entity) and EyeTrace.Entity:IsPlayer() and ix.config.Get("sitOnPlayerEntities", true) and shouldSitOnPlayer then
ent = EyeTrace.Entity
if IsValid(ent:GetVehicle()) then return end
local min, max = ent:GetCollisionBounds()
local zadjust = math.abs(min.z) + math.abs(max.z)
local seatPos = ent:GetPos() + Vector(0, 0, 10 + zadjust / 2)
local vehicle = Sit(ply, seatPos, ply:GetAngles(), ent, EyeTrace.PhysicsBone or 0)
return vehicle
end
if math.abs(surfaceAng.pitch) <= 15 then
ang = Angle()
local sampleResolution = 24
local dists, distsang, ang_smallest_hori, smallest_hori = SitAnywhere.GetAreaProfile(EyeTrace.HitPos, sampleResolution, false)
local infront = ((ang_smallest_hori or 0) + 180) % 360
local cancelSit, seat = hook.Run("HandleSit", ply, dists, EyeTrace)
if cancelSit then
return seat
end
if ang_smallest_hori and distsang[infront].Hit and distsang[infront].Distance > 14 and smallest_hori <= 16 then
local hori = distsang[ang_smallest_hori].HorizontalTrace
ang.yaw = (hori.HitNormal:Angle().yaw - 90)
return Sit(ply, EyeTrace.HitPos - Vector(0, 0, 23), ang, (not EyeTrace.HitWorld) and EyeTrace.Entity, EyeTrace.PhysicsBone or 0)
else
table.sort(dists, function(a,b) return b.Distance < a.Distance end)
local wants = {}
local eyeang = ply:EyeAngles() + Angle(0, 180, 0)
for I = 1, #dists do
local trace = dists[I]
local behind = distsang[(trace.ang + 180) % 360]
if behind.Distance2 > 3 then
table.insert(wants, {
cost = math.abs(eyeang.yaw - trace.ang),
ang = trace.ang,
})
end
end
table.sort(wants,function(a,b) return b.cost > a.cost end)
if #wants == 0 then return end
ang.yaw = (wants[1].ang - 90)
return Sit(ply, EyeTrace.HitPos - Vector(0, 0, 23), ang, (not EyeTrace.HitWorld) and EyeTrace.Entity, EyeTrace.PhysicsBone or 0)
end
end
end
local function checkAllowSit(ply)
local allowSit = hook.Run("ShouldAllowSit", ply)
local bottom, top = ply:GetHull()
local diff = top.Z - bottom.Z
local trace = util.QuickTrace(ply:GetPos(), Vector(0, 0, diff), player.GetAll())
if not ix.config.Get("sitAllowTightPlaces", false) and trace.HitWorld then return false end
if allowSit == false or allowSit == true then
return allowSit
end
if ix.config.Get("sitAdminOnly", false) and not ply:IsAdmin() then
return false
end
return true
end
local function sitcmd(ply)
if not IsValid(ply) then return end
if ply:InVehicle() then return end
if not checkAllowSit(ply) then return end
local now = CurTime()
if NextUse[ply] > now then return end
if ply:Sit() then
NextUse[ply] = now + 1
else
NextUse[ply] = now + 0.1
end
end
concommand.Add("sit", function(ply, cmd, args)
sitcmd(ply)
end)
local function UndoSitting(ply)
if not IsValid(ply) then return end
local prev = ply.sitting_allowswep
if prev ~= nil then
ply.sitting_allowswep = nil
ply:SetAllowWeaponsInVehicle(prev)
end
if ix.config.Get("sitPlayerDamage", false) then
ply:SetCollisionGroup(COLLISION_GROUP_PLAYER)
ply:CollisionRulesChanged()
end
if ply.seatExit then
ply.seatExit(ply)
ply.seatExit = nil
end
end
-- Хуки
function PLUGIN:CanExitVehicle(seat, ply)
if not IsValid(seat) or not IsValid(ply) then return end
if not seat.playerdynseat then return end
if CurTime() < NextUse[ply] then return false end
end
function PLUGIN:PlayerLeaveVehicle(ply, seat)
if not IsValid(seat) or not IsValid(ply) then return end
if not seat.playerdynseat then return end
local oldpos = seat:LocalToWorld(seat.oldpos)
ply:SetPos(oldpos)
if ply.UnStuck then
ply:UnStuck()
end
for _, v in next, seat:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
SafeRemoveEntityDelayed(seat, 1)
UndoSitting(ply)
end
function PLUGIN:AllowPlayerPickup(ply)
if ply:KeyDown(IN_WALK) then
return false
end
end
function PLUGIN:PlayerDeath(pl)
local veh = pl:GetVehicle()
if IsValid(veh) and veh.playerdynseat then
SafeRemoveEntity(veh)
end
for k, v in next, pl:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
end
function PLUGIN:PlayerEnteredVehicle(pl, veh)
for k,v in next, pl:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
DropEntityIfHeld(veh)
local parent = veh:GetParent()
if IsValid(parent) then
DropEntityIfHeld(parent)
end
end
function PLUGIN:OnPlayerSit(ply, pos, ang, parent, parentbone, vehicle)
if IsValid(parent) and parent ~= game.GetWorld() then
if parent:GetModel():sub(1, 6) ~= "models" then return false end
if parent:IsPlayer() then
if not ix.config.Get("sitOnPlayerEntities", true) then return false end
if parent:GetInfoNum("sitting_allow_on_me", 1) == 0 then
ply:ChatPrint(("%s отключил возможность сидеть на нём!"):format(parent:Name()))
return false
end
if IsValid(parent:GetVehicle()) then return false end
end
end
end
function PLUGIN:EntityRemoved(ent)
if ent.playerdynseat and IsValid(ent.sittingPly) then
UndoSitting(ent.sittingPly)
end
for _, v in next, ent:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
end
function PLUGIN:PhysgunPickup(ply, ent)
if ix.config.Get("sitAntiPropSurf", true) then
local function CheckSeat(checkPly, checkEnt, tbl)
if not checkPly:InVehicle() then return true end
local vehicle = checkPly:GetVehicle()
local parent = vehicle.parent
if parent == checkEnt then return false end
for _,v in next, checkEnt:GetChildren() do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
local cEnts = constraint.GetAllConstrainedEntities(checkEnt)
if cEnts then
for _,v in next, cEnts do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
end
end
if IsValid(ply:GetVehicle()) and ply:GetVehicle().playerdynseat then
if CheckSeat(ply, ent, {}) == false then
return false
end
end
end
end
function PLUGIN:CanTool(ply, tr)
if ix.config.Get("sitAntiToolAbuse", true) and IsValid(tr.Entity) then
local function CheckSeat(checkPly, checkEnt, tbl)
if not checkPly:InVehicle() then return true end
local vehicle = checkPly:GetVehicle()
local parent = vehicle.parent
if parent == checkEnt then return false end
for _,v in next, checkEnt:GetChildren() do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
local cEnts = constraint.GetAllConstrainedEntities(checkEnt)
if cEnts then
for _,v in next, cEnts do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
end
end
if IsValid(ply:GetVehicle()) and ply:GetVehicle().playerdynseat then
if CheckSeat(ply, tr.Entity, {}) == false then
return false
end
end
end
end
timer.Create("SitAnywhere_RemoveSeats", 15, 0, function()
for k,v in pairs(ents.FindByClass("prop_vehicle_prisoner_pod")) do
if v.playerdynseat and (not IsValid(v.sittingPly) or v:GetDriver() == nil or not v:GetDriver():IsValid() or v:GetDriver():GetVehicle() ~= v) then
v:Remove()
end
end
end)

View File

@@ -0,0 +1,99 @@
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