Files
wnsrc/lua/includes/extensions/util.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

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