mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Added Roles
This commit is contained in:
@@ -26,4 +26,5 @@ return {
|
||||
'config.command_auth_admin', -- commands tagged with admin_only are blocked for non admins
|
||||
'config.command_auth_runtime_disable', -- allows commands to be enabled and disabled during runtime
|
||||
'config.permission_groups', -- loads some predefined permission groups
|
||||
'config.roles', -- loads some predefined roles
|
||||
}
|
||||
1
config/roles.lua
Normal file
1
config/roles.lua
Normal file
@@ -0,0 +1 @@
|
||||
local Roles = require 'expcore.roles'
|
||||
@@ -14,4 +14,10 @@ invalid-param=Invalid Param "__1__"; __2__
|
||||
command-help=__1__ - __2__
|
||||
command-ran=Command Complete
|
||||
command-fail=Command failed to run: __1__
|
||||
command-error-log-format=[ERROR] command/__1__ :: __2__
|
||||
command-error-log-format=[ERROR] command/__1__ :: __2__
|
||||
|
||||
[expcore-roles]
|
||||
error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__
|
||||
error-log-format-promote=[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__
|
||||
421
expcore/roles.lua
Normal file
421
expcore/roles.lua
Normal file
@@ -0,0 +1,421 @@
|
||||
local Game = require 'utils.game'
|
||||
local Global = require 'utils.global'
|
||||
local Event = require 'utils.event'
|
||||
local Groups = require 'expcore.permission_groups'
|
||||
local Colours = require 'resources.color_presets'
|
||||
|
||||
local Roles = {
|
||||
config={
|
||||
order={}, -- Contains the order of the roles, lower index is better
|
||||
roles={}, -- 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={}
|
||||
},
|
||||
player_role_assigned=script.generate_event_name(),
|
||||
player_role_unassigned=script.generate_event_name(),
|
||||
_prototype={}
|
||||
}
|
||||
|
||||
local function emit_player_roles_updated(player,type,roles,by_player_name)
|
||||
local event = Roles.player_role_assigned
|
||||
if type == 'unassign' then
|
||||
event = Roles.player_role_unassigned
|
||||
end
|
||||
local by_player = Game.get_player_from_any(by_player_name)
|
||||
local by_player_index = by_player and by_player.index or 0
|
||||
local role_names = {}
|
||||
for _,role in pairs(roles) do
|
||||
table.insert(role_names,role.name)
|
||||
end
|
||||
game.print({'expcore-roles.game-message-'..type,player.name,role_names.join(', '),by_player_name or '<server>'},Colours.cyan)
|
||||
script.raise_event(event,{
|
||||
name=Roles.player_roles_updated,
|
||||
tick=game.tick,
|
||||
player_index=player.index,
|
||||
by_player_index=by_player_index,
|
||||
roles=roles
|
||||
})
|
||||
game.write_file('log/roles.log',game.table_to_json{
|
||||
player_name=player.name,
|
||||
by_player_name=by_player_name or '<server>',
|
||||
type=type,
|
||||
roles_changed=roles
|
||||
}..'\n',true,0)
|
||||
end
|
||||
|
||||
Global.register(Roles.config,function(tbl)
|
||||
Roles.config = tbl
|
||||
for _,role in pairs(Roles.config.roles) do
|
||||
setmetatable(role,{__index=Roles._prototype})
|
||||
local parent = Roles.config.roles[role.parent]
|
||||
if parent then
|
||||
setmetatable(role.allow, {__index=parent.allow})
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function Roles.get_role_by_name(name)
|
||||
return Roles.config.roles[name]
|
||||
end
|
||||
|
||||
function Roles.get_role_by_order(index)
|
||||
local name = Roles.config.order[index]
|
||||
return Roles.config.roles[name]
|
||||
end
|
||||
|
||||
function Roles.get_role_from_any(any)
|
||||
local tany = type(any)
|
||||
if tany == 'number' or tonumber(any) then
|
||||
any = tonumber(any)
|
||||
return Roles.get_role_by_order(any)
|
||||
elseif tany == 'string' then
|
||||
return Roles.get_role_by_name(any)
|
||||
elseif tany == 'table' then
|
||||
return Roles.get_role_by_name(any.name)
|
||||
end
|
||||
end
|
||||
|
||||
function Roles.get_player_roles(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
if not player then return end
|
||||
local roles = Roles.config.players[player.name] or {}
|
||||
table.insert(roles,Roles.config.internal.default)
|
||||
for index,role_name in pairs(roles) do
|
||||
roles[index] = Roles.config.roles[role_name]
|
||||
end
|
||||
return roles
|
||||
end
|
||||
|
||||
function Roles.assign_player(player,roles,by_player_name)
|
||||
player = Game.get_player_from_any(player)
|
||||
if not player then return end
|
||||
if type(roles) ~= 'table' or roles.name then
|
||||
roles = {roles}
|
||||
end
|
||||
for _,role in pairs(roles) do
|
||||
role = Roles.get_role_from_any(role)
|
||||
if role then
|
||||
role:add_player(player,false,true)
|
||||
end
|
||||
end
|
||||
emit_player_roles_updated(player,'assign',roles,by_player_name)
|
||||
end
|
||||
|
||||
function Roles.unassign_player(player,roles,by_player_name)
|
||||
player = Game.get_player_from_any(player)
|
||||
if not player then return end
|
||||
if type(roles) ~= 'table' or roles.name then
|
||||
roles = {roles}
|
||||
end
|
||||
for _,role in pairs(roles) do
|
||||
role = Roles.get_role_from_any(role)
|
||||
if role then
|
||||
role:remove_player(player,false,true)
|
||||
end
|
||||
end
|
||||
emit_player_roles_updated(player,'unassign',roles,by_player_name)
|
||||
end
|
||||
|
||||
function Roles.override_player_roles(roles)
|
||||
Roles.config.players = roles
|
||||
end
|
||||
|
||||
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 pairs(roles) do
|
||||
if role == search_role.name then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Roles.player_has_flag(player,flag_name)
|
||||
local roles = Roles.get_player_roles(player)
|
||||
if not roles then return end
|
||||
for _,role in pairs(roles) do
|
||||
if role:has_flag(flag_name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Roles.player_allowed(player,action)
|
||||
local roles = Roles.get_player_roles(player)
|
||||
if not roles then return end
|
||||
for _,role in pairs(roles) do
|
||||
if role:allowed(action) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Roles.define_role_order(order)
|
||||
local sanitized = {}
|
||||
for _,role in ipairs(order) do
|
||||
if type(role) == 'table' and role.name then
|
||||
table.insert(sanitized,role.name)
|
||||
else
|
||||
table.insert(sanitized,role)
|
||||
end
|
||||
end
|
||||
Roles.config.order = sanitized
|
||||
for index,role in pairs(sanitized) do
|
||||
Roles.config.roles[role].index = index
|
||||
end
|
||||
end
|
||||
|
||||
function Roles.define_flag_trigger(name,callback)
|
||||
Roles.config.flags[name] = callback -- this can desync if there are upvalues
|
||||
end
|
||||
|
||||
function Roles.set_default(name)
|
||||
local role = Roles.config.roles[name]
|
||||
if not role then return end
|
||||
Roles.config.internal.default = name
|
||||
end
|
||||
|
||||
function Roles.set_root(name)
|
||||
local role = Roles.config.roles[name]
|
||||
if not role then return end
|
||||
Roles.config.internal.root = name
|
||||
end
|
||||
|
||||
function Roles.new_role(name,short_hand)
|
||||
if Roles.config.roles[name] then return error('Role name is non unique') end
|
||||
local role = setmetatable({
|
||||
name=name,
|
||||
short_hand=short_hand or name,
|
||||
allow={},
|
||||
allow_all_actions=false,
|
||||
flags={}
|
||||
},{__index=Roles._prototype})
|
||||
Roles.config.roles[name] = role
|
||||
return role
|
||||
end
|
||||
|
||||
function Roles._prototype:set_allow_all(state)
|
||||
self.allow_all_actions = not not state
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:allow(actions)
|
||||
if type(actions) ~= 'table' then
|
||||
actions = {actions}
|
||||
end
|
||||
for _,action in pairs(actions) do
|
||||
self.allow[action]=true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:disallow(actions)
|
||||
if type(actions) ~= 'table' then
|
||||
actions = {actions}
|
||||
end
|
||||
for _,action in pairs(actions) do
|
||||
self.allow[action]=false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:is_allowed(action)
|
||||
local is_root = Roles.config.internal.root.name == self.name
|
||||
return self.allowed[action] or self.allow_all_actions or is_root
|
||||
end
|
||||
|
||||
function Roles._prototype:set_flag(name,value)
|
||||
self.flags[name] = value
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:clear_flags()
|
||||
self.flags = {}
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:has_flag(name)
|
||||
return self.flags[name] or false
|
||||
end
|
||||
|
||||
function Roles._prototype:set_custom_tag(tag)
|
||||
self.custom_tag = tag
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:set_permission_group(name,use_factorio_api)
|
||||
if not use_factorio_api then
|
||||
self.permission_group = {true,name}
|
||||
else
|
||||
local group = Groups.get_group_by_name(name)
|
||||
if not group then return end
|
||||
self.permission_group = name
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:set_parent(role)
|
||||
role = Role.get_role_from_any(role)
|
||||
if not role then return end
|
||||
self.parent = role.name
|
||||
setmetatable(self.allow, {__index=role.allow})
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:set_auto_promote_condition(callback)
|
||||
self.auto_promote_condition = callback
|
||||
return self
|
||||
end
|
||||
|
||||
function Roles._prototype:add_player(player,skip_check,skip_event)
|
||||
player = Game.get_player_from_any(player)
|
||||
-- Check the player is valid, can be skipped but a name must be given
|
||||
if not player then
|
||||
if skip_check then
|
||||
player = {name=player}
|
||||
else
|
||||
return false
|
||||
end
|
||||
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 pairs(player_roles) do
|
||||
if role_name == self.name then return false end
|
||||
end
|
||||
table.insert(player_roles,self.name)
|
||||
else
|
||||
Roles.config.players[player.name] = {self.name}
|
||||
end
|
||||
-- Emits event if required
|
||||
if not skip_event then
|
||||
local by_player_name
|
||||
if game.player then by_player_name = game.player.name end
|
||||
emit_player_roles_updated(player,'assign',{self},by_player_name)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Roles._prototype:remove_player(player,skip_check,skip_event)
|
||||
player = Game.get_player_from_any(player)
|
||||
-- Check the player is valid, can be skipped but a name must be given
|
||||
if not player then
|
||||
if skip_check then
|
||||
player = {name=player}
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
-- Remove the role from the players roles
|
||||
local player_roles = Roles.config.players[player.name]
|
||||
local rtn = false
|
||||
if player_roles then
|
||||
for index,role_name in pairs(player_roles) do
|
||||
if role_name == self.name then
|
||||
table.remove(player_roles,index)
|
||||
rtn = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if #player_roles == 0 then
|
||||
Roles.config.players[player.name] = nil
|
||||
end
|
||||
end
|
||||
-- Emits event if required
|
||||
if not skip_event then
|
||||
local by_player_name
|
||||
if game.player then by_player_name = game.player.name end
|
||||
emit_player_roles_updated(player,'unassign',{self},by_player_name)
|
||||
end
|
||||
return rtn
|
||||
end
|
||||
|
||||
function Roles._prototype:get_players(online)
|
||||
local players = {}
|
||||
-- Gets all players that have this role
|
||||
for player_name,player_roles in pairs(Roles.config.players) do
|
||||
for _,role_name in pairs(player_roles) do
|
||||
if role_name == self.name then
|
||||
table.insert(players,player_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Convert the player names to LuaPlayer
|
||||
for index,player_name in pairs(players) do
|
||||
players[index] = Game.get_player_from_any(player_name)
|
||||
end
|
||||
-- Filter by online if param is defined
|
||||
if online == nil then
|
||||
return players
|
||||
else
|
||||
local filtered = {}
|
||||
for _,player in pairs(players) do
|
||||
if player.connected == online then
|
||||
table.insert(filtered,player)
|
||||
end
|
||||
end
|
||||
return filtered
|
||||
end
|
||||
end
|
||||
|
||||
function Roles._prototype:print(message)
|
||||
local players = self:get_players(true)
|
||||
for _,player in pairs(players) do
|
||||
player.print(message)
|
||||
end
|
||||
return #players
|
||||
end
|
||||
|
||||
local function role_update(event)
|
||||
local player = Game.get_player_by_idnex(event.player_index)
|
||||
-- Updates flags given to the player
|
||||
for flag,callback in pairs(Role.config.flags) do
|
||||
local state = Role.player_has_flag(player,flag)
|
||||
local success,err = pcall(callback,player,state)
|
||||
if not success then
|
||||
log{'expcore-roles.error-log-format-flag',flag,err}
|
||||
end
|
||||
end
|
||||
-- Updates the players permission group
|
||||
local highest
|
||||
local roles = Roles.get_player_roles(player)
|
||||
for _,role in pairs(roles) do
|
||||
if not highest or role.index < highest.index then
|
||||
highest = role
|
||||
end
|
||||
end
|
||||
Groups.set_player_group(player,highest.permission_group)
|
||||
end
|
||||
|
||||
Event.add(Roles.player_role_assigned,role_update)
|
||||
Event.add(Roles.player_role_unassigned,role_update)
|
||||
Event.on_nth_tick(300,function()
|
||||
local promotes = {}
|
||||
for _,player in pairs(game.connected_players) do
|
||||
for _,role in pairs(Roles.config.roles) do
|
||||
if role.auto_promote_condition then
|
||||
local success,err = pcall(role.auto_promote_condition,player)
|
||||
if not success then
|
||||
log{'expcore-roles.error-log-format-promote',role.name,err}
|
||||
else
|
||||
if err == true then
|
||||
if promotes[player.name] then
|
||||
table.insert(promotes[player.name],role.name)
|
||||
else
|
||||
promotes[player.name] = {role.name}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for player_name,roles in pairs(promotes) do
|
||||
Roles.assign(player_name,roles)
|
||||
end
|
||||
end)
|
||||
|
||||
return Roles
|
||||
Reference in New Issue
Block a user