From 7034f17b5d8308e7124e39a7d7f720dfff6e1329 Mon Sep 17 00:00:00 2001 From: bbassie <17990055+bbassie@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:36:58 +0000 Subject: [PATCH] Move the scenario onto exp_roles and remove the legacy role system Every call site of expcore.roles now uses exp_roles, and the legacy module, its config, and the glue which refreshed guis on role events are deleted. Where a file only renamed the require and the permission strings the change is mechanical; the rest: - Jail is now "give the Jail role" and unjail "take it away". The role has a higher priority than every other so holding it suppresses them, which is what stashing and restoring the roles was for. - The command role authority derives exp_scenario.command. from the command name, and the role parsers use player_outranks rather than comparing indexes with their own root check. - The admin and spectator triggers, and the gui refresh on role changes, live in exp_scenario/control/roles.lua; the system commands trigger stays with the command authority. - The player list warn button is keyed on create_warning, the permission the command behind it already required, and report on create_report. Both were keyed on names no role held, so only root ever saw them. - The warps and tasks configs say exp_roles where they said expcore.roles. - The role tables the readme and player list read are replaced by get_player_names and get_roles. Co-Authored-By: Claude Fable 5 --- exp_legacy/module/config/_file_loader.lua | 2 - exp_legacy/module/config/afk_kick.lua | 5 +- exp_legacy/module/config/chat_reply.lua | 2 +- exp_legacy/module/config/expcore/roles.lua | 363 ----- .../module/config/gui/player_list_actions.lua | 34 +- exp_legacy/module/config/gui/rockets.lua | 4 +- exp_legacy/module/config/gui/tasks.lua | 8 +- exp_legacy/module/config/gui/warps.lua | 16 +- exp_legacy/module/config/nukeprotect.lua | 2 +- exp_legacy/module/config/protection.lua | 2 +- exp_legacy/module/expcore/roles.lua | 1192 ----------------- exp_legacy/module/locale/en/expcore.cfg | 8 - exp_legacy/module/locale/zh-CN/expcore.cfg | 8 - exp_legacy/module/locale/zh-TW/expcore.cfg | 8 - exp_legacy/module/module.json | 1 + exp_legacy/module/modules/control/jail.lua | 31 +- .../module/modules/control/protection.lua | 8 +- exp_legacy/module/modules/data/greetings.lua | 2 +- exp_legacy/module/modules/data/quickbar.lua | 2 +- exp_legacy/module/modules/data/tag.lua | 8 +- .../module/modules/gui/_role_updates.lua | 7 - exp_legacy/module/modules/gui/vlayer.lua | 11 +- exp_legacy/module/modules/gui/warp-list.lua | 11 +- exp_scenario/module/commands/_authorities.lua | 14 +- exp_scenario/module/commands/_rcon.lua | 2 +- exp_scenario/module/commands/_types.lua | 46 +- exp_scenario/module/commands/kill.lua | 6 +- .../module/commands/protected_entities.lua | 2 +- exp_scenario/module/commands/reports.lua | 6 +- exp_scenario/module/commands/roles.lua | 12 +- exp_scenario/module/commands/teleport.lua | 6 +- exp_scenario/module/control.lua | 1 + exp_scenario/module/control/bonus.lua | 4 +- .../module/control/chat_auto_reply.lua | 4 +- .../module/control/deconstruction_log.lua | 4 +- .../module/control/fast_deconstruction.lua | 8 +- .../module/control/nuke_protection.lua | 4 +- exp_scenario/module/control/roles.lua | 21 + exp_scenario/module/gui/autofill.lua | 4 +- exp_scenario/module/gui/module_inserter.lua | 4 +- exp_scenario/module/gui/player_bonus.lua | 16 +- exp_scenario/module/gui/player_list.lua | 12 +- exp_scenario/module/gui/player_stats.lua | 4 +- exp_scenario/module/gui/production_stats.lua | 4 +- exp_scenario/module/gui/quick_actions.lua | 7 +- exp_scenario/module/gui/readme.lua | 20 +- .../module/gui/research_milestones.lua | 4 +- exp_scenario/module/gui/rocket_info.lua | 4 +- .../module/gui/science_production.lua | 4 +- exp_scenario/module/gui/surveillance.lua | 4 +- exp_scenario/module/gui/task_list.lua | 15 +- exp_scenario/module/module.json | 1 + exp_server_ups/module/control.lua | 2 +- 53 files changed, 204 insertions(+), 1776 deletions(-) delete mode 100644 exp_legacy/module/config/expcore/roles.lua delete mode 100644 exp_legacy/module/expcore/roles.lua delete mode 100644 exp_legacy/module/modules/gui/_role_updates.lua create mode 100644 exp_scenario/module/control/roles.lua diff --git a/exp_legacy/module/config/_file_loader.lua b/exp_legacy/module/config/_file_loader.lua index aaf9984a..88fdec5e 100644 --- a/exp_legacy/module/config/_file_loader.lua +++ b/exp_legacy/module/config/_file_loader.lua @@ -22,10 +22,8 @@ return { --- GUI "modules.gui.warp-list", "modules.gui.vlayer", - "modules.gui._role_updates", "modules.graftorio.require", -- graftorio --- Config Files "config.expcore.permission_groups", -- loads some predefined permission groups - "config.expcore.roles", -- loads some predefined roles } diff --git a/exp_legacy/module/config/afk_kick.lua b/exp_legacy/module/config/afk_kick.lua index cb982ade..f02be428 100644 --- a/exp_legacy/module/config/afk_kick.lua +++ b/exp_legacy/module/config/afk_kick.lua @@ -1,4 +1,4 @@ -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") return { admin_as_active = true, --- @setting admin_as_active When true admins will be treated as active regardless of afk time @@ -8,6 +8,7 @@ return { trust_time = 3600 * 60 * 10, --- @setting trust_time The time in ticks that a player must be online for to count as trusted update_time = 3600 * 30, --- @setting update_time How often in ticks the script checks for active players custom_active_check = function(player) - return Roles.get_player_highest_role(player).index <= Roles.get_role_from_any("Veteran").index + local veteran = Roles.get_role("Veteran") + return veteran ~= nil and Roles.get_player_highest_role(player).index <= veteran.index end, } diff --git a/exp_legacy/module/config/chat_reply.lua b/exp_legacy/module/config/chat_reply.lua index 5eabb22d..97e035d7 100644 --- a/exp_legacy/module/config/chat_reply.lua +++ b/exp_legacy/module/config/chat_reply.lua @@ -65,7 +65,7 @@ return { }, allow_command_prefix_for_messages = true, --- @setting allow_command_prefix_for_messages when true any message trigger will print to all player when prefixed command_admin_only = false, --- @setting command_admin_only when true will only allow chat commands for admins - command_permission = "command/chat-commands", --- @setting command_permission the permission used to allow command prefixes + command_permission = "exp_scenario.chat.commands", --- @setting command_permission the permission used to allow command prefixes command_prefix = "!", --- @setting command_prefix prefix used for commands below and to print to all players (if enabled above) --- @type table commands = { --- @setting commands will trigger only when command prefix is given diff --git a/exp_legacy/module/config/expcore/roles.lua b/exp_legacy/module/config/expcore/roles.lua deleted file mode 100644 index 8ffbb53f..00000000 --- a/exp_legacy/module/config/expcore/roles.lua +++ /dev/null @@ -1,363 +0,0 @@ ---- This is the main config file for the role system; file includes defines for roles and role flags and default values --- @config Roles - -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data -local Statistics = PlayerData.Statistics - ---- Role flags that will run when a player changes roles -Roles.define_flag_trigger("is_admin", function(player, state) - player.admin = state -end) -Roles.define_flag_trigger("is_spectator", function(player, state) - player.spectator = state -end) -Roles.define_flag_trigger("is_jail", function(player, state) - if player.character then - player.character.disabled_by_script = not state - end -end) - ---- Admin Roles -Roles.new_role("System", "SYS") - :set_permission_group("Default", true) - :set_flag("is_admin") - :set_flag("is_system") - :set_flag("is_spectator") - :set_flag("report-immune") - :set_flag("instant-respawn") - :set_allow_all() - -Roles.new_role("Senior Administrator", "SAdmin") - :set_permission_group("Admin") - :set_custom_color{ r = 233, g = 63, b = 233 } - :set_flag("is_admin") - :set_flag("is_system") - :set_flag("is_spectator") - :set_flag("report-immune") - :set_flag("instant-respawn") - :set_parent("Administrator") - :allow{ - "command/_rcon", - "command/debug", - "command/set-cheat-mode", - "command/research-all", - } - -Roles.new_role("Administrator", "Admin") - :set_permission_group("Admin") - :set_custom_color{ r = 233, g = 63, b = 233 } - :set_flag("is_admin") - :set_flag("is_spectator") - :set_flag("report-immune") - :set_flag("instant-respawn") - :set_parent("Moderator") - :allow{ - "gui/warp-list/bypass-proximity", - "gui/warp-list/bypass-cooldown", - "command/connect-all", - } - -Roles.new_role("Moderator", "Mod") - :set_permission_group("Admin") - :set_custom_color{ r = 0, g = 170, b = 0 } - :set_flag("is_admin") - :set_flag("is_spectator") - :set_flag("report-immune") - :set_flag("instant-respawn") - :set_parent("Trainee") - :allow{ - "command/assign-role", - "command/unassign-role", - "command/repair", - "command/kill/always", - "command/clear-tag/always", - "command/spawn/always", - "command/clear-reports", - "command/clear-warnings", - "command/clear-script-warnings", - "command/clear-last-warnings", - "command/clear-inventory", - "command/kill-enemies", - "command/remove-enemies", - "command/home", - "command/set-home", - "command/get-home", - "command/return", - "command/connect-player", - "command/set-bot-queue", - "command/set-game-speed", - "command/set-friendly-fire", - "command/set-always-day", - "command/set-pollution-enabled", - "command/clear-pollution", - "gui/rocket-info/toggle-active", - "gui/rocket-info/remote_launch", - "gui/bonus", - "fast-tree-decon", - } - -Roles.new_role("Trainee", "TrMod") - :set_permission_group("Admin") - :set_custom_color{ r = 0, g = 170, b = 0 } - :set_flag("is_admin") - :set_flag("is_spectator") - :set_flag("report-immune") - :set_parent("Veteran") - :allow{ - "command/admin-chat", - "command/goto", - "command/teleport", - "command/bring", - "command/create-warning", - "command/get-warnings", - "command/get-reports", - "command/protect-entity", - "command/protect-area", - "command/protect-tag", - "command/jail", - "command/unjail", - "command/kick", - "command/ban", - "command/spectate", - "command/follow", - "command/search", - "command/search-online", - "command/search-amount", - "command/search-recent", - "command/clear-blueprints-surface", - "gui/playerdata", - } - ---- Trusted Roles -Roles.new_role("Board Member", "Board") - :set_permission_group("Trusted") - :set_custom_color{ r = 247, g = 246, b = 54 } - :set_flag("is_spectator") - :set_flag("report-immune") - :set_flag("instant-respawn") - :set_parent("Sponsor") - :allow{ - "command/goto", - "command/repair", - "command/spectate", - "command/follow", - "gui/playerdata", - } - -Roles.new_role("Senior Backer", "Backer") - :set_permission_group("Trusted") - :set_custom_color{ r = 238, g = 172, b = 44 } - :set_flag("is_spectator") - :set_flag("report-immune") - :set_flag("instant-respawn") - :set_parent("Sponsor") - :allow{ - } - -Roles.new_role("Sponsor", "Spon") - :set_permission_group("Trusted") - :set_custom_color{ r = 238, g = 172, b = 44 } - :set_flag("is_spectator") - :set_flag("report-immune") - :set_flag("instant-respawn") - :set_parent("Supporter") - :allow{ - "gui/rocket-info/toggle-active", - "gui/rocket-info/remote_launch", - "gui/bonus", - "command/home", - "command/set-home", - "command/get-home", - "command/return", - "fast-tree-decon", - } - -Roles.new_role("Supporter", "Sup") - :set_permission_group("Trusted") - :set_custom_color{ r = 230, g = 99, b = 34 } - :set_flag("is_spectator") - :set_parent("Veteran") - :allow{ - "command/tag-color", - "command/jail", - "command/unjail", - "command/set-join-message", - "command/remove-join-message", - } - -Roles.new_role("Partner", "Part") - :set_permission_group("Trusted") - :set_custom_color{ r = 140, g = 120, b = 200 } - :set_flag("is_spectator") - :set_parent("Veteran") - :allow{ - "command/jail", - "command/unjail", - } - -local hours10, hours250 = 10 * 216000, 250 * 60 -Roles.new_role("Veteran", "Vet") - :set_permission_group("Trusted") - :set_custom_color{ r = 140, g = 120, b = 200 } - :set_parent("Member") - :allow{ - "command/chat-commands", - "command/clear-ground-items", - "command/clear-blueprints", - "command/set-trains-to-automatic", - } - :set_auto_assign_condition(function(player) - if player.online_time >= hours10 then - return true - else - local stats = Statistics:get(player, {}) - local playtime, afk_time, map_count = stats.Playtime or 0, stats.AfkTime or 0, stats.MapsPlayed or 0 - return playtime - afk_time >= hours250 and map_count >= 25 - end - end) - ---- Standard User Roles -Roles.new_role("Member", "Mem") - :set_permission_group("Standard") - :set_custom_color{ r = 24, g = 172, b = 188 } - :set_flag("deconlog-bypass") - :set_parent("Regular") - :allow{ - "gui/task-list/add", - "gui/task-list/edit", - "gui/warp-list/add", - "gui/warp-list/edit", - "gui/surveillance", - "gui/vlayer-edit", - "gui/tool", - "command/save-quickbar", - "command/vlayer-info", - "command/lawnmower", - "command/waterfill", - "command/artillery", - } - -local hours3, hours15 = 3 * 216000, 15 * 60 -Roles.new_role("Regular", "Reg") - :set_permission_group("Standard") - :set_custom_color{ r = 79, g = 155, b = 163 } - :set_parent("Guest") - :allow{ - "command/kill", - "command/rainbow", - "command/spawn", - "command/me", - "standard-decon", - "bypass-entity-protection", - "bypass-nukeprotect", - } - :set_auto_assign_condition(function(player) - if player.online_time >= hours3 then - return true - else - local stats = Statistics:get(player, {}) - local playtime, afk_time, map_count = stats.Playtime or 0, stats.AfkTime or 0, stats.MapsPlayed or 0 - return playtime - afk_time >= hours15 and map_count >= 5 - end - end) - ---- Guest/Default role -local default = Roles.new_role("Guest", "") - :set_permission_group("Guest") - :set_custom_color{ r = 185, g = 187, b = 160 } - :allow{ - "command/tag", - "command/tag-clear", - "command/commands", - "command/get-roles", - "command/locate", - "command/create-report", - "command/ratio", - "command/server-ups", - "command/save-data", - "command/data-preference", - "command/connect", - "gui/player-list", - "gui/rocket-info", - "gui/science-info", - "gui/task-list", - "gui/warp-list", - "gui/readme", - "gui/vlayer", - "gui/research", - "gui/autofill", - "gui/module", - "gui/production", - } - ---- Jail role -Roles.new_role("Jail") - :set_permission_group("Restricted") - :set_custom_color{ r = 50, g = 50, b = 50 } - :set_block_auto_assign(true) - :set_flag("defer_role_changes") - :disallow(default.allowed) - ---- System defaults which are required to be set -Roles.set_root("System") -Roles.set_default("Guest") - -Roles.define_role_order{ - "System", -- Best to keep root at top - "Senior Administrator", - "Administrator", - "Moderator", - "Trainee", - "Board Member", - "Senior Backer", - "Sponsor", - "Supporter", - "Partner", - "Veteran", - "Member", - "Regular", - "Jail", - "Guest", -- Default must be last if you want to apply restrictions to other roles -} - -Roles.override_player_roles{ - ["PHIDIAS0303"] = { "Moderator", "Board Member", "Member" }, - ["aldldl"] = { "Administrator", "Moderator", "Member" }, - ["arty714"] = { "Senior Administrator", "Moderator", "Member" }, - ["Cooldude2606"] = { "Senior Administrator", "Moderator", "Member" }, - ["Drahc_pro"] = { "Administrator", "Moderator", "Member" }, - ["mark9064"] = { "Administrator", "Moderator", "Member" }, - ["7h3w1z4rd"] = { "Moderator", "Member" }, - ["FlipHalfling90"] = { "Moderator", "Member" }, - ["hamsterbryan"] = { "Moderator", "Member" }, - ["HunterOfGames"] = { "Moderator", "Member" }, - ["NextIdea"] = { "Moderator", "Member" }, - ["TheKernel32"] = { "Moderator", "Member" }, - ["TheKernel64"] = { "Moderator", "Member" }, - ["tovernaar123"] = { "Moderator", "Member" }, - ["UUBlueFire"] = { "Moderator", "Member" }, - ["AssemblyStorm"] = { "Moderator", "Member" }, - ["banakeg"] = { "Moderator", "Member" }, - ["connormkii"] = { "Moderator", "Member" }, - ["cydes"] = { "Moderator", "Member" }, - ["darklich14"] = { "Moderator", "Member" }, - ["facere"] = { "Moderator", "Member" }, - ["freek18"] = { "Moderator", "Member" }, - ["Gizan"] = { "Moderator", "Member" }, - ["LoicB"] = { "Moderator", "Member" }, - ["M74132"] = { "Moderator", "Member" }, - ["mafisch3"] = { "Moderator", "Member" }, - ["maplesyrup01"] = { "Moderator", "Member" }, - ["ookl"] = { "Moderator", "Member" }, - ["Phoenix27833"] = { "Moderator", "Member" }, - ["porelos"] = { "Moderator", "Member" }, - ["Ruuyji"] = { "Moderator", "Member" }, - ["samy115"] = { "Moderator", "Member" }, - ["SilentLog"] = { "Moderator", "Member" }, - ["Tcheko"] = { "Moderator", "Member" }, - ["thadius856"] = { "Moderator", "Member" }, - ["whoami32"] = { "Moderator", "Member" }, - ["Windbomb"] = { "Moderator", "Member" }, - ["XenoCyber"] = { "Moderator", "Member" }, -} diff --git a/exp_legacy/module/config/gui/player_list_actions.lua b/exp_legacy/module/config/gui/player_list_actions.lua index c6bb968c..b3e265dd 100644 --- a/exp_legacy/module/config/gui/player_list_actions.lua +++ b/exp_legacy/module/config/gui/player_list_actions.lua @@ -7,7 +7,7 @@ local ExpUtil = require("modules/exp_util") local Gui = require("modules/exp_gui") -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local Roles = require("modules/exp_roles") local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail @@ -23,11 +23,7 @@ end -- auth that will only allow when on player's of lower roles local function auth_lower_role(player, selected_player_name) - local player_highest = Roles.get_player_highest_role(player) - local action_player_highest = Roles.get_player_highest_role(selected_player_name) - if player_highest.index < action_player_highest.index then - return true - end + return Roles.player_outranks(player, selected_player_name) end -- gets the action player and a coloured name for the action to be used on @@ -94,7 +90,7 @@ local report_player = new_button("utility/spawn_flag", { "exp-gui_player-list.re if Reports.is_reported(selected_player.name, player.name) then player.print({ "exp-commands_report.already-reported" }, Colors.orange_red) else - set_selected_action(player, "command/report") + set_selected_action(player, "exp_scenario.command.create_report") end end) @@ -110,7 +106,7 @@ end -- @element warn_player local warn_player = new_button("utility/spawn_flag", { "exp-gui_player-list.warn-player" }) :on_click(function(def, player, element) - set_selected_action(player, "command/give-warning") + set_selected_action(player, "exp_scenario.command.create_warning") end) local function warn_player_callback(player, reason) @@ -128,7 +124,7 @@ local jail_player = new_button("utility/multiplayer_waiting_icon", { "exp-gui_pl if Jail.is_jailed(selected_player.name) then player.print({ "exp-commands_jail.already-jailed", selected_player_color }, Colors.orange_red) else - set_selected_action(player, "command/jail") + set_selected_action(player, "exp_scenario.command.jail") end end) @@ -143,7 +139,7 @@ end -- @element kick_player local kick_player = new_button("utility/warning_icon", { "exp-gui_player-list.kick-player" }) :on_click(function(def, player, element) - set_selected_action(player, "command/kick") + set_selected_action(player, "exp_scenario.gui.player_list.kick") end) local function kick_player_callback(player, reason) @@ -155,7 +151,7 @@ end -- @element ban_player local ban_player = new_button("utility/danger_icon", { "exp-gui_player-list.ban-player" }) :on_click(function(def, player, element) - set_selected_action(player, "command/ban") + set_selected_action(player, "exp_scenario.gui.player_list.ban") end) local function ban_player_callback(player, reason) @@ -166,39 +162,39 @@ end return { set_accessors = set_accessors, buttons = { - ["command/teleport"] = { + ["exp_scenario.command.teleport"] = { auth = function(player, selected_player) return player.name ~= selected_player.name end, -- cant teleport to your self goto_player, bring_player, }, - ["command/report"] = { + ["exp_scenario.command.create_report"] = { auth = function(player, selected_player) if player == selected_player then return false end - if not Roles.player_allowed(player, "command/give-warning") then - return not Roles.player_has_flag(selected_player, "report-immune") + if not Roles.player_has_permission(player, "exp_scenario.command.create_warning") then + return not Roles.player_has_permission(selected_player, "exp_scenario.bypass.reports") end end, -- can report any player that isn't immune and you aren't able to give warnings reason_callback = report_player_callback, report_player, }, - ["command/give-warning"] = { + ["exp_scenario.command.create_warning"] = { auth = auth_lower_role, -- warn a lower user, replaces report reason_callback = warn_player_callback, warn_player, }, - ["command/jail"] = { + ["exp_scenario.command.jail"] = { auth = auth_lower_role, reason_callback = jail_player_callback, jail_player, }, - ["command/kick"] = { + ["exp_scenario.gui.player_list.kick"] = { auth = auth_lower_role, reason_callback = kick_player_callback, kick_player, }, - ["command/ban"] = { + ["exp_scenario.gui.player_list.ban"] = { auth = auth_lower_role, reason_callback = ban_player_callback, ban_player, diff --git a/exp_legacy/module/config/gui/rockets.lua b/exp_legacy/module/config/gui/rockets.lua index 2d90778d..c1c7e53f 100644 --- a/exp_legacy/module/config/gui/rockets.lua +++ b/exp_legacy/module/config/gui/rockets.lua @@ -39,9 +39,9 @@ return { allow_zoom_to_map = true, --- @setting allow_zoom_to_map false will disable the zoom to map feature allow_remote_launch = true, --- @setting allow_remote_launch false removes the remote launch button for all players remote_launch_admins_only = false, --- @setting remote_launch_admins_only true will remove the remote launch button for all non (game) admins - remote_launch_role_permission = "gui/rocket-info/remote_launch", --- @setting remote_launch_role_permission value used by custom permission system to allow or disallow the button + remote_launch_role_permission = "exp_scenario.gui.rocket_info.remote_launch", --- @setting remote_launch_role_permission value used by custom permission system to allow or disallow the button allow_toggle_active = true, --- @setting allow_toggle_active false removes the remote toggle auto launch button for all players toggle_active_admins_only = false, --- @setting toggle_active_admins_only true will remove the toggle auto launch button for all non (game) admins - toggle_active_role_permission = "gui/rocket-info/toggle-active", --- @setting toggle_active_role_permission value used by custom permission system to allow or disallow the button + toggle_active_role_permission = "exp_scenario.gui.rocket_info.toggle_active", --- @setting toggle_active_role_permission value used by custom permission system to allow or disallow the button }, } diff --git a/exp_legacy/module/config/gui/tasks.lua b/exp_legacy/module/config/gui/tasks.lua index 91f6bdcd..969b6ab3 100644 --- a/exp_legacy/module/config/gui/tasks.lua +++ b/exp_legacy/module/config/gui/tasks.lua @@ -3,11 +3,11 @@ return { -- Adding tasks - allow_add_task = "all", --- @setting allow_add_task dictates who is allowed to add new tasks; values: all, admin, expcore.roles, none - expcore_roles_allow_add_task = "gui/task-list/add", --- @setting expcore_roles_allow_add_task if expcore.roles is used then this is the required permission + allow_add_task = "all", --- @setting allow_add_task dictates who is allowed to add new tasks; values: all, admin, exp_roles, none + exp_roles_allow_add_task = "exp_scenario.gui.task_list.add", --- @setting exp_roles_allow_add_task if exp_roles is used then this is the required permission -- Editing tasks - allow_edit_task = "expcore.roles", --- @setting allow_edit_task dictates who is allowed to edit existing tasks; values: all, admin, expcore.roles, none - expcore_roles_allow_edit_task = "gui/task-list/edit", --- @setting expcore_roles_allow_edit_task if expcore.roles is used then this is the required permission + allow_edit_task = "exp_roles", --- @setting allow_edit_task dictates who is allowed to edit existing tasks; values: all, admin, exp_roles, none + exp_roles_allow_edit_task = "exp_scenario.gui.task_list.edit", --- @setting exp_roles_allow_edit_task if exp_roles is used then this is the required permission user_can_edit_own_tasks = true, --- @settings if true then the user who made the task can edit it regardless of the allow_edit_task setting } diff --git a/exp_legacy/module/config/gui/warps.lua b/exp_legacy/module/config/gui/warps.lua index af1a8bab..fa6c142b 100644 --- a/exp_legacy/module/config/gui/warps.lua +++ b/exp_legacy/module/config/gui/warps.lua @@ -8,23 +8,23 @@ return { default_icon = { type = "item", name = "discharge-defense-equipment" }, --- @setting default_icon the default icon that will be used for warps -- Warp cooldowns - bypass_warp_cooldown = "expcore.roles", --- @setting bypass_warp_cooldown dictates who the warp cooldown is applied to; values: all, admin, expcore.roles, none - expcore_roles_bypass_warp_cooldown = "gui/warp-list/bypass-cooldown", --- @setting expcore_roles_bypass_warp_cooldown if expcore.roles is used then this is the required permission + bypass_warp_cooldown = "exp_roles", --- @setting bypass_warp_cooldown dictates who the warp cooldown is applied to; values: all, admin, exp_roles, none + exp_roles_bypass_warp_cooldown = "exp_scenario.gui.warp_list.bypass_cooldown", --- @setting exp_roles_bypass_warp_cooldown if exp_roles is used then this is the required permission cooldown_duration = 60, --- @setting cooldown_duration the duration of the warp cooldown in seconds -- Warp proximity - bypass_warp_proximity = "expcore.roles", --- @setting bypass_warp_proximity dictates who the warp proximity is applied to; values: all, admin, expcore.roles, none - expcore_roles_bypass_warp_proximity = "gui/warp-list/bypass-proximity", --- @setting expcore_roles_bypass_warp_proximity if expcore.roles is used then this is the required permission + bypass_warp_proximity = "exp_roles", --- @setting bypass_warp_proximity dictates who the warp proximity is applied to; values: all, admin, exp_roles, none + exp_roles_bypass_warp_proximity = "exp_scenario.gui.warp_list.bypass_proximity", --- @setting exp_roles_bypass_warp_proximity if exp_roles is used then this is the required permission standard_proximity_radius = 4, --- @setting standard_proximity_radius the minimum distance a player is allowed to be to a warp in order to use it spawn_proximity_radius = 20, --- @setting spawn_proximity_radius the minimum distance a player is allowed to be from they spawn point to use warps -- Adding warps - allow_add_warp = "expcore.roles", --- @setting allow_add_warp dictates who is allowed to add warps; values: all, admin, expcore.roles, none - expcore_roles_allow_add_warp = "gui/warp-list/add", --- @setting expcore_roles_allow_add_warp if expcore.roles is used then this is the required permission + allow_add_warp = "exp_roles", --- @setting allow_add_warp dictates who is allowed to add warps; values: all, admin, exp_roles, none + exp_roles_allow_add_warp = "exp_scenario.gui.warp_list.add", --- @setting exp_roles_allow_add_warp if exp_roles is used then this is the required permission -- Editing warps - allow_edit_warp = "expcore.roles", --- @setting allow_edit_warp dictates who is allowed to edit warps; values: all, admin, expcore.roles, none - expcore_roles_allow_edit_warp = "gui/warp-list/edit", --- @setting expcore_roles_allow_edit_warp if expcore.roles is used then this is the required permission + allow_edit_warp = "exp_roles", --- @setting allow_edit_warp dictates who is allowed to edit warps; values: all, admin, exp_roles, none + exp_roles_allow_edit_warp = "exp_scenario.gui.warp_list.edit", --- @setting exp_roles_allow_edit_warp if exp_roles is used then this is the required permission user_can_edit_own_warps = false, --- @settings user_can_edit_own_warps if true then the user who made the warp can edit it regardless of the allow_edit_warp setting -- Warp area generation diff --git a/exp_legacy/module/config/nukeprotect.lua b/exp_legacy/module/config/nukeprotect.lua index a49c4e12..197ddb00 100644 --- a/exp_legacy/module/config/nukeprotect.lua +++ b/exp_legacy/module/config/nukeprotect.lua @@ -25,6 +25,6 @@ return { }, }, }, - ignore_permission = "bypass-nukeprotect", -- @setting ignore_permission The permission that nukeprotect will ignore + ignore_permission = "exp_scenario.bypass.nuke_protection", -- @setting ignore_permission The permission that nukeprotect will ignore ignore_admins = true, -- @setting ignore_admins Ignore admins, true by default. Allows usage outside of the roles module } diff --git a/exp_legacy/module/config/protection.lua b/exp_legacy/module/config/protection.lua index d598fb65..d645d04b 100644 --- a/exp_legacy/module/config/protection.lua +++ b/exp_legacy/module/config/protection.lua @@ -1,6 +1,6 @@ return { ignore_admins = true, --- @setting ignore_admins If admins are ignored by the protection filter - ignore_permission = "bypass-entity-protection", --- @setting ignore_permission Players with this permission will be ignored by the protection filter, leave nil if expcore.roles is not used + ignore_permission = "exp_scenario.bypass.entity_protection", --- @setting ignore_permission Players with this permission will be ignored by the protection filter, leave nil to protect against every player repeat_count = 5, --- @setting repeat_count Number of protected entities that must be removed within repeat_lifetime in order to trigger repeated removal protection repeat_lifetime = 3600 * 20, --- @setting repeat_lifetime The length of time, in ticks, that protected removals will be remembered for refresh_rate = 3600 * 5, --- @setting refresh_rate How often the age of protected removals are checked against repeat_lifetime diff --git a/exp_legacy/module/expcore/roles.lua b/exp_legacy/module/expcore/roles.lua deleted file mode 100644 index 641eeaea..00000000 --- a/exp_legacy/module/expcore/roles.lua +++ /dev/null @@ -1,1192 +0,0 @@ ---[[-- Core Module - Roles -- Factorio role system to manage custom permissions. -@core Roles -@alias Roles - -@usage--- Using Role System (assignment): ---When a map first starts you will want to define on mass all the players you expect to join and the roles to give them: -Roles.override_player_roles{ - Cooldude2606 = {'Owner', 'Admin', 'Member'}, - NotCooldude2606 = {'Member'} -} - ---Once the game is running you still want to be able to give role and remove them which is when you would use: -Roles.assign_player(player, 'Admin', by_player_name) -- this will give the "Admin" role to the player -Roles.unassign_player(player, {'Admin', 'Moderator'}, by_player_name) -- this will remove "Admin" and "Moderator" role in one go - -@usage--- Using Role System (role testing): ---To comparer two players you can comparer the index of they highest roles, can be used when you want to allow a "write" down type system: -Roles.get_player_highest_role(playerOne).index < Roles.get_player_highest_role(playerTwo).index -- remember that less means a higher role - ---Listing all of a players roles can also be useful which is when you would want to use: -Roles.get_player_roles(player) -- the return is an array that can be looped over however this is not in particular order - ---Finally you may want to test if a player has a certain role, flag or action allowed which is when you would use: -Roles.player_has_role(player, 'Admin') -- you can provide a role name if you only want a name based system -Roles.player_has_flag(player, 'is_donator') -- your roles can be grouped together with flags such as is_donator -Roles.player_allowed(player, 'game modifiers') -- or you can have an action based system where each action is something the player can do - -@usage--- Example Flag Define: ---Flags can be used to group multiple roles and actions under one catch all, for example if you want a piece of code to only ---be active for your donators then you would add a "is_donator" flag to all your donator roles and then in the code test if ---a player has that tag present: - --- give you donators a speed boost when they join; these functions aren't required but can be useful -Roles.define_flag_trigger('is_donator', function(player, state) - if state then - player.character_running_speed_modifier = 1.5 - else - player.character_running_speed_modifier = 1 - end -end) - --- then on all your donator roles you would add -Roles.new_role('Donator') -:set_flag('is_donator') - --- and in your code you would test for -if Roles.player_has_flag(player, 'is_donator') then - -- some donator only code -end - -@usage--- Example Role Define: ---You can't use a role system without any roles so first you must define your roles; each role has a minimum of a name with ---the option for a shorthand: -Roles.new_role('Administrator', 'Admin') - ---Next you will want to add any extras you want to have, such as a tag, colour, permission group or any custom flags: -Roles.new_role('Administrator', 'Admin') -:set_custom_tag('[Admin]') -:set_custom_color('red') -- this can be {r=0, g=0, b=0} or a predefined value -:set_permission_group('Staff') -- a second argument can be added if you have not used the custom permission group config -:set_flag('is_admin') - ---You will then want to decide if you want to allow all actions, this should of course be used sparely: -Roles.new_role('Administrator', 'Admin') -...extras... -:set_allow_all() - ---If you don't do this want this as i would advise you do then you will want to define what the role can do; this comes with ---an optional inheritance system if you like those sort of things in which case disallow may also be of some use to you: -Roles.new_role('Administrator', 'Admin') -...extras... -:set_parent('Moderator') -- the admin can do anything that a moderator can do -:allow{ -- these actions can be anything just try to keep them without conflicts - 'command/kill', - 'gui/game settings' -} - ---Here is what the finished admin role would look like: -Roles.new_role('Administrator', 'Admin') -:set_custom_tag('[Admin]') -:set_custom_color('red') -:set_permission_group('Staff') -:set_flag('is_admin') -:set_parent('Moderator') -:allow{ - 'command/kill', - 'gui/game settings' -} - -@usage--- Example System Define: ---Once all roles are defined these steps must be done to ensure the system is ready to use, this includes setting a default ---role, assigning a root (all permission) role that the server/system will use and the linear order that the roles fall into: - -Roles.set_default('Guest') -Roles.set_root('System') - -Roles.define_role_order{ - 'System', - 'Administrator', - 'Moderator', - 'Donator', - 'Guest' -} - ---Just remember that in this example all these roles have not been defined; so make sure all your roles that are used are defined ---before hand; a config file on load is useful for this to ensure that its loaded before the first player even joins. - -]] - -local ExpUtil = require("modules/exp_util") -local Async = require("modules/exp_util/async") -local Storage = require("modules/exp_util/storage") -local Event = require("modules/exp_legacy/utils/event") -local Groups = require("modules.exp_legacy.expcore.permission_groups") - -local Colours = ExpUtil.color -local write_json = ExpUtil.write_json - - ---- @class Roles.Role ---- @field name string ---- @field short_hand string ---- @field index number Position within the role order ---- @field allowed_actions table ---- @field allow_all_actions boolean ---- @field flags table ---- @field disallowed_actions table? ---- @field permission_group ([boolean, string] | string)? ---- @field custom_tag string? ---- @field custom_color Color? ---- @field parent string? ---- @field block_auto_assign boolean? ---- @field auto_assign_condition function? ---- @field set_allow_all fun(self: Roles.Role, state: boolean?): Roles.Role Defined on Roles._prototype - -local Roles = { - _prototype = {}, - config = { - order = {}, --- @type string[] Contains the order of the roles, lower index is better - roles = {}, --- @type table Contains the raw info for the roles, indexed by role name - flags = {}, -- Contains functions that run when a flag is added/removed from a player - internal = {}, -- Contains all internally accessed roles, such as root, default - players = {}, -- Contains the roles that players have - auto_assign = {}, -- Contains references to all roles which have auto assign conditions - deferred_roles = {}, -- Contains the roles that are to be assigned to players when they are unjailed - }, - events = { - on_role_assigned = script.generate_event_name(), - on_role_unassigned = script.generate_event_name(), - }, -} - ---- When global is loaded it will have the metatable re-assigned to the roles -Storage.register({ - Roles.config.players, - Roles.config.deferred_roles, -}, function(tbl) - Roles.config.players = tbl[1] - Roles.config.deferred_roles = tbl[2] -end) - ---- Getter. --- Functions which get roles --- @section get - ---- Internal function used to trigger a few different things when roles are changed --- this is the raw internal trigger as the other function is called at other times --- there is a second half called role_update which triggers after the event call, it also is called when a player joins -local function emit_player_roles_updated(player, type, roles, by_player_name, skip_game_print) - by_player_name = by_player_name or game.player and game.player.name or "" - local by_player = game.players[by_player_name] - local by_player_index = by_player and by_player.index or 0 - -- get the event id from the type of emit - local event = Roles.events.on_role_assigned - if type == "unassign" then - event = Roles.events.on_role_unassigned - end - -- Get the names of the roles - local role_names = {} - for index, role in ipairs(roles) do - role_names[index] = role.name - end - - -- output to all the different locations: game print, player sound, event trigger and role log - if not skip_game_print then - game.print({ "expcore-roles.game-message-" .. type, player.name, table.concat(role_names, ", "), by_player_name }, Colours.cyan) - end - if type == "assign" then - player.play_sound{ path = "utility/achievement_unlocked" } - else - player.play_sound{ path = "utility/game_lost" } - end - script.raise_event(event, { - name = event, - tick = game.tick, - player_index = player.index, - by_player_index = by_player_index, - roles = role_names, - }) - write_json("log/roles.log", { - player_name = player.name, - by_player_name = by_player_name, - type = type, - roles_changed = role_names, - }) -end - ---[[-- Returns a string which contains all roles in index order displaying all data for them -@treturn string the debug output string - -@usage-- Print the debug string -game.player.print(Roles.debug()) - -]] -function Roles.debug() - local output = "" - for index, role_name in ipairs(Roles.config.order) do - local role = Roles.config.roles[role_name] - local color = (role.custom_color or Colours.white) --[[@as Color.struct]] - local color_str = string.format("[color=%d, %d, %d]", color.r, color.g, color.b) - output = output .. string.format("\n%s %s) %s[/color]", color_str, index, serpent.line(role)) - end - - return output -end - ---[[-- Prints a message to all players in the given roles, may send duplicate message however factorio blocks spam -@tparam table roles table a of roles which to send the message to -@tparam string message the message to send to the players - -@usage-- Print a message to the given roles -Roles.print_to_roles({'Administrator', 'Moderator'}, 'Hello, World!') - -]] -function Roles.print_to_roles(roles, message) - for _, role in ipairs(roles) do - role = Roles.get_role_from_any(role) - if role then role:print(message) end - end -end - ---[[-- Prints a message to all players who have the given role or one which is higher (excluding default) -@tparam string role the name of the role to send the message to -@tparam string message the message to send to the players - -@usage-- Print a message to the roles above this role, includes the given role -Roles.print_to_roles_higher('Moderator', 'Hello, World!') - -]] -function Roles.print_to_roles_higher(role, message) - role = Roles.get_role_from_any(role) - if not role then return end - local roles = {} - for index, role_name in ipairs(Roles.config.order) do - if index <= role.index and role_name ~= Roles.config.internal.default then - roles[#roles + 1] = role_name - end - end - - Roles.print_to_roles(roles, message) -end - ---[[-- Prints a message to all players who have the given role or one which is lower (excluding default) -@tparam string role the name of the role to send the message to -@tparam string message the message to send to the players - -@usage-- Print a message to the roles below this role, includes the given role -Roles.print_to_roles_higher('Moderator', 'Hello, World!') - -]] -function Roles.print_to_roles_lower(role, message) - role = Roles.get_role_from_any(role) - if not role then return end - local roles = {} - for index, role_name in ipairs(Roles.config.order) do - if index >= role.index and role_name ~= Roles.config.internal.default then - roles[#roles + 1] = role_name - end - end - - Roles.print_to_roles(roles, message) -end - ---[[-- Get a role for the given name -@tparam string name the name of the role to get -@treturn Roles._prototype the role with that name or nil - -@usage-- Get a role by its name -local role = Roles.get_role_by_name('Moderator') - -]] -function Roles.get_role_by_name(name) - return Roles.config.roles[name] -end - ---[[-- Get a role with the given order index -@tparam number index the place in the order list of the role to get -@treturn Roles._prototype the role with that index in the order list or nil - -@usage-- Get a role by its index in the order list -local role = Roles.get_role_by_name(2) - -]] -function Roles.get_role_by_order(index) - local name = Roles.config.order[index] - if not name then return end - return Roles.config.roles[name] -end - ---[[-- Gets a role from a name, index or role object (where it is just returned) -nb: this function is used for the input for most outward facing functions -@tparam ?number|string|table any the value used to find the role -@treturn Roles._prototype the role that was found or nil see above - -@usage-- Get a role by its name or order -local role = Roles.get_role_from_any('Moderator') - -]] -function Roles.get_role_from_any(any) - local t_any = type(any) - if t_any == "number" or tonumber(any) then - any = tonumber(any) - return Roles.get_role_by_order(any) - elseif t_any == "string" then - return Roles.get_role_by_name(any) - elseif t_any == "table" then - return Roles.get_role_by_name(any.name) - end -end - ---- Returns all roles in order of index -function Roles.get_roles_ordered() - local rtn = {} - for index, role_name in ipairs(Roles.config.order) do - rtn[index] = Roles.config.roles[role_name] - end - return rtn -end - ---[[-- Gets all the roles of the given player, this will always contain the default role -@tparam LuaPlayer player the player to get the roles of -@treturn table a table where the values are the roles which the player has - -@usage-- Get the roles that a player has -local roles = Roles.get_player_roles(game.player) - -]] -function Roles.get_player_roles(player) - if not player or player.index == 0 then return { Roles.config.roles[Roles.config.internal.root] } end - local roles = Roles.config.players[player.name] or {} - local default = Roles.config.roles[Roles.config.internal.default] - local rtn = { default } - for index, role_name in ipairs(roles) do - rtn[index + 1] = Roles.config.roles[role_name] - end - - return rtn -end - ---[[-- Gets the highest role which the player has, can be used to compeer one player to another -@tparam LuaPlayer player the player to get the highest role of -@treturn the role with the highest order index which this player has - -@usage-- Get the highest role that a player has -local role = Roles.get_player_highest_role(game.player) - -]] ---- @return Roles.Role -function Roles.get_player_highest_role(player) - local roles = Roles.get_player_roles(player) - local highest --- @type Roles.Role? - for _, role in ipairs(roles) do - if not highest or role.index < highest.index then - highest = role - end - end - - return (assert(highest, "Player has no roles")) -end - ---- Assignment. --- Functions for changing player's roles --- @section assignment - ---[[-- Gives a player the given role(s) with an option to pass a by player name used in the log -@tparam LuaPlayer player the player that will be assigned the roles -@tparam table roles table a of roles that the player will be given, can be one role and can be role names -@tparam[opt=] string by_player_name the name of the player that will be shown in the log -@tparam[opt=false] boolean skip_checks when true there will be no checks are done for if the player is valid -@tparam[opt=false] boolean silent when true there will be no game message printed - -@usage-- Assign a player to the Moderator role -Roles.assign_player(game.player, 'Moderator') - -@usage-- Assign a player to the Moderator role, even if the player has never been on the map -Roles.assign_player('Cooldude2606', 'Moderator', nil, true) - -]] -function Roles.assign_player(player, roles, by_player_name, skip_checks, silent) - local valid_player = type(player) == "userdata" and player or game.get_player(player) - if not skip_checks and not valid_player then return end - - -- Convert the roles into a table (allows for optional array) - if type(roles) ~= "table" or roles.name then - roles = { roles } - end - - -- Convert to role objects - local role_objects = {} - for _, role in ipairs(roles) do - local role_object = Roles.get_role_from_any(role) - if role_object then table.insert(role_objects, role_object) end - end - - -- If the player has a role that needs to defer the role changes, save the roles that need to be assigned later into a table - if valid_player and Roles.player_has_flag(valid_player, "defer_role_changes") then - local assign_later = Roles.config.deferred_roles[valid_player.name] or {} - for _, role in ipairs(role_objects) do - local role_change = assign_later[role.name] - if role_change then - role_change.count = role_change.count + 1 - if role_change.count == 1 then - role_change.by_player_name = by_player_name or "" - role_change.silent = silent - end - else - assign_later[role.name] = { - count = 1, by_player_name = by_player_name or "", silent = silent, - } - end - end - - Roles.config.deferred_roles[valid_player.name] = assign_later - return - end - - for _, role in ipairs(role_objects) do - role:add_player(valid_player or player, valid_player == nil, true) - end - - if valid_player then - emit_player_roles_updated(valid_player, "assign", role_objects, by_player_name, silent) - end -end - ---[[-- Removes a player from the given role(s) with an option to pass a by player name used in the log -@tparam LuaPlayer player the player that will have the roles removed -@tparam table roles table a of roles to be removed from the player, can be one role and can be role names -@tparam[opt=] string by_player_name the name of the player that will be shown in the logs -@tparam[opt=false] boolean skip_checks when true there will be no checks are done for if the player is valid -@tparam[opt=false] boolean silent when true there will be no game message printed - -@usage-- Unassign a player from the Moderator role -Roles.unassign_player(game.player, 'Moderator') - -@usage-- Unassign a player from the Moderator role, even if the player has never been on the map -Roles.unassign_player('Cooldude2606', 'Moderator', nil, true) - -]] -function Roles.unassign_player(player, roles, by_player_name, skip_checks, silent) - local valid_player = type(player) == "userdata" and player or game.get_player(player) - if not skip_checks and not valid_player then return end - if not player then return end - - -- Convert the roles into a table (allows for optional array) - if type(roles) ~= "table" or roles.name then - roles = { roles } - end - - -- Convert to role objects - local role_objects = {} - for _, role in ipairs(roles) do - local role_object = Roles.get_role_from_any(role) - if role_object then table.insert(role_objects, role_object) end - end - - -- If the player has a role that needs to defer the role changes, save the roles that need to be unassigned later into a table - local defer_changes = Roles.player_has_flag(player, "defer_role_changes") - if defer_changes and valid_player then - local assign_later = Roles.config.deferred_roles[valid_player.name] or {} - for _, role in ipairs(role_objects) do - local role_change = assign_later[role.name] - if role_change then - role_change.count = role_change.count - 1 - if role_change.count == -1 then - role_change.by_player_name = by_player_name or "" - role_change.silent = silent - end - else - assign_later[role.name] = { - count = -1, by_player_name = by_player_name or "", silent = silent, - } - end - end - - Roles.config.deferred_roles[valid_player.name] = assign_later - end - - -- Remove the player from roles - local role_changes = {} - for _, role in ipairs(role_objects) do - if not defer_changes or role:has_flag("defer_role_changes") then - role:remove_player(valid_player or player, valid_player == nil, true) - table.insert(role_changes, role) - end - end - - -- If there are deferred role changes, apply them now - if defer_changes and not Roles.player_has_flag(valid_player, "defer_role_changes") then - local assign_later = Roles.config.deferred_roles[player.name] or {} - local assigns, unassigns = {}, {} - for role_name, details in pairs(assign_later) do - local role = Roles.get_role_from_any(role_name) - if role then - if details.count > 0 then - role:add_player(valid_player or player, valid_player == nil, true) - if not assigns[details.by_player_name] then assigns[details.by_player_name] = {} end - if not details.silent then table.insert(assigns[details.by_player_name], role) end - elseif details.count < 0 then - role:remove_player(valid_player or player, valid_player == nil, true) - if not unassigns[details.by_player_name] then unassigns[details.by_player_name] = {} end - if not details.silent then table.insert(unassigns[details.by_player_name], role) end - end - end - end - - for assign_by_player_name, assign_roles in pairs(assigns) do - if #assign_roles > 0 then emit_player_roles_updated(valid_player, "assign", assign_roles, assign_by_player_name) end - end - - for unassign_by_player_name, unassign_roles in pairs(unassigns) do - if #unassign_roles > 0 then emit_player_roles_updated(valid_player, "unassign", unassign_roles, unassign_by_player_name) end - end - - Roles.config.deferred_roles[player.name] = nil - end - - if valid_player and #role_changes > 0 then - emit_player_roles_updated(valid_player, "unassign", role_changes, by_player_name, silent) - end -end - ---[[-- Overrides all player roles with the given table of roles, useful to mass set roles on game start -@tparam[opt] string player_name the player to set the roles for, if not given all roles are overriden -@tparam table roles table a which is indexed by case sensitive player names and has the value of a table of role names - -@usage-- Override the roles of a single player, other users are not effected -Roles.override_player_roles('Cooldude2606', {'Moderator'}) - -@usage-- Override all existing roles, effects all users not just ones listed -Roles.override_player_roles{ - ['Cooldude2606'] = {'Administrator', 'Moderator'}, - ['arty714'] = {'Administrator', 'Moderator'}, -} - -]] -function Roles.override_player_roles(player_name, roles) - local player_roles = Roles.config.players - if not roles then - for k in pairs(player_roles) do player_roles[k] = nil end - - for k, new_roles in pairs(player_name) do player_roles[k] = new_roles end - else - Roles.config.players[player_name] = roles - end -end - ---- Checks. --- Functions for checking player's roles --- @section checks - ---[[-- A test for weather a player has the given role -@tparam LuaPlayer player the player to test the roles of -@tparam ?string|number|table search_role a pointer to the role that is being searched for -@treturn boolean true if the player has the role, false otherwise, nil for errors - -@usage-- Test if a player has a role -local has_role = Roles.player_has_role(game.player, 'Moderator') - -]] -function Roles.player_has_role(player, search_role) - local roles = Roles.get_player_roles(player) - if not roles then return end - search_role = Roles.get_role_from_any(search_role) - if not search_role then return end - for _, role in ipairs(roles) do - if role.name == search_role.name then return true end - end - - return false -end - ---[[-- A test for weather a player has the given flag true for at least one of they roles -@tparam LuaPlayer player the player to test the roles of -@tparam string flag_name the name of the flag that is being looked for -@treturn boolean true if the player has at least one role which has the flag set to true, false otherwise, nil for errors - -@usage-- Test if a player has a role -local has_flag = Roles.player_has_flag(game.player, 'is_donator') - -]] -function Roles.player_has_flag(player, flag_name) - local roles = Roles.get_player_roles(player) - if not roles then return end - for _, role in ipairs(roles) do - if role:has_flag(flag_name) then - return true - end - end - - return false -end - ---[[-- A test for weather a player has at least one role which is allowed the given action -@tparam LuaPlayer player the player to test the roles of -@tparam string action the name of the action that is being tested for -@treturn boolean true if the player has at least one role which is allowed this action, false otherwise, nil for errors - -@usage-- Test if a player has a role -local has_flag = Roles.player_has_flag(game.player, 'is_donator') - -]] -function Roles.player_allowed(player, action) - local roles = Roles.get_player_roles(player) - for _, role in ipairs(roles) do - if role:is_allowed(action) then - return true - end - end - - return false -end - ---- Definitions. --- Functions which are used to define roles --- @section checks - ---[[-- Used to set the role order, higher in the list is better, must be called at least once in config --- nb: function also re links parents due to expected position in the config file -@tparam table order table a which is keyed only by numbers (start 1) and values are roles in order with highest first - -@usage-- Define which roles are higher than others -Roles.define_role_order{ - 'System', - 'Administrator', - 'Moderator', - 'Donator', - 'Guest' -} - -]] -function Roles.define_role_order(order) - -- Clears and then rebuilds the order table - ExpUtil.assert_not_runtime() - Roles.config.order = {} - local done = {} - for index, role in ipairs(order) do - if type(role) == "table" and role.name then - done[role.name] = true - Roles.config.order[index] = role.name - else - done[role] = true - Roles.config.order[index] = role - end - end - - -- Check no roles were missed - for role_name in pairs(Roles.config.roles) do - if not done[role_name] then - error("Role missing " .. role_name .. " from role order, all defined roles must be included.", 2) - end - end - - -- Re-links roles to they parents as this is called at the end of the config - for index, role_name in pairs(Roles.config.order) do - local role = Roles.config.roles[role_name] - if not role then - error("Role with name " .. role_name .. " has not beed defined, either define it or remove it from the order list.", 2) - end - role.index = index - local parent = Roles.config.roles[role.parent] - if parent then - setmetatable(role.allowed_actions, { __index = parent.allowed_actions }) - end - end -end - ---[[-- Defines a new trigger for when a tag is added or removed from a player -@tparam string name the name of the flag which the roles will have -@tparam function callback the function that is called when roles are assigned - -@usage-- Defining a flag trigger -Roles.define_flag_trigger('is_donator', function(player, state) - player.character_running_speed_modifier = state and 1.5 or 1 -end) - -]] -function Roles.define_flag_trigger(name, callback) - Roles.config.flags[name] = Async.register(callback) -end - ---[[-- Sets the default role which every player will have, this needs to be called at least once -@tparam string name the name of the default role - -@usage-- Setting the default role -Roles.set_default('Guest') - -]] -function Roles.set_default(name) - local role = Roles.config.roles[name] - if not role then return end - Roles.config.internal.default = name -end - ---[[-- Sets the root role which will always have all permissions, any server actions act from this role -@tparam string name the name of the root role - -@usage-- Setting the root role -Roles.set_root('System') - -]] -function Roles.set_root(name) - local role = Roles.config.roles[name] - if not role then return end - role:set_allow_all(true) - Roles.config.internal.root = name -end - ---[[-- Defines a new role and returns the prototype to allow configuration -@tparam string name the name of the new role, must be unique -@tparam[opt=name] string short_hand the shortened version of the name -@treturn Roles._prototype the start of the config chain for this role - -@usage-- Defining a new role -local role = Roles.new_role('Moderator', 'Mod') - -]] -function Roles.new_role(name, short_hand) - ExpUtil.assert_not_runtime() - if Roles.config.roles[name] then error("Role name is non unique") end - local role = setmetatable({ - name = name, - short_hand = short_hand or name, - allowed_actions = {}, - allow_all_actions = false, - flags = {}, - }, { __index = Roles._prototype }) - Roles.config.roles[name] = role - return role -end - ---- Role Actions. --- Functions for using the role action system --- @section actions - ---[[-- Sets the default allow state of the role, true will allow all actions -@tparam[opt=true] boolean state true will allow all actions -@treturn Roles._prototype allows chaining - -@usage-- Allow all actions for this role, useful for root like roles -role:set_allow_all() - -]] -function Roles._prototype:set_allow_all(state) - if state == nil then state = true end - self.allow_all_actions = not not state -- not not forces a boolean value - return self -end - ---[[-- Sets the allow actions for this role, actions in this list will be allowed for this role -@tparam table actions indexed with numbers and is an array of action names, order has no effect -@treturn Roles._prototype allows chaining - -@usage-- Allow some actions for a role -role:allow{ - 'command/kill', - 'gui/game settings' -} - -]] -function Roles._prototype:allow(actions) - if type(actions) ~= "table" then - actions = { actions } - end - for _, action in ipairs(actions) do - self.allowed_actions[action] = true - end - - return self -end - ---[[-- Sets the disallow actions for this role, will prevent actions from being allowed regardless of inheritance -@tparam table actions indexed with numbers and is an array of action names, order has no effect -@treturn Roles._prototype allows chaining - -@usage-- Disallow an action for a role, useful if inherit an action from a parent -role:disallow{ - 'command/kill', - 'gui/game settings' -} - -]] -function Roles._prototype:disallow(actions) - if type(actions) ~= "table" then - actions = { actions } - end - for _, action in ipairs(actions) do - self.allowed_actions[action] = false - end - - return self -end - ---[[-- Test for if a role is allowed the given action, mostly internal see Roles.player_allowed -@tparam string action the name of the action to test if it is allowed -@treturn boolean true if action is allowed, false otherwise - -@usage-- Test if a role is allowed an action -local allowed = role:is_allowed('command/kill') - -]] -function Roles._prototype:is_allowed(action) - local is_root = Roles.config.internal.root == self.name - return self.allowed_actions[action] or self.allow_all_actions or is_root -end - ---- Role Flags. --- Functions for using the role flag system --- @section flags - ---[[-- Sets the state of a flag for a role, flags can be used to apply effects to players -@tparam string name the name of the flag to set the value of -@tparam[opt=true] boolean value the state to set the flag to -@treturn Roles._prototype allows chaining - -@usage-- Set a flag for a role -role:set_flag('is_admin') - -]] -function Roles._prototype:set_flag(name, value) - if value == nil then value = true end - self.flags[name] = not not value -- not not forces a boolean value - return self -end - ---[[-- Clears all flags from this role, individual flags can be removed with set_flag(name, false) -@treturn Roles._prototype allows chaining - -@usage-- Remove all flags from a role -role:clear_flags() - -]] -function Roles._prototype:clear_flags() - self.flags = {} - return self -end - ---[[-- A test for if the role has a flag set -@tparam string name the name of the flag to test for -@treturn boolean true if the flag is set, false otherwise - -@usage-- Test if a role has a flag -local has_flag = role:has_flag('is_admin') - -]] -function Roles._prototype:has_flag(name) - return self.flags[name] or false -end - ---- Role Properties. --- Functions for changing other properties --- @section properties - ---[[-- Sets a custom player tag for the role, can be accessed by other code -@tparam string tag the value that the tag will be -@treturn Roles._prototype allows chaining - -@usage-- Set a custom tag for this role, other code is required to set the tag -role:set_custom_tag('Mod') - -]] -function Roles._prototype:set_custom_tag(tag) - self.custom_tag = tag - return self -end - ---[[-- Sets a custom colour for the role, can be accessed by other code -@tparam table color ?string|table can either be and rgb colour or the name of a colour defined in the presets -@treturn Roles._prototype allows chaining - -@usage-- Set a custom colour for this role, other code is required to use this value -role:set_custom_color{ r=255, g=100, b=100} - -]] -function Roles._prototype:set_custom_color(color) - if type(color) ~= "table" then - color = Colours[color] - end - self.custom_color = color - return self -end - ---[[-- Sets the permission group for this role, players will be moved to the group of they highest role -@tparam string name the name of the permission group to have players moved to -@tparam[opt=false] boolean use_factorio_api when true the custom permission group module is ignored -@treturn Roles._prototype allows chaining - -@usage-- Set the permission group for this role, see permission_groups.lua -role:set_permission_group('Admin') - -]] -function Roles._prototype:set_permission_group(name, use_factorio_api) - ExpUtil.assert_not_runtime() - if use_factorio_api then - self.permission_group = { true, name } --[[@as [boolean, string] ]] - else - assert(Groups.get_group_by_name(name), "Permission group not found: " .. name) - self.permission_group = name - end - return self -end - ---[[-- Sets the parent for a role, any action not in allow or disallow will be looked for in its parents -nb: this is a recursive action, and changing the allows and disallows will effect all children roles -@tparam string role the name of the role that will be the parent; has imminent effect if role is already defined -@treturn Roles._prototype allows chaining - -@usage-- Set the parent for this role to inherit all actions allowed -role:set_parent('Guest') - -]] -function Roles._prototype:set_parent(role) - ExpUtil.assert_not_runtime() - self.parent = role - role = Roles.get_role_from_any(role) - if not role then return self end - setmetatable(self.allowed_actions, { __index = role.allowed_actions }) - return self -end - ---[[-- Sets an auto assign condition that is checked every 60 seconds, if true is returned then the player will receive the role -nb: this is one way, failing false after already gaining the role will not revoke the role -@tparam function callback receives only one param which is player to assign, return true to assign the player -@treturn Roles._prototype allows chaining - -@usage-- Give this role to a user if there are admin, ran every 60 seconds -role:set_auto_assign_condition(function(player) - return player.admin -end) - -]] -function Roles._prototype:set_auto_assign_condition(callback) - ExpUtil.assert_not_runtime() - self.auto_assign_condition = true - Roles.config.auto_assign[self.name] = callback - return self -end - ---[[-- Get the auto assign condition for this role, returns nil if no condition is set -@treturn function The callback which was assigned as the auto assign condition - -@usage-- Give this role to a user if there are admin, ran every 60 seconds -local condition = role:get_auto_assign_condition() - -]] -function Roles._prototype:get_auto_assign_condition() - return Roles.config.auto_assign[self.name] -end - ---[[-- Sets the role to not allow players to have auto assign effect them, useful to keep people locked to a role -@tparam[opt=true] boolean state when true the players with this role will not be auto assigned to other roles -@treturn Roles._prototype allows chaining - -@usage-- Make a role stop players from being auto assigned to other roles -role:set_block_auto_assign() - -]] -function Roles._prototype:set_block_auto_assign(state) - if state == nil then state = true end - self.block_auto_assign = not not state -- forces a boolean value - return self -end - ---- Role Players. --- Functions that control players in a role --- @section players - ---[[-- Adds a player to this role, players can have more than one role at a time, used internally see Roles.assign -@tparam LuaPlayer player the player that will be given this role -@tparam boolean skip_check when true player will be taken as the player name (use when player has not yet joined) -@tparam boolean skip_event when true the event emit will be skipped, this is used internally with Roles.assign -@treturn boolean true if the player was added successfully - -@usage-- Assign a player to this role -role:add_player(game.player) - -]] -function Roles._prototype:add_player(player, skip_check, skip_event) - local valid_player = type(player) == "userdata" and player or game.get_player(player) - -- Default role cant have players added or removed - if self.name == Roles.config.internal.default then return end - -- Check the player is valid, can be skipped but a name must be given - local player_name - if valid_player then - player_name = valid_player.name - elseif skip_check then - player_name = player - else - return false - end - -- Add the role name to the player's roles - local player_roles = Roles.config.players[player_name] - if player_roles then - for _, role_name in ipairs(player_roles) do - if role_name == self.name then return false end - end - - player_roles[#player_roles + 1] = self.name - else - Roles.config.players[player_name] = { self.name } - end - -- Emits event if required - if valid_player and not skip_event then - emit_player_roles_updated(valid_player, "assign", { self }) - end - return true -end - ---[[-- Removes a player from this role, players can have more than one role at a time, used internally see Roles.unassign -@tparam LuaPlayer player the player that will lose this role -@tparam boolean skip_check when true player will be taken as the player name (use when player has not yet joined) -@tparam boolean skip_event when true the event emit will be skipped, this is used internally with Roles.unassign -@treturn boolean true if the player was removed successfully - -@usage-- Unassign a player from this role -role:remove_player(game.player) - -]] -function Roles._prototype:remove_player(player, skip_check, skip_event) - local valid_player = type(player) == "userdata" and player or game.get_player(player) - -- Default role cant have players added or removed - if self.name == Roles.config.internal.default then return end - -- Check the player is valid, can be skipped but a name must be given - local player_name - if valid_player then - player_name = valid_player.name - elseif skip_check then - player_name = player - else - return false - end - -- Remove the role from the players roles - local player_roles = Roles.config.players[player_name] - local found = false - if player_roles then - for index, role_name in ipairs(player_roles) do - if role_name == self.name then - player_roles[index] = player_roles[#player_roles] - player_roles[#player_roles] = nil - found = true - break - end - end - - if #player_roles == 0 then - Roles.config.players[player_name] = nil - end - end - -- Emits event if required - if valid_player and not skip_event then - emit_player_roles_updated(valid_player, "unassign", { self }) - end - return found -end - ---[[-- Returns an array of all the players who have this role, can be filtered by online status -@tparam[opt=nil] boolean online when given will filter by this online state, nil will return all players -@treturn table all the players who have this role, indexed order is meaningless - -@usage-- Get all the players with this role -local players = role:get_players() - -@usage-- Get all online players with this role -local players = role:get_players(true) - -]] -function Roles._prototype:get_players(online) - local players = {} - -- Search all players to check if they have this role - for player_name, player_roles in pairs(Roles.config.players) do - for _, role_name in ipairs(player_roles) do - if role_name == self.name then - local player = game.players[player_name] - -- Filter by online state if required - if player and (online == nil or player.connected == online) then - players[#players + 1] = player - end - break - end - end - end - - return players -end - ---[[-- Will print a message to all players with this role -@tparam string message the message that will be printed to the players -@treturn number the number of players who received the message - -@usage-- Print a message to all players with this role -role:print('Hello, World!') - -]] -function Roles._prototype:print(message) - local players = self:get_players(true) - for _, player in ipairs(players) do - player.print(message) - end - - return #players -end - ---- Used internally to be the first trigger on an event change, would be messy to include this in 4 different places -local function role_update(event) - local player = game.players[event.player_index] - -- Updates flags given to the player - for flag, async_function in pairs(Roles.config.flags) do - local state = Roles.player_has_flag(player, flag) - async_function(player, state) - end - - -- Updates the players permission group - local highest = Roles.get_player_highest_role(player) - if highest.permission_group then - local permission_group = highest.permission_group --[[@as [boolean, string] ]] - if permission_group[1] then - local group = game.permissions.get_group(permission_group[2]) - if group then - Groups.add_to_permission_group_async(group, player) - end - else - Groups.set_player_group(player, highest.permission_group) - end - end -end - ---- Used internally to test if a player should be auto assigned a role -local function auto_assign(event) - local player = game.players[event.player_index] - local roles = Roles.config.players[player.name] or {} - - local lookup = {} - -- Create a lookup table for existing roles, and check for block auto assign - for _, role in ipairs(roles) do - if role.block_auto_assign then return end - lookup[role] = true - end - - local assigns, ctn = {}, 0 - -- Check roles with auto assign conditions and run the handler - for role, condition in pairs(Roles.config.auto_assign) do - if not lookup[role] then - local success, rtn = pcall(condition, player) - if not success then - log{ "expcore-roles.error-log-format-assign", role.name, rtn } - elseif rtn == true then - ctn = ctn + 1 - assigns[ctn] = role - end - end - end - - -- Assign new roles if any were passed - if ctn > 0 then Roles.assign_player(player, assigns) end -end - ---- When a player joined or has a role change then the update is triggered -Event.add(Roles.events.on_role_assigned, role_update) -Event.add(Roles.events.on_role_unassigned, role_update) -Event.add(defines.events.on_player_joined_game, role_update) - ---- Every 60 seconds and on join auto role assignment is checked -Event.add(defines.events.on_player_joined_game, auto_assign) -Event.on_nth_tick(3600, function() - for _, player in ipairs(game.connected_players) do - auto_assign{ player_index = player.index } - end -end) - --- Return Roles -return Roles diff --git a/exp_legacy/module/locale/en/expcore.cfg b/exp_legacy/module/locale/en/expcore.cfg index 0225b9f8..ed40d1ca 100644 --- a/exp_legacy/module/locale/en/expcore.cfg +++ b/exp_legacy/module/locale/en/expcore.cfg @@ -1,11 +1,3 @@ -[expcore-roles] -error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ -error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ -game-message-assign=__1__ has been assigned to __2__ by __3__ -game-message-unassign=__1__ has been unassigned from __2__ by __3__ -reject-role=Invalid Role Name. -reject-player-role=Player has a higher role. - [expcore-data] description-preference=Allows you to set/get your data saving preference. description-data=Writes all your player data to a file on your computer. diff --git a/exp_legacy/module/locale/zh-CN/expcore.cfg b/exp_legacy/module/locale/zh-CN/expcore.cfg index 5f4c5f12..01466073 100644 --- a/exp_legacy/module/locale/zh-CN/expcore.cfg +++ b/exp_legacy/module/locale/zh-CN/expcore.cfg @@ -1,11 +1,3 @@ -[expcore-roles] -error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ -error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ -game-message-assign=__1__ 已被 __3__ 指派到身分組 __2__ -game-message-unassign=__1__ 已被 __3__ 取消指派到身分組 __2__ -reject-role=無效的身分組。 -reject-player-role=用戶已有更高的身分組。 - [expcore-data] description-preference=允許寫入資料。 description-data=把用戶資料寫入電腦 diff --git a/exp_legacy/module/locale/zh-TW/expcore.cfg b/exp_legacy/module/locale/zh-TW/expcore.cfg index 5f4c5f12..01466073 100644 --- a/exp_legacy/module/locale/zh-TW/expcore.cfg +++ b/exp_legacy/module/locale/zh-TW/expcore.cfg @@ -1,11 +1,3 @@ -[expcore-roles] -error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ -error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ -game-message-assign=__1__ 已被 __3__ 指派到身分組 __2__ -game-message-unassign=__1__ 已被 __3__ 取消指派到身分組 __2__ -reject-role=無效的身分組。 -reject-player-role=用戶已有更高的身分組。 - [expcore-data] description-preference=允許寫入資料。 description-data=把用戶資料寫入電腦 diff --git a/exp_legacy/module/module.json b/exp_legacy/module/module.json index 2a2ec59e..bf21f097 100644 --- a/exp_legacy/module/module.json +++ b/exp_legacy/module/module.json @@ -8,6 +8,7 @@ "dependencies": { "clusterio": "*", "exp_util": "*", + "exp_roles": "*", "exp_gui": "*" } } diff --git a/exp_legacy/module/modules/control/jail.lua b/exp_legacy/module/modules/control/jail.lua index a60f7ab4..3409619b 100644 --- a/exp_legacy/module/modules/control/jail.lua +++ b/exp_legacy/module/modules/control/jail.lua @@ -7,25 +7,23 @@ -- import the module from the control modules local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail - -- This will move 'MrBiter' to the jail role and remove all other roles from them + -- This will give 'MrBiter' the jail role, which suppresses all of their other roles -- the player name and reason are only so they can be included in the event for user feedback Jail.jail_player('MrBiter', 'Cooldude2606', 'Likes biters too much') - -- This will give 'MrBiter' all his roles back and remove him from jail + -- This will remove the jail role from 'MrBiter', restoring their other roles -- again as above the player name is only used in the event for user feedback Jail.unjail_player('MrBiter', 'Cooldude2606') ]] -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local valid_player = function(p) return type(p) == "userdata" and p or game.get_player(p) end -local assign_roles = Roles.assign_player -local unassign_roles = Roles.unassign_player -local has_role = Roles.player_has_role -local get_roles = Roles.get_player_roles + +--- The role which is given to jailed players, it has a higher priority than every other role +local jail_role = "Jail" local Jail = { - old_roles = {}, events = { --- When a player is assigned to jail -- @event on_player_jailed @@ -64,10 +62,10 @@ end -- @tparam LuaPlayer player the player to check if they are in jail -- @treturn boolean whether the player is currently in jail function Jail.is_jailed(player) - return has_role(valid_player(player), "Jail") + return Roles.player_has_role(valid_player(player), jail_role) end ---- Moves a player to jail and removes all other roles +--- Moves a player to jail, which suppresses all of their other roles -- @tparam LuaPlayer player the player who will be jailed -- @tparam string by_player_name the name of the player who is doing the jailing -- @tparam[opt='Non given.'] string reason the reason that the player is being jailed @@ -79,8 +77,7 @@ function Jail.jail_player(player, by_player_name, reason) reason = reason or "Non given." - if has_role(player, "Jail") then return end - local roles = get_roles(player) + if Roles.player_has_role(player, jail_role) then return end player.walking_state = { walking = false, direction = player.walking_state.direction } player.riding_state = { acceleration = defines.riding.acceleration.nothing, direction = player.riding_state.direction } @@ -89,16 +86,14 @@ function Jail.jail_player(player, by_player_name, reason) player.picking_state = false player.repair_state = { repairing = false, position = player.repair_state.position } - unassign_roles(player, roles, by_player_name, nil, true) - assign_roles(player, "Jail", by_player_name, nil, true) - assign_roles(player, roles, by_player_name, nil, true) + Roles.assign_player(player, jail_role, by_player_name, true) event_emit(Jail.events.on_player_jailed, player, by_player_name, reason) return true end ---- Moves a player out of jail and restores all roles previously removed +--- Moves a player out of jail, which restores all of their other roles -- @tparam LuaPlayer player the player that will be unjailed -- @tparam string by_player_name the name of the player that is doing the unjail -- @treturn boolean whether the player was unjailed successfully @@ -107,9 +102,9 @@ function Jail.unjail_player(player, by_player_name) if not player then return end if not by_player_name then return end - if not has_role(player, "Jail") then return end + if not Roles.player_has_role(player, jail_role) then return end - unassign_roles(player, "Jail", by_player_name, nil, true) + Roles.unassign_player(player, jail_role, by_player_name, true) event_emit(Jail.events.on_player_unjailed, player, by_player_name) diff --git a/exp_legacy/module/modules/control/protection.lua b/exp_legacy/module/modules/control/protection.lua index 506d889d..b0c35a0b 100644 --- a/exp_legacy/module/modules/control/protection.lua +++ b/exp_legacy/module/modules/control/protection.lua @@ -33,11 +33,7 @@ for _, config_key in ipairs{ "always_protected_names", "always_protected_types", end end --- Require roles if a permission is assigned in the config -local Roles --- @type table -if config.ignore_permission then - Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -end +local Roles = require("modules/exp_roles") ----- Storage Variables ----- --- Variables stored in the global table @@ -159,7 +155,7 @@ Event.add(defines.events.on_pre_player_mined_item, function(event) -- Check if the player should be ignored if config.ignore_admins and player.admin then return end if entity.last_user == nil or entity.last_user.index == player.index then return end - if config.ignore_permission and Roles.player_allowed(player, config.ignore_permission) then return end + if config.ignore_permission and Roles.player_has_permission(player, config.ignore_permission) then return end -- Check if the entity is protected if EntityProtection.is_entity_protected(entity) diff --git a/exp_legacy/module/modules/data/greetings.lua b/exp_legacy/module/modules/data/greetings.lua index e8eade90..d4b159c2 100644 --- a/exp_legacy/module/modules/data/greetings.lua +++ b/exp_legacy/module/modules/data/greetings.lua @@ -8,7 +8,7 @@ local Commands = require("modules/exp_commands") local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data local CustomMessages = PlayerData.Settings:combine("JoinMessage") CustomMessages:set_metadata{ - permission = "command/join-message", + permission = "exp_scenario.command.set_join_message", } --- When a players data loads show their message diff --git a/exp_legacy/module/modules/data/quickbar.lua b/exp_legacy/module/modules/data/quickbar.lua index 52f8a4be..8550cae9 100644 --- a/exp_legacy/module/modules/data/quickbar.lua +++ b/exp_legacy/module/modules/data/quickbar.lua @@ -10,7 +10,7 @@ local config = require("modules.exp_legacy.config.preset_player_quickbar") --- @ local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data local PlayerFilters = PlayerData.Settings:combine("QuickbarFilters") PlayerFilters:set_metadata{ - permission = "command/save-quickbar", + permission = "exp_scenario.command.save_quickbar", stringify = function(value) if not value then return "No filters set" end local count = 0 diff --git a/exp_legacy/module/modules/data/tag.lua b/exp_legacy/module/modules/data/tag.lua index 89329ad0..e12e4229 100644 --- a/exp_legacy/module/modules/data/tag.lua +++ b/exp_legacy/module/modules/data/tag.lua @@ -4,17 +4,17 @@ ]] local Commands = require("modules/exp_commands") -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local Roles = require("modules/exp_roles") --- Stores the tag for a player local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data local PlayerTags = PlayerData.Settings:combine("Tag") local PlayerTagColors = PlayerData.Settings:combine("TagColor") PlayerTags:set_metadata{ - permission = "command/tag", + permission = "exp_scenario.command.tag", } PlayerTagColors:set_metadata{ - permission = "command/tag-color", + permission = "exp_scenario.command.tag_color", } local set_tag = function(player, tag, color) @@ -72,7 +72,7 @@ Commands.new("tag-clear", "Clears your tag. Or another player if you are admin." if other_player == player then -- No player given so removes your tag PlayerTags:remove(other_player) - elseif Roles.player_allowed(player, "command/clear-tag/always") then + elseif Roles.player_has_permission(player, "exp_scenario.command.tag_clear.always") then -- Player given and user is admin so clears that player's tag PlayerTags:remove(other_player) else diff --git a/exp_legacy/module/modules/gui/_role_updates.lua b/exp_legacy/module/modules/gui/_role_updates.lua deleted file mode 100644 index ac171b49..00000000 --- a/exp_legacy/module/modules/gui/_role_updates.lua +++ /dev/null @@ -1,7 +0,0 @@ -local Gui = require("modules/exp_gui") -local Roles = require("modules.exp_legacy.expcore.roles") -local Event = require("modules/exp_legacy/utils/event") - ---- @diagnostic disable: access-invisible -Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency) -Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency) diff --git a/exp_legacy/module/modules/gui/vlayer.lua b/exp_legacy/module/modules/gui/vlayer.lua index 727f9b9d..5cd33356 100644 --- a/exp_legacy/module/modules/gui/vlayer.lua +++ b/exp_legacy/module/modules/gui/vlayer.lua @@ -5,7 +5,7 @@ ]] local Gui = require("modules/exp_gui") -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local Roles = require("modules/exp_roles") local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local format_number = require("util").format_number --- @dep util local config = require("modules.exp_legacy.config.vlayer") --- @dep config.vlayer @@ -457,7 +457,7 @@ local vlayer_control_set = Gui.define("vlayer_control_set") vlayer_gui_control_see(disp) local b = vlayer_gui_control_build(disp) local r = vlayer_gui_control_remove(disp) - local v = Roles.player_allowed(player, "gui/vlayer-edit") + local v = Roles.player_has_permission(player, "exp_scenario.gui.vlayer_edit") b.visible = v r.visible = v @@ -484,22 +484,21 @@ Gui.toolbar.create_button{ sprite = "entity/solar-panel", tooltip = { "vlayer.main-tooltip" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/vlayer") + return Roles.player_has_permission(player, "exp_scenario.gui.vlayer") end } --- Update the visibly of the buttons based on a players roles local function role_update_event(event) local player = game.players[event.player_index] - local visible = Roles.player_allowed(player, "gui/vlayer-edit") + local visible = Roles.player_has_permission(player, "exp_scenario.gui.vlayer_edit") local container = Gui.get_left_element(vlayer_container, player) local disp = container.frame["vlayer_st_2"].disp.table disp[vlayer_gui_control_build.name].visible = visible disp[vlayer_gui_control_remove.name].visible = visible end -Event.add(Roles.events.on_role_assigned, role_update_event) -Event.add(Roles.events.on_role_unassigned, role_update_event) +Event.add(Roles.events.on_player_roles_changed, role_update_event) Event.on_nth_tick(config.update_tick_gui, function(_) local stats = vlayer.get_statistics() diff --git a/exp_legacy/module/modules/gui/warp-list.lua b/exp_legacy/module/modules/gui/warp-list.lua index 15359dbc..5c456558 100644 --- a/exp_legacy/module/modules/gui/warp-list.lua +++ b/exp_legacy/module/modules/gui/warp-list.lua @@ -9,7 +9,7 @@ local Gui = require("modules/exp_gui") local Datastore = require("modules.exp_legacy.expcore.datastore") --- @dep expcore.datastore local Storage = require("modules/exp_util/storage") local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local Roles = require("modules/exp_roles") local Colors = require("modules/exp_util/include/color") local config = require("modules.exp_legacy.config.gui.warps") --- @dep config.gui.warps local Warps = require("modules.exp_legacy.modules.control.warps") --- @dep modules.control.warps @@ -68,8 +68,8 @@ local function check_player_permissions(player, action, warp) return true elseif action_config == "admin" then return player.admin - elseif action_config == "expcore.roles" then - return Roles.player_allowed(player, config["expcore_roles_" .. action]) + elseif action_config == "exp_roles" then + return Roles.player_has_permission(player, config["exp_roles_" .. action]) end -- Return false as all other conditions have not been met @@ -708,7 +708,7 @@ Gui.toolbar.create_button{ sprite = config.default_icon.type .. "/" .. config.default_icon.name, tooltip = { "warp-list.main-tooltip" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/warp-list") + return Roles.player_has_permission(player, "exp_scenario.gui.warp_list") end }:on_click(function(def, player, element) -- Set gui keep open state for player that clicked the button: true if visible, false if invisible @@ -885,8 +885,7 @@ local function role_update_event(event) add_new_warp_element.visible = allow_add_warp end -Event.add(Roles.events.on_role_assigned, role_update_event) -Event.add(Roles.events.on_role_unassigned, role_update_event) +Event.add(Roles.events.on_player_roles_changed, role_update_event) --- When a chart tag is removed or edited make sure it is not one that belongs to a warp local function maintain_tag(event) diff --git a/exp_scenario/module/commands/_authorities.lua b/exp_scenario/module/commands/_authorities.lua index dc6f9383..41e41cf9 100644 --- a/exp_scenario/module/commands/_authorities.lua +++ b/exp_scenario/module/commands/_authorities.lua @@ -1,26 +1,28 @@ --[[-- Command Authorities - Roles -Adds a permission authority for exp roles +Adds a permission authority which checks the clusterio permission for a command ]] local Commands = require("modules/exp_commands") local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised -local Roles = require("modules/exp_legacy/expcore/roles") -local player_allowed = Roles.player_allowed +local Roles = require("modules/exp_roles") +local player_has_permission = Roles.player_has_permission local authorities = {} ---- If a command has the flag "character_only" then the command can only be used outside of remote view +--- Every command requires the permission `exp_scenario.command.`, with +--- hyphens replaced by underscores, see permissions.ts for their definitions authorities.exp_permission = add(function(player, command) - if not player_allowed(player, command.flags.exp_permission or ("command/" .. command.name)) then + local permission = "exp_scenario.command." .. command.name:gsub("%-", "_") + if not player_has_permission(player, permission) then return deny{ "exp-commands-authorities_role.deny" } else return allow() end end) -Roles.define_flag_trigger("is_system", function(player, state) +Roles.define_permission_trigger("exp_scenario.player.system_commands", function(player, state) if state then Commands.unlock_system_commands(player.name) else diff --git a/exp_scenario/module/commands/_rcon.lua b/exp_scenario/module/commands/_rcon.lua index 7ce7ed0d..ef3febbc 100644 --- a/exp_scenario/module/commands/_rcon.lua +++ b/exp_scenario/module/commands/_rcon.lua @@ -8,6 +8,6 @@ local add_static, add_dynamic = Commands.add_rcon_static, Commands.add_rcon_dyna add_static("Gui", require("modules/exp_gui")) add_static("Group", require("modules.exp_legacy.expcore.permission_groups")) -add_static("Roles", require("modules.exp_legacy.expcore.roles")) +add_static("Roles", require("modules/exp_roles")) add_static("Datastore", require("modules.exp_legacy.expcore.datastore")) add_static("External", require("modules.exp_legacy.expcore.external")) diff --git a/exp_scenario/module/commands/_types.lua b/exp_scenario/module/commands/_types.lua index f23ff943..4c18de0f 100644 --- a/exp_scenario/module/commands/_types.lua +++ b/exp_scenario/module/commands/_types.lua @@ -1,4 +1,3 @@ - --[[-- Command Types - Roles The data types that are used with exp_roles A lower role index indicates it is more privileged @@ -11,28 +10,42 @@ Adds parsers for: lower_role_player_alive ]] +local ExpUtil = require("modules/exp_util") +local auto_complete = ExpUtil.auto_complete + local Commands = require("modules/exp_commands") local add, parse = Commands.add_data_type, Commands.parse_input local valid, invalid = Commands.status.success, Commands.status.invalid_input -local Roles = require("modules.exp_legacy.expcore.roles") -local highest_role = Roles.get_player_highest_role +local Roles = require("modules/exp_roles") +local player_outranks = Roles.player_outranks local types = {} --- @class (partial) Commands.types ---- A role defined by exp roles -types.role = add("role", Commands.types.key_of(Roles.config.roles)) +--- A role known to exp roles, matched on its name +types.role = + add("role", function(input) + local names = {} + for index, role in ipairs(Roles.get_roles()) do + names[index] = role.name + end + + local name = auto_complete(names, input) + if name == nil then + return invalid{ "exp-commands-parse.string-options", table.concat(names, ", ") } + else + return valid(Roles.get_role(name)) + end + end) --- A role which is lower than the players highest role types.lower_role = add("lower_role", function(input, player) local success, status, result = parse(input, player, types.role) if not success then return status, result end - --- @cast result any TODO role is not a defined type + --- @cast result ExpRoles.Role - local player_highest = highest_role(player) - local is_root = Roles.config.internal.root == player_highest.name - if not is_root and player_highest.index >= result.index then + if not Roles.player_outranks_role(player, result) then return invalid{ "exp-commands-parse_role.lower-role" } else return valid(result) @@ -46,10 +59,7 @@ types.lower_role_player = if not success then return status, result end --- @cast result LuaPlayer - local other_highest = highest_role(result) - local player_highest = highest_role(player) - local is_root = Roles.config.internal.root == player_highest.name - if not is_root and player_highest.index >= other_highest.index then + if not player_outranks(player, result) then return invalid{ "exp-commands-parse_role.lower-role-player" } else return valid(result) @@ -63,10 +73,7 @@ types.lower_role_player_online = if not success then return status, result end --- @cast result LuaPlayer - local other_highest = highest_role(result) - local player_highest = highest_role(player) - local is_root = Roles.config.internal.root == player_highest.name - if not is_root and player_highest.index >= other_highest.index then + if not player_outranks(player, result) then return invalid{ "exp-commands-parse_role.lower-role-player" } else return valid(result) @@ -80,10 +87,7 @@ types.lower_role_player_alive = if not success then return status, result end --- @cast result LuaPlayer - local other_highest = highest_role(result) - local player_highest = highest_role(player) - local is_root = Roles.config.internal.root == player_highest.name - if not is_root and player_highest.index >= other_highest.index then + if not player_outranks(player, result) then return invalid{ "exp-commands-parse_role.lower-role-player" } else return valid(result) diff --git a/exp_scenario/module/commands/kill.lua b/exp_scenario/module/commands/kill.lua index a71528ed..9d655ff9 100644 --- a/exp_scenario/module/commands/kill.lua +++ b/exp_scenario/module/commands/kill.lua @@ -4,8 +4,8 @@ Adds a command that allows players to kill themselves and others local Commands = require("modules/exp_commands") -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local highest_role = Roles.get_player_highest_role +local Roles = require("modules/exp_roles") +local player_outranks = Roles.player_outranks --- Kills yourself or another player. Commands.new("kill", { "exp-commands_kill.description" }) @@ -20,7 +20,7 @@ Commands.new("kill", { "exp-commands_kill.description" }) if other_player == nil then -- Can only be nil if the target is the player and they are already dead return Commands.status.error{ "exp-commands_kill.already-dead" } - elseif (other_player == player) or (highest_role(player).index < highest_role(other_player).index) then + elseif other_player == player or player_outranks(player, other_player) then -- You can always kill yourself or can kill lower role players if script.active_mods["space-age"] then other_player.surface.create_entity{ name = "lightning", position = { other_player.position.x, other_player.position.y - 16 }, target = other_player.character } diff --git a/exp_scenario/module/commands/protected_entities.lua b/exp_scenario/module/commands/protected_entities.lua index 7f906413..9f810634 100644 --- a/exp_scenario/module/commands/protected_entities.lua +++ b/exp_scenario/module/commands/protected_entities.lua @@ -11,7 +11,7 @@ local expand_area = AABB.expand local Commands = require("modules/exp_commands") local format_player_name = Commands.format_player_name_locale -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local Roles = require("modules/exp_roles") local EntityProtection = require("modules.exp_legacy.modules.control.protection") --- @dep modules.control.protection local format_string = string.format diff --git a/exp_scenario/module/commands/reports.lua b/exp_scenario/module/commands/reports.lua index aab4351c..166d4b64 100644 --- a/exp_scenario/module/commands/reports.lua +++ b/exp_scenario/module/commands/reports.lua @@ -6,8 +6,8 @@ local Commands = require("modules/exp_commands") local format_player_name = Commands.format_player_name_locale local parse_input = Commands.parse_input -local Roles = require("modules.exp_legacy.expcore.roles") -local player_has_flag = Roles.player_has_flag +local Roles = require("modules/exp_roles") +local player_has_permission = Roles.player_has_permission local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports @@ -20,7 +20,7 @@ local function reportable_player(input, player) if not success then return status, result end --- @cast result LuaPlayer - if player_has_flag(input, "report-immune") then + if player_has_permission(input, "exp_scenario.bypass.reports") then return Commands.status.invalid_input{ "exp-commands_reports.player-immune" } elseif player == input then return Commands.status.invalid_input{ "exp-commands_reports.self-report" } diff --git a/exp_scenario/module/commands/roles.lua b/exp_scenario/module/commands/roles.lua index b8a510ad..b8231ebd 100644 --- a/exp_scenario/module/commands/roles.lua +++ b/exp_scenario/module/commands/roles.lua @@ -6,8 +6,8 @@ local Commands = require("modules/exp_commands") local format_player_name = Commands.format_player_name_locale local format_text = Commands.format_rich_text_color_locale -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local get_roles_ordered = Roles.get_roles_ordered +local Roles = require("modules/exp_roles") +local get_roles = Roles.get_roles local get_player_roles = Roles.get_player_roles --- Assigns a role to a player @@ -18,7 +18,7 @@ Commands.new("assign-role", { "exp-commands_roles.description-assign" }) :add_flags{ "admin_only" } :register(function(player, other_player, role) --- @cast other_player LuaPlayer - --- @cast role any -- TODO + --- @cast role ExpRoles.Role Roles.assign_player(other_player, role, player.name) end) @@ -30,7 +30,7 @@ Commands.new("unassign-role", { "exp-commands_roles.description-unassign" }) :add_flags{ "admin_only" } :register(function(player, other_player, role) --- @cast other_player LuaPlayer - --- @cast role any -- TODO + --- @cast role ExpRoles.Role Roles.unassign_player(other_player, role, player.name) end) @@ -40,7 +40,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" }) :add_aliases{ "roles" } :register(function(player, other_player) --- @cast other_player LuaPlayer? - local roles = get_roles_ordered() + local roles = get_roles() local roles_formatted = { "" } --- @type LocalisedString local response = { "exp-commands_roles.list-roles", roles_formatted } --[[@as LocalisedString]] if other_player then @@ -50,7 +50,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" }) end for index, role in ipairs(roles) do - local role_name = format_text(role.name, role.custom_color or Commands.color.white) + local role_name = format_text(role.name, role.color or Commands.color.white) roles_formatted[index + 1] = { "exp-commands_roles.list-element", role_name } end diff --git a/exp_scenario/module/commands/teleport.lua b/exp_scenario/module/commands/teleport.lua index a7892047..c4acf1f7 100644 --- a/exp_scenario/module/commands/teleport.lua +++ b/exp_scenario/module/commands/teleport.lua @@ -7,8 +7,8 @@ local teleport_player = ExpUtil.teleport_player local Commands = require("modules/exp_commands") -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local player_allowed = Roles.player_allowed +local Roles = require("modules/exp_roles") +local player_has_permission = Roles.player_has_permission --- @class ExpCommands_Teleport.commands local commands = {} @@ -85,7 +85,7 @@ commands.spawn = Commands.new("spawn", { "exp-commands_teleport.description-spaw if not teleport_player(player, game.surfaces.nauvis, { 0, 0 }, "dismount") then return Commands.status.error{ "exp-commands_teleport.unavailable" } end - elseif player_allowed(player, "command/spawn/always") then + elseif player_has_permission(player, "exp_scenario.command.spawn.always") then if not teleport_player(other_player, game.surfaces.nauvis, { 0, 0 }, "dismount") then return Commands.status.error{ "exp-commands_teleport.unavailable" } end diff --git a/exp_scenario/module/control.lua b/exp_scenario/module/control.lua index 3b00dcde..2e04e552 100644 --- a/exp_scenario/module/control.lua +++ b/exp_scenario/module/control.lua @@ -63,6 +63,7 @@ add(require("modules/exp_scenario/control/pollution_grading")) add(require("modules/exp_scenario/control/protection_jail")) add(require("modules/exp_scenario/control/report_jail")) add(require("modules/exp_scenario/control/research")) +add(require("modules/exp_scenario/control/roles")) add(require("modules/exp_scenario/control/spawn_area")) add(require("modules/exp_scenario/control/station_auto_name")) diff --git a/exp_scenario/module/control/bonus.lua b/exp_scenario/module/control/bonus.lua index f8b532cb..8d0a192d 100644 --- a/exp_scenario/module/control/bonus.lua +++ b/exp_scenario/module/control/bonus.lua @@ -4,7 +4,7 @@ Various bonus related event handlers TODO Refactor this fully, this is temp to get it out of the player bonus gui file ]] -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local config = require("modules/exp_legacy/config/bonus") --- @param event EventData.on_force_created @@ -26,7 +26,7 @@ end --- @param event EventData.on_player_died local function fast_respawn(event) local player = assert(game.get_player(event.player_index)) - if Roles.player_has_flag(player, "instant-respawn") then + if Roles.player_has_permission(player, "exp_scenario.player.instant_respawn") then player.ticks_to_respawn = 120 end end diff --git a/exp_scenario/module/control/chat_auto_reply.lua b/exp_scenario/module/control/chat_auto_reply.lua index 8d5ccc8f..4e60ca40 100644 --- a/exp_scenario/module/control/chat_auto_reply.lua +++ b/exp_scenario/module/control/chat_auto_reply.lua @@ -2,7 +2,7 @@ Adds auto replies to chat messages, as well as chat commands ]] -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local config = require("modules.exp_legacy.config.chat_reply") local prefix = config.command_prefix local prefix_len = string.len(prefix) @@ -20,7 +20,7 @@ local function on_console_chat(event) -- Check if the player can chat commands local commands_allowed = true if config.command_admin_only and not player.admin then commands_allowed = false end - if config.command_permission and not Roles.player_allowed(player, config.command_permission) then commands_allowed = false end + if config.command_permission and not Roles.player_has_permission(player, config.command_permission) then commands_allowed = false end -- Check if a key word appears in the message for key_word, reply in pairs(config.messages) do diff --git a/exp_scenario/module/control/deconstruction_log.lua b/exp_scenario/module/control/deconstruction_log.lua index b6d2b05d..ddfeb979 100644 --- a/exp_scenario/module/control/deconstruction_log.lua +++ b/exp_scenario/module/control/deconstruction_log.lua @@ -3,7 +3,7 @@ Log certain actions into a file when events are triggered ]] local ExpUtil = require("modules/exp_util") -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local config = require("modules.exp_legacy.config.deconlog") local seconds_time_format = ExpUtil.format_time_factory{ format = "short", hours = true, minutes = true, seconds = true } @@ -79,7 +79,7 @@ end local function get_log_player(event) local player = assert(game.get_player(event.player_index)) - if Roles.player_has_flag(player, "deconlog-bypass") then + if Roles.player_has_permission(player, "exp_scenario.bypass.deconstruction_log") then return nil end diff --git a/exp_scenario/module/control/fast_deconstruction.lua b/exp_scenario/module/control/fast_deconstruction.lua index acd83069..34544496 100644 --- a/exp_scenario/module/control/fast_deconstruction.lua +++ b/exp_scenario/module/control/fast_deconstruction.lua @@ -4,7 +4,7 @@ Makes trees which are marked for decon "decay" quickly to allow faster building local Gui = require("modules/exp_gui") local Async = require("modules/exp_util/async") -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local PlayerData = require("modules.exp_legacy.expcore.player_data") local HasEnabledDecon = PlayerData.Settings:combine("HasEnabledDecon") @@ -57,9 +57,9 @@ local remove_trees_async = --- @param player LuaPlayer --- @return "fast" | "allow" | "disallow" local function get_permission(player) - if Roles.player_allowed(player, "fast-tree-decon") then + if Roles.player_has_permission(player, "exp_scenario.decon.fast_trees") then return HasEnabledDecon:get(player) and "fast" or "allow" - elseif Roles.player_allowed(player, "standard-decon") then + elseif Roles.player_has_permission(player, "exp_scenario.decon.standard") then return "allow" else return "disallow" @@ -101,7 +101,7 @@ Gui.toolbar.create_button{ tooltip = { "exp_fast-decon.tooltip-main" }, auto_toggle = true, visible = function(player, _) - return Roles.player_allowed(player, "fast-tree-decon") + return Roles.player_has_permission(player, "exp_scenario.decon.fast_trees") end }:on_click(function(def, player, element) local state = Gui.toolbar.get_button_toggled_state(def, player) diff --git a/exp_scenario/module/control/nuke_protection.lua b/exp_scenario/module/control/nuke_protection.lua index cfff046b..c8798388 100644 --- a/exp_scenario/module/control/nuke_protection.lua +++ b/exp_scenario/module/control/nuke_protection.lua @@ -3,7 +3,7 @@ Disable new players from having certain items in their inventory, most commonly ]] local ExpUtil = require("modules/exp_util") -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local config = require("modules.exp_legacy.config.nukeprotect") --- Check all items in the given inventory @@ -12,7 +12,7 @@ local config = require("modules.exp_legacy.config.nukeprotect") --- @param banned_items string[] local function check_items(player, type, banned_items) -- If the player has perms to be ignored, then they should be - if config.ignore_permission and Roles.player_allowed(player, config.ignore_permission) then return end + if config.ignore_permission and Roles.player_has_permission(player, config.ignore_permission) then return end if config.ignore_admins and player.admin then return end local items = {} --- @type LuaItemStack[] diff --git a/exp_scenario/module/control/roles.lua b/exp_scenario/module/control/roles.lua new file mode 100644 index 00000000..1c4ecf66 --- /dev/null +++ b/exp_scenario/module/control/roles.lua @@ -0,0 +1,21 @@ +--[[-- Control - Roles +Applies the in game effects of the player permissions defined by the scenario +]] + +local Gui = require("modules/exp_gui") +local Roles = require("modules/exp_roles") + +Roles.define_permission_trigger("exp_scenario.player.admin", function(player, state) + player.admin = state +end) + +Roles.define_permission_trigger("exp_scenario.player.spectator", function(player, state) + player.spectator = state +end) + +return { + events = { + --- @diagnostic disable-next-line: access-invisible + [Roles.events.on_player_roles_changed] = Gui._ensure_consistency, + } +} diff --git a/exp_scenario/module/gui/autofill.lua b/exp_scenario/module/gui/autofill.lua index 3dc16175..8c663af4 100644 --- a/exp_scenario/module/gui/autofill.lua +++ b/exp_scenario/module/gui/autofill.lua @@ -3,7 +3,7 @@ Adds a config menu for setting autofill of placed entities ]] local Gui = require("modules/exp_gui") -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local config = require("modules.exp_legacy.config.gui.autofill") local FlyingText = require("modules/exp_util/flying_text") @@ -330,7 +330,7 @@ Gui.toolbar.create_button{ sprite = config.icon, tooltip = { "exp-gui_autofill.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/autofill") + return Roles.player_has_permission(player, "exp_scenario.gui.autofill") end } diff --git a/exp_scenario/module/gui/module_inserter.lua b/exp_scenario/module/gui/module_inserter.lua index 33011cec..ed320137 100644 --- a/exp_scenario/module/gui/module_inserter.lua +++ b/exp_scenario/module/gui/module_inserter.lua @@ -4,7 +4,7 @@ Adds a Gui which creates an selection planner to insert modules into buildings local Gui = require("modules/exp_gui") local AABB = require("modules/exp_util/aabb") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local Selection = require("modules/exp_util/selection") local SelectArea = Selection.connect("ModuleArea") @@ -259,7 +259,7 @@ Gui.toolbar.create_button{ sprite = "item/productivity-module-3", tooltip = { "exp-gui_module-inserter.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/module") + return Roles.player_has_permission(player, "exp_scenario.gui.module") end } diff --git a/exp_scenario/module/gui/player_bonus.lua b/exp_scenario/module/gui/player_bonus.lua index 054c3088..10cdc212 100644 --- a/exp_scenario/module/gui/player_bonus.lua +++ b/exp_scenario/module/gui/player_bonus.lua @@ -3,7 +3,7 @@ Adds a gui that allows players to apply various bonuses ]] local Gui = require("modules/exp_gui") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local config = require("modules/exp_legacy/config/bonus") local vlayer = require("modules/exp_legacy/modules/control/vlayer") local format_number = require("util").format_number @@ -68,7 +68,8 @@ do local _points_limit = {} --- @type table --- @param player LuaPlayer --- @return number function Elements.bonus_used._calculate_points_limit(player) - local role_diff = Roles.get_role_by_name(config.points.role_name).index - Roles.get_player_highest_role(player).index + local role = assert(Roles.get_role(config.points.role_name), "Bonus points role does not exist") + local role_diff = role.index - Roles.get_player_highest_role(player).index local points_limit = math.floor(config.points.base * (1 + config.points.increase_percentage_per_role_level * role_diff)) _points_limit[player.index] = points_limit return points_limit @@ -458,19 +459,19 @@ Gui.toolbar.create_button{ sprite = "item/exoskeleton-equipment", tooltip = { "exp-gui_player-bonus.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/bonus") + return Roles.player_has_permission(player, "exp_scenario.gui.bonus") end } --- Recalculate and apply the bonus for a player local function recalculate_bonus(event) local player = Gui.get_player(event) - if event.name == Roles.events.on_role_assigned or event.name == Roles.events.on_role_unassigned then + if event.name == Roles.events.on_player_roles_changed then -- If the player's roles changed then we will need to recalculate their limit Elements.bonus_used._clear_points_limit_cache(player) local bonus_cost = Elements.container.calculate_cost(player) local within_limit = Elements.bonus_used.refresh_player(player, bonus_cost) - if not within_limit or not Roles.player_allowed(player, "gui/bonus") then + if not within_limit or not Roles.player_has_permission(player, "exp_scenario.gui.bonus") then Elements.container.clear_player_bonus(player) return end @@ -512,7 +513,7 @@ end --- Apply the periodic bonus to all players local function apply_periodic_bonus_online() for _, player in pairs(game.connected_players) do - if player.character and Roles.player_allowed(player, "gui/bonus") then + if player.character and Roles.player_has_permission(player, "exp_scenario.gui.bonus") then apply_personal_battery_recharge(player) end end @@ -524,8 +525,7 @@ return { elements = Elements, events = { [e.on_player_respawned] = recalculate_bonus, - [Roles.events.on_role_assigned] = recalculate_bonus, - [Roles.events.on_role_unassigned] = recalculate_bonus, + [Roles.events.on_player_roles_changed] = recalculate_bonus, }, on_nth_tick = { [config.periodic_bonus_rate] = apply_periodic_bonus_online, diff --git a/exp_scenario/module/gui/player_list.lua b/exp_scenario/module/gui/player_list.lua index 905b5be2..42258e30 100644 --- a/exp_scenario/module/gui/player_list.lua +++ b/exp_scenario/module/gui/player_list.lua @@ -4,7 +4,7 @@ Adds a player list to show names and play time; also includes action buttons whi local ExpUtil = require("modules/exp_util") local Gui = require("modules/exp_gui") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local config = require("modules/exp_legacy/config/gui/player_list_actions") --- @class ExpGui_PlayerList.elements @@ -203,7 +203,8 @@ function Elements.player_table.calculate_row_data() -- Flatten the roles into a single ordered list local count = 0 local row_data = {} - for _, role_name in pairs(Roles.config.order) do + for _, role in ipairs(Roles.get_roles()) do + local role_name = role.name if players[role_name] then for _, player in pairs(players[role_name]) do count = count + 1 @@ -360,7 +361,7 @@ function Elements.action_bar.refresh(action_bar, player, selected_player) if buttons.auth and not buttons.auth(player, selected_player) then flow.visible = false else - flow.visible = Roles.player_allowed(player, action_name) + flow.visible = Roles.player_has_permission(player, action_name) end end end @@ -492,7 +493,7 @@ Gui.toolbar.create_button{ sprite = "entity/character", tooltip = { "exp-gui_player-list.main-tooltip" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/player-list") + return Roles.player_has_permission(player, "exp_scenario.gui.player_list") end } @@ -534,8 +535,7 @@ return { events = { [e.on_player_joined_game] = redraw_player_list, [e.on_player_left_game] = on_player_left_game, - [Roles.events.on_role_assigned] = redraw_player_list, - [Roles.events.on_role_unassigned] = redraw_player_list, + [Roles.events.on_player_roles_changed] = redraw_player_list, }, on_nth_tick = { [1800] = refresh_player_times, diff --git a/exp_scenario/module/gui/player_stats.lua b/exp_scenario/module/gui/player_stats.lua index b0a57df3..5740aa2a 100644 --- a/exp_scenario/module/gui/player_stats.lua +++ b/exp_scenario/module/gui/player_stats.lua @@ -5,7 +5,7 @@ Displays the player data for a player local ExpUtil = require("modules/exp_util") local Gui = require("modules/exp_gui") local ElementsExtra = require("modules/exp_scenario/gui/elements") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") require("modules/exp_legacy/modules/data/statistics") local PlayerData = require("modules/exp_legacy/expcore/player_data") @@ -214,7 +214,7 @@ Gui.toolbar.create_button{ tooltip = { "exp-gui_player-stats.tooltip-main" }, left_element = Elements.container, visible = function(player, element) - return Roles.player_allowed(player, "gui/playerdata") + return Roles.player_has_permission(player, "exp_scenario.gui.playerdata") end } diff --git a/exp_scenario/module/gui/production_stats.lua b/exp_scenario/module/gui/production_stats.lua index 94b49562..e8728055 100644 --- a/exp_scenario/module/gui/production_stats.lua +++ b/exp_scenario/module/gui/production_stats.lua @@ -3,7 +3,7 @@ Adds a Gui for displaying item production stats ]] local Gui = require("modules/exp_gui") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") --- @class ExpGui_ProductionStats.elements local Elements = {} @@ -250,7 +250,7 @@ Gui.toolbar.create_button{ sprite = "entity/assembling-machine-3", tooltip = { "exp-gui_production-stats.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/production") + return Roles.player_has_permission(player, "exp_scenario.gui.production") end } diff --git a/exp_scenario/module/gui/quick_actions.lua b/exp_scenario/module/gui/quick_actions.lua index 92d358aa..2d9c7cdb 100644 --- a/exp_scenario/module/gui/quick_actions.lua +++ b/exp_scenario/module/gui/quick_actions.lua @@ -4,7 +4,7 @@ Adds a few buttons for common actions local Gui = require("modules/exp_gui") local Commands = require("modules/exp_commands") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local addon_artillery = require("modules/exp_scenario/commands/artillery") local addon_trains = require("modules/exp_scenario/commands/trains") @@ -116,7 +116,7 @@ Gui.toolbar.create_button{ sprite = "item/repair-pack", tooltip = { "exp-gui_quick-actions.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/tool") + return Roles.player_has_permission(player, "exp_scenario.gui.tool") end } @@ -129,7 +129,6 @@ end return { elements = Elements, events = { - [Roles.events.on_role_assigned] = on_role_changed, - [Roles.events.on_role_unassigned] = on_role_changed, + [Roles.events.on_player_roles_changed] = on_role_changed, } } diff --git a/exp_scenario/module/gui/readme.lua b/exp_scenario/module/gui/readme.lua index 5a7749b6..4a3ebc05 100644 --- a/exp_scenario/module/gui/readme.lua +++ b/exp_scenario/module/gui/readme.lua @@ -4,7 +4,7 @@ Adds a main gui that contains important information about the server. local ExpUtil = require("modules/exp_util") local Gui = require("modules/exp_gui") -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local Commands = require("modules/exp_commands") local PlayerData = require("modules.exp_legacy.expcore.player_data") local External = require("modules.exp_legacy.expcore.external") @@ -392,14 +392,16 @@ define_tab( local done = {} - -- Fill groups from configured roles - for player_name, player_roles in pairs(Roles.config.players) do - for _, group in ipairs(groups) do - for _, role_name in ipairs(group.roles) do - if table.contains(player_roles, role_name) then + -- Fill groups from the players who hold the roles, a player can be in more than one group + for _, group in ipairs(groups) do + local seen = {} + for _, role_name in ipairs(group.roles) do + local role = Roles.get_role(role_name) + for _, player_name in ipairs(role and role:get_player_names() or {}) do + if not seen[player_name] then + seen[player_name] = true done[player_name] = true group.players[#group.players + 1] = player_name - break end end end @@ -463,7 +465,7 @@ local function render_data_category(opts) for name, child in pairs(opts.children) do local metadata = child.metadata - if not metadata.permission or Roles.player_allowed(opts.player, metadata.permission) then + if not metadata.permission or Roles.player_has_permission(opts.player, metadata.permission) then local value = child:get(opts.player_name) if value ~= nil or metadata.show_always then @@ -663,7 +665,7 @@ Elements.toggle_button = Gui.toolbar.create_button{ sprite = "virtual-signal/signal-info", tooltip = { "exp-gui_readme.main-tooltip" }, visible = function(player) - return Roles.player_allowed(player, "gui/readme") + return Roles.player_has_permission(player, "exp_scenario.gui.readme") end, } :on_click(function(_, player) diff --git a/exp_scenario/module/gui/research_milestones.lua b/exp_scenario/module/gui/research_milestones.lua index 4652edcd..390867c8 100644 --- a/exp_scenario/module/gui/research_milestones.lua +++ b/exp_scenario/module/gui/research_milestones.lua @@ -4,7 +4,7 @@ Adds a gui for tracking research milestones local ExpUtil = require("modules/exp_util") local Gui = require("modules/exp_gui") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local config = require("modules/exp_legacy/config/research") local table_to_json = helpers.table_to_json @@ -339,7 +339,7 @@ Gui.toolbar.create_button{ sprite = "item/space-science-pack", tooltip = { "exp-gui_research-milestones.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/research") + return Roles.player_has_permission(player, "exp_scenario.gui.research") end } diff --git a/exp_scenario/module/gui/rocket_info.lua b/exp_scenario/module/gui/rocket_info.lua index d7999db3..e0b9074a 100644 --- a/exp_scenario/module/gui/rocket_info.lua +++ b/exp_scenario/module/gui/rocket_info.lua @@ -4,7 +4,7 @@ Adds a rocket information gui which shows general stats, milestones and build pr local ExpUtil = require("modules/exp_util") local Gui = require("modules/exp_gui") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local config = require("modules/exp_legacy/config/gui/rockets") --- @class ExpGui_RocketInfo.elements @@ -651,7 +651,7 @@ Gui.toolbar.create_button{ sprite = "item/rocket-silo", tooltip = { "exp-gui_rocket-info.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/rocket-info") + return Roles.player_has_permission(player, "exp_scenario.gui.rocket_info") end } diff --git a/exp_scenario/module/gui/science_production.lua b/exp_scenario/module/gui/science_production.lua index ad7772af..c2ef7273 100644 --- a/exp_scenario/module/gui/science_production.lua +++ b/exp_scenario/module/gui/science_production.lua @@ -5,7 +5,7 @@ Adds a science info gui that shows production usage and net for the different sc local ExpUtil = require("modules/exp_util") local Gui = require("modules/exp_gui") local Colors = require("modules/exp_util/include/color") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") local config = require("modules/exp_legacy/config/gui/science") local _format_number = require("util").format_number @@ -571,7 +571,7 @@ Gui.toolbar.create_button{ sprite = "entity/lab", tooltip = { "exp-gui_science-production.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/science-info") + return Roles.player_has_permission(player, "exp_scenario.gui.science_info") end } diff --git a/exp_scenario/module/gui/surveillance.lua b/exp_scenario/module/gui/surveillance.lua index 0fd65924..e9910723 100644 --- a/exp_scenario/module/gui/surveillance.lua +++ b/exp_scenario/module/gui/surveillance.lua @@ -4,7 +4,7 @@ Adds cameras which can be used to view players and locations local Gui = require("modules/exp_gui") local ElementsExtra = require("modules/exp_scenario/gui/elements") -local Roles = require("modules/exp_legacy/expcore/roles") +local Roles = require("modules/exp_roles") --- @class ExpGui_Surveillance.elements local Elements = {} @@ -234,7 +234,7 @@ Gui.toolbar.create_button{ sprite = "entity/radar", tooltip = { "exp-gui_surveillance.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/surveillance") + return Roles.player_has_permission(player, "exp_scenario.gui.surveillance") end }:on_click(function(def, player, element, event) Elements.container(player.gui.screen) diff --git a/exp_scenario/module/gui/task_list.lua b/exp_scenario/module/gui/task_list.lua index 75858bad..c628063a 100644 --- a/exp_scenario/module/gui/task_list.lua +++ b/exp_scenario/module/gui/task_list.lua @@ -3,7 +3,7 @@ Adds a task list to the game which players can add, remove and edit items on ]] local Gui = require("modules/exp_gui") -local Roles = require("modules.exp_legacy.expcore.roles") +local Roles = require("modules/exp_roles") local config = require("modules.exp_legacy.config.gui.tasks") local ExpUtil = require("modules/exp_util") @@ -43,8 +43,8 @@ local function has_permission_create_task(player) return true elseif allow_add_task == "admin" then return player.admin - elseif allow_add_task == "expcore.roles" then - return Roles.player_allowed(player, config.expcore_roles_allow_add_task) + elseif allow_add_task == "exp_roles" then + return Roles.player_has_permission(player, config.exp_roles_allow_add_task) end return false @@ -67,8 +67,8 @@ local function has_permission_edit_task(player, task) return true elseif allow_edit_task == "admin" then return player.admin - elseif allow_edit_task == "expcore.roles" then - return Roles.player_allowed(player, config.expcore_roles_allow_edit_task) + elseif allow_edit_task == "exp_roles" then + return Roles.player_has_permission(player, config.exp_roles_allow_edit_task) end return false @@ -922,7 +922,7 @@ Gui.toolbar.create_button{ sprite = "utility/not_enough_repair_packs_icon", tooltip = { "exp-gui_task-list.tooltip-main" }, visible = function(player, element) - return Roles.player_allowed(player, "gui/task-list") + return Roles.player_has_permission(player, "exp_scenario.gui.task_list") end } @@ -950,7 +950,6 @@ return { events = { [e.on_player_joined_game] = refresh_player_tasks, [e.on_player_changed_force] = refresh_player_tasks, - [Roles.events.on_role_assigned] = refresh_player_permissions, - [Roles.events.on_role_unassigned] = refresh_player_permissions, + [Roles.events.on_player_roles_changed] = refresh_player_permissions, } } diff --git a/exp_scenario/module/module.json b/exp_scenario/module/module.json index 56b58778..23b572f0 100644 --- a/exp_scenario/module/module.json +++ b/exp_scenario/module/module.json @@ -8,6 +8,7 @@ "dependencies": { "clusterio": "*", "exp_util": "*", + "exp_roles": "*", "exp_gui": "*", "exp_commands": "*" } diff --git a/exp_server_ups/module/control.lua b/exp_server_ups/module/control.lua index 6d51c9d3..cd2d5b19 100644 --- a/exp_server_ups/module/control.lua +++ b/exp_server_ups/module/control.lua @@ -14,7 +14,7 @@ local PlayerData = require("modules/exp_legacy/expcore/player_data") local UsesServerUps = PlayerData.Settings:combine("UsesServerUps") UsesServerUps:set_default(false) UsesServerUps:set_metadata{ - permission = "command/server-ups", + permission = "exp_scenario.command.server_ups", stringify = function(value) return value and "Visible" or "Hidden" end, }