Files
factorio-scenario-ExpCluster/modules/ExpGamingCore/Sync/control.lua
2018-05-30 20:05:12 +01:00

276 lines
12 KiB
Lua

--[[
Explosive Gaming
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-----------------------------------------------------------
-- this file is used to allow easy syncing with out side programes
local Sync = {}
local Sync_updates = {}
--- Used to standidise the tick format for any sync info
-- @usage Sync.tick_format(60) -- return {60,'1.00M'}
-- @treturn {number,string} table containg both the raw number and clean version of a time
function Sync.tick_format(tick)
if not is_type(tick,'number') then error('Tick was not given to Sync.tick_format',2) end
return {tick,tick_to_display_format(tick)}
end
--- Prints to chat as if it were a player
-- @usage Sync.print('Test','Cooldude2606')
-- @tparam string player_message the message to be printed in chat
-- @tparam string player_name the name of the player sending the message
-- @tparam[opt] string player_tag the tag apllied to the player's name
-- @tparam[opt] string player_colour the colour of the message, either hex or named colour
-- @tparam[opt] string prefix add a prefix before the chat eg [IRC]
function Sync.print(player_message,player_name,player_tag,player_colour,prefix)
if not player_message then error('No message given to Sync.print',2) end
local player = game.player or game.players[player_name]
local tag = player_tag and player_tag ~= '' and ' '..player_tag or ''
local colour = type(player_colour) == 'string' and player_colour or '#FFFFFF'
local prefix = prefix and prefix..' ' or ''
-- if it is an ingame player it will over ride the given params
if player then
tag = ' '..player.tag
colour = player.chat_color
player_name = player.name
else
-- converts colour into the accepted factorio version
if colour:find('#') then colour = Color.from_hex(colour)
else colour = defines.color[player_colour] end
end
game.print(prefix..player_name..tag..': '..player_message,colour)
end
--- Logs an embed to the json.data we use a js script to add things we cant here
-- @usage Sync.emit_embeded{title='BAN',color='0x0',description='A player was banned' ... }
-- @tparam table args a table which contains everything that the embeded will use
-- @table args
-- @field title the tile of the embed
-- @field color the color given in hex you can use Color.to_hex{r=0,g=0,b=0}
-- @field description the description of the embed
-- @field server_detail sting to add onto the pre-set server detail
-- @field fieldone the filed to add to the embed (key is name) (value is text) (start value with <<inline>> to make inline)
-- @field fieldtwo the filed to add to the embed (key is name) (value is text) (start value with <<inline>> to make inline)
function Sync.emit_embeded(args)
if not is_type(args,'table') then error('Args table not given to Sync.emit_embeded',2) end
local title = is_type(args.title,'string') and args.title or ''
local color = is_type(args.color,'string') and args.color:find("0x") and args.color or '0x0'
local description = is_type(args.description,'string') and args.description or ''
local server_detail = is_type(args.server_detail,'string') and args.server_detail or ''
local mods_online = 'Mods Online: '..Sync.info.players.admins_online
-- creates the first field given for every emit
local done, fields = {title=true,color=true,description=true,server_detail=true}, {{
name='Server Details',
value='Server Name: {{ serverName }} Online Players: '..#game.connected_players..' '..mods_online..' Server Time: '..tick_to_display_format(game.tick)..' '..server_detail
}}
-- for each value given in args it will create a new field for the embed
for key, value in pairs(args) do
if not done[key] then
done[key] = true
local f = {name=key,value='',inline=false}
-- if <<inline>> is present then it will cause the field to be inline if the previous
local value, inline = value:gsub("<<inline>>",'',1)
if inline > 0 then f.inline = true end
f.value = value
table.insert(fields,f)
end
end
-- forms the data that will be emited to the file
local log_data = {
title=title,
description=description,
color=color,
fields=fields
}
game.write_file('embeded.json',table.json(log_data)..'\n',true,0)
end
--- The error handle setup by sync to emit a discord embed for any errors
-- @function errorHandler
-- @tparam string err the error passed by the err control
error.addHandler('Discord Emit',function(err)
local color = Color and Color.to_hex(defines.textcolor.bg) or '0x0'
Sync.emit_embeded{title='SCRIPT ERROR',color=color,description='There was an error in the script @Developers ',Error=err}
end)
--- Used to get the number of admins currently online
-- @usage Sync.count_admins() -- returns number
-- @treturn number the number of admins online
function Sync.count_admins()
-- game check
if not game then return 0 end
local _count = 0
for _,player in pairs(game.connected_players) do
if player.admin then _count=_count+1 end
end
return _count
end
--- Used to get the number of afk players defined by 2 min by default
-- @usage Sync.count_afk()
-- @tparam[opt=7200] int time in ticks that a player is called afk
-- @treturn number the number of afk players
function Sync.count_afk(time)
if not game then return 0 end
local time = time or 7200
local _count = 0
for _,player in pairs(game.connected_players) do
if player.afk_time > time then _count=_count+1 end
end
return _count
end
--- Used to get the number of players in each rank and currently online; if ExpGamingCore/Ranking is present then it will give more than admin and user
-- @usage Sync.count_ranks()
-- @treturn table contains the ranks and the players in that rank
function Sync.count_ranks()
if not game then return {'Offline'} end
local _ranks = {admin={online={},players={}},user={online={},players={}}}
for power,rank in pairs(game.players) do
if player.admin then
table.insert(_ranks.admin.players,player.name)
if player.connected then table.insert(_ranks.admin.online,player.name) end
else
table.insert(_ranks.user.players,player.name)
if player.connected then table.insert(_ranks.user.online,player.name) end
end
end
_ranks.admin.n_players,_ranks.admin.n_online=#_ranks.admin.players,#_ranks.admin.online
_ranks.user.n_players,_ranks.user.n_online=#_ranks.user.players,#_ranks.user.online
return _ranks
end
--- Used to get a list of every player name with the option to limit to only online players
-- @usage Sync.count_players()
-- @tparam boolean online true will get only the online players
-- @treturn table table of player names
function Sync.count_players(online)
if not game then return {'Offline'} end
local _players = {}
local players = {}
if online then _players = game.connected_players else _players = game.players end
for k,player in pairs(_players) do table.insert(players,player.name) end
return players
end
--- Used to get a list of every player name with the amount of time they have played for
-- @usage Sync.count_player_times()
-- @treturn table table indexed by player name, each value contains the raw tick and then the clean string
function Sync.count_player_times()
if not game then return {'Offline'} end
local _players = {}
for index,player in pairs(game.players) do
_players[player.name] = Sync.tick_format(player.online_time)
end
return _players
end
--- used to get the global list that has been defined, also used to set that list
-- @usage Sync.info{server_name='Factorio Server 2'} -- returns true
-- @usage Sync.info -- table of info
-- @tparam[opt=nil] table set keys to be replaced in the server info
-- @treturn boolean success was the data set
Sync.info = setmetatable({},{
__index=function(tbl,key)
if not global.exp_core then global.exp_core = {} end
if not global.exp_core.sync then global.exp_core.sync = {
server_name='Factorio Server',
server_description='A factorio server for everyone',
reset_time='On Demand',
time='Day Mth 00 00:00:00 UTC Year',
time_set=Sync.tick_format(0),
last_update=Sync.tick_format(0),
time_period=Sync.tick_format(18000),
players={
online=Sync.count_players(true),
n_online=#game.connected_players,
all=Sync.count_players(),
n_all=#game.players,
admins_online=Sync.count_admins(),
afk_players=Sync.count_afk(),
times=Sync.count_player_times()
},
ranks=Sync.count_ranks(),
rockets=game.forces['player'].get_item_launched('satellite'),
mods={'base'}
} end
return global.exp_core.sync[key]
end,
__call=function(tbl,set)
local _ = tbl.time -- used to create the global if not made
if not is_type(set,'table') then return false end
for key,value in pairs(set) do global.exp_core.sync[key] = value end
return true
end
})
--- Called to update values inside of the info
-- @usage Sync.update()
-- @return all of the new info
function Sync.update()
local info = Sync.info
info.time_period[2] = tick_to_display_format(info.time_period[1])
info.last_update[1] = game.tick
info.last_update[2] = tick_to_display_format(game.tick)
info.players={
online=Sync.count_players(true),
n_online=#game.connected_players,
all=Sync.count_players(),
n_all=#game.players,
admins_online=Sync.count_admins(),
afk_players=Sync.count_afk(),
times=Sync.count_player_times()
}
info.ranks = Sync.count_ranks()
info.rockets = game.forces['player'].get_item_launched('satellite')
for key,callback in pairs(Sync_updates) do info[key] = callback() end
return info
end
--- Adds a callback to be called when the info is updated
-- @usage Sync.add_update('players',function() return #game.players end)
-- @tparam string key the key that the value will be stored in
-- @tparam function callback the function which will return this value
function Sync.add_update(key,callback)
if game then return end
if not is_type(callback,'function') then return end
Sync_updates[key] = callback
end
--- outputs the curent server info into a file
-- @usage Sync.emit_data()
function Sync.emit_data()
local info = Sync.info
game.write_file('server-info.json',table.json(info),false,0)
end
-- will auto replace the file every 5 min by default
script.on_event('on_tick',function(event)
local time = Sync.info.time_period[1]
if (event.tick%time)==0 then Sync.update() Sync.emit_data() end
end)
function Sync:on_init()
--- Used to return and set the current IRL time; not very good need a better way to do this
-- @usage Sync.time('Sun Apr 1 18:44:30 UTC 2018')
-- @usage Sync.time -- string
-- @tparam[opt=nil] string set the date time to be set
-- @treturn boolean if the datetime set was successful
Sync.time=add_metatable({},function(set)
local info = Sync.info
if not is_type(set,'string') then return false end
info.time = set
info.time_set[1] = game.tick
info.time_set[2] = tick_to_display_format(game.tick)
return true
end,function() local info = Sync.info return info.time..' (+'..(game.tick-info.time_set[1])..' Ticks)' end)
-- optinal dependies
if loaded_modules.Gui then verbose('ExpGamingCore.Gui is installed; Loading gui lib') require(module_path..'/lib/gui') end
if loaded_modules.Ranking then verbose('ExpGamingCore.Ranking is installed; Loading ranking lib') require(module_path..'/lib/ranking') end
end
return Sync