From 9128ad58579d511df979d8285dd4018c634d8554 Mon Sep 17 00:00:00 2001 From: Ihsan <122683406+rwixy@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:10:58 +0530 Subject: [PATCH 1/3] feat(commands): centralize admin permissions via Config.AdminGroups --- .../es_extended/server/modules/commands.lua | 84 +++++++++++-------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/[core]/es_extended/server/modules/commands.lua b/[core]/es_extended/server/modules/commands.lua index 2320e82f..1796b8c1 100644 --- a/[core]/es_extended/server/modules/commands.lua +++ b/[core]/es_extended/server/modules/commands.lua @@ -1,6 +1,22 @@ +local adminGroups = {} +if Config.AdminGroups then + for groupName, enabled in pairs(Config.AdminGroups) do + if enabled then + adminGroups[#adminGroups + 1] = groupName + end + end +else + adminGroups = { "admin" } +end + +local userAndAdminGroups = { "user" } +for _, v in ipairs(adminGroups) do + userAndAdminGroups[#userAndAdminGroups + 1] = v +end + ESX.RegisterCommand( { "setcoords", "tp" }, - "admin", + adminGroups, function(xPlayer, args) xPlayer.setCoords({ x = args.x, y = args.y, z = args.z }) if Config.AdminLogging then @@ -27,7 +43,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "setjob", - "admin", + adminGroups, function(xPlayer, args, showError) if not ESX.DoesJobExist(args.job, args.grade) then return showError(TranslateCap("command_setjob_invalid")) @@ -68,7 +84,7 @@ local upgrades = Config.SpawnVehMaxUpgrades and { ESX.RegisterCommand( "car", - "admin", + adminGroups, function(xPlayer, args, showError) if not xPlayer then return showError("[^1ERROR^7] The xPlayer value is nil") @@ -132,7 +148,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( { "cardel", "dv" }, - "admin", + adminGroups, function(xPlayer, args) local ped = GetPlayerPed(xPlayer.source) local pedVehicle = GetVehiclePedIsIn(ped, false) @@ -168,7 +184,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( { "fix", "repair" }, - "admin", + adminGroups, function(xPlayer, args, showError) local xTarget = args.playerId local ped = GetPlayerPed(xTarget.source) @@ -202,7 +218,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "setaccountmoney", - "admin", + adminGroups, function(xPlayer, args, showError) if not args.playerId.getAccount(args.account) then return showError(TranslateCap("command_giveaccountmoney_invalid")) @@ -232,7 +248,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "giveaccountmoney", - "admin", + adminGroups, function(xPlayer, args, showError) if not args.playerId.getAccount(args.account) then return showError(TranslateCap("command_giveaccountmoney_invalid")) @@ -262,7 +278,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "removeaccountmoney", - "admin", + adminGroups, function(xPlayer, args, showError) if not args.playerId.getAccount(args.account) then return showError(TranslateCap("command_removeaccountmoney_invalid")) @@ -293,7 +309,7 @@ ESX.RegisterCommand( if not Config.CustomInventory then ESX.RegisterCommand( "giveitem", - "admin", + adminGroups, function(xPlayer, args) args.playerId.addInventoryItem(args.item, args.count) if Config.AdminLogging then @@ -323,7 +339,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "giveweapon", - "admin", + adminGroups, function(xPlayer, args, showError) if args.playerId.hasWeapon(args.weapon) then return showError(TranslateCap("command_giveweapon_hasalready")) @@ -353,7 +369,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "giveammo", - "admin", + adminGroups, function(xPlayer, args, showError) if not args.playerId.hasWeapon(args.weapon) then return showError(TranslateCap("command_giveammo_noweapon_found")) @@ -383,7 +399,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "giveweaponcomponent", - "admin", + adminGroups, function(xPlayer, args, showError) if args.playerId.hasWeapon(args.weaponName) then local component = ESX.GetWeaponComponent(args.weaponName, args.componentName) @@ -427,7 +443,7 @@ ESX.RegisterCommand({ "clear", "cls" }, "user", function(xPlayer) xPlayer.triggerEvent("chat:clear") end, false, { help = TranslateCap("command_clear") }) -ESX.RegisterCommand({ "clearall", "clsall" }, "admin", function(xPlayer) +ESX.RegisterCommand({ "clearall", "clsall" }, adminGroups, function(xPlayer) TriggerClientEvent("chat:clear", -1) if Config.AdminLogging then ESX.DiscordLogFields("UserActions", "Clear Chat /clearall Triggered!", "pink", { @@ -437,12 +453,12 @@ ESX.RegisterCommand({ "clearall", "clsall" }, "admin", function(xPlayer) end end, true, { help = TranslateCap("command_clearall") }) -ESX.RegisterCommand("refreshjobs", "admin", function() +ESX.RegisterCommand("refreshjobs", adminGroups, function() ESX.RefreshJobs() end, true, { help = TranslateCap("command_clearall") }) if not Config.CustomInventory then - ESX.RegisterCommand("refreshitems", "admin", function(xPlayer) + ESX.RegisterCommand("refreshitems", adminGroups, function(xPlayer) local itemCount = ESX.RefreshItems() xPlayer.showNotification(Translate("command_refreshitems_success", itemCount), true, false, 140) @@ -450,7 +466,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "clearinventory", - "admin", + adminGroups, function(xPlayer, args) for _, v in ipairs(args.playerId.inventory) do if v.count > 0 then @@ -478,7 +494,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "clearloadout", - "admin", + adminGroups, function(xPlayer, args) for i = #args.playerId.loadout, 1, -1 do args.playerId.removeWeapon(args.playerId.loadout[i].name) @@ -505,7 +521,7 @@ end ESX.RegisterCommand( "setgroup", - "admin", + adminGroups, function(xPlayer, args) if not args.playerId then args.playerId = xPlayer.source @@ -537,7 +553,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "save", - "admin", + adminGroups, function(_, args) Core.SavePlayer(args.playerId) print(("[^2Info^0] Saved Player - ^5%s^0"):format(args.playerId.source)) @@ -552,26 +568,26 @@ ESX.RegisterCommand( } ) -ESX.RegisterCommand("saveall", "admin", function() +ESX.RegisterCommand("saveall", adminGroups, function() Core.SavePlayers() end, true, { help = TranslateCap("command_saveall") }) -ESX.RegisterCommand("group", { "user", "admin" }, function(xPlayer, _, _) +ESX.RegisterCommand("group", userAndAdminGroups, function(xPlayer, _, _) print(("%s, you are currently: ^5%s^0"):format(xPlayer.getName(), xPlayer.getGroup())) end, true) -ESX.RegisterCommand("job", { "user", "admin" }, function(xPlayer, _, _) +ESX.RegisterCommand("job", userAndAdminGroups, function(xPlayer, _, _) local job = xPlayer.getJob() print(("%s, your job is: ^5%s^0 - ^5%s^0 - ^5%s^0"):format(xPlayer.getName(), job.name, job.grade_label, job.onDuty and "On Duty" or "Off Duty")) end, false) -ESX.RegisterCommand("info", { "user", "admin" }, function(xPlayer) +ESX.RegisterCommand("info", userAndAdminGroups, function(xPlayer) local job = xPlayer.getJob().name print(("^2ID: ^5%s^0 | ^2Name: ^5%s^0 | ^2Group: ^5%s^0 | ^2Job: ^5%s^0"):format(xPlayer.source, xPlayer.getName(), xPlayer.getGroup(), job)) end, false) -ESX.RegisterCommand("playtime", { "user", "admin" }, function(xPlayer) +ESX.RegisterCommand("playtime", userAndAdminGroups, function(xPlayer) local playtime = xPlayer.getPlayTime() local days = math.floor(playtime / 86400) local hours = math.floor((playtime % 86400) / 3600) @@ -579,7 +595,7 @@ ESX.RegisterCommand("playtime", { "user", "admin" }, function(xPlayer) print(("Playtime: ^5%s^0 Days | ^5%s^0 Hours | ^5%s^0 Minutes"):format(days, hours, minutes)) end, false) -ESX.RegisterCommand("coords", "admin", function(xPlayer) +ESX.RegisterCommand("coords", adminGroups, function(xPlayer) local ped = GetPlayerPed(xPlayer.source) local coords = GetEntityCoords(ped, false) local heading = GetEntityHeading(ped) @@ -587,7 +603,7 @@ ESX.RegisterCommand("coords", "admin", function(xPlayer) print(("Coords - Vector4: ^5%s^0"):format(vector4(coords.x, coords.y, coords.z, heading))) end, false) -ESX.RegisterCommand("tpm", "admin", function(xPlayer) +ESX.RegisterCommand("tpm", adminGroups, function(xPlayer) xPlayer.triggerEvent("esx:tpm") if Config.AdminLogging then ESX.DiscordLogFields("UserActions", "Admin Teleport /tpm Triggered!", "pink", { @@ -599,7 +615,7 @@ end, false) ESX.RegisterCommand( "goto", - "admin", + adminGroups, function(xPlayer, args) local targetCoords = args.playerId.getCoords() local srcDim = GetPlayerRoutingBucket(xPlayer.source) @@ -630,7 +646,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "bring", - "admin", + adminGroups, function(xPlayer, args) local targetCoords = args.playerId.getCoords() local playerCoords = xPlayer.getCoords() @@ -662,7 +678,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "kill", - "admin", + adminGroups, function(xPlayer, args) args.playerId.triggerEvent("esx:killPlayer") if Config.AdminLogging then @@ -685,7 +701,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "freeze", - "admin", + adminGroups, function(xPlayer, args) args.playerId.triggerEvent("esx:freezePlayer", "freeze") if Config.AdminLogging then @@ -708,7 +724,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "unfreeze", - "admin", + adminGroups, function(xPlayer, args) args.playerId.triggerEvent("esx:freezePlayer", "unfreeze") if Config.AdminLogging then @@ -729,7 +745,7 @@ ESX.RegisterCommand( } ) -ESX.RegisterCommand("noclip", "admin", function(xPlayer) +ESX.RegisterCommand("noclip", adminGroups, function(xPlayer) xPlayer.triggerEvent("esx:noclip") if Config.AdminLogging then ESX.DiscordLogFields("UserActions", "Admin NoClip /noclip Triggered!", "pink", { @@ -739,7 +755,7 @@ ESX.RegisterCommand("noclip", "admin", function(xPlayer) end end, false) -ESX.RegisterCommand("players", "admin", function() +ESX.RegisterCommand("players", adminGroups, function() local xPlayers = ESX.GetExtendedPlayers() -- Returns all xPlayers print(("^5%s^2 online player(s)^0"):format(#xPlayers)) for i = 1, #xPlayers do @@ -750,7 +766,7 @@ end, true) ESX.RegisterCommand( {"setdim", "setbucket"}, - "admin", + adminGroups, function(xPlayer, args) SetPlayerRoutingBucket(args.playerId.source, args.dimension) if Config.AdminLogging then From e85b05558c79572895b0c6f49b11de92a78345b0 Mon Sep 17 00:00:00 2001 From: Ihsan <122683406+rwixy@users.noreply.github.com> Date: Wed, 5 Aug 2026 13:54:44 +0530 Subject: [PATCH 2/3] feat: per-command group permissions for admin commands --- .../es_extended/server/modules/commands.lua | 90 +++++++++---------- [core]/es_extended/shared/config/main.lua | 38 ++++++++ 2 files changed, 81 insertions(+), 47 deletions(-) diff --git a/[core]/es_extended/server/modules/commands.lua b/[core]/es_extended/server/modules/commands.lua index 1796b8c1..0a800f7a 100644 --- a/[core]/es_extended/server/modules/commands.lua +++ b/[core]/es_extended/server/modules/commands.lua @@ -1,22 +1,18 @@ -local adminGroups = {} -if Config.AdminGroups then - for groupName, enabled in pairs(Config.AdminGroups) do - if enabled then - adminGroups[#adminGroups + 1] = groupName +local CommandPermissions = Config.CommandPermissions or {} + +local function FilterGroups(groups) + local filtered = {} + for _, group in ipairs(groups or {}) do + if Config.AdminGroups[group] ~= false then + filtered[#filtered + 1] = group end end -else - adminGroups = { "admin" } -end - -local userAndAdminGroups = { "user" } -for _, v in ipairs(adminGroups) do - userAndAdminGroups[#userAndAdminGroups + 1] = v + return #filtered > 0 and filtered or { "admin" } end ESX.RegisterCommand( { "setcoords", "tp" }, - adminGroups, + FilterGroups(CommandPermissions.setcoords), function(xPlayer, args) xPlayer.setCoords({ x = args.x, y = args.y, z = args.z }) if Config.AdminLogging then @@ -43,7 +39,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "setjob", - adminGroups, + FilterGroups(CommandPermissions.setjob), function(xPlayer, args, showError) if not ESX.DoesJobExist(args.job, args.grade) then return showError(TranslateCap("command_setjob_invalid")) @@ -84,7 +80,7 @@ local upgrades = Config.SpawnVehMaxUpgrades and { ESX.RegisterCommand( "car", - adminGroups, + FilterGroups(CommandPermissions.car), function(xPlayer, args, showError) if not xPlayer then return showError("[^1ERROR^7] The xPlayer value is nil") @@ -148,7 +144,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( { "cardel", "dv" }, - adminGroups, + FilterGroups(CommandPermissions.cardel), function(xPlayer, args) local ped = GetPlayerPed(xPlayer.source) local pedVehicle = GetVehiclePedIsIn(ped, false) @@ -184,7 +180,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( { "fix", "repair" }, - adminGroups, + FilterGroups(CommandPermissions.fix), function(xPlayer, args, showError) local xTarget = args.playerId local ped = GetPlayerPed(xTarget.source) @@ -218,7 +214,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "setaccountmoney", - adminGroups, + FilterGroups(CommandPermissions.setaccountmoney), function(xPlayer, args, showError) if not args.playerId.getAccount(args.account) then return showError(TranslateCap("command_giveaccountmoney_invalid")) @@ -248,7 +244,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "giveaccountmoney", - adminGroups, + FilterGroups(CommandPermissions.giveaccountmoney), function(xPlayer, args, showError) if not args.playerId.getAccount(args.account) then return showError(TranslateCap("command_giveaccountmoney_invalid")) @@ -278,7 +274,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "removeaccountmoney", - adminGroups, + FilterGroups(CommandPermissions.removeaccountmoney), function(xPlayer, args, showError) if not args.playerId.getAccount(args.account) then return showError(TranslateCap("command_removeaccountmoney_invalid")) @@ -309,7 +305,7 @@ ESX.RegisterCommand( if not Config.CustomInventory then ESX.RegisterCommand( "giveitem", - adminGroups, + FilterGroups(CommandPermissions.giveitem), function(xPlayer, args) args.playerId.addInventoryItem(args.item, args.count) if Config.AdminLogging then @@ -339,7 +335,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "giveweapon", - adminGroups, + FilterGroups(CommandPermissions.giveweapon), function(xPlayer, args, showError) if args.playerId.hasWeapon(args.weapon) then return showError(TranslateCap("command_giveweapon_hasalready")) @@ -369,7 +365,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "giveammo", - adminGroups, + FilterGroups(CommandPermissions.giveammo), function(xPlayer, args, showError) if not args.playerId.hasWeapon(args.weapon) then return showError(TranslateCap("command_giveammo_noweapon_found")) @@ -399,7 +395,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "giveweaponcomponent", - adminGroups, + FilterGroups(CommandPermissions.giveweaponcomponent), function(xPlayer, args, showError) if args.playerId.hasWeapon(args.weaponName) then local component = ESX.GetWeaponComponent(args.weaponName, args.componentName) @@ -439,11 +435,11 @@ if not Config.CustomInventory then ) end -ESX.RegisterCommand({ "clear", "cls" }, "user", function(xPlayer) +ESX.RegisterCommand({ "clear", "cls" }, FilterGroups(CommandPermissions.clear), function(xPlayer) xPlayer.triggerEvent("chat:clear") end, false, { help = TranslateCap("command_clear") }) -ESX.RegisterCommand({ "clearall", "clsall" }, adminGroups, function(xPlayer) +ESX.RegisterCommand({ "clearall", "clsall" }, FilterGroups(CommandPermissions.clearall), function(xPlayer) TriggerClientEvent("chat:clear", -1) if Config.AdminLogging then ESX.DiscordLogFields("UserActions", "Clear Chat /clearall Triggered!", "pink", { @@ -453,12 +449,12 @@ ESX.RegisterCommand({ "clearall", "clsall" }, adminGroups, function(xPlayer) end end, true, { help = TranslateCap("command_clearall") }) -ESX.RegisterCommand("refreshjobs", adminGroups, function() +ESX.RegisterCommand("refreshjobs", FilterGroups(CommandPermissions.refreshjobs), function() ESX.RefreshJobs() end, true, { help = TranslateCap("command_clearall") }) if not Config.CustomInventory then - ESX.RegisterCommand("refreshitems", adminGroups, function(xPlayer) + ESX.RegisterCommand("refreshitems", FilterGroups(CommandPermissions.refreshitems), function(xPlayer) local itemCount = ESX.RefreshItems() xPlayer.showNotification(Translate("command_refreshitems_success", itemCount), true, false, 140) @@ -466,7 +462,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "clearinventory", - adminGroups, + FilterGroups(CommandPermissions.clearinventory), function(xPlayer, args) for _, v in ipairs(args.playerId.inventory) do if v.count > 0 then @@ -494,7 +490,7 @@ if not Config.CustomInventory then ESX.RegisterCommand( "clearloadout", - adminGroups, + FilterGroups(CommandPermissions.clearloadout), function(xPlayer, args) for i = #args.playerId.loadout, 1, -1 do args.playerId.removeWeapon(args.playerId.loadout[i].name) @@ -521,7 +517,7 @@ end ESX.RegisterCommand( "setgroup", - adminGroups, + FilterGroups(CommandPermissions.setgroup), function(xPlayer, args) if not args.playerId then args.playerId = xPlayer.source @@ -553,7 +549,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "save", - adminGroups, + FilterGroups(CommandPermissions.save), function(_, args) Core.SavePlayer(args.playerId) print(("[^2Info^0] Saved Player - ^5%s^0"):format(args.playerId.source)) @@ -568,26 +564,26 @@ ESX.RegisterCommand( } ) -ESX.RegisterCommand("saveall", adminGroups, function() +ESX.RegisterCommand("saveall", FilterGroups(CommandPermissions.saveall), function() Core.SavePlayers() end, true, { help = TranslateCap("command_saveall") }) -ESX.RegisterCommand("group", userAndAdminGroups, function(xPlayer, _, _) +ESX.RegisterCommand("group", FilterGroups(CommandPermissions.group), function(xPlayer, _, _) print(("%s, you are currently: ^5%s^0"):format(xPlayer.getName(), xPlayer.getGroup())) end, true) -ESX.RegisterCommand("job", userAndAdminGroups, function(xPlayer, _, _) +ESX.RegisterCommand("job", FilterGroups(CommandPermissions.job), function(xPlayer, _, _) local job = xPlayer.getJob() print(("%s, your job is: ^5%s^0 - ^5%s^0 - ^5%s^0"):format(xPlayer.getName(), job.name, job.grade_label, job.onDuty and "On Duty" or "Off Duty")) end, false) -ESX.RegisterCommand("info", userAndAdminGroups, function(xPlayer) +ESX.RegisterCommand("info", FilterGroups(CommandPermissions.info), function(xPlayer) local job = xPlayer.getJob().name print(("^2ID: ^5%s^0 | ^2Name: ^5%s^0 | ^2Group: ^5%s^0 | ^2Job: ^5%s^0"):format(xPlayer.source, xPlayer.getName(), xPlayer.getGroup(), job)) end, false) -ESX.RegisterCommand("playtime", userAndAdminGroups, function(xPlayer) +ESX.RegisterCommand("playtime", FilterGroups(CommandPermissions.playtime), function(xPlayer) local playtime = xPlayer.getPlayTime() local days = math.floor(playtime / 86400) local hours = math.floor((playtime % 86400) / 3600) @@ -595,7 +591,7 @@ ESX.RegisterCommand("playtime", userAndAdminGroups, function(xPlayer) print(("Playtime: ^5%s^0 Days | ^5%s^0 Hours | ^5%s^0 Minutes"):format(days, hours, minutes)) end, false) -ESX.RegisterCommand("coords", adminGroups, function(xPlayer) +ESX.RegisterCommand("coords", FilterGroups(CommandPermissions.coords), function(xPlayer) local ped = GetPlayerPed(xPlayer.source) local coords = GetEntityCoords(ped, false) local heading = GetEntityHeading(ped) @@ -603,7 +599,7 @@ ESX.RegisterCommand("coords", adminGroups, function(xPlayer) print(("Coords - Vector4: ^5%s^0"):format(vector4(coords.x, coords.y, coords.z, heading))) end, false) -ESX.RegisterCommand("tpm", adminGroups, function(xPlayer) +ESX.RegisterCommand("tpm", FilterGroups(CommandPermissions.tpm), function(xPlayer) xPlayer.triggerEvent("esx:tpm") if Config.AdminLogging then ESX.DiscordLogFields("UserActions", "Admin Teleport /tpm Triggered!", "pink", { @@ -615,7 +611,7 @@ end, false) ESX.RegisterCommand( "goto", - adminGroups, + FilterGroups(CommandPermissions["goto"]), function(xPlayer, args) local targetCoords = args.playerId.getCoords() local srcDim = GetPlayerRoutingBucket(xPlayer.source) @@ -646,7 +642,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "bring", - adminGroups, + FilterGroups(CommandPermissions.bring), function(xPlayer, args) local targetCoords = args.playerId.getCoords() local playerCoords = xPlayer.getCoords() @@ -678,7 +674,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "kill", - adminGroups, + FilterGroups(CommandPermissions.kill), function(xPlayer, args) args.playerId.triggerEvent("esx:killPlayer") if Config.AdminLogging then @@ -701,7 +697,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "freeze", - adminGroups, + FilterGroups(CommandPermissions.freeze), function(xPlayer, args) args.playerId.triggerEvent("esx:freezePlayer", "freeze") if Config.AdminLogging then @@ -724,7 +720,7 @@ ESX.RegisterCommand( ESX.RegisterCommand( "unfreeze", - adminGroups, + FilterGroups(CommandPermissions.unfreeze), function(xPlayer, args) args.playerId.triggerEvent("esx:freezePlayer", "unfreeze") if Config.AdminLogging then @@ -745,7 +741,7 @@ ESX.RegisterCommand( } ) -ESX.RegisterCommand("noclip", adminGroups, function(xPlayer) +ESX.RegisterCommand("noclip", FilterGroups(CommandPermissions.noclip), function(xPlayer) xPlayer.triggerEvent("esx:noclip") if Config.AdminLogging then ESX.DiscordLogFields("UserActions", "Admin NoClip /noclip Triggered!", "pink", { @@ -755,7 +751,7 @@ ESX.RegisterCommand("noclip", adminGroups, function(xPlayer) end end, false) -ESX.RegisterCommand("players", adminGroups, function() +ESX.RegisterCommand("players", FilterGroups(CommandPermissions.players), function() local xPlayers = ESX.GetExtendedPlayers() -- Returns all xPlayers print(("^5%s^2 online player(s)^0"):format(#xPlayers)) for i = 1, #xPlayers do @@ -766,7 +762,7 @@ end, true) ESX.RegisterCommand( {"setdim", "setbucket"}, - adminGroups, + FilterGroups(CommandPermissions.setdim), function(xPlayer, args) SetPlayerRoutingBucket(args.playerId.source, args.dimension) if Config.AdminLogging then diff --git a/[core]/es_extended/shared/config/main.lua b/[core]/es_extended/shared/config/main.lua index 0bb55117..2c32180b 100644 --- a/[core]/es_extended/shared/config/main.lua +++ b/[core]/es_extended/shared/config/main.lua @@ -39,6 +39,44 @@ Config.AdminGroups = { ["admin"] = true, } +Config.CommandPermissions = { + ["setcoords"] = { "owner", "admin" }, -- /setcoords, /tp + ["setjob"] = { "owner", "admin" }, + ["car"] = { "owner", "admin" }, + ["cardel"] = { "owner", "admin" }, -- /cardel, /dv + ["fix"] = { "owner", "admin" }, -- /fix, /repair + ["setaccountmoney"] = { "owner", "admin" }, + ["giveaccountmoney"] = { "owner", "admin" }, + ["removeaccountmoney"] = { "owner", "admin" }, + ["giveitem"] = { "owner", "admin" }, + ["giveweapon"] = { "owner", "admin" }, + ["giveammo"] = { "owner", "admin" }, + ["giveweaponcomponent"] = { "owner", "admin" }, + ["clearall"] = { "owner", "admin" }, -- /clearall, /clsall + ["refreshjobs"] = { "owner", "admin" }, + ["refreshitems"] = { "owner", "admin" }, + ["clearinventory"] = { "owner", "admin" }, + ["clearloadout"] = { "owner", "admin" }, + ["setgroup"] = { "owner", "admin" }, + ["save"] = { "owner", "admin" }, + ["saveall"] = { "owner", "admin" }, + ["goto"] = { "owner", "admin" }, + ["bring"] = { "owner", "admin" }, + ["kill"] = { "owner", "admin" }, + ["freeze"] = { "owner", "admin" }, + ["unfreeze"] = { "owner", "admin" }, + ["setdim"] = { "owner", "admin" }, -- /setdim, /setbucket + ["players"] = { "owner", "admin" }, + ["noclip"] = { "owner", "admin" }, + ["tpm"] = { "owner", "admin" }, + ["coords"] = { "owner", "admin" }, + ["clear"] = { "user", "admin", "owner" }, -- /clear, /cls + ["group"] = { "user", "admin", "owner" }, + ["job"] = { "user", "admin", "owner" }, + ["info"] = { "user", "admin", "owner" }, + ["playtime"] = { "user", "admin", "owner" }, +} + Config.ValidCharacterSets = { -- Only enable additional charsets if your server is multilingual. By default everything is false. ['el'] = false, -- Greek ['sr'] = false, -- Cyrillic From 4a22b68511796c8252b4d70bd142c747f6739e9a Mon Sep 17 00:00:00 2001 From: Ihsan <122683406+rwixy@users.noreply.github.com> Date: Sat, 8 Aug 2026 00:16:03 +0530 Subject: [PATCH 3/3] refactor(commands): simplify group filtering and update deprecation notice for AdminGroups --- [core]/es_extended/server/modules/commands.lua | 8 +------- [core]/es_extended/shared/config/main.lua | 3 +++ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/[core]/es_extended/server/modules/commands.lua b/[core]/es_extended/server/modules/commands.lua index 0a800f7a..0542d3f9 100644 --- a/[core]/es_extended/server/modules/commands.lua +++ b/[core]/es_extended/server/modules/commands.lua @@ -1,13 +1,7 @@ local CommandPermissions = Config.CommandPermissions or {} local function FilterGroups(groups) - local filtered = {} - for _, group in ipairs(groups or {}) do - if Config.AdminGroups[group] ~= false then - filtered[#filtered + 1] = group - end - end - return #filtered > 0 and filtered or { "admin" } + return (groups and #groups > 0) and groups or { "user" } end ESX.RegisterCommand( diff --git a/[core]/es_extended/shared/config/main.lua b/[core]/es_extended/shared/config/main.lua index 2c32180b..f61ff88c 100644 --- a/[core]/es_extended/shared/config/main.lua +++ b/[core]/es_extended/shared/config/main.lua @@ -34,6 +34,9 @@ Config.DefaultSpawns = { -- If you want to have more spawn positions and select --{x = 233.5459, y = -868.2626, z = 30.2922, heading = 1.0} } +---@deprecated Use `Config.CommandPermissions` as the single source of truth for command ACLs. +--- Kept temporarily for backwards compatibility with external resources that still read `Config.AdminGroups`. +--- Will be removed in ESX 1.15. Config.AdminGroups = { ["owner"] = true, ["admin"] = true,