Added module: ExpGamingCore.Ranking

This commit is contained in:
Cooldude2606
2018-06-02 21:08:33 +01:00
parent 4d05f13cb3
commit b8b514b133
12 changed files with 432 additions and 353 deletions

View File

@@ -1,104 +1,168 @@
--[[
Explosive Gaming
--- A full ranking system for factorio.
-- @module ExpGamingCore.Ranking
-- @alias Ranking
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
This file can be used with permission but this and the credit below must remain in the file.
Contact a member of management on our discord to seek permission to use our code.
Any changes that you may make to the code are yours but that does not make the script yours.
Discord: https://discord.gg/r6dC2uK
]]
--Please Only Edit Below This Line-----------------------------------------------------------
local Ranking = {}
defines.events.rank_change = script.generate_event_name()
Ranking._rank = {}
Ranking._group = {}
-- this is just for debuging when setting you rank powers
local module_verbose = false --true|false
--- Global Table
-- @table global
-- @field old contains the previous rank a use had before a rank change
-- @field preset contains the preset ranks that users will recive apon joining
-- @filed last_change contains the name of the player who last had there rank chagned
local global = global{old={},preset={},last_change=nil}
--- Called when there is a rank change for a user
-- @event rank_change
-- @field name the rank id
-- @field tick the tick which the event was raised on
-- @field player_index the player whos rank was changed
-- @field by_player_index the player who changed the rank, 0 means server
-- @field new_rank the name of the rank that was given
-- @field old_rank the name of the rank the player had
script.generate_event_name('rank_change')
--- Outputs as a string all the ranks and the loaded order
-- @usage Ranking.output_ranks(player) -- prints to player
-- @tparam[opt=server] ?player_name|player_index|LuaPlayer player the player that the info will be printed to, nil will print to server
-- @todo show inheritance of ranks
function Ranking.output_ranks(player)
local player = Game.get_player(player) or game.player or nil
if not player then return end
for power,rank in pairs(Ranking._ranks()) do
local output = power..') '..rank.name
output=output..' '..rank.tag
local function output(rank)
local admin = 'No'; if rank.is_root then admin = 'Root' elseif rank.is_admin then admin = 'Yes' end
output=output..' Admin: '..admin
output=output..' Group: '..rank.group.name
output=output..' AFK: '..tostring(rank.base_afk_time)
player_return(output,rank.colour,player)
local rtn = string.format('%s) %q %s > Admin: %s Group: %q AFK: %s Time: %s',
rank.power,rank.name,rank.tag,admin,rank.group,tostring(rank.base_afk_time),tostring(rank.time))
player_return(rtn,rank.colour,player)
end
local function recur(_rank)
for name,rank in pairs(_rank.children) do output(Ranking.ranks[rank]) end
for name,rank in pairs(_rank.children) do recur(Ranking.ranks[rank]) end
end
local root = Ranking.get_rank(Ranking.meta.root)
output(root)
recur(root)
end
-- this function is to avoid errors - see /ranks.lua
function Ranking._ranks(names)
return {}
end
--- Contains the location of all the ranks, readonly during runtime
-- @table Ranking.ranks
Ranking.ranks = setmetatable({},{
__metatable=false,
__index=table.autokey,
__newindex=function(tbl,key,value) if game then error('Can not create new ranks during runtime',2) else rawset(tbl,key,value) end end,
__len=function(tbl)
local rtn = 0
for name,rank in pairs(tbl) do
rtn=rtn+1
end
return rtn
end
})
-- this function is to avoid errors - see /ranks.lua
function Ranking._groups(names)
return {}
end
--- Contains the location of all the rank groups, readonly during runtime
-- @table Ranking.ranks
Ranking.groups = setmetatable({},{
__metatable=false,
__index=table.autokey,
__newindex=function(tbl,key,value) if game then error('Can not create new rank groups during runtime',2) else rawset(tbl,key,value) end end,
__len=function(tbl)
local rtn = 0
for name,rank in pairs(tbl) do
rtn=rtn+1
end
return rtn
end
})
-- this function is to avoid errors - see /ranks.lua
function Ranking._meta()
return {}
end
--- Contains some meta data about the ranks
-- @table Ranking.meta
-- @field default this is the name of the default rank
-- @filed root this is the name of the root rank
-- @field time_ranks a list of all ranks which have a time requirement
-- @field time_highest the power of the highest rank that has a time requirement
-- @field time_lowest the lowest amount of time required for a time rank
Ranking.meta = setmetatable({},{
__metatable=false,
__call=function(tbl)
rawset(tbl,'time_ranks',{})
for name,rank in pairs(Ranking.ranks) do
if not rawget(tbl,'default') and rank.is_default then rawset(tbl,'default',rank.name) end
if not rawget(tbl,'root') and rank.is_root then rawset(tbl,'root',rank.name) end
if rank.time then
table.insert(tbl.time_ranks,rank.name)
if not rawget(tbl,'time_highest') or rank.power < tbl.time_highest then if rank.power then rawset(tbl,'time_highest',rank.power) end end
if not rawget(tbl,'time_lowest') or rank.time < tbl.time_lowest then rawset(tbl,'time_lowest',rank.time) end
end
end
if not rawget(tbl,'default') then error('No default rank') end
if not rawget(tbl,'root') then error('No root rank') end
end,
__index=function(tbl,key)
tbl()
return rawget(tbl,key)
end,
__newindex=function() error('Ranking metadata is read only',2) end
})
-- this function is to avoid errors - see addons/playerRanks.lua
function Ranking._base_preset(table)
Ranking._presets().current = table
end
-- this returns a global list
function Ranking._presets()
if not global.exp_core then global.exp_core = {} end
if not global.exp_core.ranking then global.exp_core.ranking = {meta=Ranking._meta(),old={},current={},last_jail=nil} end
return global.exp_core.ranking
--- Used to set the prset ranks that will be given to players
-- @usage Ranking._base_preset{name=rank_name,nameTwo=rank_name_two} -- sets player name to have rank rank_name on join
-- @tparam table ranks table of player names with the player name as the key and rank name as the value
function Ranking._base_preset(ranks)
if not is_type(ranks,'table') then error('Ranking._base_preset was not given a table',2) end
global.preset = ranks
end
--- Returns a rank object given a player or rank name
-- @usage Ranking.get_rank(game.player)
-- Ranking.get_rank('admin')
-- @param mixed player|player index|player name|rank name|rank|'server'|'root' what rank to get
-- @treturn table the rank that is linked to mixed
-- @usage Ranking.get_rank(game.player) -- returns player's rank
-- @usage Ranking.get_rank('admin') -- returns rank by the name of admin
-- @tparam ?player|player_index|player_name|rank_name|Ranking._rank|'server'|'root' mixed what rank to get
-- @treturn[1] table the rank that is linked to mixed
-- @trrturn[2] nil there was no rank found
function Ranking.get_rank(mixed)
if not mixed then return false end
local ranks = Ranking._ranks(true)
if not mixed then return error('Ranking.get_rank recived no paramerters') end
local ranks = Ranking.ranks
local _return = false
if is_type(mixed,'table') then
if mixed.index then
_return = game.players[mixed.index] and ranks[mixed.permission_group.name] or nil
else
_return = mixed.group and mixed or nil
end
-- is it a player, then get player rank; if it is a rank then return the rank
if mixed.index then _return = game.players[mixed.index] and ranks[mixed.permission_group.name] or error('Invalid player name to Ranking.get_rank',2)
else _return = mixed.group and mixed or nil end
else
_return = game.players[mixed] and ranks[game.players[mixed].permission_group.name]
-- if it is a player name/index, then get player rank; if it is a rank name, get that rank; if it is server or root; return root rank; else nil
_return = game and game.players[mixed] and ranks[game.players[mixed].permission_group.name]
or table.autokey(ranks,mixed) and table.autokey(ranks,mixed)
or string.contains(mixed,'server') and Ranking.get_rank(Ranking._presets().meta.root)
or string.contains(mixed,'root') and Ranking.get_rank(Ranking._presets().meta.root)
or string.contains(mixed,'server') and Ranking.get_rank(Ranking.meta.root)
or string.contains(mixed,'root') and Ranking.get_rank(Ranking.meta.root)
or nil
end
return _return
end
--- Returns the group object used to sort ranks given group name or see Ranking.get_rank
-- @usage Ranking.get_group(game.player)
-- Ranking.get_group('root')
-- @param mixed player|player index|player name|rank name|rank|'server'|'root'|group name|group what group to get
-- @treturn table the group that is linked to mixed
--- Returns the group object used to sort ranks given group name or rank
-- @usage Ranking.get_group(game.player) -- returns player's rank group
-- @usage Ranking.get_group('root') -- returns group by name of root
-- @tparam ?player|player_index|player_name|rank_name|rank|'server'|'root'|group name|group mixed what group to get
-- @see Ranking.get_rank
-- @treturn[1] table the group that is linked to mixed
-- @trrturn[2] nil there was no rank group found
function Ranking.get_group(mixed)
if not mixed then return false end
local groups = Ranking._groups(true)
if not mixed then return error('Ranking.get_group recived no paramerters') end
local groups = Ranking.groups
local rank = Ranking.get_rank(mixed)
return rank and rank.group
or is_type(mixed,'table') and mixed.ranks and mixed
or is_type(mixed,'string') and table.autokey(groups,mixed) and table.autokey(groups,mixed)
or false
-- if it is a table see if it is a group, return the group; if it is a string, return group by that name; if there is a rank found, return the ranks group
return is_type(mixed,'table') and not mixed.__self and mixed.ranks and mixed
or is_type(mixed,'string') and table.autokey(groups,mixed)
or rank and rank.group
or nil
end
--- Prints to all rank of greater/lower power of the rank given
-- @usage Ranking.print('admin','We got a grifer')
-- @param rank_base the rank that acts as the cut off point (rank is always included)
-- @todo change to use parent and child ranks rather than power
-- @tparam ?Ranking._rank|pointerToRank rank_base the rank that acts as the cut off point (rank is always included)
-- @param rtn what do you want to return to the players
-- @tparam defines.color colour the colour that will be used to print
-- @tparam bolean below if true rank below base are printed to
-- @tparam[opt=defines.color.white] defines.color colour the colour that will be used to print
-- @tparam[opt=false] boolean below if true print to children rather than parents
function Ranking.print(rank_base,rtn,colour,below)
local colour = colour or defines.color.white
local rank_base = Ranking.get_rank(rank_base)
@@ -116,89 +180,83 @@ end
--- Gives a user a rank
-- @usage Ranking.give_rank(1,'admin')
-- @param player the player to give the rank to
-- @param rank the rank to give to the player
-- @param[opt='server'] by_player the player who is giving the rank
-- @param[opt=game.tick] tick the tick that the rank is being given on
-- @tparam ?LuaPlayer|pointerToPlayer player the player to give the rank to
-- @tparam[opt=default] ?Ranking._rank|pointerToRank rank the rank to give to the player
-- @tparam[opt='server'] ?LuaPlayer|pointerToPlayer by_player the player who is giving the rank
-- @tparam[opt=game.tick] number tick the tick that the rank is being given on, used as pass though
function Ranking.give_rank(player,rank,by_player,tick)
local print_colour = defines.textcolor.info
local tick = tick or game.tick
local by_player_name = Game.get_player(by_player) and Game.get_player(by_player).name or game.player and game.player.name or is_type(by_player,'string') and by_player or 'server'
local rank = Ranking.get_rank(rank) or Ranking.get_rank(Ranking._presets().meta.default)
local player = Game.get_player(player) or error('No Player To Give Rank')
local old_rank = Ranking.get_rank(player) or Ranking.get_rank(Ranking._presets().meta.default)
local rank = Ranking.get_rank(rank) or Ranking.get_rank(Ranking.meta.default)
local player = Game.get_player(player) or error('No player given to Ranking.give_rank',2)
local old_rank = Ranking.get_rank(player) or Ranking.get_rank(Ranking.meta.default)
local message = 'ranking.rank-down'
-- messaging
if old_rank.name == rank.name then return end
if rank.power < old_rank.power then message = 'ranking.rank-up' player.play_sound{path='utility/achievement_unlocked'}
else player.play_sound{path='utility/game_lost'} end
if player.online_time > 60 or by_player_name ~= 'server' then game.print({message,player.name,rank.name,by_player_name},print_colour) end
if rank.group.name ~= 'User' then player_return({'ranking.rank-given',rank.name},print_colour,player) end
if rank.group ~= 'User' then player_return({'ranking.rank-given',rank.name},print_colour,player) end
if player.tag ~= old_rank.tag then player_return({'ranking.tag-reset'},print_colour,player) end
-- rank change
player.permission_group = game.permissions.get_group(rank.name)
player.tag = rank.tag
if old_rank.group.name ~= 'Jail' then Ranking._presets().old[player.index] = old_rank.name end
if old_rank.group ~= 'Jail' then global.old[player.index] = old_rank.name end
player.admin = rank.is_admin or false
player.spectator = rank.is_spectator or false
if defines.events.rank_change then
script.raise_event(defines.events.rank_change,{
name=defines.events.rank_change,
tick=tick,
player_index=player.index,
by_player_name=by_player_name,
new_rank=rank,
old_rank=old_rank
})
local by_player_index = by_player_name == 'server' and 0 or Game.get_player(by_player_name).index
script.raise_event(defines.events.rank_change,{
name=defines.events.rank_change,
tick=tick,
player_index=player.index,
by_player_index=by_player_index,
new_rank=rank.name,
old_rank=old_rank.name
})
-- logs to file if rank is chagned after first join
if player.online_time > 60 then
game.write_file('ranking-change.json',
table.json({
tick=tick,
play_time=player.online_time,
player_name=player.name,
by_player_name=by_player_name,
new_rank=rank.name,
old_rank=old_rank.name
})..'\n'
, true, 0)
end
if rank.group.name == 'Jail' and Ranking._presets().last_jail ~= player.name then
Sync.emit_embeded{
title='Player Jail',
color=Color.to_hex(defines.textcolor.med),
description='There was a player jailed.',
['Player:']=player.name,
['By:']='<<inline>>'..by_player_name,
['Reason:']='No Reason'
}
end
game.write_file('ranking-change.json',
table.json({
tick=tick,
play_time=player.online_time,
player_name=player.name,
by_player_name=by_player_name,
new_rank=rank.name,
old_rank=old_rank.name,
power_increase=(old_rank.power-rank.power)
})..'\n'
, true, 0)
end
--- Revert the last change to a players rank
-- @usage Ranking.revert(1)
-- @param player the player to revert the rank of
-- @usage Ranking.revert(1) -- reverts the rank of player with index 1
-- @tparam ?LuaPlayer|pointerToPlayer player the player to revert the rank of
-- @param[opt=nil] by_player the player who is doing the revert
function Ranking.revert(player,by_player)
local player = Game.get_player(player)
Ranking.give_rank(player,Ranking._presets().old[player.index],by_player)
Ranking.give_rank(player,global.old[player.index],by_player)
end
--- Given the player has a rank in the preset table it is given
-- @usage Ranking.find_preset(1)
-- @param player the player to test for an auto rank
--- Given that the player has a rank in the preset table it is given; also will attempt to promote players if a time requirement is met
-- @usage Ranking.find_preset(1) -- attemps to find the preset for player with index 1
-- @tparam ?LuaPlayer|pointerToPlayer player the player to test for an auto rank
-- @tparam[opt=nil] number tick the tick it happens on
function Ranking.find_preset(player,tick)
local presets = Ranking._presets().current
local meta_data = Ranking._presets().meta
local presets = global.preset
local meta_data = Ranking.meta
local default = Ranking.get_rank(meta_data.default)
local player = Game.get_player(player)
local current_rank = Ranking.get_rank(player) or {power=-1,group={name='not jail'}}
local current_rank = Ranking.get_rank(player) or {power=-1,group='not jail'}
local ranks = {default}
if current_rank.group.name == 'Jail' then return end
-- users in rank group jail are ingroned
if current_rank.group == 'Jail' then return end
-- looks in preset table for player name
if presets[string.lower(player.name)] then
local rank = Ranking.get_rank(presets[string.lower(player.name)])
table.insert(ranks,rank)
end
-- if the player mets check requirements then play time is checked
if current_rank.power > meta_data.time_highest and tick_to_min(player.online_time) > meta_data.time_lowest then
for _,rank_name in pairs(meta_data.time_ranks) do
local rank = Ranking.get_rank(rank_name)
@@ -207,186 +265,213 @@ function Ranking.find_preset(player,tick)
end
end
end
-- if the new rank is closer to root then it is the new rank
local _rank = current_rank
for _,rank in pairs(ranks) do
if rank.power < _rank.power or _rank.power == -1 then _rank = rank end
end
if _rank then
if _rank.name == default.name then
player.tag = _rank.tag
player.permission_group = game.permissions.get_group(_rank.name)
else
Ranking.give_rank(player,_rank,nil,tick)
end
-- this new rank is given to the player
if _rank.name == current_rank.name then return end
if _rank.name == default.name then
player.tag = _rank.tag
player.permission_group = game.permissions.get_group(_rank.name)
else
Ranking.give_rank(player,_rank,nil,tick)
end
end
-- this is the base rank object, do not store in global
--- The class for the ranks
-- @type Rank
-- @alias Ranking._rank
-- @field name the name that is given to the rank, must be unique
-- @field short_hand the shorter way of displaying this rank, can be used by other modules
-- @field tag the tag that player in this rank will be given
-- @field colour the colour that modules should display this rank as in guis
-- @field parent the name of the rank that permissions are inherited from, allow comes from children, disallow given to children
-- @field base_afk_time a relative number that the rank should be given that other modules can use for relitive importance
-- @field time the time that is requied for this rank to be given, can be nil for manal only
-- @field allow a list of permissions that this rank is allowed
-- @field disallow a list of acctions that is blocked by the ingame permission system
-- @field is_default will be given to all players if no other rank is set for them
-- @field is_admin will promote player to ingame admin if flag set (will auto demote if not set)
-- @field is_spectator will auto set the spectator option for the player (will cleat option if not set)
-- @field is_root rank is always allowed all action, when present in root group will become the root child that all ranks are indexed from
Ranking._rank = {}
--- Is this rank allowed to open this gui or use this command etc.
-- @usage rank:allowed('server-interface')
-- @usage rank:allowed('interface') -- does the rank have permision for 'interface'
-- @tparam teh action to test for
-- @treturn bolean is it allowed
-- @treturn boolean is it allowed
function Ranking._rank:allowed(action)
return self.allow[action] or self.is_root or false
end
--- Get all the players in this rank
-- @usage rank:get_players()
-- @tparam bolean online get only online players
-- @tparam[opt=false] boolean online get only online players
-- @treturn table a table of all players in this rank
function Ranking._rank:get_players(online)
local players = game.permissions.get_group(self.name).players
local _return = {}
if online then
for _,player in pairs(players) do
if player.connected then table.insert(_return,player) end
end
else
_return = players
end
for _,player in pairs(players) do if player.connected then table.insert(_return,player) end end
else _return = players end
return _return
end
--- Print a message to all players of this rank
-- @usage rank:print('foo')
-- @usage rank:print('foo') -- prints to all members of this rank
-- @param rtn any value you want to return
-- @tparam define.color colour the colour that will be used to print
-- @tparam boolean show_default weather to use the default rank name for the print
-- @tparam[opt=defines.color.white] define.color colour the colour that will be used to print
-- @tparam[opt=false] boolean show_default weather to use the default rank name for the print, used as a pass though
function Ranking._rank:print(rtn,colour,show_default)
local colour = colour or defines.color.white
local meta_data = Ranking._presets().meta
local default = Ranking.get_rank(meta_data.default)
if not Server or not Server._thread then
for _,player in pairs(self:get_players(true)) do
if self.name == default.name or show_default then
player_return({'ranking.all-rank-print',rtn},colour,player)
else
player_return({'ranking.rank-print',self.name,rtn},colour,player)
end
end
else
-- using threads to make less lag
Server.new_thread{
data={rank=self,rtn=rtn,default=default.name,all=show_default}
}:on_event('resolve',function(thread)
return thread.data.rank:get_players(true)
end):on_event('success',function(thread,players)
for _,player in pairs(players) do
if thread.data.rank.name == thread.data.default or thread.data.all then
player_return({'ranking.all-rank-print',thread.data.rtn},colour,player)
else
player_return({'ranking.rank-print',thread.data.rank.name,thread.data.rtn},colour,player)
end
end
end):queue()
local default = Ranking.get_rank(Ranking.meta.default)
for _,player in pairs(self:get_players(true)) do
if self.name == default.name or show_default then player_return({'ranking.all-rank-print',rtn},colour,player)
else player_return({'ranking.rank-print',self.name,rtn},colour,player) end
end
end
-- this is used to edit a group once made key is what is being edited and set_value makes it over ride the current value
-- see Addons/playerRanks for examples
function Ranking._rank:edit(key,set_value,value)
--- Allows for a clean way to edit rank objects
-- @usage rank:edit('allow',{'interface'}) -- allows this rank to use 'interface'
-- @tparam string key the key to edit, often allow or disallow
-- @param value the new value to be set
function Ranking._rank:edit(key,value)
if game then return end
verbose('Edited Rank: '..self.name..'/'..key)
if set_value then self[key] = value return end
if key == 'disallow' then
self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then
self.allow = table.merge(self.allow,value)
end
Ranking._update_rank(self)
verbose('Edited Rank: '..self.group..'/'..self.name..'/'..key)
if key == 'disallow' then self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then self.allow = table.merge(self.allow,value)
else self[key] = value end
end
-- this is the base group object, do not store in global, these cant be used in game
--- The class for the rank groups, the way to allow modules to idex a group that is always present, ranks will always look to there group as a parent
-- @type Group
-- @alias Ranking._group
-- @field name the name that is given to the rank group, must be unique
-- @field parent the name of the group that permissions are inherited from
-- @field allow a list of permissions that this rank is allowed
-- @field disallow a list of acctions that is blocked by the ingame permission system
Ranking._group = {}
-- this makes a new group
-- {name='root',allow={},disallow={}}
--- Creates a new group
-- @usage Ranking._group:create{name='root'} -- returns group with name root
-- @tparam table obj the fields for this object
-- @treturn Ranking._group returns the object to allow chaining
function Ranking._group:create(obj)
if game then return end
if not is_type(obj.name,'string') then return end
if not is_type(obj.name,'string') then error('Group creationg is invalid',2) end
verbose('Created Group: '..obj.name)
setmetatable(obj,{__index=Ranking._group})
self.index = #Ranking._groups(names)+1
obj.ranks = {}
obj.allow = obj.allow or {}
obj.disallow = obj.disallow or {}
Ranking._add_group(obj)
Ranking.groups[obj.name] = obj
return obj
end
-- this makes a new rank in side this group
-- {name='Root',short_hand='Root',tag='[Root]',time=nil,colour=defines.colors.white,allow={},disallow={}}
-- if the rank is given power then it is given that place realative to the highest rank in that group,if no power then it is added to the end
--- Creats a new rank with this group as its group
-- @usage group:add_rank{name='root'} -- returns self
-- @tparam table obj the fields for this object
-- @treturn Ranking._group returns the object to allow chaining
function Ranking._group:add_rank(obj)
if game then return end
if not is_type(obj.name,'string') or
not is_type(obj.short_hand,'string') or
not is_type(obj.tag,'string') or
not is_type(obj.colour,'table') then return end
not is_type(obj.colour,'table') then error('Rank creation is invalid',2) end
verbose('Created Rank: '..obj.name)
setmetatable(obj,{__index=Ranking._rank})
obj.group = self
obj.group = self.name
obj.children = {}
obj.allow = obj.allow or {}
obj.disallow = obj.disallow or {}
obj.power = obj.power and self.highest and self.highest.power+obj.power or obj.power or self.lowest and self.lowest.power+1 or nil
setmetatable(obj.allow,{__index=self.allow})
setmetatable(obj.disallow,{__index=self.disallow})
Ranking._add_rank(obj,obj.power)
Ranking._set_rank_power()
table.insert(self.ranks,obj)
if not self.highest or obj.power < self.highest.power then self.highest = obj end
if not self.lowest or obj.power > self.lowest.power then self.lowest = obj end
table.insert(self.ranks,obj.name)
Ranking.ranks[obj.name] = obj
return self
end
-- this is used to edit a group once made key is what is being edited and set_value makes it over ride the current value
-- see Addons/playerRanks for examples
function Ranking._group:edit(key,set_value,value)
--- Allows for a clean way to edit rank group objects
-- @usage group:edit('allow',{'interface'}) -- allows this rank to use 'interface'
-- @tparam string key the key to edit, often allow or disallow
-- @param value the new value to be set
function Ranking._group:edit(key,value)
if game then return end
verbose('Edited Group: '..self.name..'/'..key)
if set_value then self[key] = value return end
if key == 'disallow' then
self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then
self.allow = table.merge(self.allow,value)
end
Ranking._update_group(self)
if key == 'disallow' then self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then self.allow = table.merge(self.allow,value)
else self[key] = value end
end
Event.register(defines.events.on_player_joined_game,function(event)
script.on_event('on_player_joined_game',function(event)
Ranking.find_preset(event.player_index)
end)
Event.register(-1,function(event)
for power,rank in pairs(Ranking._ranks()) do
local perm = game.permissions.create_group(rank.name)
script.on_event('on_init',function(event)
for name,rank in pairs(Ranking.ranks) do
local perm = game.permissions.create_group(name)
for _,toRemove in pairs(rank.disallow) do
perm.set_allows_action(defines.input_action[toRemove],false)
end
end
end)
Event.register(defines.events.on_tick,function(event)
script.on_event('on_tick',function(event)
if (((event.tick+10)/(3600*game.speed))+(15/2))% 15 == 0 then
-- this is the system to auto rank players
if not Server or not Server._thread then
for _,player in pairs(game.connected_players) do
Ranking.find_preset(player,tick)
end
else
Server.new_thread{
data={players=game.connected_players}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
Ranking.find_preset(player,tick)
end):open()
for _,player in pairs(game.connected_players) do
Ranking.find_preset(player,tick)
end
end
end
end)
Ranking.on_init=function(self)
require(module_path.."/base_ranks")
require(module_path.."/config_ranks")
if loaded_modules.Server then require(module_path..'/src/server') end
require(module_path..'/src/core')
require(module_path..'/src/config')
-- sets up the power system, the lower the power the closer to root, root is 0
-- there must be a rank with is_root flag set and one rank with is_default flag set, if multiple found then first found is used
local root = Ranking.get_rank(Ranking.meta.root)
root:edit('power',0)
-- asigning of children
verbose('Creating Rank Tree')
for name,rank in pairs(Ranking.ranks) do
if rank ~= root then
if not rank.parent then error('Rank has no parent: "'..name..'"') end
if not Ranking.ranks[rank.parent] then error('Invalid parent rank: "'..rank.parent..'"') end
table.insert(Ranking.ranks[rank.parent].children,name)
Ranking.ranks[rank.parent]:edit('allow',rank.allow)
rank:edit('disallow',Ranking.ranks[rank.parent].disallow)
end
end
-- asigning of powers
verbose('Assigning Rank Powers')
local power = 1
local function set_powers(rank)
for _,name in pairs(rank.children) do
Ranking.ranks[name]:edit('power',power)
power=power+1
end
for _,name in pairs(rank.children) do set_powers(Ranking.ranks[name]) end
end
set_powers(root)
-- asigning group meta data
verbose('Creating Rank-Group Relationship')
for name,group in pairs(Ranking.groups) do
if name ~= 'Root' then
if not group.parent then error('Group has no parent: "'..name..'"') end
if not Ranking.groups[group.parent] then error('Invalid parent rank: "'..group.parent..'"') end
Ranking.groups[group.parent]:edit('allow',group.allow)
group:edit('disallow',Ranking.groups[group.parent].disallow)
end
for _,name in pairs(group.ranks) do
local rank = Ranking.ranks[name]
rank:edit('disallow',group.disallow)
rank:edit('allow',group.allow)
if not group.highest or Ranking.ranks[group.highest].power > rank.power then group.highest = rank.name end
if not group.lowest or Ranking.ranks[group.highest].power < rank.power then group.lowest = rank.name end
end
end
end
return Ranking