mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
421 lines
10 KiB
Lua
421 lines
10 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
|
|
-- Return if there's nothing to add on to
|
|
if ( !util ) then return end
|
|
|
|
if ( CLIENT ) then
|
|
include( "util/worldpicker.lua" )
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: IsValidPhysicsObject
|
|
Params: <ent> <num>
|
|
Desc: Returns true if physics object is valid, false if not
|
|
-----------------------------------------------------------]]
|
|
function util.IsValidPhysicsObject( ent, num )
|
|
|
|
-- Make sure the entity is valid
|
|
if ( !ent or ( !ent:IsValid() and !ent:IsWorld() ) ) then return false end
|
|
|
|
-- This is to stop attaching to walking NPCs.
|
|
-- Although this is possible and `works', it can severly reduce the
|
|
-- performance of the server.. Plus they don't pay attention to constraints
|
|
-- anyway - so we're not really losing anything.
|
|
|
|
local MoveType = ent:GetMoveType()
|
|
if ( !ent:IsWorld() and MoveType != MOVETYPE_VPHYSICS and !( ent:GetModel() and ent:GetModel():StartsWith( "*" ) ) ) then return false end
|
|
|
|
local Phys = ent:GetPhysicsObjectNum( num )
|
|
return IsValid( Phys )
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: GetPlayerTrace( ply, dir )
|
|
Desc: Returns a generic trace table for the player
|
|
(dir is optional, defaults to the player's aim)
|
|
-----------------------------------------------------------]]
|
|
function util.GetPlayerTrace( ply, dir )
|
|
|
|
dir = dir or ply:GetAimVector()
|
|
|
|
local trace = {}
|
|
|
|
trace.start = ply:EyePos()
|
|
trace.endpos = trace.start + ( dir * ( 4096 * 8 ) )
|
|
trace.filter = ply
|
|
|
|
return trace
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: QuickTrace( origin, offset, filter )
|
|
Desc: Quick trace
|
|
-----------------------------------------------------------]]
|
|
function util.QuickTrace( origin, dir, filter )
|
|
|
|
local trace = {}
|
|
|
|
trace.start = origin
|
|
trace.endpos = origin + dir
|
|
trace.filter = filter
|
|
|
|
return util.TraceLine( trace )
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: tobool( in )
|
|
Desc: Turn variable into bool
|
|
-----------------------------------------------------------]]
|
|
util.tobool = tobool
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: LocalToWorld( ent, lpos, bone )
|
|
Desc: Convert the local position on an entity to world pos
|
|
-----------------------------------------------------------]]
|
|
function util.LocalToWorld( ent, lpos, bone )
|
|
|
|
bone = bone or 0
|
|
if ( ent:EntIndex() == 0 ) then
|
|
return lpos
|
|
else
|
|
if ( IsValid( ent:GetPhysicsObjectNum( bone ) ) ) then
|
|
return ent:GetPhysicsObjectNum( bone ):LocalToWorld( lpos )
|
|
else
|
|
return ent:LocalToWorld( lpos )
|
|
end
|
|
end
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Returns year, month, day and hour, minute, second in a formatted string.
|
|
-----------------------------------------------------------]]
|
|
function util.DateStamp()
|
|
|
|
local t = os.date( '*t' )
|
|
return t.year .. "-" .. t.month .. "-" .. t.day .. " " .. Format( "%02i-%02i-%02i", t.hour, t.min, t.sec )
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Convert a string to a certain type
|
|
-----------------------------------------------------------]]
|
|
function util.StringToType( str, typename )
|
|
|
|
typename = typename:lower()
|
|
|
|
if ( typename == "vector" ) then return Vector( str ) end
|
|
if ( typename == "angle" ) then return Angle( str ) end
|
|
if ( typename == "float" || typename == "number" ) then return tonumber( str ) end
|
|
if ( typename == "int" ) then local v = tonumber( str ) return v and math.Round( v ) or nil end
|
|
if ( typename == "bool" || typename == "boolean" ) then return tobool( str ) end
|
|
if ( typename == "string" ) then return tostring( str ) end
|
|
if ( typename == "entity" ) then return Entity( str ) end
|
|
|
|
MsgN( "util.StringToType: unknown type \"", typename, "\"!" )
|
|
|
|
end
|
|
|
|
--
|
|
-- Convert a type to a (nice, but still parsable) string
|
|
--
|
|
function util.TypeToString( v )
|
|
|
|
local iD = TypeID( v )
|
|
|
|
if ( iD == TYPE_VECTOR or iD == TYPE_ANGLE ) then
|
|
return string.format( "%.2f %.2f %.2f", v:Unpack() )
|
|
end
|
|
|
|
if ( iD == TYPE_NUMBER ) then
|
|
return util.NiceFloat( v )
|
|
end
|
|
|
|
return tostring( v )
|
|
|
|
end
|
|
|
|
|
|
--
|
|
-- Formats a float by stripping off extra 0's and .'s
|
|
--
|
|
-- 0.00 -> 0
|
|
-- 0.10 -> 0.1
|
|
-- 1.00 -> 1
|
|
-- 1.49 -> 1.49
|
|
-- 5.90 -> 5.9
|
|
--
|
|
function util.NiceFloat( f )
|
|
|
|
local str = string.format( "%f", f )
|
|
|
|
str = str:TrimRight( "0" )
|
|
str = str:TrimRight( "." )
|
|
|
|
return str
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
-- Timer
|
|
--
|
|
--
|
|
local T =
|
|
{
|
|
--
|
|
-- Resets the timer to nothing
|
|
--
|
|
Reset = function( self )
|
|
|
|
self.endtime = nil
|
|
|
|
end,
|
|
|
|
--
|
|
-- Starts the timer, call with end time
|
|
--
|
|
Start = function( self, time )
|
|
|
|
self.endtime = CurTime() + time
|
|
|
|
end,
|
|
|
|
--
|
|
-- Returns true if the timer has been started
|
|
--
|
|
Started = function( self )
|
|
|
|
return self.endtime != nil
|
|
|
|
end,
|
|
|
|
--
|
|
-- Returns true if the time has elapsed
|
|
--
|
|
Elapsed = function( self )
|
|
|
|
return self.endtime == nil or self.endtime <= CurTime()
|
|
|
|
end
|
|
}
|
|
|
|
T.__index = T
|
|
|
|
--
|
|
-- Create a new timer object
|
|
--
|
|
function util.Timer( startdelay )
|
|
|
|
startdelay = startdelay or 0
|
|
|
|
local t = {}
|
|
setmetatable( t, T )
|
|
t.endtime = CurTime() + startdelay
|
|
return t
|
|
|
|
end
|
|
|
|
|
|
local function PopStack( self, num )
|
|
|
|
if ( num == nil ) then
|
|
num = 1
|
|
elseif ( num < 0 ) then
|
|
error( string.format( "attempted to pop %d elements in stack, expected >= 0", num ), 3 )
|
|
else
|
|
num = math.floor( num )
|
|
end
|
|
|
|
local len = self[ 0 ]
|
|
|
|
if ( num > len ) then
|
|
error( string.format( "attempted to pop %u element%s in stack of length %u", num, num == 1 and "" or "s", len ), 3 )
|
|
end
|
|
|
|
return num, len
|
|
|
|
end
|
|
|
|
local STACK =
|
|
{
|
|
Push = function( self, obj )
|
|
local len = self[ 0 ] + 1
|
|
self[ len ] = obj
|
|
self[ 0 ] = len
|
|
end,
|
|
|
|
Pop = function( self, num )
|
|
local len
|
|
num, len = PopStack( self, num )
|
|
|
|
if ( num == 0 ) then
|
|
return nil
|
|
end
|
|
|
|
local newlen = len - num
|
|
self[ 0 ] = newlen
|
|
|
|
newlen = newlen + 1
|
|
local ret = self[ newlen ]
|
|
|
|
-- Pop up to the last element
|
|
for i = len, newlen, -1 do
|
|
self[ i ] = nil
|
|
end
|
|
|
|
return ret
|
|
end,
|
|
|
|
PopMulti = function( self, num )
|
|
local len
|
|
num, len = PopStack( self, num )
|
|
|
|
if ( num == 0 ) then
|
|
return {}
|
|
end
|
|
|
|
local newlen = len - num
|
|
self[ 0 ] = newlen
|
|
|
|
local ret = {}
|
|
local retpos = 0
|
|
|
|
-- Pop each element and add it to the table
|
|
-- Iterate in reverse since the stack is internally stored
|
|
-- with 1 being the bottom element and len being the top
|
|
-- But the return will have 1 as the top element
|
|
for i = len, newlen + 1, -1 do
|
|
retpos = retpos + 1
|
|
ret[ retpos ] = self[ i ]
|
|
|
|
self[ i ] = nil
|
|
end
|
|
|
|
return ret
|
|
end,
|
|
|
|
Top = function( self )
|
|
local len = self[ 0 ]
|
|
|
|
if ( len == 0 ) then
|
|
return nil
|
|
end
|
|
|
|
return self[ len ]
|
|
end,
|
|
|
|
Size = function( self )
|
|
return self[ 0 ]
|
|
end
|
|
}
|
|
|
|
STACK.__index = STACK
|
|
|
|
function util.Stack()
|
|
return setmetatable( { [ 0 ] = 0 }, STACK )
|
|
end
|
|
|
|
-- Helper for the following functions. This is not ideal but we cannot change this because it will break existing addons.
|
|
local function GetUniqueID( sid )
|
|
return util.CRC( "gm_" .. sid .. "_gm" )
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: GetPData( steamid, name, default )
|
|
Desc: Gets the persistant data from a player by steamid
|
|
-----------------------------------------------------------]]
|
|
function util.GetPData( steamid, name, default )
|
|
|
|
-- First try looking up using the new key
|
|
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
|
local val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( key ) .. " LIMIT 1" )
|
|
if ( val == nil ) then
|
|
|
|
-- Not found? Look using the old key
|
|
local oldkey = Format( "%s[%s]", GetUniqueID( steamid ), name )
|
|
val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) .. " LIMIT 1" )
|
|
if ( val == nil ) then return default end
|
|
|
|
end
|
|
|
|
return val
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: SetPData( steamid, name, value )
|
|
Desc: Sets the persistant data of a player by steamid
|
|
-----------------------------------------------------------]]
|
|
function util.SetPData( steamid, name, value )
|
|
|
|
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
|
sql.Query( "REPLACE INTO playerpdata ( infoid, value ) VALUES ( " .. SQLStr( key ) .. ", " .. SQLStr( value ) .. " )" )
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: RemovePData( steamid, name )
|
|
Desc: Removes the persistant data from a player by steamid
|
|
-----------------------------------------------------------]]
|
|
function util.RemovePData( steamid, name )
|
|
|
|
-- First the old key
|
|
local oldkey = Format( "%s[%s]", GetUniqueID( steamid ), name )
|
|
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) )
|
|
|
|
-- Then the new key. util.SteamIDTo64 is not ideal, but nothing we can do about it now
|
|
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
|
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( key ) )
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: IsBinaryModuleInstalled( name )
|
|
Desc: Returns whether a binary module with the given name is present on disk
|
|
-----------------------------------------------------------]]
|
|
local suffix = ( { "osx64", "osx", "linux64", "linux", "win64", "win32" } )[
|
|
( system.IsWindows() and 4 or 0 )
|
|
+ ( system.IsLinux() and 2 or 0 )
|
|
+ ( jit.arch == "x86" and 1 or 0 )
|
|
+ 1
|
|
]
|
|
local fmt = "lua/bin/gm" .. ( ( CLIENT and !MENU_DLL ) and "cl" or "sv" ) .. "_%s_%s.dll"
|
|
function util.IsBinaryModuleInstalled( name )
|
|
if ( !isstring( name ) ) then
|
|
error( "bad argument #1 to 'IsBinaryModuleInstalled' (string expected, got " .. type( name ) .. ")" )
|
|
elseif ( #name == 0 ) then
|
|
error( "bad argument #1 to 'IsBinaryModuleInstalled' (string cannot be empty)" )
|
|
end
|
|
|
|
if ( file.Exists( string.format( fmt, name, suffix ), "MOD" ) ) then
|
|
return true
|
|
end
|
|
|
|
-- Edge case - on Linux 32-bit x86-64 branch, linux32 is also supported as a suffix
|
|
if ( jit.versionnum != 20004 and jit.arch == "x86" and system.IsLinux() ) then
|
|
return file.Exists( string.format( fmt, name, "linux32" ), "MOD" )
|
|
end
|
|
|
|
return false
|
|
end
|