From 0a98975a90cd5e85b2c0412612ad0123bb18a45b Mon Sep 17 00:00:00 2001 From: thecraftianman <64441307+thecraftianman@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:46:35 -0400 Subject: [PATCH 1/2] Rework UCL client update networking --- lua/ulib/server/ucl.lua | 41 +++++++++++++++++++++++--------------- lua/ulib/shared/sh_ucl.lua | 15 +++++++++++++- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/lua/ulib/server/ucl.lua b/lua/ulib/server/ucl.lua index b647667..e53fb84 100644 --- a/lua/ulib/server/ucl.lua +++ b/lua/ulib/server/ucl.lua @@ -336,6 +336,7 @@ function ucl.addGroup( name, allows, inherit_from, from_CAMI ) ucl.groups[ name ] = { allow=allows, inherit_from=inherit_from } ucl.saveGroups() + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", name, ucl.groups[ name ] ) hook.Call( ULib.HOOK_GROUP_CREATED, _, name, ucl.groups[ name ] ) hook.Call( ULib.HOOK_UCLCHANGED ) @@ -415,6 +416,7 @@ function ucl.groupAllow( name, access, revoke ) ucl.saveGroups() + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", name, ucl.groups[ name ] ) hook.Call( ULib.HOOK_GROUP_ACCESS_CHANGE, _, name, access, revoke ) hook.Call( ULib.HOOK_UCLCHANGED ) end @@ -475,6 +477,8 @@ function ucl.renameGroup( orig, new ) ucl.saveUsers() ucl.saveGroups() + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", new, ucl.groups[ new ] ) + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", orig, _ ) hook.Call( ULib.HOOK_GROUP_RENAMED, _, orig, new ) hook.Call( ULib.HOOK_UCLCHANGED ) @@ -539,6 +543,7 @@ function ucl.setGroupInheritance( group, inherit_from, from_CAMI ) ucl.saveGroups() + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", group, ucl.groups[ group ] ) hook.Call( ULib.HOOK_GROUP_INHERIT_CHANGE, _, group, inherit_from, old_inherit ) hook.Call( ULib.HOOK_UCLCHANGED ) @@ -577,6 +582,7 @@ function ucl.setGroupCanTarget( group, can_target ) ucl.saveGroups() + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", group, ucl.groups[ group ] ) hook.Call( ULib.HOOK_UCLCHANGED ) end @@ -624,15 +630,17 @@ function ucl.removeGroup( name, from_CAMI ) end local oldgroup = table.Copy( ucl.groups[ name ] ) ucl.groups[ name ] = nil - for _, groupInfo in pairs( ucl.groups ) do + for groupName, groupInfo in pairs( ucl.groups ) do if groupInfo.inherit_from == name then groupInfo.inherit_from = inherits_from + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", groupName, groupInfo ) end end ucl.saveUsers() ucl.saveGroups() + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", name, _ ) hook.Call( ULib.HOOK_GROUP_REMOVED, _, name, oldgroup ) hook.Call( ULib.HOOK_UCLCHANGED ) @@ -983,11 +991,12 @@ function ucl.registerAccess( access, groups, comment, category ) if table.HasValue( groupInfo.allow, access ) then return end -- Found, don't add again end - for _, group in ipairs( groups ) do + for name, group in ipairs( groups ) do -- Create group if it doesn't exist if not ucl.groups[ group ] then ucl.addGroup( group ) end table.insert( ucl.groups[ group ].allow, access ) + ULib.clientRPC( _, "ULib.ucl.updateClientUCLGroup", name, ucl.groups[ name ] ) end timer.Create( "ULibSaveGroups", 1, 1, function() -- 1 sec delay, 1 rep @@ -1046,6 +1055,7 @@ function ucl.probe( ply ) end end + ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", uid, ucl.authed[ uid ] ) hook.Call( ULib.HOOK_UCLCHANGED ) hook.Call( ULib.HOOK_UCLAUTH, _, ply ) end @@ -1075,28 +1085,24 @@ end hook.Add( ULib.HOOK_UCLAUTH, "ULibSendAuthToClients", sendAuthToClients, HOOK_MONITOR_LOW ) local function sendUCLDataToClient( ply ) - ULib.clientRPC( ply, "ULib.ucl.initClientUCL", ucl.authed, ucl.groups ) -- Send all UCL data (minus offline users) to all loaded users - ULib.clientRPC( ply, "hook.Call", ULib.HOOK_UCLCHANGED ) -- Call hook on client - ULib.clientRPC( ply, "authPlayerIfReady", ply, ply:UserID() ) -- Call on client + timer.Simple(0, function() + ULib.clientRPC( ply, "ULib.ucl.initClientUCL", ucl.authed, ucl.groups ) -- Send all UCL data (minus offline users) to the current user + ULib.clientRPC( ply, "authPlayerIfReady", ply, ply:UserID() ) -- Call on client + end) end -hook.Add( ULib.HOOK_LOCALPLAYERREADY, "ULibSendUCLDataToClient", sendUCLDataToClient, HOOK_MONITOR_HIGH ) +hook.Add( "PlayerInitialSpawn", "ULibSendUCLDataToClient", sendUCLDataToClient, HOOK_MONITOR_HIGH ) local function playerDisconnected( ply ) -- We want to perform these actions after everything else has processed through, but we need high priority hook to ensure we don't get sniped. local uid = ply:UniqueID() ULib.queueFunctionCall( function() ucl.authed[ uid ] = nil + ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", uid, _ ) hook.Call( ULib.HOOK_UCLCHANGED ) end ) end hook.Add( "PlayerDisconnected", "ULibUCLDisconnect", playerDisconnected, HOOK_MONITOR_HIGH ) -local function UCLChanged() - ULib.clientRPC( _, "ULib.ucl.initClientUCL", ucl.authed, ucl.groups ) -- Send all UCL data (minus offline users) to all loaded users - ULib.clientRPC( _, "hook.Call", ULib.HOOK_UCLCHANGED ) -- Call hook on client -end -hook.Add( ULib.HOOK_UCLCHANGED, "ULibSendUCLToClients", UCLChanged ) - --[[ -- The following is useful for debugging since Garry changes client bootstrapping so frequently hook.Add( ULib.HOOK_UCLCHANGED, "UTEST", function() print( "HERE HERE: UCL Changed" ) end ) @@ -1127,16 +1133,19 @@ function meta:SetUserGroup( group, dontCall ) local oldGroup = self:GetUserGroup() oldSetUserGroup( self, group ) - if ucl.authed[ self:UniqueID() ] then - if ucl.authed[ self:UniqueID() ] == ULib.DEFAULT_GRANT_ACCESS then - ucl.authed[ self:UniqueID() ] = table.Copy( ULib.DEFAULT_GRANT_ACCESS ) + local uid = self:UniqueID() + + if ucl.authed[ uid ] then + if ucl.authed[ uid ] == ULib.DEFAULT_GRANT_ACCESS then + ucl.authed[ uid ] = table.Copy( ULib.DEFAULT_GRANT_ACCESS ) end - ucl.authed[ self:UniqueID() ].group = group + ucl.authed[ uid ].group = group else self.tmp_group = group end if not dontCall and self:GetUserGroup() ~= oldGroup then -- Changed! Inform the masses of the change + ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", uid, ucl.authed[ uid ] ) hook.Call( ULib.HOOK_UCLCHANGED ) hook.Call( ULib.HOOK_UCLAUTH, _, self ) end diff --git a/lua/ulib/shared/sh_ucl.lua b/lua/ulib/shared/sh_ucl.lua index 2052853..2589ea5 100644 --- a/lua/ulib/shared/sh_ucl.lua +++ b/lua/ulib/shared/sh_ucl.lua @@ -177,12 +177,25 @@ if CLIENT then function ucl.initClientUCL( authed, groups ) ucl.authed = authed ucl.groups = groups + for name, data in pairs( groups ) do if not ULib.findInTable( {"superadmin", "admin", "user"}, name ) then inherit_from = data.inherit_from or "user" - CAMI.RegisterUsergroup( {Name=name, Inherits=inherit_from}, CAMI.ULX_TOKEN ) + CAMI.RegisterUsergroup( {Name = name, Inherits = inherit_from}, CAMI.ULX_TOKEN ) end end + + hook.Call( ULib.HOOK_UCLCHANGED ) + end + + function ucl.updateClientUCLPlayer( id, data ) + ucl.authed[ id ] = data + hook.Call( ULib.HOOK_UCLCHANGED ) + end + + function ucl.updateClientUCLGroup( name, data ) + ucl.groups[ name ] = data + hook.Call( ULib.HOOK_UCLCHANGED ) end end From d8ccd854a9fb9ea6f483d45b8f54a4ccf622d318 Mon Sep 17 00:00:00 2001 From: thecraftianman <64441307+thecraftianman@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:15:14 -0400 Subject: [PATCH 2/2] Replace UniqueID with SteamID64 where applicable A couple uses of UniqueID in functions have been kept for backwards compatibility, but honestly I'm not sure if those need to remain either --- lua/ulib/server/ucl.lua | 59 +++++++++++++++++++------------------- lua/ulib/shared/player.lua | 4 +-- lua/ulib/shared/sh_ucl.lua | 21 ++++++-------- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/lua/ulib/server/ucl.lua b/lua/ulib/server/ucl.lua index e53fb84..1011426 100644 --- a/lua/ulib/server/ucl.lua +++ b/lua/ulib/server/ucl.lua @@ -653,7 +653,7 @@ end --[[ Function: ucl.getUserRegisteredID - Returns the SteamID, IP, or UniqueID of a player if they're registered under any of those IDs under ucl.users. Checks in order. Returns nil if not registered. + Returns the SteamID, SteamID64, IP, or UniqueID of a player if they're registered under any of those IDs under ucl.users. Checks in order. Returns nil if not registered. Parameters: @@ -666,9 +666,10 @@ end function ucl.getUserRegisteredID( ply ) local id = ply:SteamID() + local id64 = ply:SteamID64() local uid = ply:UniqueID() local ip = ULib.splitPort( ply:IPAddress() ) - local checkIndexes = { id, ip, uid } + local checkIndexes = { id, id64, ip, uid } for _, index in ipairs( checkIndexes ) do if ULib.ucl.users[ index ] then return id @@ -683,7 +684,7 @@ end Parameters: - id - The SteamID, IP, or UniqueID of the user you wish to check. + id - The SteamID, SteamID64, IP, or UniqueID of the user you wish to check. ]] function ucl.getUserInfoFromID( id ) @@ -706,7 +707,7 @@ end Parameters: - id - The SteamID, IP, or UniqueID of the user you wish to add. + id - The SteamID, SteamID64, IP, or UniqueID of the user you wish to add. allows - *(Optional, defaults to empty table)* The list of access you wish to give this user. denies - *(Optional, defaults to empty table)* The list of access you wish to explicitly deny this user. group - *(Optional)* The string of the group this user should belong to. Must be a valid group. @@ -767,7 +768,7 @@ end Parameters: - id - The SteamID, IP, or UniqueID of the user to change. Must be a valid, existing ID, or an ID of a connected player. + id - The SteamID, SteamID64, IP, or UniqueID of the user to change. Must be a valid, existing ID, or an ID of a connected player. access - The string of the access or a table of accesses to add or remove. Access tags can be specified in values in the table for allows. revoke - *(Optional, defaults to false)* A boolean of whether the access tag should be added or removed from the allow or deny list. If true, it's removed. @@ -793,15 +794,15 @@ function ucl.userAllow( id, access, revoke, deny ) id = id:upper() -- In case of steamid, needs to be upper case if type( access ) == "string" then access = { access } end - local uid = id - if not ucl.authed[ uid ] then -- Check to see if it's a steamid or IP + local id64 = id + if not ucl.authed[ id64 ] then -- Check to see if it's a steamid or IP local ply = ULib.getPlyByID( id ) if ply and ply:IsValid() then - uid = ply:UniqueID() + id64 = ply:SteamID64() end end - local userInfo = ucl.users[ id ] or ucl.authed[ uid ] -- Check both tables + local userInfo = ucl.users[ id ] or ucl.authed[ id64 ] -- Check both tables if not userInfo then return error( "User id does not exist for changing access (" .. id .. ")", 2 ) end -- If they're connected but don't exist in the ULib user database, add them. @@ -889,7 +890,7 @@ end Parameters: - id - The SteamID, IP, or UniqueID of the user you wish to remove. Must be a valid, existing ID. + id - The SteamID, SteamID64, IP, or UniqueID of the user you wish to remove. Must be a valid, existing ID. The unique id of a connected user is always valid. from_CAMI - *(Optional)* An indicator for this information coming from CAMI. @@ -912,7 +913,7 @@ function ucl.removeUser( id, from_CAMI ) if not ply then return error( "SANITY CHECK FAILED!" ) end -- Should never be invalid local ip = ULib.splitPort( ply:IPAddress() ) - local checkIndexes = { ply:UniqueID(), ip, ply:SteamID() } + local checkIndexes = { ply:SteamID64(), ply:UniqueID(), ip, ply:SteamID() } for _, index in ipairs( checkIndexes ) do if ucl.users[ index ] then @@ -1024,22 +1025,22 @@ end ]] function ucl.probe( ply ) local ip = ULib.splitPort( ply:IPAddress() ) - local uid = ply:UniqueID() - local checkIndexes = { uid, ip, ply:SteamID() } + local id64 = ply:SteamID64() + local checkIndexes = { id64, ply:UniqueID(), ip, ply:SteamID() } local match = false for _, index in ipairs( checkIndexes ) do if ucl.users[ index ] then - ucl.authed[ uid ] = ucl.users[ index ] -- Setup an ALIAS + ucl.authed[ id64 ] = ucl.users[ index ] -- Setup an ALIAS -- If they have a group, set it - local group = ucl.authed[ uid ].group + local group = ucl.authed[ id64 ].group if group and group ~= "" then ply:SetUserGroup( group, true ) end -- Update their name - ucl.authed[ uid ].name = ply:Nick() + ucl.authed[ id64 ].name = ply:Nick() ucl.saveUsers() match = true @@ -1048,14 +1049,14 @@ function ucl.probe( ply ) end if not match then - ucl.authed[ ply:UniqueID() ] = ULib.DEFAULT_GRANT_ACCESS + ucl.authed[ id64 ] = ULib.DEFAULT_GRANT_ACCESS if ply.tmp_group then ply:SetUserGroup( ply.tmp_group, true ) -- Make sure they keep the group ply.tmp_group = nil end end - ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", uid, ucl.authed[ uid ] ) + ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", id64, ucl.authed[ id64 ] ) hook.Call( ULib.HOOK_UCLCHANGED ) hook.Call( ULib.HOOK_UCLAUTH, _, ply ) end @@ -1064,7 +1065,7 @@ end local function setupBot( ply ) if not ply or not ply:IsValid() then return end - if not ucl.authed[ ply:UniqueID() ] then + if not ucl.authed[ ply:SteamID64() ] then ply:SetUserGroup( ULib.ACCESS_ALL, true ) -- Give it a group! ucl.probe( ply ) end @@ -1094,10 +1095,10 @@ hook.Add( "PlayerInitialSpawn", "ULibSendUCLDataToClient", sendUCLDataToClient, local function playerDisconnected( ply ) -- We want to perform these actions after everything else has processed through, but we need high priority hook to ensure we don't get sniped. - local uid = ply:UniqueID() + local id64 = ply:SteamID64() ULib.queueFunctionCall( function() - ucl.authed[ uid ] = nil - ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", uid, _ ) + ucl.authed[ id64 ] = nil + ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", id64, _ ) hook.Call( ULib.HOOK_UCLCHANGED ) end ) end @@ -1117,7 +1118,7 @@ local playerAuth = hook.GetTable().PlayerInitialSpawn.PlayerAuthSpawn hook.Remove( "PlayerInitialSpawn", "PlayerAuthSpawn" ) -- Remove from original spot local function newPlayerAuth( ply, ... ) - ucl.authed[ ply:UniqueID() ] = nil -- If the player ent is removed before disconnecting, we can have this hanging out there. + ucl.authed[ ply:SteamID64() ] = nil -- If the player ent is removed before disconnecting, we can have this hanging out there. playerAuth( ply, ... ) -- Put here, slightly ahead of ucl. ucl.probe( ply, ... ) end @@ -1133,19 +1134,19 @@ function meta:SetUserGroup( group, dontCall ) local oldGroup = self:GetUserGroup() oldSetUserGroup( self, group ) - local uid = self:UniqueID() + local id64 = self:SteamID64() - if ucl.authed[ uid ] then - if ucl.authed[ uid ] == ULib.DEFAULT_GRANT_ACCESS then - ucl.authed[ uid ] = table.Copy( ULib.DEFAULT_GRANT_ACCESS ) + if ucl.authed[ id64 ] then + if ucl.authed[ id64 ] == ULib.DEFAULT_GRANT_ACCESS then + ucl.authed[ id64 ] = table.Copy( ULib.DEFAULT_GRANT_ACCESS ) end - ucl.authed[ uid ].group = group + ucl.authed[ id64 ].group = group else self.tmp_group = group end if not dontCall and self:GetUserGroup() ~= oldGroup then -- Changed! Inform the masses of the change - ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", uid, ucl.authed[ uid ] ) + ULib.clientRPC( _, "ULib.ucl.updateClientUCLPlayer", id64, ucl.authed[ id64 ] ) hook.Call( ULib.HOOK_UCLCHANGED ) hook.Call( ULib.HOOK_UCLAUTH, _, self ) end diff --git a/lua/ulib/shared/player.lua b/lua/ulib/shared/player.lua index d2f60d9..7eac9b2 100644 --- a/lua/ulib/shared/player.lua +++ b/lua/ulib/shared/player.lua @@ -59,7 +59,7 @@ 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 } +local checkIndexes = { Player.SteamID64, Player.UniqueID, function( ply ) if CLIENT then return "" end local ip = ULib.splitPort( ply:IPAddress() ) return ip end, Player.SteamID, Player.UserID } --[[ Function: getPlyByID @@ -67,7 +67,7 @@ local checkIndexes = { Player.UniqueID, function( ply ) if CLIENT then return "" Parameters: - id - The ID to try to match against connected players. Can be a unique id, ip address, steam id, or user id. + id - The ID to try to match against connected players. Can be a SteamID64, UniqueID, IP address, SteamID, or UserID. Returns: diff --git a/lua/ulib/shared/sh_ucl.lua b/lua/ulib/shared/sh_ucl.lua index 2589ea5..4042f72 100644 --- a/lua/ulib/shared/sh_ucl.lua +++ b/lua/ulib/shared/sh_ucl.lua @@ -15,7 +15,7 @@ local ucl = ULib.ucl -- Make it easier for us to refer to -- Setup! ucl.groups = ucl.groups or {} -- Stores allows, inheritance, and custom addon info keyed by group name ucl.users = ucl.users or {} -- Stores allows, denies, group, and last seen name keyed by user id (steamid, ip, whatever) -ucl.authed = ucl.authed or {} -- alias to ucl.users subtable for player if they have an entry, otherwise a "guest" entry. Keyed by uniqueid. +ucl.authed = ucl.authed or {} -- alias to ucl.users subtable for player if they have an entry, otherwise a "guest" entry. Keyed by SteamID64. -- End setup --[[ @@ -45,13 +45,10 @@ function ucl.query( ply, access, hide ) access = access:lower() - local unique_id = ply:UniqueID() - if CLIENT and game.SinglePlayer() then - unique_id = "1" -- Fix garry's bug - end + local id64 = ply:SteamID64() - if not ucl.authed[ unique_id ] then return error( "[ULIB] Unauthed player" ) end -- Sanity check - local playerInfo = ucl.authed[ unique_id ] + if not ucl.authed[ id64 ] then return error( "[ULIB] Unauthed player" ) end -- Sanity check + local playerInfo = ucl.authed[ id64 ] -- First check the player's info if table.HasValue( playerInfo.deny, access ) then return false end -- Deny overrides all else @@ -282,12 +279,10 @@ end function meta:GetUserGroup() if not self:IsValid() then return "" end -- Not a valid player - local uid = self:UniqueID() - if CLIENT and game.SinglePlayer() then - uid = "1" -- Fix garry's bug - end - if not ucl.authed[ uid ] then return "" end - return ucl.authed[ uid ].group or "user" + local id64 = self:SteamID64() + + if not ucl.authed[ id64 ] then return "" end + return ucl.authed[ id64 ].group or "user" end