forked from TeamUlysses/ulib
Implements #332
This commit is contained in:
parent
27cd8afbf9
commit
5a393ca6fd
@ -49,6 +49,7 @@ v2.60 - *(00/00/00)*
|
||||
* [ADD] ULib.ucl.getUserInfoFromID for getting user info from an ID.
|
||||
* [ADD] CAMI support.
|
||||
* [ADD] "noMount" parameter to file-related APIs.
|
||||
* [ADD] ULibGetUser(s)CustomKeyword hooks (Thanks, LuaTenshi).
|
||||
* [FIX] The usual random slew of Garry-breakages (Thanks, Fuzzik).
|
||||
* [FIX] An assumption regarding player authentication that led to a player's group being reset to user sometimes.
|
||||
* [FIX] Garry API change for ULib.findinDir (Thanks, ascentechit).
|
||||
|
@ -1,247 +1,286 @@
|
||||
--[[
|
||||
Title: Defines
|
||||
|
||||
Holds some defines used on both client and server.
|
||||
]]
|
||||
|
||||
ULib = ULib or {}
|
||||
|
||||
|
||||
ULib.VERSION = 2.60
|
||||
|
||||
ULib.ACCESS_ALL = "user"
|
||||
ULib.ACCESS_OPERATOR = "operator"
|
||||
ULib.ACCESS_ADMIN = "admin"
|
||||
ULib.ACCESS_SUPERADMIN = "superadmin"
|
||||
|
||||
ULib.DEFAULT_ACCESS = ULib.ACCESS_ALL
|
||||
|
||||
ULib.DEFAULT_TSAY_COLOR = Color( 151, 211, 255 ) -- Found by using MS Paint
|
||||
|
||||
|
||||
--[[
|
||||
Section: Umsg Helpers
|
||||
|
||||
These are ids for the ULib umsg functions, so the client knows what they're getting.
|
||||
]]
|
||||
ULib.TYPE_ANGLE = 1
|
||||
ULib.TYPE_BOOLEAN = 2
|
||||
ULib.TYPE_CHAR = 3
|
||||
ULib.TYPE_ENTITY = 4
|
||||
ULib.TYPE_FLOAT = 5
|
||||
ULib.TYPE_LONG = 6
|
||||
ULib.TYPE_SHORT = 7
|
||||
ULib.TYPE_STRING = 8
|
||||
ULib.TYPE_VECTOR = 9
|
||||
-- These following aren't actually datatypes, we handle them ourselves
|
||||
ULib.TYPE_TABLE_BEGIN = 10
|
||||
ULib.TYPE_TABLE_END = 11
|
||||
ULib.TYPE_NIL = 12
|
||||
|
||||
ULib.RPC_UMSG_NAME = "URPC"
|
||||
|
||||
ULib.TYPE_SIZE = {
|
||||
[ULib.TYPE_ANGLE] = 12, -- 3 floats
|
||||
[ULib.TYPE_BOOLEAN] = 1,
|
||||
[ULib.TYPE_CHAR] = 1,
|
||||
[ULib.TYPE_ENTITY] = 4, -- Found through trial and error
|
||||
[ULib.TYPE_FLOAT] = 4,
|
||||
[ULib.TYPE_LONG] = 4,
|
||||
[ULib.TYPE_SHORT] = 2,
|
||||
[ULib.TYPE_VECTOR] = 12, -- 3 floats
|
||||
[ULib.TYPE_NIL] = 0, -- Not technically a type but we handle it anyways
|
||||
}
|
||||
|
||||
ULib.MAX_UMSG_BYTES = 255
|
||||
|
||||
--[[
|
||||
Section: Hooks
|
||||
|
||||
These are the hooks that ULib has created that other modders are free to make use of.
|
||||
]]
|
||||
|
||||
--[[
|
||||
Hook: UCLAuthed
|
||||
|
||||
Called *on both server and client* when a player has been (re)authenticated by UCL. Called for ALL players, regardless of access.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that got (re)authenticated.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_UCLAUTH = "UCLAuthed"
|
||||
|
||||
--[[
|
||||
Hook: UCLChanged
|
||||
|
||||
Called *on both server and client* when anything in ULib.ucl.users, ULib.ucl.authed, or ULib.ucl.groups changes. No parameters are passed to callbacks.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_UCLCHANGED = "UCLChanged"
|
||||
|
||||
--[[
|
||||
Hook: ULibReplicatedCvarChanged
|
||||
|
||||
Called *on both client and server* when a replicated cvar changes or is created.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
sv_cvar - The name of the server-side cvar.
|
||||
cl_cvar - The name of the client-side cvar.
|
||||
ply - The player changing the cvar or nil on initial value.
|
||||
old_value - The previous value of the cvar, nil if this call is to set the initial value.
|
||||
new_value - The new value of the cvar.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
v2.50 - Removed nil on client side restriction.
|
||||
]]
|
||||
ULib.HOOK_REPCVARCHANGED = "ULibReplicatedCvarChanged"
|
||||
|
||||
--[[
|
||||
Hook: ULibLocalPlayerReady
|
||||
|
||||
Called *on both client and server* when a player entity is created. (can now run commands). Only works for local
|
||||
player on the client side.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that's ready (local player on client side).
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_LOCALPLAYERREADY = "ULibLocalPlayerReady"
|
||||
|
||||
--[[
|
||||
Hook: ULibCommandCalled
|
||||
|
||||
Called *on server* whenever a ULib command is run, return false to override and not allow, true to stop executing callbacks and allow.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player attempting to execute the command.
|
||||
commandName - The command that's being executed.
|
||||
args - The table of args for the command.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_COMMAND_CALLED = "ULibCommandCalled"
|
||||
|
||||
--[[
|
||||
Hook: ULibPlayerTarget
|
||||
|
||||
Called whenever one player is about to target another player. Called *BEFORE* any other validation
|
||||
takes place. Return false and error message to disallow target completely, return true to
|
||||
override any other validation logic and allow the target to take place, return a player to force
|
||||
the target to be the specified player.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player attempting to execute the command.
|
||||
commandName - The command that's being executed.
|
||||
target - The proposed target of the command before any other validation logic takes place.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_PLAYER_TARGET = "ULibPlayerTarget"
|
||||
|
||||
--[[
|
||||
Hook: ULibPlayerTargets
|
||||
|
||||
Called whenever one player is about to target another set of players. Called *BEFORE* any other validation
|
||||
takes place. Return false and error message to disallow target completely, return true to
|
||||
override any other validation logic and allow the target to take place, return a table of players to force
|
||||
the targets to be the specified players.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player attempting to execute the command.
|
||||
commandName - The command that's being executed.
|
||||
targets - The proposed targets of the command before any other validation logic takes place.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_PLAYER_TARGETS = "ULibPlayerTargets" -- Exactly the same as the above but used when the player is using a command that can target multiple players.
|
||||
|
||||
--[[
|
||||
Hook: ULibPostTranslatedCommand
|
||||
|
||||
*Server hook*. Called after a translated command (ULib.cmds.TranslatedCommand) has been successfully
|
||||
verified. This hook directly follows the callback for the command itself.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that executed the command.
|
||||
commandName - The command that's being executed.
|
||||
translated_args - A table of the translated arguments, as passed into the callback function itself.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_POST_TRANSLATED_COMMAND = "ULibPostTranslatedCommand"
|
||||
|
||||
--[[
|
||||
Hook: ULibPlayerNameChanged
|
||||
|
||||
Called within one second of a player changing their name.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that changed names.
|
||||
oldName - The player's old name, before the change.
|
||||
newName - The player's new name, after the change.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_PLAYER_NAME_CHANGED = "ULibPlayerNameChanged"
|
||||
|
||||
--[[
|
||||
Section: UCL Helpers
|
||||
|
||||
These defines are server-only, to help with UCL.
|
||||
]]
|
||||
if SERVER then
|
||||
ULib.UCL_LOAD_DEFAULT = true -- Set this to false to ignore the SetUserGroup() call.
|
||||
ULib.UCL_USERS = "data/ulib/users.txt"
|
||||
ULib.UCL_GROUPS = "data/ulib/groups.txt"
|
||||
ULib.UCL_REGISTERED = "data/ulib/misc_registered.txt" -- Holds access strings that ULib has already registered
|
||||
ULib.BANS_FILE = "data/ulib/bans.txt"
|
||||
ULib.VERSION_FILE = "data/ulib/version.txt"
|
||||
|
||||
ULib.DEFAULT_GRANT_ACCESS = { allow={}, deny={}, guest=true }
|
||||
|
||||
hook.Add( "Initialize", "ULibCheckFileInit", function()
|
||||
if ULib.fileExists( ULib.UCL_REGISTERED ) and ULib.fileExists( "addons/ulib/data/" .. ULib.UCL_GROUPS ) and ULib.fileRead( ULib.UCL_GROUPS ) == ULib.fileRead( "addons/ulib/data/" .. ULib.UCL_GROUPS ) then
|
||||
-- File has been reset, delete registered
|
||||
ULib.fileDelete( ULib.UCL_REGISTERED )
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--[[
|
||||
Section: Net pooled strings
|
||||
|
||||
These defines are server-only, to help with the networking library.
|
||||
]]
|
||||
if SERVER then
|
||||
util.AddNetworkString( "URPC" )
|
||||
end
|
||||
--[[
|
||||
Title: Defines
|
||||
|
||||
Holds some defines used on both client and server.
|
||||
]]
|
||||
|
||||
ULib = ULib or {}
|
||||
|
||||
|
||||
ULib.VERSION = 2.60
|
||||
|
||||
ULib.ACCESS_ALL = "user"
|
||||
ULib.ACCESS_OPERATOR = "operator"
|
||||
ULib.ACCESS_ADMIN = "admin"
|
||||
ULib.ACCESS_SUPERADMIN = "superadmin"
|
||||
|
||||
ULib.DEFAULT_ACCESS = ULib.ACCESS_ALL
|
||||
|
||||
ULib.DEFAULT_TSAY_COLOR = Color( 151, 211, 255 ) -- Found by using MS Paint
|
||||
|
||||
|
||||
--[[
|
||||
Section: Umsg Helpers
|
||||
|
||||
These are ids for the ULib umsg functions, so the client knows what they're getting.
|
||||
]]
|
||||
ULib.TYPE_ANGLE = 1
|
||||
ULib.TYPE_BOOLEAN = 2
|
||||
ULib.TYPE_CHAR = 3
|
||||
ULib.TYPE_ENTITY = 4
|
||||
ULib.TYPE_FLOAT = 5
|
||||
ULib.TYPE_LONG = 6
|
||||
ULib.TYPE_SHORT = 7
|
||||
ULib.TYPE_STRING = 8
|
||||
ULib.TYPE_VECTOR = 9
|
||||
-- These following aren't actually datatypes, we handle them ourselves
|
||||
ULib.TYPE_TABLE_BEGIN = 10
|
||||
ULib.TYPE_TABLE_END = 11
|
||||
ULib.TYPE_NIL = 12
|
||||
|
||||
ULib.RPC_UMSG_NAME = "URPC"
|
||||
|
||||
ULib.TYPE_SIZE = {
|
||||
[ULib.TYPE_ANGLE] = 12, -- 3 floats
|
||||
[ULib.TYPE_BOOLEAN] = 1,
|
||||
[ULib.TYPE_CHAR] = 1,
|
||||
[ULib.TYPE_ENTITY] = 4, -- Found through trial and error
|
||||
[ULib.TYPE_FLOAT] = 4,
|
||||
[ULib.TYPE_LONG] = 4,
|
||||
[ULib.TYPE_SHORT] = 2,
|
||||
[ULib.TYPE_VECTOR] = 12, -- 3 floats
|
||||
[ULib.TYPE_NIL] = 0, -- Not technically a type but we handle it anyways
|
||||
}
|
||||
|
||||
ULib.MAX_UMSG_BYTES = 255
|
||||
|
||||
--[[
|
||||
Section: Hooks
|
||||
|
||||
These are the hooks that ULib has created that other modders are free to make use of.
|
||||
]]
|
||||
|
||||
--[[
|
||||
Hook: UCLAuthed
|
||||
|
||||
Called *on both server and client* when a player has been (re)authenticated by UCL. Called for ALL players, regardless of access.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that got (re)authenticated.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_UCLAUTH = "UCLAuthed"
|
||||
|
||||
--[[
|
||||
Hook: UCLChanged
|
||||
|
||||
Called *on both server and client* when anything in ULib.ucl.users, ULib.ucl.authed, or ULib.ucl.groups changes. No parameters are passed to callbacks.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_UCLCHANGED = "UCLChanged"
|
||||
|
||||
--[[
|
||||
Hook: ULibReplicatedCvarChanged
|
||||
|
||||
Called *on both client and server* when a replicated cvar changes or is created.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
sv_cvar - The name of the server-side cvar.
|
||||
cl_cvar - The name of the client-side cvar.
|
||||
ply - The player changing the cvar or nil on initial value.
|
||||
old_value - The previous value of the cvar, nil if this call is to set the initial value.
|
||||
new_value - The new value of the cvar.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
v2.50 - Removed nil on client side restriction.
|
||||
]]
|
||||
ULib.HOOK_REPCVARCHANGED = "ULibReplicatedCvarChanged"
|
||||
|
||||
--[[
|
||||
Hook: ULibLocalPlayerReady
|
||||
|
||||
Called *on both client and server* when a player entity is created. (can now run commands). Only works for local
|
||||
player on the client side.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that's ready (local player on client side).
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_LOCALPLAYERREADY = "ULibLocalPlayerReady"
|
||||
|
||||
--[[
|
||||
Hook: ULibCommandCalled
|
||||
|
||||
Called *on server* whenever a ULib command is run, return false to override and not allow, true to stop executing callbacks and allow.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player attempting to execute the command.
|
||||
commandName - The command that's being executed.
|
||||
args - The table of args for the command.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_COMMAND_CALLED = "ULibCommandCalled"
|
||||
|
||||
--[[
|
||||
Hook: ULibPlayerTarget
|
||||
|
||||
Called whenever one player is about to target another player. Called *BEFORE* any other validation
|
||||
takes place. Return false and error message to disallow target completely, return true to
|
||||
override any other validation logic and allow the target to take place, return a player to force
|
||||
the target to be the specified player.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player attempting to execute the command.
|
||||
commandName - The command that's being executed.
|
||||
target - The proposed target of the command before any other validation logic takes place.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_PLAYER_TARGET = "ULibPlayerTarget"
|
||||
|
||||
--[[
|
||||
Hook: ULibPlayerTargets
|
||||
|
||||
Called whenever one player is about to target another set of players. Called *BEFORE* any other validation
|
||||
takes place. Return false and error message to disallow target completely, return true to
|
||||
override any other validation logic and allow the target to take place, return a table of players to force
|
||||
the targets to be the specified players.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player attempting to execute the command.
|
||||
commandName - The command that's being executed.
|
||||
targets - The proposed targets of the command before any other validation logic takes place.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_PLAYER_TARGETS = "ULibPlayerTargets" -- Exactly the same as the above but used when the player is using a command that can target multiple players.
|
||||
|
||||
--[[
|
||||
Hook: ULibPostTranslatedCommand
|
||||
|
||||
*Server hook*. Called after a translated command (ULib.cmds.TranslatedCommand) has been successfully
|
||||
verified. This hook directly follows the callback for the command itself.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that executed the command.
|
||||
commandName - The command that's being executed.
|
||||
translated_args - A table of the translated arguments, as passed into the callback function itself.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_POST_TRANSLATED_COMMAND = "ULibPostTranslatedCommand"
|
||||
|
||||
--[[
|
||||
Hook: ULibPlayerNameChanged
|
||||
|
||||
Called within one second of a player changing their name.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
ply - The player that changed names.
|
||||
oldName - The player's old name, before the change.
|
||||
newName - The player's new name, after the change.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial
|
||||
]]
|
||||
ULib.HOOK_PLAYER_NAME_CHANGED = "ULibPlayerNameChanged"
|
||||
|
||||
--[[
|
||||
Hook: ULibGetUsersCustomKeyword
|
||||
|
||||
Called during ULib.getUsers when considering a target string for keywords.
|
||||
This could be used to create a new, custom keyword for targetting users who
|
||||
have been connected for less than five minutes, for example.
|
||||
Return nil or a table of player objects to add to the target list.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
target - A string chunk of a possibly larger target list to operate on.
|
||||
ply - The player doing the targetting, not always specified (can be nil).
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.60 - Initial
|
||||
]]
|
||||
ULib.HOOK_GETUSERS_CUSTOM_KEYWORD = "ULibGetUsersCustomKeyword"
|
||||
|
||||
--[[
|
||||
Hook: ULibGetUserCustomKeyword
|
||||
|
||||
Called during ULib.getUser when considering a target string for keywords.
|
||||
This could be used to create a new, custom keyword for always targetting a
|
||||
specific connected steamid, for example. Or, to target the shortest connected
|
||||
player.
|
||||
Return nil or a player object.
|
||||
|
||||
Parameters passed to callback:
|
||||
|
||||
target - A string target.
|
||||
ply - The player doing the targetting, not always specified (can be nil).
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.60 - Initial
|
||||
]]
|
||||
ULib.HOOK_GETUSER_CUSTOM_KEYWORD = "ULibGetUserCustomKeyword"
|
||||
|
||||
--[[
|
||||
Section: UCL Helpers
|
||||
|
||||
These defines are server-only, to help with UCL.
|
||||
]]
|
||||
if SERVER then
|
||||
ULib.UCL_LOAD_DEFAULT = true -- Set this to false to ignore the SetUserGroup() call.
|
||||
ULib.UCL_USERS = "data/ulib/users.txt"
|
||||
ULib.UCL_GROUPS = "data/ulib/groups.txt"
|
||||
ULib.UCL_REGISTERED = "data/ulib/misc_registered.txt" -- Holds access strings that ULib has already registered
|
||||
ULib.BANS_FILE = "data/ulib/bans.txt"
|
||||
ULib.VERSION_FILE = "data/ulib/version.txt"
|
||||
|
||||
ULib.DEFAULT_GRANT_ACCESS = { allow={}, deny={}, guest=true }
|
||||
|
||||
hook.Add( "Initialize", "ULibCheckFileInit", function()
|
||||
if ULib.fileExists( ULib.UCL_REGISTERED ) and ULib.fileExists( "addons/ulib/data/" .. ULib.UCL_GROUPS ) and ULib.fileRead( ULib.UCL_GROUPS ) == ULib.fileRead( "addons/ulib/data/" .. ULib.UCL_GROUPS ) then
|
||||
-- File has been reset, delete registered
|
||||
ULib.fileDelete( ULib.UCL_REGISTERED )
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--[[
|
||||
Section: Net pooled strings
|
||||
|
||||
These defines are server-only, to help with the networking library.
|
||||
]]
|
||||
if SERVER then
|
||||
util.AddNetworkString( "URPC" )
|
||||
end
|
||||
|
@ -1,337 +1,344 @@
|
||||
--[[
|
||||
Title: Player
|
||||
|
||||
Has useful player-related functions.
|
||||
]]
|
||||
|
||||
--[[
|
||||
Function: getPicker
|
||||
|
||||
Gets the player directly in front of the specified player
|
||||
|
||||
Parameters:
|
||||
|
||||
ply - The player to look for another player in front of.
|
||||
radius - *(Optional, defaults to 30)* How narrow to make our checks for players in front of us.
|
||||
|
||||
Returns:
|
||||
|
||||
The player most directly in front of us if one exists with the given constraints, otherwise nil.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial.
|
||||
]]
|
||||
function ULib.getPicker( ply, radius )
|
||||
radius = radius or 30
|
||||
|
||||
local trace = util.GetPlayerTrace( ply )
|
||||
local trace_results = util.TraceLine( trace )
|
||||
|
||||
if not trace_results.Entity:IsValid() or not trace_results.Entity:IsPlayer() then
|
||||
-- Try finding a best choice
|
||||
local best_choice
|
||||
local best_choice_diff
|
||||
local pos = ply:GetPos()
|
||||
local ang = ply:GetAimVector():Angle()
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if player ~= ply then
|
||||
local vec_diff = player:GetPos() - Vector( 0, 0, 16 ) - pos
|
||||
local newang = vec_diff:Angle()
|
||||
local diff = math.abs( math.NormalizeAngle( newang.pitch - ang.pitch ) ) + math.abs( math.NormalizeAngle( newang.yaw - ang.yaw ) )
|
||||
if not best_choice_diff or diff < best_choice_diff then
|
||||
best_choice_diff = diff
|
||||
best_choice = player
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not best_choice or best_choice_diff > radius then
|
||||
return -- Give up
|
||||
else
|
||||
return best_choice
|
||||
end
|
||||
else
|
||||
return trace_results.Entity
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local Player = FindMetaTable( "Player" )
|
||||
local checkIndexes = { Player.UniqueID, function( ply ) if CLIENT then return "" end local ip = ULib.splitPort( ply:IPAddress() ) return ip end, Player.SteamID, Player.UserID }
|
||||
--[[
|
||||
Function: getPlyByID
|
||||
|
||||
Finds a user identified by the given ID.
|
||||
|
||||
Parameters:
|
||||
|
||||
id - The ID to try to match against connected players. Can be a unique id, ip address, steam id, or user id.
|
||||
|
||||
Returns:
|
||||
|
||||
The player matching the id given or nil if none match.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.50 - Initial.
|
||||
]]
|
||||
function ULib.getPlyByID( id )
|
||||
id = id:upper()
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, indexFn in ipairs( checkIndexes ) do
|
||||
for _, ply in ipairs( players ) do
|
||||
if tostring( indexFn( ply ) ) == id then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Function: getUniqueIDForPly
|
||||
|
||||
Finds a unique ID for a player, suitable for use in getUsers or getUser to uniquely identify the given player.
|
||||
|
||||
Parameters:
|
||||
|
||||
ply - The player we want an ID for
|
||||
|
||||
Returns:
|
||||
|
||||
The id for the player or nil if none are unique.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.50 - Initial.
|
||||
v2.51 - Added exception for single player since it's handled differently on client and server.
|
||||
]]
|
||||
function ULib.getUniqueIDForPlayer( ply )
|
||||
if game.SinglePlayer() then
|
||||
return "1"
|
||||
end
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, indexFn in ipairs( checkIndexes ) do
|
||||
local id = indexFn( ply )
|
||||
if ULib.getUser( "$" .. id, true ) == ply then
|
||||
return id
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Function: getUsers
|
||||
|
||||
Finds users matching an identifier.
|
||||
|
||||
Parameters:
|
||||
|
||||
target - A string of what you'd like to target. Accepts a comma separated list.
|
||||
enable_keywords - *(Optional, defaults to false)* If true, the keywords "*" for all players, "^" for self,
|
||||
"@" for picker (person in front of you), "#<group>" for those inside a specific group,
|
||||
"%<group>" for users inside a group (counting inheritance), and "$<id>" for users matching a
|
||||
particular ID will be activated.
|
||||
Any of these can be negated with "!" before it. IE, "!^" targets everyone but yourself.
|
||||
ply - *(Optional)* Player needing getUsers, this is necessary for some of the keywords.
|
||||
|
||||
Returns:
|
||||
|
||||
A table of players (false and message if none found).
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Rewrite, added more keywords, removed immunity.
|
||||
v2.50 - Added "#" and '$' keywords, removed special exception for "%user" (replaced by "#user").
|
||||
]]
|
||||
function ULib.getUsers( target, enable_keywords, ply )
|
||||
local players = player.GetAll()
|
||||
|
||||
-- First, do a full name match in case someone's trying to exploit our target system
|
||||
for _, player in ipairs( players ) do
|
||||
if target:lower() == player:Nick():lower() then
|
||||
return { player }
|
||||
end
|
||||
end
|
||||
|
||||
-- Okay, now onto the show!
|
||||
local targetPlys = {}
|
||||
local pieces = ULib.explode( ",", target )
|
||||
for _, piece in ipairs( pieces ) do
|
||||
piece = piece:Trim()
|
||||
if piece ~= "" then
|
||||
local keywordMatch = false
|
||||
if enable_keywords then
|
||||
local tmpTargets = {}
|
||||
local negate = false
|
||||
if piece:sub( 1, 1 ) == "!" and piece:len() > 1 then
|
||||
negate = true
|
||||
piece = piece:sub( 2 )
|
||||
end
|
||||
|
||||
if piece:sub( 1, 1 ) == "$" then
|
||||
local player = ULib.getPlyByID( piece:sub( 2 ) )
|
||||
if player then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
elseif piece == "*" then -- All!
|
||||
table.Add( tmpTargets, players )
|
||||
elseif piece == "^" then -- Self!
|
||||
if ply then
|
||||
if ply:IsValid() then
|
||||
table.insert( tmpTargets, ply )
|
||||
elseif not negate then
|
||||
return false, "You cannot target yourself from console!"
|
||||
end
|
||||
end
|
||||
elseif piece == "@" then
|
||||
if IsValid( ply ) then
|
||||
local player = ULib.getPicker( ply )
|
||||
if player then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
end
|
||||
elseif piece:sub( 1, 1 ) == "#" and ULib.ucl.groups[ piece:sub( 2 ) ] then
|
||||
local group = piece:sub( 2 )
|
||||
for _, player in ipairs( players ) do
|
||||
if player:GetUserGroup() == group then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
end
|
||||
elseif piece:sub( 1, 1 ) == "%" and ULib.ucl.groups[ piece:sub( 2 ) ] then
|
||||
local group = piece:sub( 2 )
|
||||
for _, player in ipairs( players ) do
|
||||
if player:CheckGroup( group ) then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if negate then
|
||||
for _, player in ipairs( players ) do
|
||||
if not table.HasValue( tmpTargets, player ) then
|
||||
keywordMatch = true
|
||||
table.insert( targetPlys, player )
|
||||
end
|
||||
end
|
||||
else
|
||||
if #tmpTargets > 0 then
|
||||
keywordMatch = true
|
||||
table.Add( targetPlys, tmpTargets )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not keywordMatch then
|
||||
for _, player in ipairs( players ) do
|
||||
if player:Nick():lower():find( piece:lower(), 1, true ) then -- No patterns
|
||||
table.insert( targetPlys, player )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now remove duplicates
|
||||
local finalTable = {}
|
||||
for _, player in ipairs( targetPlys ) do
|
||||
if not table.HasValue( finalTable, player ) then
|
||||
table.insert( finalTable, player )
|
||||
end
|
||||
end
|
||||
|
||||
if #finalTable < 1 then
|
||||
return false, "No target found or target has immunity!"
|
||||
end
|
||||
|
||||
return finalTable
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Function: getUser
|
||||
|
||||
Finds a user matching an identifier.
|
||||
|
||||
Parameters:
|
||||
|
||||
target - A string of the user you'd like to target. IE, a partial player name.
|
||||
enable_keywords - *(Optional, defaults to false)* If true, the keywords "^" for self, "@" for picker (person in
|
||||
front of you), and "$<id>" will be activated.
|
||||
ply - *(Optional)* Player needing getUsers, this is necessary to use keywords.
|
||||
|
||||
Returns:
|
||||
|
||||
The resulting player target, false and message if no user found.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Rewrite, added keywords, removed immunity.
|
||||
v2.50 - Added "$" keyword.
|
||||
]]
|
||||
function ULib.getUser( target, enable_keywords, ply )
|
||||
local players = player.GetAll()
|
||||
target = target:lower()
|
||||
|
||||
local plyMatches = {}
|
||||
if enable_keywords and target:sub( 1, 1 ) == "$" then
|
||||
possibleId = target:sub( 2 )
|
||||
table.insert( plyMatches, ULib.getPlyByID( possibleId ) )
|
||||
end
|
||||
|
||||
-- First, do a full name match in case someone's trying to exploit our target system
|
||||
for _, player in ipairs( players ) do
|
||||
if target == player:Nick():lower() then
|
||||
if #plyMatches == 0 then
|
||||
return player
|
||||
else
|
||||
return false, "Found multiple targets! Please choose a better string for the target. (EG, the whole name)"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if enable_keywords then
|
||||
if target == "^" and ply then
|
||||
if ply:IsValid() then
|
||||
return ply
|
||||
else
|
||||
return false, "You cannot target yourself from console!"
|
||||
end
|
||||
elseif IsValid( ply ) and target == "@" then
|
||||
local player = ULib.getPicker( ply )
|
||||
if not player then
|
||||
return false, "No player found in the picker"
|
||||
else
|
||||
return player
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, player in ipairs( players ) do
|
||||
if player:Nick():lower():find( target, 1, true ) then -- No patterns
|
||||
table.insert( plyMatches, player )
|
||||
end
|
||||
end
|
||||
|
||||
if #plyMatches == 0 then
|
||||
return false, "No target found or target has immunity!"
|
||||
elseif #plyMatches > 1 then
|
||||
local str = plyMatches[ 1 ]:Nick()
|
||||
for i=2, #plyMatches do
|
||||
str = str .. ", " .. plyMatches[ i ]:Nick()
|
||||
end
|
||||
|
||||
return false, "Found multiple targets: " .. str .. ". Please choose a better string for the target. (EG, the whole name)"
|
||||
end
|
||||
|
||||
return plyMatches[ 1 ]
|
||||
end
|
||||
|
||||
--[[
|
||||
Title: Player
|
||||
|
||||
Has useful player-related functions.
|
||||
]]
|
||||
|
||||
--[[
|
||||
Function: getPicker
|
||||
|
||||
Gets the player directly in front of the specified player
|
||||
|
||||
Parameters:
|
||||
|
||||
ply - The player to look for another player in front of.
|
||||
radius - *(Optional, defaults to 30)* How narrow to make our checks for players in front of us.
|
||||
|
||||
Returns:
|
||||
|
||||
The player most directly in front of us if one exists with the given constraints, otherwise nil.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Initial.
|
||||
]]
|
||||
function ULib.getPicker( ply, radius )
|
||||
radius = radius or 30
|
||||
|
||||
local trace = util.GetPlayerTrace( ply )
|
||||
local trace_results = util.TraceLine( trace )
|
||||
|
||||
if not trace_results.Entity:IsValid() or not trace_results.Entity:IsPlayer() then
|
||||
-- Try finding a best choice
|
||||
local best_choice
|
||||
local best_choice_diff
|
||||
local pos = ply:GetPos()
|
||||
local ang = ply:GetAimVector():Angle()
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if player ~= ply then
|
||||
local vec_diff = player:GetPos() - Vector( 0, 0, 16 ) - pos
|
||||
local newang = vec_diff:Angle()
|
||||
local diff = math.abs( math.NormalizeAngle( newang.pitch - ang.pitch ) ) + math.abs( math.NormalizeAngle( newang.yaw - ang.yaw ) )
|
||||
if not best_choice_diff or diff < best_choice_diff then
|
||||
best_choice_diff = diff
|
||||
best_choice = player
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not best_choice or best_choice_diff > radius then
|
||||
return -- Give up
|
||||
else
|
||||
return best_choice
|
||||
end
|
||||
else
|
||||
return trace_results.Entity
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local Player = FindMetaTable( "Player" )
|
||||
local checkIndexes = { Player.UniqueID, function( ply ) if CLIENT then return "" end local ip = ULib.splitPort( ply:IPAddress() ) return ip end, Player.SteamID, Player.UserID }
|
||||
--[[
|
||||
Function: getPlyByID
|
||||
|
||||
Finds a user identified by the given ID.
|
||||
|
||||
Parameters:
|
||||
|
||||
id - The ID to try to match against connected players. Can be a unique id, ip address, steam id, or user id.
|
||||
|
||||
Returns:
|
||||
|
||||
The player matching the id given or nil if none match.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.50 - Initial.
|
||||
]]
|
||||
function ULib.getPlyByID( id )
|
||||
id = id:upper()
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, indexFn in ipairs( checkIndexes ) do
|
||||
for _, ply in ipairs( players ) do
|
||||
if tostring( indexFn( ply ) ) == id then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Function: getUniqueIDForPly
|
||||
|
||||
Finds a unique ID for a player, suitable for use in getUsers or getUser to uniquely identify the given player.
|
||||
|
||||
Parameters:
|
||||
|
||||
ply - The player we want an ID for
|
||||
|
||||
Returns:
|
||||
|
||||
The id for the player or nil if none are unique.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.50 - Initial.
|
||||
v2.51 - Added exception for single player since it's handled differently on client and server.
|
||||
]]
|
||||
function ULib.getUniqueIDForPlayer( ply )
|
||||
if game.SinglePlayer() then
|
||||
return "1"
|
||||
end
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, indexFn in ipairs( checkIndexes ) do
|
||||
local id = indexFn( ply )
|
||||
if ULib.getUser( "$" .. id, true ) == ply then
|
||||
return id
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Function: getUsers
|
||||
|
||||
Finds users matching an identifier.
|
||||
|
||||
Parameters:
|
||||
|
||||
target - A string of what you'd like to target. Accepts a comma separated list.
|
||||
enable_keywords - *(Optional, defaults to false)* If true, the keywords "*" for all players, "^" for self,
|
||||
"@" for picker (person in front of you), "#<group>" for those inside a specific group,
|
||||
"%<group>" for users inside a group (counting inheritance), and "$<id>" for users matching a
|
||||
particular ID will be activated.
|
||||
Any of these can be negated with "!" before it. IE, "!^" targets everyone but yourself.
|
||||
ply - *(Optional)* Player needing getUsers, this is necessary for some of the keywords.
|
||||
|
||||
Returns:
|
||||
|
||||
A table of players (false and message if none found).
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Rewrite, added more keywords, removed immunity.
|
||||
v2.50 - Added "#" and '$' keywords, removed special exception for "%user" (replaced by "#user").
|
||||
]]
|
||||
function ULib.getUsers( target, enable_keywords, ply )
|
||||
local players = player.GetAll()
|
||||
|
||||
-- First, do a full name match in case someone's trying to exploit our target system
|
||||
for _, player in ipairs( players ) do
|
||||
if target:lower() == player:Nick():lower() then
|
||||
return { player }
|
||||
end
|
||||
end
|
||||
|
||||
-- Okay, now onto the show!
|
||||
local targetPlys = {}
|
||||
local pieces = ULib.explode( ",", target )
|
||||
for _, piece in ipairs( pieces ) do
|
||||
piece = piece:Trim()
|
||||
if piece ~= "" then
|
||||
local keywordMatch = false
|
||||
if enable_keywords then
|
||||
local tmpTargets = {}
|
||||
local negate = false
|
||||
if piece:sub( 1, 1 ) == "!" and piece:len() > 1 then
|
||||
negate = true
|
||||
piece = piece:sub( 2 )
|
||||
end
|
||||
|
||||
if piece:sub( 1, 1 ) == "$" then
|
||||
local player = ULib.getPlyByID( piece:sub( 2 ) )
|
||||
if player then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
elseif piece == "*" then -- All!
|
||||
table.Add( tmpTargets, players )
|
||||
elseif piece == "^" then -- Self!
|
||||
if ply then
|
||||
if ply:IsValid() then
|
||||
table.insert( tmpTargets, ply )
|
||||
elseif not negate then
|
||||
return false, "You cannot target yourself from console!"
|
||||
end
|
||||
end
|
||||
elseif piece == "@" then
|
||||
if IsValid( ply ) then
|
||||
local player = ULib.getPicker( ply )
|
||||
if player then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
end
|
||||
elseif piece:sub( 1, 1 ) == "#" and ULib.ucl.groups[ piece:sub( 2 ) ] then
|
||||
local group = piece:sub( 2 )
|
||||
for _, player in ipairs( players ) do
|
||||
if player:GetUserGroup() == group then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
end
|
||||
elseif piece:sub( 1, 1 ) == "%" and ULib.ucl.groups[ piece:sub( 2 ) ] then
|
||||
local group = piece:sub( 2 )
|
||||
for _, player in ipairs( players ) do
|
||||
if player:CheckGroup( group ) then
|
||||
table.insert( tmpTargets, player )
|
||||
end
|
||||
end
|
||||
else
|
||||
local tblForHook = hook.Run( ULib.HOOK_GETUSERS_CUSTOM_KEYWORD, piece, ply )
|
||||
if tblForHook then
|
||||
table.Add( tmpTargets, tblForHook )
|
||||
end
|
||||
end
|
||||
|
||||
if negate then
|
||||
for _, player in ipairs( players ) do
|
||||
if not table.HasValue( tmpTargets, player ) then
|
||||
keywordMatch = true
|
||||
table.insert( targetPlys, player )
|
||||
end
|
||||
end
|
||||
else
|
||||
if #tmpTargets > 0 then
|
||||
keywordMatch = true
|
||||
table.Add( targetPlys, tmpTargets )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not keywordMatch then
|
||||
for _, player in ipairs( players ) do
|
||||
if player:Nick():lower():find( piece:lower(), 1, true ) then -- No patterns
|
||||
table.insert( targetPlys, player )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now remove duplicates
|
||||
local finalTable = {}
|
||||
for _, player in ipairs( targetPlys ) do
|
||||
if not table.HasValue( finalTable, player ) then
|
||||
table.insert( finalTable, player )
|
||||
end
|
||||
end
|
||||
|
||||
if #finalTable < 1 then
|
||||
return false, "No target found or target has immunity!"
|
||||
end
|
||||
|
||||
return finalTable
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Function: getUser
|
||||
|
||||
Finds a user matching an identifier.
|
||||
|
||||
Parameters:
|
||||
|
||||
target - A string of the user you'd like to target. IE, a partial player name.
|
||||
enable_keywords - *(Optional, defaults to false)* If true, the keywords "^" for self, "@" for picker (person in
|
||||
front of you), and "$<id>" will be activated.
|
||||
ply - *(Optional)* Player needing getUsers, this is necessary to use keywords.
|
||||
|
||||
Returns:
|
||||
|
||||
The resulting player target, false and message if no user found.
|
||||
|
||||
Revisions:
|
||||
|
||||
v2.40 - Rewrite, added keywords, removed immunity.
|
||||
v2.50 - Added "$" keyword.
|
||||
]]
|
||||
function ULib.getUser( target, enable_keywords, ply )
|
||||
local players = player.GetAll()
|
||||
target = target:lower()
|
||||
|
||||
local plyMatches = {}
|
||||
if enable_keywords and target:sub( 1, 1 ) == "$" then
|
||||
possibleId = target:sub( 2 )
|
||||
table.insert( plyMatches, ULib.getPlyByID( possibleId ) )
|
||||
end
|
||||
|
||||
-- First, do a full name match in case someone's trying to exploit our target system
|
||||
for _, player in ipairs( players ) do
|
||||
if target == player:Nick():lower() then
|
||||
if #plyMatches == 0 then
|
||||
return player
|
||||
else
|
||||
return false, "Found multiple targets! Please choose a better string for the target. (EG, the whole name)"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if enable_keywords then
|
||||
if target == "^" and ply then
|
||||
if ply:IsValid() then
|
||||
return ply
|
||||
else
|
||||
return false, "You cannot target yourself from console!"
|
||||
end
|
||||
elseif IsValid( ply ) and target == "@" then
|
||||
local player = ULib.getPicker( ply )
|
||||
if not player then
|
||||
return false, "No player found in the picker"
|
||||
else
|
||||
return player
|
||||
end
|
||||
else
|
||||
local player = hook.Run( ULib.HOOK_GETUSER_CUSTOM_KEYWORD, target, ply )
|
||||
if player then return player end
|
||||
end
|
||||
end
|
||||
|
||||
for _, player in ipairs( players ) do
|
||||
if player:Nick():lower():find( target, 1, true ) then -- No patterns
|
||||
table.insert( plyMatches, player )
|
||||
end
|
||||
end
|
||||
|
||||
if #plyMatches == 0 then
|
||||
return false, "No target found or target has immunity!"
|
||||
elseif #plyMatches > 1 then
|
||||
local str = plyMatches[ 1 ]:Nick()
|
||||
for i=2, #plyMatches do
|
||||
str = str .. ", " .. plyMatches[ i ]:Nick()
|
||||
end
|
||||
|
||||
return false, "Found multiple targets: " .. str .. ". Please choose a better string for the target. (EG, the whole name)"
|
||||
end
|
||||
|
||||
return plyMatches[ 1 ]
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user