diff --git a/lib/cmdrhandler/src/Server/init.luau b/lib/cmdrhandler/src/Server/init.luau index 55f0e7f..9cebc39 100644 --- a/lib/cmdrhandler/src/Server/init.luau +++ b/lib/cmdrhandler/src/Server/init.luau @@ -294,6 +294,41 @@ function CmdrServer:Init() end -- Sync initial player permissions to client + --[[ + [⚠️ • NOTE]: Player:GetRoleInGroup() still returns the player rank, + so this should not be used until Roblox fixes it. + + [⚠️ • NOTE]: When getting back to this, check again this implementation. + A player might have multiple roles with different permissions, and :GetRoleInGroup() + assumes only one role per player. + + local groupRolePermissionGroups = Client.GroupRolePermissionGroups:Get() + for groupId, roleData in groupRolePermissionGroups do + if player:IsInGroup(groupId) then + for role, permissionGroups in roleData do + if player:GetRoleInGroup(groupId) == role then + CmdrServer.PermissionsHandler:GivePlayerPermissionGroups(player, permissionGroups) + end + end + end + end + --]] + + local groupRankPermissionGroups = Client.GroupRankPermissionGroups:Get() + for groupId, rankData in groupRankPermissionGroups do + if player:IsInGroup(groupId) then + for _, rankPermissionsData in rankData do + local playerRank = player:GetRankInGroup(groupId) + if playerRank >= rankPermissionsData.Ranks.Min and playerRank <= rankPermissionsData.Ranks.Max then + CmdrServer.PermissionsHandler:GivePlayerPermissionGroups( + player, + rankPermissionsData.Permissions + ) + end + end + end + end + local playerPerms = CmdrServer.PermissionsHandler:_getPlayerPermissionGroupsData()[player] Client.Permissions:SetFor(player, playerPerms) end) diff --git a/lib/cmdrhandler/src/Shared/CmdrUtil.luau b/lib/cmdrhandler/src/Shared/CmdrUtil.luau index 7f50b46..49e20ae 100644 --- a/lib/cmdrhandler/src/Shared/CmdrUtil.luau +++ b/lib/cmdrhandler/src/Shared/CmdrUtil.luau @@ -6,40 +6,43 @@ local GroupService = game:GetService("GroupService") local Players = game:GetService("Players") --// Imports //-- -local GroupCache = (setmetatable({}, {__mode = "k"}) :: any) :: {[Player]: {{ - Name: string, - Id: number, - Rank: number, - Role: string, - IsPrimary: boolean, -}}} +local GroupCache = (setmetatable({}, { __mode = "k" }) :: any) :: { + [Player]: { + { + Name: string, + Id: number, + Rank: number, + Role: string, + IsPrimary: boolean, + } + }, +} local function RefreshGroupCache(plr: Player) - task.spawn(function() - local groups = GroupService:GetGroupsAsync(plr.UserId) - GroupCache[plr] = groups - -- if RunService:IsStudio() then - -- print("[Cmdr] Cached Groups for ", plr.Name, ":", groups) - -- end - end) + task.spawn(function() + local groups = GroupService:GetGroupsAsync(plr.UserId) + GroupCache[plr] = groups + -- if RunService:IsStudio() then + -- print("[Cmdr] Cached Groups for ", plr.Name, ":", groups) + -- end + end) end Players.PlayerAdded:Connect(RefreshGroupCache) for _, plr in ipairs(Players:GetPlayers()) do - RefreshGroupCache(plr) + RefreshGroupCache(plr) end - -------------------------------------------------------------------------------- - --// Class //-- +--// Class //-- -------------------------------------------------------------------------------- local Util = {} -function Util.getPlayerPermissions(cmdrWrapper, plr: Player, rawPlayerPerms: {string}): {string} - local playerPerms = table.clone(rawPlayerPerms) +function Util.getPlayerPermissions(cmdrWrapper, plr: Player, rawPlayerPerms: { string }): { string } + local playerPerms = table.clone(rawPlayerPerms) - for _, permissionGroup: string in playerPerms do + for _, permissionGroup: string in playerPerms do for _, inheritedPerm in cmdrWrapper:GetPermissionInheritance(permissionGroup) do if not table.find(playerPerms, inheritedPerm) then table.insert(playerPerms, inheritedPerm) @@ -47,20 +50,25 @@ function Util.getPlayerPermissions(cmdrWrapper, plr: Player, rawPlayerPerms: {st end end - for _, groupData in GroupCache[plr] or {} do - for _, groupPerm in Util.getGroupRankPermissions(cmdrWrapper, groupData.Id, groupData.Rank) do - if not table.find(playerPerms, groupPerm) then - table.insert(playerPerms, groupPerm) - end - end - end + for _, groupData in GroupCache[plr] or {} do + for _, groupPerm in Util.getGroupRankPermissions(cmdrWrapper, groupData.Id, groupData.Rank) do + if not table.find(playerPerms, groupPerm) then + table.insert(playerPerms, groupPerm) + end + end + for _, groupPerm in Util.getGroupRolePermissions(cmdrWrapper, groupData.Id, groupData.Role) do + if not table.find(playerPerms, groupPerm) then + table.insert(playerPerms, groupPerm) + end + end + end - return playerPerms + return playerPerms end -function Util.getGroupRankPermissions(cmdrWrapper, groupId: number, rank: number): {string} - local groupData = cmdrWrapper:_getRawGroupPerms(groupId) - local rankPerms = {} +function Util.getGroupRankPermissions(cmdrWrapper, groupId: number, rank: number): { string } + local groupData = cmdrWrapper:_getRawGroupPerms(groupId) + local rankPerms = {} -- This is terribly unoptimized, feel free to optimize it for _, groupPermData in groupData do @@ -81,4 +89,25 @@ function Util.getGroupRankPermissions(cmdrWrapper, groupId: number, rank: number return rankPerms end -return Util \ No newline at end of file +function Util.getGroupRolePermissions(cmdrWrapper, groupId: number, role: string): { string } + local groupData = cmdrWrapper:_getRawGroupPerms(groupId) + local rolePerms = {} + + -- This is terribly unoptimized, feel free to optimize it + for _, groupPermData in groupData do + for _, permissionGroup: string in groupPermData.Permissions do + if not table.find(rolePerms, permissionGroup) then + table.insert(rolePerms, permissionGroup) + end + for _, inheritedPerm in cmdrWrapper:GetPermissionInheritance(permissionGroup) do + if not table.find(rolePerms, inheritedPerm) then + table.insert(rolePerms, inheritedPerm) + end + end + end + end + + return rolePerms +end + +return Util diff --git a/lib/cmdrhandler/src/Shared/PermissionsHandler.luau b/lib/cmdrhandler/src/Shared/PermissionsHandler.luau index 5dd1e9e..b58eab5 100644 --- a/lib/cmdrhandler/src/Shared/PermissionsHandler.luau +++ b/lib/cmdrhandler/src/Shared/PermissionsHandler.luau @@ -26,6 +26,7 @@ type CmdrRegistry = { local Packages = script.Parent.Parent.Parent local Signal = require(Packages.Signal) :: any +local IS_SERVER = RunService:IsServer() -- Default permission inheritance structure (shared constant) local DEFAULT_PERMISSION_INHERITANCE: { [string]: { string } } = { @@ -115,6 +116,7 @@ end @param permissions -- The permission group(s) to set ]=] function PermissionsHandler:SetPlayerPermissionGroups(plr: Player, permissions: string | { string }): () + assert(IS_SERVER, "PermissionsHandler:SetPlayerPermissionGroups can only be called on the server") if typeof(permissions) == "string" then permissions = { permissions } end @@ -128,6 +130,7 @@ end @param permissionGroups -- The permission groups to grant ]=] function PermissionsHandler:GivePlayerPermissionGroups(plr: Player, permissionGroups: string | { string }): () + assert(IS_SERVER, "PermissionsHandler:GivePlayerPermissionGroups can only be called on the server") if typeof(permissionGroups) == "string" then permissionGroups = { permissionGroups } end @@ -192,9 +195,10 @@ function PermissionsHandler:GiveRobloxGroupRankPermissionGroups( if RunService:IsStudio() then print( - `[PermissionsHandler] - Granted group [{robloxGroupId}] permissions [{table.concat(permissionGroups :: any, ", ")}] for ranks [{( - ranks :: NumberRange - ).Min}, {(ranks :: NumberRange).Max}]` + `[PermissionsHandler] - Granted group [{robloxGroupId}] permissions [{table.concat( + permissionGroups :: any, + ", " + )}] for ranks [{(ranks :: NumberRange).Min}, {(ranks :: NumberRange).Max}]` ) end @@ -208,6 +212,9 @@ function PermissionsHandler:GiveRobloxGroupRankPermissionGroups( end --[=[ + @ignore + @unreleased + Grants specified roles in a Roblox Group permission to use commands under a given PermissionGroup. @param robloxGroupId -- The Roblox group id to grant permissions to @param role -- The role name to grant permissions to @@ -219,6 +226,9 @@ function PermissionsHandler:GiveRobloxGroupRolePermissionGroups( role: string, permissionGroups: string | { string } ): () -> () + error( + "Using group roles for permissions does not work properly yet since Player:GetRoleInGroup() returns the player rank instead of the role. Use :GiveRobloxGroupRankPermissionGroups() instead." + ) assert(typeof(robloxGroupId) == "number", "Bad robloxGroupId") assert(typeof(role) == "string", "Bad role") assert(typeof(permissionGroups) == "string" or typeof(permissionGroups) == "table", "Bad permissions") @@ -250,7 +260,10 @@ function PermissionsHandler:GiveRobloxGroupRolePermissionGroups( if RunService:IsStudio() then print( - `[PermissionsHandler] - Granted group [{robloxGroupId}] permissions [{table.concat(permissionGroups :: any, ", ")}] for role [{role}]` + `[PermissionsHandler] - Granted group [{robloxGroupId}] permissions [{table.concat( + permissionGroups :: any, + ", " + )}] for role [{role}]` ) end @@ -271,7 +284,11 @@ end @param permissionGroup -- The permission group to set the inheritance for @param inheritedGroups -- The group(s) to inherit permissions from ]=] -function PermissionsHandler:SetPermissionGroupInheritance(permissionGroup: string, inheritedGroups: string | { string }): () +function PermissionsHandler:SetPermissionGroupInheritance( + permissionGroup: string, + inheritedGroups: string | { string } +): () + assert(IS_SERVER, "PermissionsHandler:SetPermissionGroupInheritance can only be called on the server") assert(typeof(permissionGroup) == "string", "Bad permissionGroup") if typeof(inheritedGroups) == "string" then inheritedGroups = { inheritedGroups } @@ -331,7 +348,9 @@ function PermissionsHandler:_getPlayerPermissionGroupsData(): { [Player]: { stri return playerPermissionGroups end -function PermissionsHandler:_getGroupRankPermissionGroupsData(): { [GroupId]: { { Ranks: NumberRange, Permissions: { string } } } } +function PermissionsHandler:_getGroupRankPermissionGroupsData(): { + [GroupId]: { { Ranks: NumberRange, Permissions: { string } } }, +} return groupRankPermissionGroups end @@ -352,7 +371,9 @@ function PermissionsHandler:_setPlayerPermissionGroupsData(data: { [Player]: { s playerPermissionGroups = data or {} end -function PermissionsHandler:_setGroupRankPermissionGroupsData(data: { [GroupId]: { { Ranks: NumberRange, Permissions: { string } } } }?): () +function PermissionsHandler:_setGroupRankPermissionGroupsData(data: { + [GroupId]: { { Ranks: NumberRange, Permissions: { string } } }, +}?): () groupRankPermissionGroups = data or {} end